changeset 1018:e8c6dbcd33d1

- Fixed x86-32 C ABI for complex number return values. - Removed unused code from the ABI class.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Sun, 01 Mar 2009 19:01:05 +0100
parents a771843e98de
children 80490f65d4e1
files gen/abi.cpp gen/abi.h gen/functions.cpp gen/llvmhelpers.cpp gen/naked.cpp gen/tocall.cpp tests/mini/asm8.d
diffstat 7 files changed, 110 insertions(+), 36 deletions(-) [+]
line wrap: on
line diff
--- a/gen/abi.cpp	Sun Mar 01 11:04:05 2009 +0100
+++ b/gen/abi.cpp	Sun Mar 01 19:01:05 2009 +0100
@@ -85,7 +85,65 @@
     }
     bool test(TypeFunction* tf)
     {
-        return (tf->next->toBasetype()->iscomplex());
+        // extern(D) && is(T:creal)
+        return (tf->linkage == LINKd && tf->next->toBasetype()->iscomplex());
+    }
+};
+
+//////////////////////////////////////////////////////////////////////////////
+
+struct X86_cfloat_rewrite : ABIRetRewrite
+{
+    // i64 -> {float,float}
+    LLValue* get(LLValue* in)
+    {
+        // extract real part
+        LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::Int32Ty);
+        rpart = gIR->ir->CreateBitCast(rpart, LLType::FloatTy, ".re");
+
+        // extract imag part
+        LLValue* ipart = gIR->ir->CreateLShr(in, LLConstantInt::get(LLType::Int64Ty, 32, false));
+        ipart = gIR->ir->CreateTrunc(ipart, LLType::Int32Ty);
+        ipart = gIR->ir->CreateBitCast(ipart, LLType::FloatTy, ".im");
+
+        // return {float,float} aggr pair with same bits
+        return DtoAggrPair(rpart, ipart, ".final_cfloat");
+    }
+
+    // {float,float} -> i64
+    LLValue* put(LLValue* v)
+    {
+        // extract real
+        LLValue* r = gIR->ir->CreateExtractValue(v, 0);
+        // cast to i32
+        r = gIR->ir->CreateBitCast(r, LLType::Int32Ty);
+        // zext to i64
+        r = gIR->ir->CreateZExt(r, LLType::Int64Ty);
+
+        // extract imag
+        LLValue* i = gIR->ir->CreateExtractValue(v, 1);
+        // cast to i32
+        i = gIR->ir->CreateBitCast(i, LLType::Int32Ty);
+        // zext to i64
+        i = gIR->ir->CreateZExt(i, LLType::Int64Ty);
+        // shift up
+        i = gIR->ir->CreateShl(i, LLConstantInt::get(LLType::Int64Ty, 32, false));
+
+        // combine and return
+        return v = gIR->ir->CreateOr(r, i);
+    }
+
+    // {float,float} -> i64
+    const LLType* type(const LLType* t)
+    {
+        return LLType::Int64Ty;
+    }
+
+    // test if rewrite applies to function
+    bool test(TypeFunction* tf)
+    {
+        return (tf->linkage != LINKd) 
+            && (tf->next->toBasetype() == Type::tcomplex32);
     }
 };
 
@@ -96,18 +154,19 @@
     X86TargetABI()
     {
         retOps.push_back(new X87_complex_swap);
+        retOps.push_back(new X86_cfloat_rewrite);
     }
 
-    bool returnInArg(Type* t)
+    bool returnInArg(TypeFunction* tf)
     {
-        Type* rt = t->toBasetype();
-        return (rt->ty == Tstruct);
-    }
-
-    bool passByRef(Type* t)
-    {
-        t = t->toBasetype();
-        return (t->ty == Tstruct || t->ty == Tsarray);
+        Type* rt = tf->next->toBasetype();
+        // D only returns structs on the stack
+        if (tf->linkage == LINKd)
+            return (rt->ty == Tstruct);
+        // other ABI's follow C, which is cdouble and creal returned on the stack
+        // as well as structs
+        else
+            return (rt->ty == Tstruct || rt->ty == Tcomplex64 || rt->ty == Tcomplex80);
     }
 };
 
@@ -194,17 +253,11 @@
         retOps.push_back(new X86_64_cfloat_rewrite);
     }
 
-    bool returnInArg(Type* t)
+    bool returnInArg(TypeFunction* tf)
     {
-        Type* rt = t->toBasetype();
+        Type* rt = tf->next->toBasetype();
         return (rt->ty == Tstruct);
     }
-
-    bool passByRef(Type* t)
-    {
-        t = t->toBasetype();
-        return (t->ty == Tstruct || t->ty == Tsarray);
-    }
 };
 
 //////////////////////////////////////////////////////////////////////////////
@@ -221,17 +274,11 @@
         // Don't push anything into retOps, assume defaults will be fine.
     }
 
-    bool returnInArg(Type* t)
+    bool returnInArg(TypeFunction* tf)
     {
-        Type* rt = t->toBasetype();
+        Type* rt = tf->next->toBasetype();
         return (rt->ty == Tstruct);
     }
-
-    bool passByRef(Type* t)
-    {
-        t = t->toBasetype();
-        return (t->ty == Tstruct || t->ty == Tsarray);
-    }
 };
 
 //////////////////////////////////////////////////////////////////////////////
