Merge change 6597
* changes:
Implement x86 floating point operations
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 @@
* 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 @@
/* 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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
}
- 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 @@
/* -, +, !, ~ */
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 @@
binaryOp(level);
if ((level == 4) | (level == 5)) {
- pGen->gcmp(t);
+ pGen->gcmp(t, mkpInt);
} else {
pGen->genOp(t);
}
@@ -3665,7 +3837,7 @@
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;
+}