From 128ad2d20497afb6ed1f2f11cfdae020f08f798c Mon Sep 17 00:00:00 2001 From: Jack Palevich Date: Wed, 8 Jul 2009 14:51:31 -0700 Subject: [PATCH] Implement x86 int <--> float. --- libacc/acc.cpp | 75 +++++++++++++++++++++++++++++++++------ libacc/tests/data/float.c | 22 ++++++++++-- 2 files changed, 85 insertions(+), 12 deletions(-) diff --git a/libacc/acc.cpp b/libacc/acc.cpp index 65b0b3917..38c23d01b 100644 --- a/libacc/acc.cpp +++ b/libacc/acc.cpp @@ -532,7 +532,10 @@ class Compiler : public ErrorSink { } bool isFloatType(Type* pType) { - TypeTag tag = pType->tag; + return isFloatTag(pType->tag); + } + + bool isFloatTag(TypeTag tag) { return tag == TY_FLOAT || tag == TY_DOUBLE; } @@ -1283,12 +1286,40 @@ class Compiler : public ErrorSink { } virtual void loadR0(int ea, bool isIncDec, int op, Type* pType) { - gmov(8, ea); /* mov EA, %eax */ - if (isIncDec) { - /* Implement post-increment or post decrement. - */ - gmov(0, ea); /* 83 ADD */ - o(decodeOp(op)); + TypeTag tag = collapseType(pType->tag); + switch (tag) { + case TY_INT: + gmov(8, ea); /* mov EA, %eax */ + if (isIncDec) { + /* Implement post-increment or post decrement. + */ + gmov(0, ea); /* 83 ADD */ + o(decodeOp(op)); + } + break; + case TY_FLOAT: + if (ea < -LOCAL || ea > LOCAL) { + oad(0x05d9, ea); // flds ea + } else { + oad(0x85d9, ea); // flds ea(%ebp) + } + if (isIncDec) { + error("inc/dec not implemented for float."); + } + break; + case TY_DOUBLE: + if (ea < -LOCAL || ea > LOCAL) { + oad(0x05dd, ea); // fldl ea + } else { + oad(0x85dd, ea); // fldl ea(%ebp) + } + if (isIncDec) { + error("inc/dec not implemented for double."); + } + break; + default: + error("Unable to load type %d", tag); + break; } setR0Type(pType); } @@ -1296,7 +1327,7 @@ class Compiler : public ErrorSink { virtual void convertR0(Type* pType){ Type* pR0Type = getR0Type(); if (pR0Type == NULL) { - error("don't know R0Type"); + assert(false); setR0Type(pType); return; } @@ -1305,8 +1336,32 @@ class Compiler : public ErrorSink { } else if (isFloatType(pType) && isFloatType(pR0Type)) { // do nothing special, both held in same register on x87. } else { - error("Incompatible types old: %d new: %d", - pR0Type->tag, pType->tag); + TypeTag r0Tag = collapseType(pR0Type->tag); + TypeTag destTag = collapseType(pType->tag); + if (r0Tag == TY_INT && isFloatTag(destTag)) { + // Convert R0 from int to float + o(0x50); // push %eax + o(0x2404DB); // fildl 0(%esp) + o(0x58); // pop %eax + } else if (isFloatTag(r0Tag) && destTag == TY_INT) { + // Convert R0 from float to int. Complicated because + // need to save and restore the rounding mode. + o(0x50); // push %eax + o(0x50); // push %eax + o(0x02247cD9); // fnstcw 2(%esp) + o(0x2444b70f); // movzwl 2(%esp), %eax + o(0x02); + o(0x0cb4); // movb $12, %ah + o(0x24048966); // movw %ax, 0(%esp) + o(0x242cd9); // fldcw 0(%esp) + o(0x04245cdb); // fistpl 4(%esp) + o(0x02246cd9); // fldcw 2(%esp) + o(0x58); // pop %eax + o(0x58); // pop %eax + } else { + error("Incompatible types old: %d new: %d", + pR0Type->tag, pType->tag); + } } setR0Type(pType); } diff --git a/libacc/tests/data/float.c b/libacc/tests/data/float.c index 5f68efc18..e53fefa0c 100644 --- a/libacc/tests/data/float.c +++ b/libacc/tests/data/float.c @@ -1,6 +1,24 @@ +int ftoi(float f) { + return f; +} + +int dtoi(double d) { + return d; +} + +float itof(int i) { + return i; +} + +double itod(int i) { + return i; +} int main() { printf("int: %d float: %g double: %g\n", 1, 2.2f, 3.3); - - return 42; + printf(" ftoi(1.4f)=%d\n", ftoi(1.4f)); + printf(" dtoi(2.4f)=%d\n", dtoi(2.4f)); + printf(" itof(3)=%g\n", itof(3)); + printf(" itod(4)=%g\n", itod(4)); + return 0; }