diff options
| author | Android (Google) Code Review <android-gerrit@google.com> | 2009-07-08 20:42:06 -0700 |
|---|---|---|
| committer | Android (Google) Code Review <android-gerrit@google.com> | 2009-07-08 20:42:06 -0700 |
| commit | 52dddc6149cde8e4bb2b3cbca53f77fcc4e62e95 (patch) | |
| tree | 8ce29339910fe12a7567b709fda59118ed5a8042 | |
| parent | de394b237210f1b9f4bba5fb2f8153a17d91b0cf (diff) | |
| parent | a39749f641f49ed1c6380bfaedad98a036a0f4a6 (diff) | |
| download | system_core-52dddc6149cde8e4bb2b3cbca53f77fcc4e62e95.zip system_core-52dddc6149cde8e4bb2b3cbca53f77fcc4e62e95.tar.gz system_core-52dddc6149cde8e4bb2b3cbca53f77fcc4e62e95.tar.bz2 | |
Merge change 6597
* changes:
Implement x86 floating point operations
| -rw-r--r-- | libacc/acc.cpp | 258 | ||||
| -rw-r--r-- | libacc/tests/data/flops.c | 115 |
2 files changed, 330 insertions, 43 deletions
diff --git a/libacc/acc.cpp b/libacc/acc.cpp index 0935be8..adc8609 100644 --- a/libacc/acc.cpp +++ b/libacc/acc.cpp @@ -316,7 +316,7 @@ class Compiler : public ErrorSink { * Pops TOS. * op specifies the comparison. */ - virtual void gcmp(int op) = 0; + virtual void gcmp(int op, Type* pResultType) = 0; /* Perform the arithmetic op specified by op. TOS is the * left argument, R0 is the right argument. @@ -327,7 +327,7 @@ class Compiler : public ErrorSink { /* Compare 0 against R0, and store the boolean result in R0. * op specifies the comparison. */ - virtual void gUnaryCmp(int op) = 0; + virtual void gUnaryCmp(int op, Type* pResultType) = 0; /* Perform the arithmetic op specified by op. 0 is the * left argument, R0 is the right argument. @@ -647,7 +647,7 @@ class Compiler : public ErrorSink { return o4(branch | encodeAddress(t)); } - virtual void gcmp(int op) { + virtual void gcmp(int op, Type* pResultType) { LOG_API("gcmp(%d);\n", op); o4(0xE8BD0002); // ldmfd sp!,{r1} mStackUse -= 4; @@ -729,12 +729,12 @@ class Compiler : public ErrorSink { popType(); } - virtual void gUnaryCmp(int op) { - LOG_API("gcmp(%d);\n", op); + virtual void gUnaryCmp(int op, Type* pResultType) { + LOG_API("gUnaryCmp(%d);\n", op); o4(0xE3A01000); // mov r1, #0 o4(0xE1510000); // cmp r1, r1 switch(op) { - case OP_NOT_EQUALS: + case OP_LOGICAL_NOT: o4(0x03A00000); // moveq r0,#0 o4(0x13A00001); // movne r0,#1 break; @@ -742,14 +742,12 @@ class Compiler : public ErrorSink { error("Unknown unary comparison op %d", op); break; } + setR0Type(pResultType); } virtual void genUnaryOp(int op) { LOG_API("genOp(%d);\n", op); switch(op) { - case OP_PLUS: - // Do nothing - break; case OP_MINUS: o4(0xE3A01000); // mov r1, #0 o4(0xE0410000); // sub r0,r1,r0 @@ -1219,38 +1217,181 @@ class Compiler : public ErrorSink { return psym(0x84 + l, t); } - virtual void gcmp(int op) { - int t = decodeOp(op); - o(0x59); /* pop %ecx */ - o(0xc139); /* cmp %eax,%ecx */ - li(0, NULL); - o(0x0f); /* setxx %al */ - o(t + 0x90); - o(0xc0); - popType(); + virtual void gcmp(int op, Type* pResultType) { + Type* pR0Type = getR0Type(); + Type* pTOSType = getTOSType(); + TypeTag tagR0 = pR0Type->tag; + TypeTag tagTOS = pTOSType->tag; + bool isFloatR0 = isFloatTag(tagR0); + bool isFloatTOS = isFloatTag(tagTOS); + if (!isFloatR0 && !isFloatTOS) { + int t = decodeOp(op); + o(0x59); /* pop %ecx */ + o(0xc139); /* cmp %eax,%ecx */ + li(0, NULL); + o(0x0f); /* setxx %al */ + o(t + 0x90); + o(0xc0); + popType(); + } else { + setupFloatOperands(); + switch (op) { + case OP_EQUALS: + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x9e); // sahf + o(0xc0940f); // sete %al + o(0xc29b0f); // setnp %dl + o(0xd021); // andl %edx, %eax + break; + case OP_NOT_EQUALS: + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x9e); // sahf + o(0xc0950f); // setne %al + o(0xc29a0f); // setp %dl + o(0xd009); // orl %edx, %eax + break; + case OP_GREATER_EQUAL: + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x05c4f6); // testb $5, %ah + o(0xc0940f); // sete %al + break; + case OP_LESS: + o(0xc9d9); // fxch %st(1) + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x9e); // sahf + o(0xc0970f); // seta %al + break; + case OP_LESS_EQUAL: + o(0xc9d9); // fxch %st(1) + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x9e); // sahf + o(0xc0930f); // setea %al + break; + case OP_GREATER: + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x45c4f6); // testb $69, %ah + o(0xc0940f); // sete %al + break; + default: + error("Unknown comparison op"); + } + o(0xc0b60f); // movzbl %al, %eax + } + setR0Type(pResultType); } virtual void genOp(int op) { - o(0x59); /* pop %ecx */ - o(decodeOp(op)); - if (op == OP_MOD) - o(0x92); /* xchg %edx, %eax */ - popType(); + Type* pR0Type = getR0Type(); + Type* pTOSType = getTOSType(); + TypeTag tagR0 = pR0Type->tag; + TypeTag tagTOS = pTOSType->tag; + bool isFloatR0 = isFloatTag(tagR0); + bool isFloatTOS = isFloatTag(tagTOS); + if (!isFloatR0 && !isFloatTOS) { + // TODO: Deal with pointer arithmetic + o(0x59); /* pop %ecx */ + o(decodeOp(op)); + if (op == OP_MOD) + o(0x92); /* xchg %edx, %eax */ + popType(); + } else { + Type* pResultType = tagR0 > tagTOS ? pR0Type : pTOSType; + setupFloatOperands(); + // Both float. x87 R0 == left hand, x87 R1 == right hand + switch (op) { + case OP_MUL: + o(0xc9de); // fmulp + break; + case OP_DIV: + o(0xf1de); // fdivp + break; + case OP_PLUS: + o(0xc1de); // faddp + break; + case OP_MINUS: + o(0xe1de); // fsubp + break; + default: + error("Unsupported binary floating operation."); + break; + } + popType(); + setR0Type(pResultType); + printf("genop: result type %d\n", pResultType->tag); + } } - virtual void gUnaryCmp(int op) { - oad(0xb9, 0); /* movl $0, %ecx */ - int t = decodeOp(op); - o(0xc139); /* cmp %eax,%ecx */ - li(0, NULL); - o(0x0f); /* setxx %al */ - o(t + 0x90); - o(0xc0); + + + virtual void gUnaryCmp(int op, Type* pResultType) { + if (op != OP_LOGICAL_NOT) { + error("Unknown unary cmp %d", op); + } else { + Type* pR0Type = getR0Type(); + TypeTag tag = collapseType(pR0Type->tag); + switch(tag) { + case TY_INT: { + oad(0xb9, 0); /* movl $0, %ecx */ + int t = decodeOp(op); + o(0xc139); /* cmp %eax,%ecx */ + li(0, NULL); + o(0x0f); /* setxx %al */ + o(t + 0x90); + o(0xc0); + } + break; + case TY_FLOAT: + case TY_DOUBLE: + o(0xeed9); // fldz + o(0xe9da); // fucompp + o(0xe0df); // fnstsw %ax + o(0x9e); // sahf + o(0xc0950f); // setne %al + o(0xc29a0f); // setp %dl + o(0xd009); // orl %edx, %eax + o(0xc0b60f); // movzbl %al, %eax + o(0x01f083); // xorl $1, %eax + break; + default: + error("genUnaryCmp unsupported type"); + break; + } + } + setR0Type(pResultType); } virtual void genUnaryOp(int op) { - oad(0xb9, 0); /* movl $0, %ecx */ - o(decodeOp(op)); + Type* pR0Type = getR0Type(); + TypeTag tag = collapseType(pR0Type->tag); + switch(tag) { + case TY_INT: + oad(0xb9, 0); /* movl $0, %ecx */ + o(decodeOp(op)); + break; + case TY_FLOAT: + case TY_DOUBLE: + switch (op) { + case OP_MINUS: + o(0xe0d9); // fchs + break; + case OP_BIT_NOT: + error("Can't apply '~' operator to a float or double."); + break; + default: + error("Unknown unary op %d\n", op); + break; + } + break; + default: + error("genUnaryOp unsupported type"); + break; + } } virtual void pushR0() { @@ -1592,6 +1733,34 @@ class Compiler : public ErrorSink { o(l + 0x83); oad((t > -LOCAL && t < LOCAL) << 7 | 5, t); } + + void setupFloatOperands() { + Type* pR0Type = getR0Type(); + Type* pTOSType = getTOSType(); + TypeTag tagR0 = pR0Type->tag; + TypeTag tagTOS = pTOSType->tag; + bool isFloatR0 = isFloatTag(tagR0); + bool isFloatTOS = isFloatTag(tagTOS); + if (! isFloatR0) { + // Convert R0 from int to float + o(0x50); // push %eax + o(0x2404DB); // fildl 0(%esp) + o(0x58); // pop %eax + } + if (! isFloatTOS){ + o(0x2404DB); // fildl 0(%esp); + o(0x58); // pop %eax + } else { + if (tagTOS == TY_FLOAT) { + o(0x2404d9); // flds (%esp) + o(0x58); // pop %eax + } else { + o(0x2404dd); // fldl (%esp) + o(0x58); // pop %eax + o(0x58); // pop %eax + } + } + } }; #endif // PROVIDE_X86_CODEGEN @@ -1656,9 +1825,9 @@ class Compiler : public ErrorSink { return result; } - virtual void gcmp(int op) { - fprintf(stderr, "gcmp(%d)\n", op); - mpBase->gcmp(op); + virtual void gcmp(int op, Type* pResultType) { + fprintf(stderr, "gcmp(%d, pResultType)\n", op); + mpBase->gcmp(op, pResultType); } virtual void genOp(int op) { @@ -1667,9 +1836,9 @@ class Compiler : public ErrorSink { } - virtual void gUnaryCmp(int op) { - fprintf(stderr, "gUnaryCmp(%d)\n", op); - mpBase->gUnaryCmp(op); + virtual void gUnaryCmp(int op, Type* pResultType) { + fprintf(stderr, "gUnaryCmp(%d, pResultType)\n", op); + mpBase->gUnaryCmp(op, pResultType); } virtual void genUnaryOp(int op) { @@ -2923,9 +3092,12 @@ class Compiler : public ErrorSink { /* -, +, !, ~ */ unary(false); if (t == '!') - pGen->gUnaryCmp(a); - else + pGen->gUnaryCmp(a, mkpInt); + else if (t == '+') { + // ignore unary plus. + } else { pGen->genUnaryOp(a); + } } else if (t == '(') { expr(); skip(')'); @@ -3090,7 +3262,7 @@ class Compiler : public ErrorSink { binaryOp(level); if ((level == 4) | (level == 5)) { - pGen->gcmp(t); + pGen->gcmp(t, mkpInt); } else { pGen->genOp(t); } @@ -3665,7 +3837,7 @@ class Compiler : public ErrorSink { char* allocGlobalSpace(size_t alignment, size_t bytes) { size_t base = (((size_t) glo) + alignment - 1) & ~(alignment-1); size_t end = base + bytes; - if ((end - (size_t) pGlobalBase) > ALLOC_SIZE) { + if ((end - (size_t) pGlobalBase) > (size_t) ALLOC_SIZE) { error("Global space exhausted"); return NULL; } diff --git a/libacc/tests/data/flops.c b/libacc/tests/data/flops.c new file mode 100644 index 0000000..347c665 --- /dev/null +++ b/libacc/tests/data/flops.c @@ -0,0 +1,115 @@ +// Test floating point operations. + +void unaryOps() { + // Unary ops + printf("-%g = %g\n", 1.1, -1.1); + printf("!%g = %d\n", 1.2, !1.2); + printf("!%g = %d\n", 0.0, !0,0); +} + +void binaryOps() { + printf("double op double:\n"); + printf("%g + %g = %g\n", 1.0, 2.0, 1.0 + 2.0); + printf("%g - %g = %g\n", 1.0, 2.0, 1.0 - 2.0); + printf("%g * %g = %g\n", 1.0, 2.0, 1.0 * 2.0); + printf("%g / %g = %g\n", 1.0, 2.0, 1.0 / 2.0); + + printf("float op float:\n"); + printf("%g + %g = %g\n", 1.0f, 2.0f, 1.0f + 2.0f); + printf("%g - %g = %g\n", 1.0f, 2.0f, 1.0f - 2.0f); + printf("%g * %g = %g\n", 1.0f, 2.0f, 1.0f * 2.0f); + printf("%g / %g = %g\n", 1.0f, 2.0f, 1.0f / 2.0f); + + printf("double op float:\n"); + printf("%g + %g = %g\n", 1.0, 2.0f, 1.0 + 2.0f); + printf("%g - %g = %g\n", 1.0, 2.0f, 1.0 - 2.0f); + printf("%g * %g = %g\n", 1.0, 2.0f, 1.0 * 2.0f); + printf("%g / %g = %g\n", 1.0, 2.0f, 1.0 / 2.0f); + + printf("double op int:\n"); + printf("%g + %d = %g\n", 1.0, 2, 1.0 + 2); + printf("%g - %d = %g\n", 1.0, 2, 1.0 - 2); + printf("%g * %d = %g\n", 1.0, 2, 1.0 * 2); + printf("%g / %d = %g\n", 1.0, 2, 1.0 / 2); + + printf("int op double:\n"); + printf("%d + %g = %g\n", 1, 2.0, 1 + 2.0); + printf("%d - %g = %g\n", 1, 2.0, 1 - 2.0); + printf("%d * %g = %g\n", 1, 2.0, 1 * 2.0); + printf("%d / %g = %g\n", 1, 2.0, 1 / 2.0); +} + +void comparisonTestdd(double a, double b) { + printf("%g op %g: < %d <= %d == %d >= %d > %d != %d\n", + a, b, a < b, a <= b, a == b, a >= b, a > b, a != b); +} + +void comparisonOpsdd() { + printf("double op double:\n"); + comparisonTestdd(1.0, 2.0); + comparisonTestdd(1.0, 1.0); + comparisonTestdd(2.0, 1.0); +} + + +void comparisonTestdf(double a, float b) { + printf("%g op %g: < %d <= %d == %d >= %d > %d != %d\n", + a, b, a < b, a <= b, a == b, a >= b, a > b, a != b); +} + +void comparisonOpsdf() { + printf("double op float:\n"); + comparisonTestdf(1.0, 2.0f); + comparisonTestdf(1.0, 1.0f); + comparisonTestdf(2.0, 1.0f); +} + +void comparisonTestff(float a, float b) { + printf("%g op %g: < %d <= %d == %d >= %d > %d != %d\n", + a, b, a < b, a <= b, a == b, a >= b, a > b, a != b); +} + +void comparisonOpsff() { + printf("float op float:\n"); + comparisonTestff(1.0f, 2.0f); + comparisonTestff(1.0f, 1.0f); + comparisonTestff(2.0f, 1.0f); +} +void comparisonTestid(int a, double b) { + printf("%d op %g: < %d <= %d == %d >= %d > %d != %d\n", + a, b, a < b, a <= b, a == b, a >= b, a > b, a != b); +} + +void comparisonOpsid() { + printf("int op double:\n"); + comparisonTestid(1, 2.0f); + comparisonTestid(1, 1.0f); + comparisonTestid(2, 1.0f); +} +void comparisonTestdi(double a, int b) { + printf("%g op %d: < %d <= %d == %d >= %d > %d != %d\n", + a, b, a < b, a <= b, a == b, a >= b, a > b, a != b); +} + +void comparisonOpsdi() { + printf("double op int:\n"); + comparisonTestdi(1.0f, 2); + comparisonTestdi(1.0f, 1); + comparisonTestdi(2.0f, 1); +} + +void comparisonOps() { + comparisonOpsdd(); + comparisonOpsdf(); + comparisonOpsff(); + comparisonOpsid(); + comparisonOpsdi(); +} + + +int main() { + unaryOps(); + binaryOps(); + comparisonOps(); + return 0; +} |