--- a/gen/abi.h	Sun Mar 01 11:04:05 2009 +0100
+++ b/gen/abi.h	Sun Mar 01 19:01:05 2009 +0100
@@ -38,8 +38,7 @@
     llvm::Value* getRet(TypeFunction* tf, llvm::Value* v);
     llvm::Value* putRet(TypeFunction* tf, llvm::Value* v);
 
-    virtual bool returnInArg(Type* t) = 0;
-    virtual bool passByRef(Type* t) = 0;
+    virtual bool returnInArg(TypeFunction* t) = 0;
 
 protected:
     std::vector<ABIRetRewrite*> retOps;
--- a/gen/functions.cpp	Sun Mar 01 11:04:05 2009 +0100
+++ b/gen/functions.cpp	Sun Mar 01 19:01:05 2009 +0100
@@ -79,7 +79,7 @@
         }
         else
         {
-            if (gABI->returnInArg(rt))
+            if (gABI->returnInArg(f))
             {
                 rettype = getPtrToType(DtoType(rt));
                 actualRettype = LLType::VoidTy;
--- a/gen/llvmhelpers.cpp	Sun Mar 01 11:04:05 2009 +0100
+++ b/gen/llvmhelpers.cpp	Sun Mar 01 19:01:05 2009 +0100
@@ -392,6 +392,8 @@
 // ASSIGNMENT HELPER (store this in that)
 ////////////////////////////////////////////////////////////////////////////////////////*/
 
+// is this a good approach at all ?
+
 void DtoAssign(Loc& loc, DValue* lhs, DValue* rhs)
 {
     Logger::println("DtoAssign(...);\n");
@@ -402,7 +404,7 @@
 
     if (t->ty == Tstruct) {
         if (!t->equals(t2)) {
-            // TODO: fix this, use 'rhs' for something
+            // FIXME: use 'rhs' for something !?!
             DtoAggrZeroInit(lhs->getLVal());
         }
         else {
@@ -476,7 +478,7 @@
         DtoStore(r, l);
     }
     else if (t->iscomplex()) {
-        LLValue* dst;
+        LLValue *dst, *src;
         if (DLRValue* lr = lhs->isLRValue()) {
             dst = lr->getLVal();
             rhs = DtoCastComplex(loc, rhs, lr->getLType());
--- a/gen/naked.cpp	Sun Mar 01 11:04:05 2009 +0100
+++ b/gen/naked.cpp	Sun Mar 01 19:01:05 2009 +0100
@@ -175,6 +175,13 @@
     return b->CreateInsertValue(undef, orig, 0, "asm.ret");
 }
 
+static LLValue* x86_cfloatRetFixup(IRBuilderHelper b, LLValue* orig) {
+    assert(orig->getType() == LLType::DoubleTy);
+    LLType* retty = LLStructType::get(LLType::DoubleTy, NULL);
+    LLValue* undef = llvm::UndefValue::get(retty);
+    return b->CreateInsertValue(undef, orig, 0, "asm.ret");
+}
+
 void emitABIReturnAsmStmt(IRAsmBlock* asmblock, Loc loc, FuncDeclaration* fdecl)
 {
     Logger::println("emitABIReturnAsmStmt(%s)", fdecl->mangle());
@@ -204,8 +211,19 @@
         else if (rt->isfloating())
         {
             if (rt->iscomplex()) {
-                as->out_c = "={st},={st(1)},";
-                asmblock->retn = 2;
+                if (fdecl->linkage == LINKd) {
+                    // extern(D) always returns on the FPU stack
+                    as->out_c = "={st},={st(1)},";
+                    asmblock->retn = 2;
+                } else if (rt->ty == Tcomplex32) {
+                    // extern(C) cfloat is return as i64
+                    as->out_c = "=A,";
+                    asmblock->retty = LLType::Int64Ty;
+                } else {
+                    // cdouble and creal extern(C) are returned in pointer
+                    // don't add anything!
+                    return;
+                }
             } else {
                 as->out_c = "={st},";
             }
--- a/gen/tocall.cpp	Sun Mar 01 11:04:05 2009 +0100
+++ b/gen/tocall.cpp	Sun Mar 01 19:01:05 2009 +0100
@@ -527,5 +527,10 @@
         call.setCallingConv(callconv);
     call.setAttributes(attrlist);
 
+    // if we are returning through a pointer arg
+    // make sure we provide a lvalue back!
+    if (retinptr)
+        return new DVarValue(resulttype, retllval);
+
     return new DImValue(resulttype, retllval);
 }
--- a/tests/mini/asm8.d	Sun Mar 01 11:04:05 2009 +0100
+++ b/tests/mini/asm8.d	Sun Mar 01 19:01:05 2009 +0100
@@ -131,7 +131,10 @@
 {
     version(X86)
     {
-        asm { fld1; fld two_f; }
+        asm {
+            mov EAX, [one_f];
+            mov EDX, [two_f];
+        }
     }
     else version (X86_64)
     {
@@ -180,8 +183,8 @@
         asm
         {
             naked;
-            fld1;
-            fld two_f;
+            mov EAX, [one_f];
+            mov EDX, [two_f];
             ret;
         }
     }