system/corennnnn
リビジョン | 2974d1fb8b0359c52765247aa2cd783e690e91de (tree) |
---|---|
日時 | 2009-07-10 14:02:45 |
作者 | Android (Google) Code Review <android-gerrit@goog...> |
コミッター | Android (Google) Code Review |
Merge change 6741
* changes:
@@ -270,7 +270,7 @@ class Compiler : public ErrorSink { | ||
270 | 270 | } |
271 | 271 | |
272 | 272 | /* Emit a function prolog. |
273 | - * argCount is the number of arguments. | |
273 | + * pDecl is the function declaration, which gives the arguments. | |
274 | 274 | * Save the old value of the FP. |
275 | 275 | * Set the new value of the FP. |
276 | 276 | * Convert from the native platform calling convention to |
@@ -282,7 +282,7 @@ class Compiler : public ErrorSink { | ||
282 | 282 | * functionExit(). |
283 | 283 | * returns address to patch with local variable size. |
284 | 284 | */ |
285 | - virtual int functionEntry(int argCount) = 0; | |
285 | + virtual int functionEntry(Type* pDecl) = 0; | |
286 | 286 | |
287 | 287 | /* Emit a function epilog. |
288 | 288 | * Restore the old SP and FP register values. |
@@ -291,7 +291,7 @@ class Compiler : public ErrorSink { | ||
291 | 291 | * localVariableAddress - returned from functionEntry() |
292 | 292 | * localVariableSize - the size in bytes of the local variables. |
293 | 293 | */ |
294 | - virtual void functionExit(int argCount, int localVariableAddress, | |
294 | + virtual void functionExit(Type* pDecl, int localVariableAddress, | |
295 | 295 | int localVariableSize) = 0; |
296 | 296 | |
297 | 297 | /* load immediate value to R0 */ |
@@ -398,7 +398,7 @@ class Compiler : public ErrorSink { | ||
398 | 398 | * On ARM for example you would pop the first 5 arguments into |
399 | 399 | * R0..R4 |
400 | 400 | */ |
401 | - virtual void endFunctionCallArguments(int a, int l) = 0; | |
401 | + virtual void endFunctionCallArguments(Type* pDecl, int a, int l) = 0; | |
402 | 402 | |
403 | 403 | /* Emit a call to an unknown function. The argument "symbol" needs to |
404 | 404 | * be stored in the location where the address should go. It forms |
@@ -424,7 +424,7 @@ class Compiler : public ErrorSink { | ||
424 | 424 | * is true if this was an indirect call. (In which case the |
425 | 425 | * address of the function is stored at location SP + l.) |
426 | 426 | */ |
427 | - virtual void adjustStackAfterCall(int l, bool isIndirect) = 0; | |
427 | + virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) = 0; | |
428 | 428 | |
429 | 429 | /* Print a disassembly of the assembled code to out. Return |
430 | 430 | * non-zero if there is an error. |
@@ -452,7 +452,7 @@ class Compiler : public ErrorSink { | ||
452 | 452 | /** |
453 | 453 | * Memory alignment (in bytes) for this type of data |
454 | 454 | */ |
455 | - virtual size_t alignment(Type* type) = 0; | |
455 | + virtual size_t alignmentOf(Type* type) = 0; | |
456 | 456 | |
457 | 457 | /** |
458 | 458 | * Array element alignment (in bytes) for this type of data. |
@@ -561,15 +561,15 @@ class Compiler : public ErrorSink { | ||
561 | 561 | |
562 | 562 | /* returns address to patch with local variable size |
563 | 563 | */ |
564 | - virtual int functionEntry(int argCount) { | |
565 | - LOG_API("functionEntry(%d);\n", argCount); | |
564 | + virtual int functionEntry(Type* pDecl) { | |
565 | + LOG_API("functionEntry(%d);\n", pDecl); | |
566 | 566 | mStackUse = 0; |
567 | 567 | // sp -> arg4 arg5 ... |
568 | 568 | // Push our register-based arguments back on the stack |
569 | - if (argCount > 0) { | |
570 | - int regArgCount = argCount <= 4 ? argCount : 4; | |
571 | - o4(0xE92D0000 | ((1 << argCount) - 1)); // stmfd sp!, {} | |
569 | + int regArgCount = calcRegArgCount(pDecl); | |
570 | + if (regArgCount > 0) { | |
572 | 571 | mStackUse += regArgCount * 4; |
572 | + o4(0xE92D0000 | ((1 << regArgCount) - 1)); // stmfd sp!, {} | |
573 | 573 | } |
574 | 574 | // sp -> arg0 arg1 ... |
575 | 575 | o4(0xE92D4800); // stmfd sp!, {fp, lr} |
@@ -583,7 +583,7 @@ class Compiler : public ErrorSink { | ||
583 | 583 | // STACK_ALIGNMENT, so it won't affect the stack alignment. |
584 | 584 | } |
585 | 585 | |
586 | - virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) { | |
586 | + virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) { | |
587 | 587 | LOG_API("functionExit(%d, %d, %d);\n", argCount, localVariableAddress, localVariableSize); |
588 | 588 | // Round local variable size up to a multiple of stack alignment |
589 | 589 | localVariableSize = ((localVariableSize + STACK_ALIGNMENT - 1) / |
@@ -601,12 +601,13 @@ class Compiler : public ErrorSink { | ||
601 | 601 | // sp -> retadr, arg0, ... |
602 | 602 | o4(0xE8BD4000); // ldmfd sp!, {lr} |
603 | 603 | // sp -> arg0 .... |
604 | - if (argCount > 0) { | |
605 | - // We store the PC into the lr so we can adjust the sp before | |
606 | - // returning. We need to pull off the registers we pushed | |
607 | - // earlier. We don't need to actually store them anywhere, | |
608 | - // just adjust the stack. | |
609 | - int regArgCount = argCount <= 4 ? argCount : 4; | |
604 | + | |
605 | + // We store the PC into the lr so we can adjust the sp before | |
606 | + // returning. We need to pull off the registers we pushed | |
607 | + // earlier. We don't need to actually store them anywhere, | |
608 | + // just adjust the stack. | |
609 | + int regArgCount = calcRegArgCount(pDecl); | |
610 | + if (regArgCount) { | |
610 | 611 | o4(0xE28DD000 | (regArgCount << 2)); // add sp, sp, #argCount << 2 |
611 | 612 | } |
612 | 613 | o4(0xE12FFF1E); // bx lr |
@@ -630,8 +631,24 @@ class Compiler : public ErrorSink { | ||
630 | 631 | } |
631 | 632 | |
632 | 633 | virtual void loadFloat(int address, Type* pType) { |
633 | - error("Unimplemented.\n"); | |
634 | 634 | setR0Type(pType); |
635 | + // Global, absolute address | |
636 | + o4(0xE59F0000); // ldr r0, .L1 | |
637 | + o4(0xEA000000); // b .L99 | |
638 | + o4(address); // .L1: .word ea | |
639 | + // .L99: | |
640 | + | |
641 | + switch (pType->tag) { | |
642 | + case TY_FLOAT: | |
643 | + o4(0xE5900000); // ldr r0, [r0] | |
644 | + break; | |
645 | + case TY_DOUBLE: | |
646 | + o4(0xE1C000D0); // ldrd r0, [r0] | |
647 | + break; | |
648 | + default: | |
649 | + assert(false); | |
650 | + break; | |
651 | + } | |
635 | 652 | } |
636 | 653 | |
637 | 654 | virtual int gjmp(int t) { |
@@ -642,6 +659,18 @@ class Compiler : public ErrorSink { | ||
642 | 659 | /* l = 0: je, l == 1: jne */ |
643 | 660 | virtual int gtst(bool l, int t) { |
644 | 661 | LOG_API("gtst(%d, %d);\n", l, t); |
662 | + Type* pR0Type = getR0Type(); | |
663 | + TypeTag tagR0 = pR0Type->tag; | |
664 | + switch(tagR0) { | |
665 | + case TY_FLOAT: | |
666 | + callRuntime((void*) runtime_is_non_zero_f); | |
667 | + break; | |
668 | + case TY_DOUBLE: | |
669 | + callRuntime((void*) runtime_is_non_zero_d); | |
670 | + break; | |
671 | + default: | |
672 | + break; | |
673 | + } | |
645 | 674 | o4(0xE3500000); // cmp r0,#0 |
646 | 675 | int branch = l ? 0x1A000000 : 0x0A000000; // bne : beq |
647 | 676 | return o4(branch | encodeAddress(t)); |
@@ -649,122 +678,273 @@ class Compiler : public ErrorSink { | ||
649 | 678 | |
650 | 679 | virtual void gcmp(int op, Type* pResultType) { |
651 | 680 | LOG_API("gcmp(%d);\n", op); |
652 | - o4(0xE8BD0002); // ldmfd sp!,{r1} | |
653 | - mStackUse -= 4; | |
654 | - o4(0xE1510000); // cmp r1, r1 | |
655 | - switch(op) { | |
656 | - case OP_EQUALS: | |
657 | - o4(0x03A00001); // moveq r0,#1 | |
658 | - o4(0x13A00000); // movne r0,#0 | |
659 | - break; | |
660 | - case OP_NOT_EQUALS: | |
661 | - o4(0x03A00000); // moveq r0,#0 | |
662 | - o4(0x13A00001); // movne r0,#1 | |
663 | - break; | |
664 | - case OP_LESS_EQUAL: | |
665 | - o4(0xD3A00001); // movle r0,#1 | |
666 | - o4(0xC3A00000); // movgt r0,#0 | |
667 | - break; | |
668 | - case OP_GREATER: | |
669 | - o4(0xD3A00000); // movle r0,#0 | |
670 | - o4(0xC3A00001); // movgt r0,#1 | |
671 | - break; | |
672 | - case OP_GREATER_EQUAL: | |
673 | - o4(0xA3A00001); // movge r0,#1 | |
674 | - o4(0xB3A00000); // movlt r0,#0 | |
675 | - break; | |
676 | - case OP_LESS: | |
677 | - o4(0xA3A00000); // movge r0,#0 | |
678 | - o4(0xB3A00001); // movlt r0,#1 | |
679 | - break; | |
680 | - default: | |
681 | - error("Unknown comparison op %d", op); | |
682 | - break; | |
681 | + Type* pR0Type = getR0Type(); | |
682 | + Type* pTOSType = getTOSType(); | |
683 | + TypeTag tagR0 = collapseType(pR0Type->tag); | |
684 | + TypeTag tagTOS = collapseType(pTOSType->tag); | |
685 | + if (tagR0 == TY_INT && tagTOS == TY_INT) { | |
686 | + o4(0xE8BD0002); // ldmfd sp!,{r1} | |
687 | + mStackUse -= 4; | |
688 | + o4(0xE1510000); // cmp r1, r1 | |
689 | + switch(op) { | |
690 | + case OP_EQUALS: | |
691 | + o4(0x03A00001); // moveq r0,#1 | |
692 | + o4(0x13A00000); // movne r0,#0 | |
693 | + break; | |
694 | + case OP_NOT_EQUALS: | |
695 | + o4(0x03A00000); // moveq r0,#0 | |
696 | + o4(0x13A00001); // movne r0,#1 | |
697 | + break; | |
698 | + case OP_LESS_EQUAL: | |
699 | + o4(0xD3A00001); // movle r0,#1 | |
700 | + o4(0xC3A00000); // movgt r0,#0 | |
701 | + break; | |
702 | + case OP_GREATER: | |
703 | + o4(0xD3A00000); // movle r0,#0 | |
704 | + o4(0xC3A00001); // movgt r0,#1 | |
705 | + break; | |
706 | + case OP_GREATER_EQUAL: | |
707 | + o4(0xA3A00001); // movge r0,#1 | |
708 | + o4(0xB3A00000); // movlt r0,#0 | |
709 | + break; | |
710 | + case OP_LESS: | |
711 | + o4(0xA3A00000); // movge r0,#0 | |
712 | + o4(0xB3A00001); // movlt r0,#1 | |
713 | + break; | |
714 | + default: | |
715 | + error("Unknown comparison op %d", op); | |
716 | + break; | |
717 | + } | |
718 | + popType(); | |
719 | + } else if (tagR0 == TY_DOUBLE || tagTOS == TY_DOUBLE) { | |
720 | + setupDoubleArgs(); | |
721 | + switch(op) { | |
722 | + case OP_EQUALS: | |
723 | + callRuntime((void*) runtime_cmp_eq_dd); | |
724 | + break; | |
725 | + case OP_NOT_EQUALS: | |
726 | + callRuntime((void*) runtime_cmp_ne_dd); | |
727 | + break; | |
728 | + case OP_LESS_EQUAL: | |
729 | + callRuntime((void*) runtime_cmp_le_dd); | |
730 | + break; | |
731 | + case OP_GREATER: | |
732 | + callRuntime((void*) runtime_cmp_gt_dd); | |
733 | + break; | |
734 | + case OP_GREATER_EQUAL: | |
735 | + callRuntime((void*) runtime_cmp_ge_dd); | |
736 | + break; | |
737 | + case OP_LESS: | |
738 | + callRuntime((void*) runtime_cmp_lt_dd); | |
739 | + break; | |
740 | + default: | |
741 | + error("Unknown comparison op %d", op); | |
742 | + break; | |
743 | + } | |
744 | + } else { | |
745 | + setupFloatArgs(); | |
746 | + switch(op) { | |
747 | + case OP_EQUALS: | |
748 | + callRuntime((void*) runtime_cmp_eq_ff); | |
749 | + break; | |
750 | + case OP_NOT_EQUALS: | |
751 | + callRuntime((void*) runtime_cmp_ne_ff); | |
752 | + break; | |
753 | + case OP_LESS_EQUAL: | |
754 | + callRuntime((void*) runtime_cmp_le_ff); | |
755 | + break; | |
756 | + case OP_GREATER: | |
757 | + callRuntime((void*) runtime_cmp_gt_ff); | |
758 | + break; | |
759 | + case OP_GREATER_EQUAL: | |
760 | + callRuntime((void*) runtime_cmp_ge_ff); | |
761 | + break; | |
762 | + case OP_LESS: | |
763 | + callRuntime((void*) runtime_cmp_lt_ff); | |
764 | + break; | |
765 | + default: | |
766 | + error("Unknown comparison op %d", op); | |
767 | + break; | |
768 | + } | |
683 | 769 | } |
684 | - popType(); | |
770 | + setR0Type(pResultType); | |
685 | 771 | } |
686 | 772 | |
687 | 773 | virtual void genOp(int op) { |
688 | 774 | LOG_API("genOp(%d);\n", op); |
689 | - o4(0xE8BD0002); // ldmfd sp!,{r1} | |
690 | - mStackUse -= 4; | |
691 | - switch(op) { | |
692 | - case OP_MUL: | |
693 | - o4(0x0E0000091); // mul r0,r1,r0 | |
694 | - break; | |
695 | - case OP_DIV: | |
696 | - callRuntime(runtime_DIV); | |
697 | - break; | |
698 | - case OP_MOD: | |
699 | - callRuntime(runtime_MOD); | |
700 | - break; | |
701 | - case OP_PLUS: | |
702 | - o4(0xE0810000); // add r0,r1,r0 | |
703 | - break; | |
704 | - case OP_MINUS: | |
705 | - o4(0xE0410000); // sub r0,r1,r0 | |
706 | - break; | |
707 | - case OP_SHIFT_LEFT: | |
708 | - o4(0xE1A00011); // lsl r0,r1,r0 | |
709 | - break; | |
710 | - case OP_SHIFT_RIGHT: | |
711 | - o4(0xE1A00051); // asr r0,r1,r0 | |
712 | - break; | |
713 | - case OP_BIT_AND: | |
714 | - o4(0xE0010000); // and r0,r1,r0 | |
715 | - break; | |
716 | - case OP_BIT_XOR: | |
717 | - o4(0xE0210000); // eor r0,r1,r0 | |
718 | - break; | |
719 | - case OP_BIT_OR: | |
720 | - o4(0xE1810000); // orr r0,r1,r0 | |
721 | - break; | |
722 | - case OP_BIT_NOT: | |
723 | - o4(0xE1E00000); // mvn r0, r0 | |
724 | - break; | |
725 | - default: | |
726 | - error("Unimplemented op %d\n", op); | |
727 | - break; | |
775 | + Type* pR0Type = getR0Type(); | |
776 | + Type* pTOSType = getTOSType(); | |
777 | + TypeTag tagR0 = collapseType(pR0Type->tag); | |
778 | + TypeTag tagTOS = collapseType(pTOSType->tag); | |
779 | + if (tagR0 == TY_INT && tagTOS == TY_INT) { | |
780 | + o4(0xE8BD0002); // ldmfd sp!,{r1} | |
781 | + mStackUse -= 4; | |
782 | + switch(op) { | |
783 | + case OP_MUL: | |
784 | + o4(0x0E0000091); // mul r0,r1,r0 | |
785 | + break; | |
786 | + case OP_DIV: | |
787 | + callRuntime((void*) runtime_DIV); | |
788 | + break; | |
789 | + case OP_MOD: | |
790 | + callRuntime((void*) runtime_MOD); | |
791 | + break; | |
792 | + case OP_PLUS: | |
793 | + o4(0xE0810000); // add r0,r1,r0 | |
794 | + break; | |
795 | + case OP_MINUS: | |
796 | + o4(0xE0410000); // sub r0,r1,r0 | |
797 | + break; | |
798 | + case OP_SHIFT_LEFT: | |
799 | + o4(0xE1A00011); // lsl r0,r1,r0 | |
800 | + break; | |
801 | + case OP_SHIFT_RIGHT: | |
802 | + o4(0xE1A00051); // asr r0,r1,r0 | |
803 | + break; | |
804 | + case OP_BIT_AND: | |
805 | + o4(0xE0010000); // and r0,r1,r0 | |
806 | + break; | |
807 | + case OP_BIT_XOR: | |
808 | + o4(0xE0210000); // eor r0,r1,r0 | |
809 | + break; | |
810 | + case OP_BIT_OR: | |
811 | + o4(0xE1810000); // orr r0,r1,r0 | |
812 | + break; | |
813 | + case OP_BIT_NOT: | |
814 | + o4(0xE1E00000); // mvn r0, r0 | |
815 | + break; | |
816 | + default: | |
817 | + error("Unimplemented op %d\n", op); | |
818 | + break; | |
819 | + } | |
820 | + popType(); | |
821 | + } else { | |
822 | + Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType; | |
823 | + if (pResultType->tag == TY_DOUBLE) { | |
824 | + setupDoubleArgs(); | |
825 | + switch(op) { | |
826 | + case OP_MUL: | |
827 | + callRuntime((void*) runtime_op_mul_dd); | |
828 | + break; | |
829 | + case OP_DIV: | |
830 | + callRuntime((void*) runtime_op_div_dd); | |
831 | + break; | |
832 | + case OP_PLUS: | |
833 | + callRuntime((void*) runtime_op_add_dd); | |
834 | + break; | |
835 | + case OP_MINUS: | |
836 | + callRuntime((void*) runtime_op_sub_dd); | |
837 | + break; | |
838 | + default: | |
839 | + error("Unsupported binary floating operation %d\n", op); | |
840 | + break; | |
841 | + } | |
842 | + } else { | |
843 | + setupFloatArgs(); | |
844 | + switch(op) { | |
845 | + case OP_MUL: | |
846 | + callRuntime((void*) runtime_op_mul_ff); | |
847 | + break; | |
848 | + case OP_DIV: | |
849 | + callRuntime((void*) runtime_op_div_ff); | |
850 | + break; | |
851 | + case OP_PLUS: | |
852 | + callRuntime((void*) runtime_op_add_ff); | |
853 | + break; | |
854 | + case OP_MINUS: | |
855 | + callRuntime((void*) runtime_op_sub_ff); | |
856 | + break; | |
857 | + default: | |
858 | + error("Unsupported binary floating operation %d\n", op); | |
859 | + break; | |
860 | + } | |
861 | + } | |
862 | + setR0Type(pResultType); | |
728 | 863 | } |
729 | - popType(); | |
730 | 864 | } |
731 | 865 | |
732 | 866 | virtual void gUnaryCmp(int op, Type* pResultType) { |
733 | 867 | LOG_API("gUnaryCmp(%d);\n", op); |
734 | - o4(0xE3A01000); // mov r1, #0 | |
735 | - o4(0xE1510000); // cmp r1, r1 | |
736 | - switch(op) { | |
737 | - case OP_LOGICAL_NOT: | |
738 | - o4(0x03A00000); // moveq r0,#0 | |
739 | - o4(0x13A00001); // movne r0,#1 | |
740 | - break; | |
741 | - default: | |
742 | - error("Unknown unary comparison op %d", op); | |
743 | - break; | |
868 | + if (op != OP_LOGICAL_NOT) { | |
869 | + error("Unknown unary cmp %d", op); | |
870 | + } else { | |
871 | + Type* pR0Type = getR0Type(); | |
872 | + TypeTag tag = collapseType(pR0Type->tag); | |
873 | + switch(tag) { | |
874 | + case TY_INT: | |
875 | + o4(0xE3A01000); // mov r1, #0 | |
876 | + o4(0xE1510000); // cmp r1, r1 | |
877 | + o4(0x03A00000); // moveq r0,#0 | |
878 | + o4(0x13A00001); // movne r0,#1 | |
879 | + break; | |
880 | + case TY_FLOAT: | |
881 | + callRuntime((void*) runtime_is_zero_f); | |
882 | + break; | |
883 | + case TY_DOUBLE: | |
884 | + callRuntime((void*) runtime_is_zero_d); | |
885 | + break; | |
886 | + default: | |
887 | + error("gUnaryCmp unsupported type"); | |
888 | + break; | |
889 | + } | |
744 | 890 | } |
745 | 891 | setR0Type(pResultType); |
746 | 892 | } |
747 | 893 | |
748 | 894 | virtual void genUnaryOp(int op) { |
749 | 895 | LOG_API("genOp(%d);\n", op); |
750 | - switch(op) { | |
751 | - case OP_MINUS: | |
752 | - o4(0xE3A01000); // mov r1, #0 | |
753 | - o4(0xE0410000); // sub r0,r1,r0 | |
754 | - break; | |
755 | - case OP_BIT_NOT: | |
756 | - o4(0xE1E00000); // mvn r0, r0 | |
757 | - break; | |
758 | - default: | |
759 | - error("Unknown unary op %d\n", op); | |
760 | - break; | |
896 | + Type* pR0Type = getR0Type(); | |
897 | + TypeTag tag = collapseType(pR0Type->tag); | |
898 | + switch(tag) { | |
899 | + case TY_INT: | |
900 | + switch(op) { | |
901 | + case OP_MINUS: | |
902 | + o4(0xE3A01000); // mov r1, #0 | |
903 | + o4(0xE0410000); // sub r0,r1,r0 | |
904 | + break; | |
905 | + case OP_BIT_NOT: | |
906 | + o4(0xE1E00000); // mvn r0, r0 | |
907 | + break; | |
908 | + default: | |
909 | + error("Unknown unary op %d\n", op); | |
910 | + break; | |
911 | + } | |
912 | + break; | |
913 | + case TY_FLOAT: | |
914 | + case TY_DOUBLE: | |
915 | + switch (op) { | |
916 | + case OP_MINUS: | |
917 | + if (tag == TY_FLOAT) { | |
918 | + callRuntime((void*) runtime_op_neg_f); | |
919 | + } else { | |
920 | + callRuntime((void*) runtime_op_neg_d); | |
921 | + } | |
922 | + break; | |
923 | + case OP_BIT_NOT: | |
924 | + error("Can't apply '~' operator to a float or double."); | |
925 | + break; | |
926 | + default: | |
927 | + error("Unknown unary op %d\n", op); | |
928 | + break; | |
929 | + } | |
930 | + break; | |
931 | + default: | |
932 | + error("genUnaryOp unsupported type"); | |
933 | + break; | |
761 | 934 | } |
762 | 935 | } |
763 | 936 | |
764 | 937 | virtual void pushR0() { |
765 | 938 | LOG_API("pushR0();\n"); |
766 | - o4(0xE92D0001); // stmfd sp!,{r0} | |
767 | - mStackUse += 4; | |
939 | + Type* pR0Type = getR0Type(); | |
940 | + TypeTag r0ct = collapseType(pR0Type->tag); | |
941 | + if (r0ct != TY_DOUBLE) { | |
942 | + o4(0xE92D0001); // stmfd sp!,{r0} | |
943 | + mStackUse += 4; | |
944 | + } else { | |
945 | + o4(0xE92D0003); // stmfd sp!,{r0,r1} | |
946 | + mStackUse += 8; | |
947 | + } | |
768 | 948 | pushType(); |
769 | 949 | LOG_STACK("pushR0: %d\n", mStackUse); |
770 | 950 | } |
@@ -772,20 +952,24 @@ class Compiler : public ErrorSink { | ||
772 | 952 | virtual void storeR0ToTOS(Type* pPointerType) { |
773 | 953 | LOG_API("storeR0ToTOS(%d);\n", isInt); |
774 | 954 | assert(pPointerType->tag == TY_POINTER); |
775 | - o4(0xE8BD0002); // ldmfd sp!,{r1} | |
955 | + o4(0xE8BD0004); // ldmfd sp!,{r2} | |
956 | + popType(); | |
776 | 957 | mStackUse -= 4; |
777 | 958 | switch (pPointerType->pHead->tag) { |
778 | 959 | case TY_INT: |
779 | - o4(0xE5810000); // str r0, [r1] | |
960 | + case TY_FLOAT: | |
961 | + o4(0xE5820000); // str r0, [r2] | |
780 | 962 | break; |
781 | 963 | case TY_CHAR: |
782 | - o4(0xE5C10000); // strb r0, [r1] | |
964 | + o4(0xE5C20000); // strb r0, [r2] | |
965 | + break; | |
966 | + case TY_DOUBLE: | |
967 | + o4(0xE1C200F0); // strd r0, [r2] | |
783 | 968 | break; |
784 | 969 | default: |
785 | 970 | error("storeR0ToTOS: unimplemented type"); |
786 | 971 | break; |
787 | 972 | } |
788 | - popType(); | |
789 | 973 | } |
790 | 974 | |
791 | 975 | virtual void loadR0FromR0(Type* pPointerType) { |
@@ -793,11 +977,15 @@ class Compiler : public ErrorSink { | ||
793 | 977 | assert(pPointerType->tag == TY_POINTER); |
794 | 978 | switch (pPointerType->pHead->tag) { |
795 | 979 | case TY_INT: |
980 | + case TY_FLOAT: | |
796 | 981 | o4(0xE5900000); // ldr r0, [r0] |
797 | 982 | break; |
798 | 983 | case TY_CHAR: |
799 | 984 | o4(0xE5D00000); // ldrb r0, [r0] |
800 | 985 | break; |
986 | + case TY_DOUBLE: | |
987 | + o4(0xE1C000D0); // ldrd r0, [r0] | |
988 | + break; | |
801 | 989 | default: |
802 | 990 | error("loadR0FromR0: unimplemented type"); |
803 | 991 | break; |
@@ -807,7 +995,7 @@ class Compiler : public ErrorSink { | ||
807 | 995 | |
808 | 996 | virtual void leaR0(int ea, Type* pPointerType) { |
809 | 997 | LOG_API("leaR0(%d);\n", ea); |
810 | - if (ea < LOCAL) { | |
998 | + if (ea > -LOCAL && ea < LOCAL) { | |
811 | 999 | // Local, fp relative |
812 | 1000 | if (ea < -1023 || ea > 1023 || ((ea & 3) != 0)) { |
813 | 1001 | error("Offset out of range: %08x", ea); |
@@ -829,69 +1017,147 @@ class Compiler : public ErrorSink { | ||
829 | 1017 | |
830 | 1018 | virtual void storeR0(int ea, Type* pType) { |
831 | 1019 | LOG_API("storeR0(%d);\n", ea); |
832 | - if (ea < LOCAL) { | |
833 | - // Local, fp relative | |
834 | - if (ea < -4095 || ea > 4095) { | |
835 | - error("Offset out of range: %08x", ea); | |
836 | - } | |
837 | - if (ea < 0) { | |
838 | - o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea] | |
839 | - } else { | |
840 | - o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea] | |
841 | - } | |
842 | - } else{ | |
843 | - // Global, absolute | |
844 | - o4(0xE59F1000); // ldr r1, .L1 | |
845 | - o4(0xEA000000); // b .L99 | |
846 | - o4(ea); // .L1: .word 0 | |
847 | - o4(0xE5810000); // .L99: str r0, [r1] | |
1020 | + TypeTag tag = pType->tag; | |
1021 | + switch (tag) { | |
1022 | + case TY_INT: | |
1023 | + case TY_FLOAT: | |
1024 | + if (ea > -LOCAL && ea < LOCAL) { | |
1025 | + // Local, fp relative | |
1026 | + if (ea < -4095 || ea > 4095) { | |
1027 | + error("Offset out of range: %08x", ea); | |
1028 | + } | |
1029 | + if (ea < 0) { | |
1030 | + o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea] | |
1031 | + } else { | |
1032 | + o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea] | |
1033 | + } | |
1034 | + } else{ | |
1035 | + // Global, absolute | |
1036 | + o4(0xE59F1000); // ldr r1, .L1 | |
1037 | + o4(0xEA000000); // b .L99 | |
1038 | + o4(ea); // .L1: .word 0 | |
1039 | + o4(0xE5810000); // .L99: str r0, [r1] | |
1040 | + } | |
1041 | + break; | |
1042 | + case TY_DOUBLE: | |
1043 | + if ((ea & 0x7) != 0) { | |
1044 | + error("double address is not aligned: %d", ea); | |
1045 | + } | |
1046 | + if (ea > -LOCAL && ea < LOCAL) { | |
1047 | + // Local, fp relative | |
1048 | + if (ea < -4095 || ea > 4095) { | |
1049 | + error("Offset out of range: %08x", ea); | |
1050 | + } | |
1051 | + if (ea < 0) { | |
1052 | + o4(0xE50B0000 | (0xfff & (-ea))); // str r0, [fp,#-ea] | |
1053 | + o4(0xE50B1000 | (0xfff & (-ea + 4))); // str r1, [fp,#-ea+4] | |
1054 | +#if 0 | |
1055 | + // strd doesn't seem to work. Is encoding wrong? | |
1056 | + } else if (ea < 0) { | |
1057 | + o4(0xE1CB000F | ((0xff & (-ea)) << 4)); // strd r0, [fp,#-ea] | |
1058 | + } else if (ea < 256) { | |
1059 | + o4(0xE14B000F | ((0xff & ea) << 4)); // strd r0, [fp,#ea] | |
1060 | +#endif | |
1061 | + } else { | |
1062 | + o4(0xE58B0000 | (0xfff & ea)); // str r0, [fp,#ea] | |
1063 | + o4(0xE58B1000 | (0xfff & (ea + 4))); // str r1, [fp,#ea+4] | |
1064 | + } | |
1065 | + } else{ | |
1066 | + // Global, absolute | |
1067 | + o4(0xE59F2000); // ldr r2, .L1 | |
1068 | + o4(0xEA000000); // b .L99 | |
1069 | + o4(ea); // .L1: .word 0 | |
1070 | + o4(0xE1C200F0); // .L99: strd r0, [r2] | |
1071 | + } | |
1072 | + break; | |
1073 | + default: | |
1074 | + error("Unable to store to type %d", tag); | |
1075 | + break; | |
848 | 1076 | } |
849 | 1077 | } |
850 | 1078 | |
851 | 1079 | virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) { |
852 | 1080 | LOG_API("loadR0(%d, %d, %d, %d);\n", ea, isIncDec, op, pType); |
853 | - if (ea < LOCAL) { | |
854 | - // Local, fp relative | |
855 | - if (ea < -4095 || ea > 4095) { | |
856 | - error("Offset out of range: %08x", ea); | |
857 | - } | |
858 | - if (ea < 0) { | |
859 | - o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea] | |
860 | - } else { | |
861 | - o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea] | |
862 | - } | |
863 | - } else { | |
864 | - // Global, absolute | |
865 | - o4(0xE59F2000); // ldr r2, .L1 | |
866 | - o4(0xEA000000); // b .L99 | |
867 | - o4(ea); // .L1: .word ea | |
868 | - o4(0xE5920000); // .L99: ldr r0, [r2] | |
869 | - } | |
1081 | + TypeTag tag = collapseType(pType->tag); | |
1082 | + switch (tag) { | |
1083 | + case TY_INT: | |
1084 | + case TY_FLOAT: | |
1085 | + if (ea < LOCAL) { | |
1086 | + // Local, fp relative | |
1087 | + if (ea < -4095 || ea > 4095) { | |
1088 | + error("Offset out of range: %08x", ea); | |
1089 | + } | |
1090 | + if (ea < 0) { | |
1091 | + o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea] | |
1092 | + } else { | |
1093 | + o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea] | |
1094 | + } | |
1095 | + } else { | |
1096 | + // Global, absolute | |
1097 | + o4(0xE59F2000); // ldr r2, .L1 | |
1098 | + o4(0xEA000000); // b .L99 | |
1099 | + o4(ea); // .L1: .word ea | |
1100 | + o4(0xE5920000); // .L99: ldr r0, [r2] | |
1101 | + } | |
870 | 1102 | |
871 | - if (isIncDec) { | |
872 | - switch (op) { | |
873 | - case OP_INCREMENT: | |
874 | - o4(0xE2801001); // add r1, r0, #1 | |
875 | - break; | |
876 | - case OP_DECREMENT: | |
877 | - o4(0xE2401001); // sub r1, r0, #1 | |
1103 | + if (isIncDec) { | |
1104 | + if (tag == TY_INT) { | |
1105 | + switch (op) { | |
1106 | + case OP_INCREMENT: | |
1107 | + o4(0xE2801001); // add r1, r0, #1 | |
1108 | + break; | |
1109 | + case OP_DECREMENT: | |
1110 | + o4(0xE2401001); // sub r1, r0, #1 | |
1111 | + break; | |
1112 | + default: | |
1113 | + error("unknown opcode: %d", op); | |
1114 | + } | |
1115 | + if (ea < LOCAL) { | |
1116 | + // Local, fp relative | |
1117 | + // Don't need range check, was already checked above | |
1118 | + if (ea < 0) { | |
1119 | + o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea] | |
1120 | + } else { | |
1121 | + o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea] | |
1122 | + } | |
1123 | + } else{ | |
1124 | + // Global, absolute | |
1125 | + // r2 is already set up from before. | |
1126 | + o4(0xE5821000); // str r1, [r2] | |
1127 | + } | |
1128 | + } | |
1129 | + else { | |
1130 | + error("inc/dec not implemented for float."); | |
1131 | + } | |
1132 | + } | |
878 | 1133 | break; |
879 | - default: | |
880 | - error("unknown opcode: %d", op); | |
881 | - } | |
882 | - if (ea < LOCAL) { | |
883 | - // Local, fp relative | |
884 | - // Don't need range check, was already checked above | |
885 | - if (ea < 0) { | |
886 | - o4(0xE50B1000 | (0xfff & (-ea))); // str r1, [fp,#-ea] | |
1134 | + case TY_DOUBLE: | |
1135 | + if ((ea & 0x7) != 0) { | |
1136 | + error("double address is not aligned: %d", ea); | |
1137 | + } | |
1138 | + if (ea < LOCAL) { | |
1139 | + // Local, fp relative | |
1140 | + if (ea < -4095 || ea > 4095) { | |
1141 | + error("Offset out of range: %08x", ea); | |
1142 | + } | |
1143 | + if (ea < 0) { | |
1144 | + o4(0xE51B0000 | (0xfff & (-ea))); // ldr r0, [fp,#-ea] | |
1145 | + o4(0xE51B1000 | (0xfff & (-ea+4))); // ldr r1, [fp,#-ea+4] | |
1146 | + } else { | |
1147 | + o4(0xE59B0000 | (0xfff & ea)); // ldr r0, [fp,#ea] | |
1148 | + o4(0xE59B1000 | (0xfff & (ea+4))); // ldr r0, [fp,#ea+4] | |
1149 | + } | |
887 | 1150 | } else { |
888 | - o4(0xE58B1000 | (0xfff & ea)); // str r1, [fp,#ea] | |
1151 | + // Global, absolute | |
1152 | + o4(0xE59F2000); // ldr r2, .L1 | |
1153 | + o4(0xEA000000); // b .L99 | |
1154 | + o4(ea); // .L1: .word ea | |
1155 | + o4(0xE1C200D0); // .L99: ldrd r0, [r2] | |
889 | 1156 | } |
890 | - } else{ | |
891 | - // Global, absolute | |
892 | - // r2 is already set up from before. | |
893 | - o4(0xE5821000); // str r1, [r2] | |
894 | - } | |
1157 | + break; | |
1158 | + default: | |
1159 | + error("Unable to load type %d", tag); | |
1160 | + break; | |
895 | 1161 | } |
896 | 1162 | setR0Type(pType); |
897 | 1163 | } |
@@ -900,11 +1166,32 @@ class Compiler : public ErrorSink { | ||
900 | 1166 | Type* pR0Type = getR0Type(); |
901 | 1167 | if (bitsSame(pType, pR0Type)) { |
902 | 1168 | // do nothing special |
903 | - } else if (isFloatType(pType) && isFloatType(pR0Type)) { | |
904 | - // do nothing special, both held in same register on x87. | |
905 | 1169 | } else { |
906 | - error("Incompatible types old: %d new: %d", | |
907 | - pR0Type->tag, pType->tag); | |
1170 | + TypeTag r0Tag = collapseType(pR0Type->tag); | |
1171 | + TypeTag destTag = collapseType(pType->tag); | |
1172 | + if (r0Tag == TY_INT) { | |
1173 | + if (destTag == TY_FLOAT) { | |
1174 | + callRuntime((void*) runtime_int_to_float); | |
1175 | + } else { | |
1176 | + assert(destTag == TY_DOUBLE); | |
1177 | + callRuntime((void*) runtime_int_to_double); | |
1178 | + } | |
1179 | + } else if (r0Tag == TY_FLOAT) { | |
1180 | + if (destTag == TY_INT) { | |
1181 | + callRuntime((void*) runtime_float_to_int); | |
1182 | + } else { | |
1183 | + assert(destTag == TY_DOUBLE); | |
1184 | + callRuntime((void*) runtime_float_to_double); | |
1185 | + } | |
1186 | + } else { | |
1187 | + assert (r0Tag == TY_DOUBLE); | |
1188 | + if (destTag == TY_INT) { | |
1189 | + callRuntime((void*) runtime_double_to_int); | |
1190 | + } else { | |
1191 | + assert(destTag == TY_FLOAT); | |
1192 | + callRuntime((void*) runtime_double_to_float); | |
1193 | + } | |
1194 | + } | |
908 | 1195 | } |
909 | 1196 | setR0Type(pType); |
910 | 1197 | } |
@@ -916,19 +1203,42 @@ class Compiler : public ErrorSink { | ||
916 | 1203 | |
917 | 1204 | virtual size_t storeR0ToArg(int l) { |
918 | 1205 | LOG_API("storeR0ToArg(%d);\n", l); |
919 | - if (l < 0 || l > 4096-4) { | |
920 | - error("l out of range for stack offset: 0x%08x", l); | |
1206 | + Type* pR0Type = getR0Type(); | |
1207 | + TypeTag r0ct = collapseType(pR0Type->tag); | |
1208 | + switch(r0ct) { | |
1209 | + case TY_INT: | |
1210 | + case TY_FLOAT: | |
1211 | + if (l < 0 || l > 4096-4) { | |
1212 | + error("l out of range for stack offset: 0x%08x", l); | |
1213 | + } | |
1214 | + o4(0xE58D0000 + l); // str r0, [sp, #l] | |
1215 | + return 4; | |
1216 | + case TY_DOUBLE: { | |
1217 | + // Align to 8 byte boundary | |
1218 | + int l2 = (l + 7) & ~7; | |
1219 | + if (l2 < 0 || l2 > 4096-8) { | |
1220 | + error("l out of range for stack offset: 0x%08x", l); | |
1221 | + } | |
1222 | + o4(0xE58D0000 + l2); // str r0, [sp, #l] | |
1223 | + o4(0xE58D1000 + l2 + 4); // str r1, [sp, #l+4] | |
1224 | + return (l2 - l) + 8; | |
1225 | + } | |
1226 | + default: | |
1227 | + assert(false); | |
1228 | + return 0; | |
921 | 1229 | } |
922 | - o4(0xE58D0000 + l); // str r0, [sp, #4] | |
923 | - return 4; | |
924 | 1230 | } |
925 | 1231 | |
926 | - virtual void endFunctionCallArguments(int a, int l) { | |
1232 | + virtual void endFunctionCallArguments(Type* pDecl, int a, int l) { | |
927 | 1233 | LOG_API("endFunctionCallArguments(0x%08x, %d);\n", a, l); |
928 | - int argCount = l >> 2; | |
929 | 1234 | int argumentStackUse = l; |
930 | - if (argCount > 0) { | |
931 | - int regArgCount = argCount > 4 ? 4 : argCount; | |
1235 | + // Have to calculate register arg count from actual stack size, | |
1236 | + // in order to properly handle ... functions. | |
1237 | + int regArgCount = l >> 2; | |
1238 | + if (regArgCount > 4) { | |
1239 | + regArgCount = 4; | |
1240 | + } | |
1241 | + if (regArgCount > 0) { | |
932 | 1242 | argumentStackUse -= regArgCount * 4; |
933 | 1243 | o4(0xE8BD0000 | ((1 << regArgCount) - 1)); // ldmfd sp!,{} |
934 | 1244 | } |
@@ -989,10 +1299,16 @@ class Compiler : public ErrorSink { | ||
989 | 1299 | o4(0xE12FFF3C); // blx r12 |
990 | 1300 | } |
991 | 1301 | |
992 | - virtual void adjustStackAfterCall(int l, bool isIndirect) { | |
1302 | + virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) { | |
993 | 1303 | LOG_API("adjustStackAfterCall(%d, %d);\n", l, isIndirect); |
994 | 1304 | int argCount = l >> 2; |
995 | - int stackArgs = argCount > 4 ? argCount - 4 : 0; | |
1305 | + // Have to calculate register arg count from actual stack size, | |
1306 | + // in order to properly handle ... functions. | |
1307 | + int regArgCount = l >> 2; | |
1308 | + if (regArgCount > 4) { | |
1309 | + regArgCount = 4; | |
1310 | + } | |
1311 | + int stackArgs = argCount - regArgCount; | |
996 | 1312 | int stackUse = stackArgs + (isIndirect ? 1 : 0) |
997 | 1313 | + (mStackAlignmentAdjustment >> 2); |
998 | 1314 | if (stackUse) { |
@@ -1062,7 +1378,7 @@ class Compiler : public ErrorSink { | ||
1062 | 1378 | /** |
1063 | 1379 | * alignment (in bytes) for this type of data |
1064 | 1380 | */ |
1065 | - virtual size_t alignment(Type* pType){ | |
1381 | + virtual size_t alignmentOf(Type* pType){ | |
1066 | 1382 | switch(pType->tag) { |
1067 | 1383 | case TY_DOUBLE: |
1068 | 1384 | return 8; |
@@ -1141,20 +1457,251 @@ class Compiler : public ErrorSink { | ||
1141 | 1457 | return BRANCH_REL_ADDRESS_MASK & (value >> 2); |
1142 | 1458 | } |
1143 | 1459 | |
1144 | - typedef int (*int2FnPtr)(int a, int b); | |
1145 | - void callRuntime(int2FnPtr fn) { | |
1146 | - o4(0xE59F2000); // ldr r2, .L1 | |
1460 | + int calcRegArgCount(Type* pDecl) { | |
1461 | + int reg = 0; | |
1462 | + Type* pArgs = pDecl->pTail; | |
1463 | + while (pArgs && reg < 4) { | |
1464 | + Type* pArg = pArgs->pHead; | |
1465 | + if ( pArg->tag == TY_DOUBLE) { | |
1466 | + int evenReg = (reg + 1) & ~1; | |
1467 | + if (evenReg >= 4) { | |
1468 | + break; | |
1469 | + } | |
1470 | + reg = evenReg + 2; | |
1471 | + } else { | |
1472 | + reg++; | |
1473 | + } | |
1474 | + pArgs = pArgs->pTail; | |
1475 | + } | |
1476 | + return reg; | |
1477 | + } | |
1478 | + | |
1479 | + /* Pop TOS to R1 | |
1480 | + * Make sure both R0 and TOS are floats. (Could be ints) | |
1481 | + * We know that at least one of R0 and TOS is already a float | |
1482 | + */ | |
1483 | + void setupFloatArgs() { | |
1484 | + Type* pR0Type = getR0Type(); | |
1485 | + Type* pTOSType = getTOSType(); | |
1486 | + TypeTag tagR0 = collapseType(pR0Type->tag); | |
1487 | + TypeTag tagTOS = collapseType(pTOSType->tag); | |
1488 | + if (tagR0 != TY_FLOAT) { | |
1489 | + assert(tagR0 == TY_INT); | |
1490 | + callRuntime((void*) runtime_int_to_float); | |
1491 | + } | |
1492 | + if (tagTOS != TY_FLOAT) { | |
1493 | + assert(tagTOS == TY_INT); | |
1494 | + assert(tagR0 == TY_FLOAT); | |
1495 | + o4(0xE92D0001); // stmfd sp!,{r0} // push R0 | |
1496 | + o4(0xE59D0004); // ldr r0, [sp, #4] | |
1497 | + callRuntime((void*) runtime_int_to_float); | |
1498 | + o4(0xE1A01000); // mov r1, r0 | |
1499 | + o4(0xE8BD0001); // ldmfd sp!,{r0} // pop R0 | |
1500 | + o4(0xE28DD004); // add sp, sp, #4 // Pop sp | |
1501 | + } else { | |
1502 | + // Pop TOS | |
1503 | + o4(0xE8BD0002); // ldmfd sp!,{r1} | |
1504 | + } | |
1505 | + mStackUse -= 4; | |
1506 | + popType(); | |
1507 | + } | |
1508 | + | |
1509 | + /* Pop TOS into R2..R3 | |
1510 | + * Make sure both R0 and TOS are doubles. Could be floats or ints. | |
1511 | + * We know that at least one of R0 and TOS are already a double. | |
1512 | + */ | |
1513 | + | |
1514 | + void setupDoubleArgs() { | |
1515 | + Type* pR0Type = getR0Type(); | |
1516 | + Type* pTOSType = getTOSType(); | |
1517 | + TypeTag tagR0 = collapseType(pR0Type->tag); | |
1518 | + TypeTag tagTOS = collapseType(pTOSType->tag); | |
1519 | + if (tagR0 != TY_DOUBLE) { | |
1520 | + if (tagR0 == TY_INT) { | |
1521 | + callRuntime((void*) runtime_int_to_double); | |
1522 | + } else { | |
1523 | + assert(tagR0 == TY_FLOAT); | |
1524 | + callRuntime((void*) runtime_float_to_double); | |
1525 | + } | |
1526 | + } | |
1527 | + if (tagTOS != TY_DOUBLE) { | |
1528 | + o4(0xE92D0003); // stmfd sp!,{r0,r1} // push r0,r1 | |
1529 | + o4(0xE59D0008); // ldr r0, [sp, #8] | |
1530 | + if (tagTOS == TY_INT) { | |
1531 | + callRuntime((void*) runtime_int_to_double); | |
1532 | + } else { | |
1533 | + assert(tagTOS == TY_FLOAT); | |
1534 | + callRuntime((void*) runtime_float_to_double); | |
1535 | + } | |
1536 | + o4(0xE1A02000); // mov r2, r0 | |
1537 | + o4(0xE1A03001); // mov r3, r1 | |
1538 | + o4(0xE8BD0003); // ldmfd sp!,{r0, r1} // Restore R0 | |
1539 | + o4(0xE28DD004); // add sp, sp, #4 // Pop sp | |
1540 | + mStackUse -= 4; | |
1541 | + } else { | |
1542 | + o4(0xE8BD000C); // ldmfd sp!,{r2,r3} | |
1543 | + mStackUse -= 8; | |
1544 | + } | |
1545 | + popType(); | |
1546 | + } | |
1547 | + | |
1548 | + void callRuntime(void* fn) { | |
1549 | + o4(0xE59FC000); // ldr r12, .L1 | |
1147 | 1550 | o4(0xEA000000); // b .L99 |
1148 | 1551 | o4((int) fn); //.L1: .word fn |
1149 | - o4(0xE12FFF32); //.L99: blx r2 | |
1552 | + o4(0xE12FFF3C); //.L99: blx r12 | |
1553 | + } | |
1554 | + | |
1555 | + // Integer math: | |
1556 | + | |
1557 | + static int runtime_DIV(int b, int a) { | |
1558 | + return a / b; | |
1559 | + } | |
1560 | + | |
1561 | + static int runtime_MOD(int b, int a) { | |
1562 | + return a % b; | |
1563 | + } | |
1564 | + | |
1565 | + // Comparison to zero | |
1566 | + | |
1567 | + static int runtime_is_non_zero_f(float a) { | |
1568 | + return a != 0; | |
1569 | + } | |
1570 | + | |
1571 | + static int runtime_is_non_zero_d(double a) { | |
1572 | + return a != 0; | |
1573 | + } | |
1574 | + | |
1575 | + // Comparison to zero | |
1576 | + | |
1577 | + static int runtime_is_zero_f(float a) { | |
1578 | + return a == 0; | |
1579 | + } | |
1580 | + | |
1581 | + static int runtime_is_zero_d(double a) { | |
1582 | + return a == 0; | |
1583 | + } | |
1584 | + | |
1585 | + // Type conversion | |
1586 | + | |
1587 | + static int runtime_float_to_int(float a) { | |
1588 | + return (int) a; | |
1589 | + } | |
1590 | + | |
1591 | + static double runtime_float_to_double(float a) { | |
1592 | + return (double) a; | |
1150 | 1593 | } |
1151 | 1594 | |
1152 | - static int runtime_DIV(int a, int b) { | |
1153 | - return b / a; | |
1595 | + static int runtime_double_to_int(double a) { | |
1596 | + return (int) a; | |
1154 | 1597 | } |
1155 | 1598 | |
1156 | - static int runtime_MOD(int a, int b) { | |
1157 | - return b % a; | |
1599 | + static float runtime_double_to_float(double a) { | |
1600 | + return (float) a; | |
1601 | + } | |
1602 | + | |
1603 | + static float runtime_int_to_float(int a) { | |
1604 | + return (float) a; | |
1605 | + } | |
1606 | + | |
1607 | + static double runtime_int_to_double(int a) { | |
1608 | + return (double) a; | |
1609 | + } | |
1610 | + | |
1611 | + // Comparisons float | |
1612 | + | |
1613 | + static int runtime_cmp_eq_ff(float b, float a) { | |
1614 | + return a == b; | |
1615 | + } | |
1616 | + | |
1617 | + static int runtime_cmp_ne_ff(float b, float a) { | |
1618 | + return a != b; | |
1619 | + } | |
1620 | + | |
1621 | + static int runtime_cmp_lt_ff(float b, float a) { | |
1622 | + return a < b; | |
1623 | + } | |
1624 | + | |
1625 | + static int runtime_cmp_le_ff(float b, float a) { | |
1626 | + return a <= b; | |
1627 | + } | |
1628 | + | |
1629 | + static int runtime_cmp_ge_ff(float b, float a) { | |
1630 | + return a >= b; | |
1631 | + } | |
1632 | + | |
1633 | + static int runtime_cmp_gt_ff(float b, float a) { | |
1634 | + return a > b; | |
1635 | + } | |
1636 | + | |
1637 | + // Comparisons double | |
1638 | + | |
1639 | + static int runtime_cmp_eq_dd(double b, double a) { | |
1640 | + return a == b; | |
1641 | + } | |
1642 | + | |
1643 | + static int runtime_cmp_ne_dd(double b, double a) { | |
1644 | + return a != b; | |
1645 | + } | |
1646 | + | |
1647 | + static int runtime_cmp_lt_dd(double b, double a) { | |
1648 | + return a < b; | |
1649 | + } | |
1650 | + | |
1651 | + static int runtime_cmp_le_dd(double b, double a) { | |
1652 | + return a <= b; | |
1653 | + } | |
1654 | + | |
1655 | + static int runtime_cmp_ge_dd(double b, double a) { | |
1656 | + return a >= b; | |
1657 | + } | |
1658 | + | |
1659 | + static int runtime_cmp_gt_dd(double b, double a) { | |
1660 | + return a > b; | |
1661 | + } | |
1662 | + | |
1663 | + // Math float | |
1664 | + | |
1665 | + static float runtime_op_add_ff(float b, float a) { | |
1666 | + return a + b; | |
1667 | + } | |
1668 | + | |
1669 | + static float runtime_op_sub_ff(float b, float a) { | |
1670 | + return a - b; | |
1671 | + } | |
1672 | + | |
1673 | + static float runtime_op_mul_ff(float b, float a) { | |
1674 | + return a * b; | |
1675 | + } | |
1676 | + | |
1677 | + static float runtime_op_div_ff(float b, float a) { | |
1678 | + return a / b; | |
1679 | + } | |
1680 | + | |
1681 | + static float runtime_op_neg_f(float a) { | |
1682 | + return -a; | |
1683 | + } | |
1684 | + | |
1685 | + // Math double | |
1686 | + | |
1687 | + static double runtime_op_add_dd(double b, double a) { | |
1688 | + return a + b; | |
1689 | + } | |
1690 | + | |
1691 | + static double runtime_op_sub_dd(double b, double a) { | |
1692 | + return a - b; | |
1693 | + } | |
1694 | + | |
1695 | + static double runtime_op_mul_dd(double b, double a) { | |
1696 | + return a * b; | |
1697 | + } | |
1698 | + | |
1699 | + static double runtime_op_div_dd(double b, double a) { | |
1700 | + return a / b; | |
1701 | + } | |
1702 | + | |
1703 | + static double runtime_op_neg_d(double a) { | |
1704 | + return -a; | |
1158 | 1705 | } |
1159 | 1706 | |
1160 | 1707 | static const int STACK_ALIGNMENT = 8; |
@@ -1176,12 +1723,12 @@ class Compiler : public ErrorSink { | ||
1176 | 1723 | |
1177 | 1724 | /* returns address to patch with local variable size |
1178 | 1725 | */ |
1179 | - virtual int functionEntry(int argCount) { | |
1726 | + virtual int functionEntry(Type* pDecl) { | |
1180 | 1727 | o(0xe58955); /* push %ebp, mov %esp, %ebp */ |
1181 | 1728 | return oad(0xec81, 0); /* sub $xxx, %esp */ |
1182 | 1729 | } |
1183 | 1730 | |
1184 | - virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) { | |
1731 | + virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) { | |
1185 | 1732 | o(0xc3c9); /* leave, ret */ |
1186 | 1733 | *(int *) localVariableAddress = localVariableSize; /* save local variables */ |
1187 | 1734 | } |
@@ -1333,7 +1880,6 @@ class Compiler : public ErrorSink { | ||
1333 | 1880 | error("Unsupported binary floating operation."); |
1334 | 1881 | break; |
1335 | 1882 | } |
1336 | - popType(); | |
1337 | 1883 | setR0Type(pResultType); |
1338 | 1884 | } |
1339 | 1885 | } |
@@ -1368,7 +1914,7 @@ class Compiler : public ErrorSink { | ||
1368 | 1914 | o(0x01f083); // xorl $1, %eax |
1369 | 1915 | break; |
1370 | 1916 | default: |
1371 | - error("genUnaryCmp unsupported type"); | |
1917 | + error("gUnaryCmp unsupported type"); | |
1372 | 1918 | break; |
1373 | 1919 | } |
1374 | 1920 | } |
@@ -1607,7 +2153,7 @@ class Compiler : public ErrorSink { | ||
1607 | 2153 | } |
1608 | 2154 | } |
1609 | 2155 | |
1610 | - virtual void endFunctionCallArguments(int a, int l) { | |
2156 | + virtual void endFunctionCallArguments(Type* pDecl, int a, int l) { | |
1611 | 2157 | * (int*) a = l; |
1612 | 2158 | } |
1613 | 2159 |
@@ -1626,7 +2172,7 @@ class Compiler : public ErrorSink { | ||
1626 | 2172 | oad(0x2494ff, l); /* call *xxx(%esp) */ |
1627 | 2173 | } |
1628 | 2174 | |
1629 | - virtual void adjustStackAfterCall(int l, bool isIndirect) { | |
2175 | + virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) { | |
1630 | 2176 | if (isIndirect) { |
1631 | 2177 | l += 4; |
1632 | 2178 | } |
@@ -1668,13 +2214,8 @@ class Compiler : public ErrorSink { | ||
1668 | 2214 | /** |
1669 | 2215 | * Alignment (in bytes) for this type of data |
1670 | 2216 | */ |
1671 | - virtual size_t alignment(Type* pType){ | |
1672 | - switch(pType->tag) { | |
1673 | - case TY_DOUBLE: | |
1674 | - return 8; | |
1675 | - default: | |
1676 | - return 4; | |
1677 | - } | |
2217 | + virtual size_t alignmentOf(Type* pType){ | |
2218 | + return 4; | |
1678 | 2219 | } |
1679 | 2220 | |
1680 | 2221 | /** |
@@ -1782,6 +2323,7 @@ class Compiler : public ErrorSink { | ||
1782 | 2323 | o(0x58); // pop %eax |
1783 | 2324 | } |
1784 | 2325 | } |
2326 | + popType(); | |
1785 | 2327 | } |
1786 | 2328 | }; |
1787 | 2329 |
@@ -1811,16 +2353,16 @@ class Compiler : public ErrorSink { | ||
1811 | 2353 | |
1812 | 2354 | /* returns address to patch with local variable size |
1813 | 2355 | */ |
1814 | - virtual int functionEntry(int argCount) { | |
1815 | - int result = mpBase->functionEntry(argCount); | |
1816 | - fprintf(stderr, "functionEntry(%d) -> %d\n", argCount, result); | |
2356 | + virtual int functionEntry(Type* pDecl) { | |
2357 | + int result = mpBase->functionEntry(pDecl); | |
2358 | + fprintf(stderr, "functionEntry(pDecl) -> %d\n", result); | |
1817 | 2359 | return result; |
1818 | 2360 | } |
1819 | 2361 | |
1820 | - virtual void functionExit(int argCount, int localVariableAddress, int localVariableSize) { | |
1821 | - fprintf(stderr, "functionExit(%d, %d, %d)\n", | |
1822 | - argCount, localVariableAddress, localVariableSize); | |
1823 | - mpBase->functionExit(argCount, localVariableAddress, localVariableSize); | |
2362 | + virtual void functionExit(Type* pDecl, int localVariableAddress, int localVariableSize) { | |
2363 | + fprintf(stderr, "functionExit(pDecl, %d, %d)\n", | |
2364 | + localVariableAddress, localVariableSize); | |
2365 | + mpBase->functionExit(pDecl, localVariableAddress, localVariableSize); | |
1824 | 2366 | } |
1825 | 2367 | |
1826 | 2368 | /* load immediate value */ |
@@ -1914,9 +2456,9 @@ class Compiler : public ErrorSink { | ||
1914 | 2456 | return mpBase->storeR0ToArg(l); |
1915 | 2457 | } |
1916 | 2458 | |
1917 | - virtual void endFunctionCallArguments(int a, int l) { | |
2459 | + virtual void endFunctionCallArguments(Type* pDecl, int a, int l) { | |
1918 | 2460 | fprintf(stderr, "endFunctionCallArguments(%d, %d)\n", a, l); |
1919 | - mpBase->endFunctionCallArguments(a, l); | |
2461 | + mpBase->endFunctionCallArguments(pDecl, a, l); | |
1920 | 2462 | } |
1921 | 2463 | |
1922 | 2464 | virtual int callForward(int symbol, Type* pFunc) { |
@@ -1935,9 +2477,9 @@ class Compiler : public ErrorSink { | ||
1935 | 2477 | mpBase->callIndirect(l, pFunc); |
1936 | 2478 | } |
1937 | 2479 | |
1938 | - virtual void adjustStackAfterCall(int l, bool isIndirect) { | |
1939 | - fprintf(stderr, "adjustStackAfterCall(%d, %d)\n", l, isIndirect); | |
1940 | - mpBase->adjustStackAfterCall(l, isIndirect); | |
2480 | + virtual void adjustStackAfterCall(Type* pDecl, int l, bool isIndirect) { | |
2481 | + fprintf(stderr, "adjustStackAfterCall(pType, %d, %d)\n", l, isIndirect); | |
2482 | + mpBase->adjustStackAfterCall(pDecl, l, isIndirect); | |
1941 | 2483 | } |
1942 | 2484 | |
1943 | 2485 | virtual int jumpOffset() { |
@@ -1963,8 +2505,8 @@ class Compiler : public ErrorSink { | ||
1963 | 2505 | /** |
1964 | 2506 | * Alignment (in bytes) for this type of data |
1965 | 2507 | */ |
1966 | - virtual size_t alignment(Type* pType){ | |
1967 | - return mpBase->alignment(pType); | |
2508 | + virtual size_t alignmentOf(Type* pType){ | |
2509 | + return mpBase->alignmentOf(pType); | |
1968 | 2510 | } |
1969 | 2511 | |
1970 | 2512 | /** |
@@ -3206,15 +3748,16 @@ class Compiler : public ErrorSink { | ||
3206 | 3748 | |
3207 | 3749 | /* function call */ |
3208 | 3750 | if (accept('(')) { |
3209 | - Type* pArgList = NULL; | |
3751 | + Type* pDecl = NULL; | |
3210 | 3752 | VariableInfo* pVI = NULL; |
3211 | 3753 | if (n == 1) { // Indirect function call, push address of fn. |
3212 | - pArgList = pGen->getR0Type()->pTail; | |
3754 | + pDecl = pGen->getR0Type(); | |
3213 | 3755 | pGen->pushR0(); |
3214 | 3756 | } else { |
3215 | 3757 | pVI = VI(t); |
3216 | - pArgList = pVI->pType->pTail; | |
3758 | + pDecl = pVI->pType; | |
3217 | 3759 | } |
3760 | + Type* pArgList = pDecl->pTail; | |
3218 | 3761 | bool varArgs = pArgList == NULL; |
3219 | 3762 | /* push args and invert order */ |
3220 | 3763 | a = pGen->beginFunctionCallArguments(); |
@@ -3252,7 +3795,7 @@ class Compiler : public ErrorSink { | ||
3252 | 3795 | if (! varArgs && pArgList) { |
3253 | 3796 | error ("Expected more argument(s). Saw %d", argCount); |
3254 | 3797 | } |
3255 | - pGen->endFunctionCallArguments(a, l); | |
3798 | + pGen->endFunctionCallArguments(pDecl, a, l); | |
3256 | 3799 | skip(')'); |
3257 | 3800 | if (!n) { |
3258 | 3801 | /* forward reference */ |
@@ -3264,7 +3807,7 @@ class Compiler : public ErrorSink { | ||
3264 | 3807 | pGen->callRelative(n - codeBuf.getPC() - pGen->jumpOffset(), |
3265 | 3808 | VI(t)->pType); |
3266 | 3809 | } |
3267 | - pGen->adjustStackAfterCall(l, n == 1); | |
3810 | + pGen->adjustStackAfterCall(pDecl, l, n == 1); | |
3268 | 3811 | } |
3269 | 3812 | } |
3270 | 3813 |
@@ -3729,8 +4272,9 @@ class Compiler : public ErrorSink { | ||
3729 | 4272 | } |
3730 | 4273 | int variableAddress = 0; |
3731 | 4274 | addLocalSymbol(pDecl); |
4275 | + size_t alignment = pGen->alignmentOf(pDecl); | |
4276 | + loc = (loc + alignment - 1) & ~ (alignment-1); | |
3732 | 4277 | loc = loc + pGen->sizeOf(pDecl); |
3733 | - loc = loc + 4; | |
3734 | 4278 | variableAddress = -loc; |
3735 | 4279 | VI(pDecl->id)->pAddress = (void*) variableAddress; |
3736 | 4280 | if (accept('=')) { |
@@ -3809,7 +4353,7 @@ class Compiler : public ErrorSink { | ||
3809 | 4353 | for(;;) { |
3810 | 4354 | if (name && !name->pAddress) { |
3811 | 4355 | name->pAddress = (int*) allocGlobalSpace( |
3812 | - pGen->alignment(name->pType), | |
4356 | + pGen->alignmentOf(name->pType), | |
3813 | 4357 | pGen->sizeOf(name->pType)); |
3814 | 4358 | } |
3815 | 4359 | if (accept('=')) { |
@@ -3855,16 +4399,18 @@ class Compiler : public ErrorSink { | ||
3855 | 4399 | Type* pArg = pP->pHead; |
3856 | 4400 | addLocalSymbol(pArg); |
3857 | 4401 | /* read param name and compute offset */ |
4402 | + size_t alignment = pGen->alignmentOf(pArg); | |
4403 | + a = (a + alignment - 1) & ~ (alignment-1); | |
3858 | 4404 | VI(pArg->id)->pAddress = (void*) a; |
3859 | 4405 | a = a + pGen->stackSizeOf(pArg); |
3860 | 4406 | argCount++; |
3861 | 4407 | } |
3862 | 4408 | rsym = loc = 0; |
3863 | 4409 | pReturnType = pDecl->pHead; |
3864 | - a = pGen->functionEntry(argCount); | |
4410 | + a = pGen->functionEntry(pDecl); | |
3865 | 4411 | block(0, true); |
3866 | 4412 | pGen->gsym(rsym); |
3867 | - pGen->functionExit(argCount, a, loc); | |
4413 | + pGen->functionExit(pDecl, a, loc); | |
3868 | 4414 | mLocals.popLevel(); |
3869 | 4415 | } |
3870 | 4416 | } |
@@ -38,13 +38,12 @@ void testVars(float arg0, float arg1, double arg2, double arg3) { | ||
38 | 38 | * (float*) & f0 = 1.1f; |
39 | 39 | * (double*) & d0 = 3.3; |
40 | 40 | printf("cast lval: %g %g %g %g\n", f0, f1, d0, d1); |
41 | - | |
42 | 41 | } |
43 | 42 | |
44 | 43 | int main() { |
45 | 44 | printf("int: %d float: %g double: %g\n", 1, 2.2f, 3.3); |
46 | 45 | printf(" ftoi(1.4f)=%d\n", ftoi(1.4f)); |
47 | - printf(" dtoi(2.4f)=%d\n", dtoi(2.4f)); | |
46 | + printf(" dtoi(2.4)=%d\n", dtoi(2.4)); | |
48 | 47 | printf(" itof(3)=%g\n", itof(3)); |
49 | 48 | printf(" itod(4)=%g\n", itod(4)); |
50 | 49 | testVars(1.0f, 2.0f, 3.0, 4.0); |
@@ -4,7 +4,7 @@ void unaryOps() { | ||
4 | 4 | // Unary ops |
5 | 5 | printf("-%g = %g\n", 1.1, -1.1); |
6 | 6 | printf("!%g = %d\n", 1.2, !1.2); |
7 | - printf("!%g = %d\n", 0.0, !0,0); | |
7 | + printf("!%g = %d\n", 0.0, !0.0); | |
8 | 8 | } |
9 | 9 | |
10 | 10 | void binaryOps() { |
@@ -75,6 +75,7 @@ void comparisonOpsff() { | ||
75 | 75 | comparisonTestff(1.0f, 1.0f); |
76 | 76 | comparisonTestff(2.0f, 1.0f); |
77 | 77 | } |
78 | + | |
78 | 79 | void comparisonTestid(int a, double b) { |
79 | 80 | printf("%d op %g: < %d <= %d == %d >= %d > %d != %d\n", |
80 | 81 | a, b, a < b, a <= b, a == b, a >= b, a > b, a != b); |
@@ -82,9 +83,9 @@ void comparisonTestid(int a, double b) { | ||
82 | 83 | |
83 | 84 | void comparisonOpsid() { |
84 | 85 | printf("int op double:\n"); |
85 | - comparisonTestid(1, 2.0f); | |
86 | - comparisonTestid(1, 1.0f); | |
87 | - comparisonTestid(2, 1.0f); | |
86 | + comparisonTestid(1, 2.0); | |
87 | + comparisonTestid(1, 1.0); | |
88 | + comparisonTestid(2, 1.0); | |
88 | 89 | } |
89 | 90 | void comparisonTestdi(double a, int b) { |
90 | 91 | printf("%g op %d: < %d <= %d == %d >= %d > %d != %d\n", |
@@ -117,10 +118,34 @@ void testBranching() { | ||
117 | 118 | printf("branching: %d %d %d\n", branch(-1.0), branch(0.0), branch(1.0)); |
118 | 119 | } |
119 | 120 | |
121 | +void testpassi(int a, int b, int c, int d, int e, int f, int g, int h) { | |
122 | + printf("testpassi: %d %d %d %d %d %d %d %d\n", a, b, c, d, e, f, g, h); | |
123 | +} | |
124 | + | |
125 | +void testpassf(float a, float b, float c, float d, float e, float f, float g, float h) { | |
126 | + printf("testpassf: %g %g %g %g %g %g %g %g\n", a, b, c, d, e, f, g, h); | |
127 | +} | |
128 | + | |
129 | +void testpassd(double a, double b, double c, double d, double e, double f, double g, double h) { | |
130 | + printf("testpassd: %g %g %g %g %g %g %g %g\n", a, b, c, d, e, f, g, h); | |
131 | +} | |
132 | + | |
133 | +void testpassidf(int i, double d, float f) { | |
134 | + printf("testpassidf: %d %g %g\n", i, d, f); | |
135 | +} | |
136 | + | |
137 | +void testParameterPassing() { | |
138 | + testpassi(1, 2, 3, 4, 5, 6, 7, 8); | |
139 | + testpassf(1, 2, 3, 4, 5, 6, 7, 8); | |
140 | + testpassd(1, 2, 3, 4, 5, 6, 7, 8); | |
141 | + testpassidf(1, 2.0, 3.0f); | |
142 | +} | |
143 | + | |
120 | 144 | int main() { |
121 | 145 | unaryOps(); |
122 | 146 | binaryOps(); |
123 | 147 | comparisonOps(); |
124 | 148 | testBranching(); |
149 | + testParameterPassing(); | |
125 | 150 | return 0; |
126 | 151 | } |
@@ -118,7 +118,7 @@ class TestACC(unittest.TestCase): | ||
118 | 118 | def testRunFloat(self): |
119 | 119 | self.compileCheck(["-R", "data/float.c"], |
120 | 120 | "Executing compiled code:\nresult: 0\n", |
121 | - "int: 1 float: 2.2 double: 3.3\n ftoi(1.4f)=1\n dtoi(2.4f)=2\n itof(3)=3\n itod(4)=4\nglobals: 1 2 3 4\nargs: 1 2 3 4\nlocals: 1 2 3 4\ncast rval: 2 4\ncast lval: 1.1 2 3.3 4\n") | |
121 | + "int: 1 float: 2.2 double: 3.3\n ftoi(1.4f)=1\n dtoi(2.4)=2\n itof(3)=3\n itod(4)=4\nglobals: 1 2 3 4\nargs: 1 2 3 4\nlocals: 1 2 3 4\ncast rval: 2 4\ncast lval: 1.1 2 3.3 4\n") | |
122 | 122 | |
123 | 123 | def testRunFlops(self): |
124 | 124 | self.compileCheck(["-R", "data/flops.c"], |
@@ -171,7 +171,12 @@ class TestACC(unittest.TestCase): | ||
171 | 171 | "1 op 2: < 1 <= 1 == 0 >= 0 > 0 != 1\n" + |
172 | 172 | "1 op 1: < 0 <= 1 == 1 >= 1 > 0 != 0\n" + |
173 | 173 | "2 op 1: < 0 <= 0 == 0 >= 1 > 1 != 1\n" + |
174 | - "branching: 1 0 1\n") | |
174 | + "branching: 1 0 1\n" + | |
175 | + "testpassi: 1 2 3 4 5 6 7 8\n" + | |
176 | + "testpassf: 1 2 3 4 5 6 7 8\n" + | |
177 | + "testpassd: 1 2 3 4 5 6 7 8\n" + | |
178 | + "testpassidf: 1 2 3\n" | |
179 | + ) | |
175 | 180 | |
176 | 181 | def testArmRunReturnVal(self): |
177 | 182 | self.compileCheckArm(["-R", "/system/bin/accdata/data/returnval-ansi.c"], |