changeset 1042:45af482e3832

Updated ABI handling to be more flexible with regard to reusing lvalues and allocating fewer temporaries.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Wed, 04 Mar 2009 17:24:25 +0100
parents 9dca7182aa75
children 0485751a40ae
files gen/abi.cpp gen/abi.h gen/functions.cpp gen/statements.cpp gen/tocall.cpp ir/irfunction.cpp ir/irfunction.h
diffstat 7 files changed, 112 insertions(+), 61 deletions(-) [+]
line wrap: on
line diff
--- a/gen/abi.cpp	Wed Mar 04 16:13:16 2009 +0100
+++ b/gen/abi.cpp	Wed Mar 04 17:24:25 2009 +0100
@@ -9,10 +9,20 @@
 #include "gen/tollvm.h"
 #include "gen/abi.h"
 #include "gen/logger.h"
+#include "gen/dvalue.h"
 
 #include "ir/irfunction.h"
 
 //////////////////////////////////////////////////////////////////////////////
+
+void ABIRewrite::getL(Type* dty, DValue* v, llvm::Value* lval)
+{
+    LLValue* rval = v->getRVal();
+    assert(rval->getType() == lval->getType()->getContainedType(0));
+    DtoStore(rval, lval);
+}
+
+//////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 /////////////////////              X86            ////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
@@ -21,13 +31,13 @@
 // simply swap of real/imag parts for proper x87 complex abi
 struct X87_complex_swap : ABIRewrite
 {
-    LLValue* get(Type*, LLValue* v)
+    LLValue* get(Type*, DValue* v)
     {
-        return DtoAggrPairSwap(v);
+        return DtoAggrPairSwap(v->getRVal());
     }
-    LLValue* put(Type*, LLValue* v)
+    LLValue* put(Type*, DValue* v)
     {
-        return DtoAggrPairSwap(v);
+        return DtoAggrPairSwap(v->getRVal());
     }
     const LLType* type(Type*, const LLType* t)
     {
@@ -40,8 +50,10 @@
 struct X86_cfloat_rewrite : ABIRewrite
 {
     // i64 -> {float,float}
-    LLValue* get(Type*, LLValue* in)
+    LLValue* get(Type*, DValue* dv)
     {
+        LLValue* in = dv->getRVal();
+
         // extract real part
         LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::Int32Ty);
         rpart = gIR->ir->CreateBitCast(rpart, LLType::FloatTy, ".re");
@@ -56,8 +68,10 @@
     }
 
     // {float,float} -> i64
-    LLValue* put(Type*, LLValue* v)
+    LLValue* put(Type*, DValue* dv)
     {
+        LLValue* v = dv->getRVal();
+
         // extract real
         LLValue* r = gIR->ir->CreateExtractValue(v, 0);
         // cast to i32
@@ -95,20 +109,29 @@
 struct X86_struct_to_register : ABIRewrite
 {
     // int -> struct
-    LLValue* get(Type* dty, LLValue* v)
+    LLValue* get(Type* dty, DValue* dv)
     {
         Logger::println("rewriting int -> struct");
         LLValue* mem = DtoAlloca(DtoType(dty), ".int_to_struct");
+        LLValue* v = dv->getRVal();
         DtoStore(v, DtoBitCast(mem, getPtrToType(v->getType())));
         return DtoLoad(mem);
     }
+    // int -> struct (with dst lvalue given)
+    void getL(Type* dty, DValue* dv, llvm::Value* lval)
+    {
+        Logger::println("rewriting int -> struct");
+        LLValue* v = dv->getRVal();
+        DtoStore(v, DtoBitCast(lval, getPtrToType(v->getType())));
+    }
     // struct -> int
-    LLValue* put(Type* dty, LLValue* v)
+    LLValue* put(Type* dty, DValue* dv)
     {
         Logger::println("rewriting struct -> int");
-        LLValue* mem = DtoAlloca(v->getType(), ".struct_to_int");
-        DtoStore(v, mem);
-        DtoLoad(DtoBitCast(mem, getPtrToType(type(dty, v->getType()))));
+        assert(dv->isLVal());
+        LLValue* mem = dv->getLVal();
+        const LLType* t = LLIntegerType::get(dty->size()*8);
+        DtoLoad(DtoBitCast(mem, getPtrToType(t)));
     }
     const LLType* type(Type*, const LLType* t)
     {
@@ -241,8 +264,10 @@
 struct X86_64_cfloat_rewrite : ABIRewrite
 {
     // {double} -> {float,float}
-    LLValue* get(Type*, LLValue* in)
+    LLValue* get(Type*, DValue* dv)
     {
+        LLValue* in = dv->getRVal();
+
         // extract double
         LLValue* v = gIR->ir->CreateExtractValue(in, 0);
         // cast to i64
@@ -262,8 +287,10 @@
     }
 
     // {float,float} -> {double}
-    LLValue* put(Type*, LLValue* v)
+    LLValue* put(Type*, DValue* dv)
     {
+        LLValue* v = dv->getRVal();
+
         // extract real
         LLValue* r = gIR->ir->CreateExtractValue(v, 0);
         // cast to i32
--- a/gen/abi.h	Wed Mar 04 16:13:16 2009 +0100
+++ b/gen/abi.h	Wed Mar 04 17:24:25 2009 +0100
@@ -5,6 +5,8 @@
 
 struct Type;
 struct IrFuncTyArg;
+struct DValue;
+
 namespace llvm
 {
     class Type;
@@ -14,13 +16,17 @@
 // return rewrite rule
 struct ABIRewrite
 {
-    // get original value from rewritten one
-    virtual LLValue* get(Type* dty, LLValue* v) = 0;
+    /// get a rewritten value back to its original form
+    virtual LLValue* get(Type* dty, DValue* v) = 0;
 
-    // rewrite original value
-    virtual LLValue* put(Type* dty, LLValue* v) = 0;
+    /// get a rewritten value back to its original form and store result in provided lvalue
+    /// this one is optional and defaults to calling the one above
+    virtual void getL(Type* dty, DValue* v, llvm::Value* lval);
 
-    // returns target type of this rewrite
+    /// put out rewritten value
+    virtual LLValue* put(Type* dty, DValue* v) = 0;
+
+    /// should return the transformed type for this rewrite
     virtual const LLType* type(Type* dty, const LLType* t) = 0;
 };
 
--- a/gen/functions.cpp	Wed Mar 04 16:13:16 2009 +0100
+++ b/gen/functions.cpp	Wed Mar 04 17:24:25 2009 +0100
@@ -684,9 +684,6 @@
             IrLocal* irloc = vd->ir.irLocal;
             assert(irloc);
 
-            // let the abi transform the argument back first
-            LLValue* argvalue = f->fty->getParam(vd->type, i, irloc->value);
-
         #if DMDV2
             if (vd->nestedrefs.dim)
         #else
@@ -701,11 +698,17 @@
 
             if (!refout && (!f->fty->args[i]->byref || lazy))
             {
-                LLValue* a = argvalue;
-                LLValue* v = DtoAlloca(a->getType(), vd->ident->toChars());
-                DtoStore(a,v);
-                irloc->value = v;
+                // alloca a stack slot for this first class value arg
+                LLValue* mem = DtoAlloca(DtoType(vd->type), vd->ident->toChars());
+
+                // let the abi transform the argument back first
+                DImValue arg_dval(vd->type, irloc->value);
+                f->fty->getParam(vd->type, i, &arg_dval, mem);
+
+                // set the arg var value to the alloca
+                irloc->value = mem;
             }
+
             if (global.params.symdebug && !(isaArgument(irloc->value) && !isaArgument(irloc->value)->hasByValAttr()) && !refout)
                 DtoDwarfLocalVariable(irloc->value, vd);
         }
--- a/gen/statements.cpp	Wed Mar 04 16:13:16 2009 +0100
+++ b/gen/statements.cpp	Wed Mar 04 17:24:25 2009 +0100
@@ -68,6 +68,8 @@
             // emit dbg line
             if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
 
+            // FIXME: is there ever a case where a sret return needs to be rewritten for the ABI?
+
             // get return pointer
             DValue* rvar = new DVarValue(f->type->next, f->decl->ir.irFunc->retArg);
             DValue* e = exp->toElem(p);
@@ -88,12 +90,9 @@
         else
         {
             if (global.params.symdebug) DtoDwarfStopPoint(loc.linnum);
-            DValue* e = exp->toElem(p);
-            LLValue* v = e->getRVal();
-            delete e;
 
             // do abi specific transformations on the return value
-            v = p->func()->type->fty->putRet(exp->type, v);
+            LLValue* v = p->func()->type->fty->putRet(exp->type, exp->toElem(p));
 
             if (Logger::enabled())
                 Logger::cout() << "return value is '" <<*v << "'\n";
--- a/gen/tocall.cpp	Wed Mar 04 16:13:16 2009 +0100
+++ b/gen/tocall.cpp	Wed Mar 04 17:24:25 2009 +0100
@@ -380,13 +380,12 @@
             Argument* fnarg = Argument::getNth(tf->parameters, i);
             assert(fnarg);
             DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
-            LLValue* arg = argval->getRVal();
+
+            // give the ABI a say
+            LLValue* arg = tf->fty->putParam(argval->getType(), i, argval);
 
             int j = tf->fty->reverseParams ? beg + n - i - 1 : beg + i;
 
-            // give the ABI a say
-            arg = tf->fty->putParam(argval->getType(), i, arg);
-
             // parameter type mismatch, this is hard to get rid of
             if (arg->getType() != callableTy->getParamType(j))
             {
@@ -483,7 +482,8 @@
     else if (!retinptr)
     {
         // do abi specific return value fixups
-        retllval = tf->fty->getRet(tf->next, retllval);
+        DImValue dretval(tf->next, retllval);
+        retllval = tf->fty->getRet(tf->next, &dretval);
     }
 
     // repaint the type if necessary
--- a/ir/irfunction.cpp	Wed Mar 04 16:13:16 2009 +0100
+++ b/ir/irfunction.cpp	Wed Mar 04 17:24:25 2009 +0100
@@ -2,6 +2,7 @@
 #include "gen/llvm.h"
 #include "gen/tollvm.h"
 #include "gen/abi.h"
+#include "gen/dvalue.h"
 #include "ir/irfunction.h"
 
 #include <sstream>
@@ -23,36 +24,49 @@
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-llvm::Value* IrFuncTy::putRet(Type* dty, llvm::Value* val)
+llvm::Value* IrFuncTy::putRet(Type* dty, DValue* val)
 {
     assert(!arg_sret);
     if (ret->rewrite)
         return ret->rewrite->put(dty, val);
-    return val;
+    return val->getRVal();
 }
 
-llvm::Value* IrFuncTy::getRet(Type* dty, llvm::Value* val)
+llvm::Value* IrFuncTy::getRet(Type* dty, DValue* val)
 {
     assert(!arg_sret);
     if (ret->rewrite)
         return ret->rewrite->get(dty, val);
-    return val;
+    return val->getRVal();
 }
 
-llvm::Value* IrFuncTy::putParam(Type* dty, int idx, llvm::Value* val)
+llvm::Value* IrFuncTy::putParam(Type* dty, int idx, DValue* val)
 {
     assert(idx >= 0 && idx < args.size() && "invalid putParam");
     if (args[idx]->rewrite)
         return args[idx]->rewrite->put(dty, val);
-    return val;
+    return val->getRVal();
 }
 
-llvm::Value* IrFuncTy::getParam(Type* dty, int idx, llvm::Value* val)
+llvm::Value* IrFuncTy::getParam(Type* dty, int idx, DValue* val)
 {
     assert(idx >= 0 && idx < args.size() && "invalid getParam");
     if (args[idx]->rewrite)
         return args[idx]->rewrite->get(dty, val);
-    return val;
+    return val->getRVal();
+}
+
+void IrFuncTy::getParam(Type* dty, int idx, DValue* val, llvm::Value* lval)
+{
+    assert(idx >= 0 && idx < args.size() && "invalid getParam");
+
+    if (args[idx]->rewrite)
+    {
+        args[idx]->rewrite->getL(dty, val, lval);
+        return;
+    }
+
+    DtoStore(val->getRVal(), lval);
 }
 
 //////////////////////////////////////////////////////////////////////////////
--- a/ir/irfunction.h	Wed Mar 04 16:13:16 2009 +0100
+++ b/ir/irfunction.h	Wed Mar 04 17:24:25 2009 +0100
@@ -19,33 +19,34 @@
      *  May NOT be rewritten!!! */
     Type* type;
 
-    /// This is the final LLVM Type used for the parameter/returnvalue type
+    /// This is the final LLVM Type used for the parameter/return value type
     const llvm::Type* ltype;
 
-    /** These are the final llvm attributes needed
-     *  must be valid for the LLVM Type and byref setting */
+    /** These are the final LLVM attributes used for the function.
+     *  Must be valid for the LLVM Type and byref setting */
     unsigned attrs;
 
-    /** true if the argument final argument is a reference argument
-     *  must be true when the D Type is a value type, but the final
-     *  LLVM Type is a reference type */
+    /** 'true' if the final LLVM argument is a LLVM reference type.
+     *  Must be true when the D Type is a value type, but the final
+     *  LLVM Type is a reference type! */
     bool byref;
 
-    /** Pointer to the ABIRewrite structure needed to rewrite llvm ValueS
-     *  to match the final LLVM Type */
+    /** Pointer to the ABIRewrite structure needed to rewrite LLVM ValueS
+     *  to match the final LLVM Type when passing arguments and getting
+     *  return values */
     ABIRewrite* rewrite;
 
-    /// Helper to check is the 'inreg' attribute is set
+    /// Helper to check if the 'inreg' attribute is set
     bool isInReg() const { return (attrs & llvm::Attribute::InReg) != 0; }
-    /// Helper to check is the 'sret' attribute is set
+    /// Helper to check if the 'sret' attribute is set
     bool isSRet() const  { return (attrs & llvm::Attribute::StructRet) != 0; }
-    /// Helper to check is the 'byval' attribute is set
+    /// Helper to check if the 'byval' attribute is set
     bool isByVal() const { return (attrs & llvm::Attribute::ByVal) != 0; }
 
-    /** Constructor
-     *  @param t D type of argument/returnvalue as known by the frontend
-     *  @param byref Initial value for the 'byref' field. If true the initial LLVM Type will be of type->pointerTo()
-     */
+    /** @param t D type of argument/return value as known by the frontend
+     *  @param byref Initial value for the 'byref' field. If true the initial
+     *               LLVM Type will be of DtoType(type->pointerTo()), instead
+     *               of just DtoType(type) */
     IrFuncTyArg(Type* t, bool byref, unsigned a = 0);
 };
 
@@ -82,11 +83,12 @@
         reverseParams(false)
     {}
 
-    llvm::Value* putRet(Type* dty, llvm::Value* val);
-    llvm::Value* getRet(Type* dty, llvm::Value* val);
+    llvm::Value* putRet(Type* dty, DValue* dval);
+    llvm::Value* getRet(Type* dty, DValue* dval);
 
-    llvm::Value* getParam(Type* dty, int idx, llvm::Value* val);
-    llvm::Value* putParam(Type* dty, int idx, llvm::Value* val);
+    llvm::Value* putParam(Type* dty, int idx, DValue* dval);
+    llvm::Value* getParam(Type* dty, int idx, DValue* dval);
+    void getParam(Type* dty, int idx, DValue* dval, llvm::Value* lval);
 };
 
 // represents a function