Merge change 6597
* changes: Implement x86 floating point operations
This commit is contained in:
commit
52dddc6149
2 changed files with 330 additions and 43 deletions
258
libacc/acc.cpp
258
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;
|
||||
}
|
||||
|
|
|
|||
115
libacc/tests/data/flops.c
Normal file
115
libacc/tests/data/flops.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue