changeset 1027:c061e0725d89

Oops, merge with mainline and actually push this time...
author Frits van Bommel <fvbommel wxs.nl>
date Tue, 03 Mar 2009 09:51:15 +0100
parents f756c47f310a (current diff) c519caae3181 (diff)
children 964af20461a9
files
diffstat 12 files changed, 490 insertions(+), 436 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/mtype.c	Sun Mar 01 22:59:03 2009 +0100
+++ b/dmd/mtype.c	Tue Mar 03 09:51:15 2009 +0100
@@ -2659,14 +2659,9 @@
     this->varargs = varargs;
     this->linkage = linkage;
     this->inuse = 0;
-    this->retInPtr = false;
-    this->usesThis = false;
-    this->usesNest = false;
-    this->structInregArg = NULL;
-    this->retAttrs = 0;
-    this->thisAttrs = 0;
-    this->reverseParams = false;
-    this->firstRealArg = 0;
+
+    // LDC
+    this->fty = NULL;
 }
 
 Type *TypeFunction::syntaxCopy()
@@ -2674,13 +2669,6 @@
     Type *treturn = next ? next->syntaxCopy() : NULL;
     Arguments *params = Argument::arraySyntaxCopy(parameters);
     TypeFunction *t = new TypeFunction(params, treturn, varargs, linkage);
-    t->retInPtr = retInPtr;
-    t->usesThis = usesThis;
-    t->usesNest = usesNest;
-    t->retAttrs = retAttrs;
-    t->thisAttrs = thisAttrs;
-    t->reverseParams = reverseParams;
-    t->firstRealArg = firstRealArg;
     return t;
 }
 
@@ -5316,7 +5304,6 @@
     this->ident = ident;
     this->storageClass = storageClass;
     this->defaultArg = defaultArg;
-    this->llvmAttrs = 0;
 }
 
 Argument *Argument::syntaxCopy()
@@ -5325,7 +5312,6 @@
 		type ? type->syntaxCopy() : NULL,
 		ident,
 		defaultArg ? defaultArg->syntaxCopy() : NULL);
-    a->llvmAttrs = llvmAttrs;
     return a;
 }
 
--- a/dmd/mtype.h	Sun Mar 01 22:59:03 2009 +0100
+++ b/dmd/mtype.h	Tue Mar 03 09:51:15 2009 +0100
@@ -24,6 +24,7 @@
 // llvm
 #include "../ir/irtype.h"
 namespace llvm { class Type; }
+struct IrFuncTy;
 
 struct Scope;
 struct Identifier;
@@ -436,17 +437,7 @@
     unsigned totym();
 
     // LDC
-    bool retInPtr;
-    bool usesThis;
-    bool usesNest;
-    // when the last arg is a struct and passed in EAX, this holds its real type
-    const llvm::Type* structInregArg;
-    unsigned retAttrs;
-    unsigned thisAttrs; // also used for nest
-    // parameter index in the llvm function that contains the first not-implicit arg
-    size_t firstRealArg;
-
-    bool reverseParams;
+    IrFuncTy* fty;
 };
 
 struct TypeDelegate : Type
@@ -699,9 +690,6 @@
     static void argsToDecoBuffer(OutBuffer *buf, Arguments *arguments);
     static size_t dim(Arguments *arguments);
     static Argument *getNth(Arguments *arguments, size_t nth, size_t *pn = NULL);
-
-    // LDC
-    unsigned llvmAttrs;
 };
 
 extern int PTRSIZE;
--- a/dmd/optimize.c	Sun Mar 01 22:59:03 2009 +0100
+++ b/dmd/optimize.c	Tue Mar 03 09:51:15 2009 +0100
@@ -46,7 +46,7 @@
     if (e1->op == TOKvar)
     {	VarExp *ve = (VarExp *)e1;
 	VarDeclaration *v = ve->var->isVarDeclaration();
-	if (v && v->isConst() && v->init)
+	if (v && v->isConst() && v->init && !v->init->isStructInitializer())
 	{   Expression *ei = v->init->toExpression();
 	    if (ei && ei->type)
 		e1 = ei;
--- a/gen/abi.cpp	Sun Mar 01 22:59:03 2009 +0100
+++ b/gen/abi.cpp	Tue Mar 03 09:51:15 2009 +0100
@@ -1,5 +1,7 @@
 #include "gen/llvm.h"
 
+#include <algorithm>
+
 #include "mars.h"
 
 #include "gen/irstate.h"
@@ -8,59 +10,7 @@
 #include "gen/abi.h"
 #include "gen/logger.h"
 
-//////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-/////////////////////        baseclass            ////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-//////////////////////////////////////////////////////////////////////////////
-
-// FIXME: Would be nice to come up a better and faster way to do this, right
-// now I'm more worried about actually making this abstraction work at all ...
-// It's definitely way overkill with the amount of return value rewrites we
-// have right now, but I expect this to change with proper x86-64 abi support
-
-TargetABI::TargetABI()
-{
-}
-
-llvm::Value* TargetABI::getRet(TypeFunction* tf, llvm::Value* io)
-{
-    if (ABIRetRewrite* r = findRetRewrite(tf))
-    {
-        return r->get(io);
-    }
-    return io;
-}
-
-llvm::Value* TargetABI::putRet(TypeFunction* tf, llvm::Value* io)
-{
-    if (ABIRetRewrite* r = findRetRewrite(tf))
-    {
-        return r->put(io);
-    }
-    return io;
-}
-
-const llvm::Type* TargetABI::getRetType(TypeFunction* tf, const llvm::Type* t)
-{
-    if (ABIRetRewrite* r = findRetRewrite(tf))
-    {
-        return r->type(t);
-    }
-    return t;
-}
-
-ABIRetRewrite * TargetABI::findRetRewrite(TypeFunction * tf)
-{
-    size_t n = retOps.size();
-    if (n)
-    for (size_t i = 0; i < n; i++)
-    {
-        if (retOps[i]->test(tf))
-            return retOps[i];
-    }
-    return NULL;
-}
+#include "ir/irfunction.h"
 
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
@@ -69,33 +19,28 @@
 //////////////////////////////////////////////////////////////////////////////
 
 // simply swap of real/imag parts for proper x87 complex abi
-struct X87_complex_swap : ABIRetRewrite
+struct X87_complex_swap : ABIRewrite
 {
-    LLValue* get(LLValue* v)
+    LLValue* get(Type*, LLValue* v)
     {
         return DtoAggrPairSwap(v);
     }
-    LLValue* put(LLValue* v)
+    LLValue* put(Type*, LLValue* v)
     {
         return DtoAggrPairSwap(v);
     }
-    const LLType* type(const LLType* t)
+    const LLType* type(Type*, const LLType* t)
     {
         return t;
     }
-    bool test(TypeFunction* tf)
-    {
-        // extern(D) && is(T:creal)
-        return (tf->linkage == LINKd && tf->next->toBasetype()->iscomplex());
-    }
 };
 
 //////////////////////////////////////////////////////////////////////////////
 
-struct X86_cfloat_rewrite : ABIRetRewrite
+struct X86_cfloat_rewrite : ABIRewrite
 {
     // i64 -> {float,float}
-    LLValue* get(LLValue* in)
+    LLValue* get(Type*, LLValue* in)
     {
         // extract real part
         LLValue* rpart = gIR->ir->CreateTrunc(in, LLType::Int32Ty);
@@ -111,7 +56,7 @@
     }
 
     // {float,float} -> i64
-    LLValue* put(LLValue* v)
+    LLValue* put(Type*, LLValue* v)
     {
         // extract real
         LLValue* r = gIR->ir->CreateExtractValue(v, 0);
@@ -134,16 +79,41 @@
     }
 
     // {float,float} -> i64
-    const LLType* type(const LLType* t)
+    const LLType* type(Type*, const LLType* t)
     {
         return LLType::Int64Ty;
     }
+};
 
-    // test if rewrite applies to function
-    bool test(TypeFunction* tf)
+//////////////////////////////////////////////////////////////////////////////
+
+// FIXME: try into eliminating the alloca or if at least check
+// if it gets optimized away
+
+// convert byval struct
+// when 
+struct X86_struct_to_register : ABIRewrite
+{
+    // int -> struct
+    LLValue* get(Type* dty, LLValue* v)
     {
-        return (tf->linkage != LINKd) 
-            && (tf->next->toBasetype() == Type::tcomplex32);
+        Logger::println("rewriting int -> struct");
+        LLValue* mem = DtoAlloca(DtoType(dty), ".int_to_struct");
+        DtoStore(v, DtoBitCast(mem, getPtrToType(v->getType())));
+        return DtoLoad(mem);
+    }
+    // struct -> int
+    LLValue* put(Type* dty, LLValue* v)
+    {
+        Logger::println("rewriting struct -> int");
+        LLValue* mem = DtoAlloca(v->getType(), ".struct_to_int");
+        DtoStore(v, mem);
+        DtoLoad(DtoBitCast(mem, getPtrToType(type(dty, v->getType()))));
+    }
+    const LLType* type(Type*, const LLType* t)
+    {
+        size_t sz = getTypePaddedSize(t)*8;
+        return LLIntegerType::get(sz);
     }
 };
 
@@ -151,11 +121,9 @@
 
 struct X86TargetABI : TargetABI
 {
-    X86TargetABI()
-    {
-        retOps.push_back(new X87_complex_swap);
-        retOps.push_back(new X86_cfloat_rewrite);
-    }
+    X87_complex_swap swapComplex;
+    X86_cfloat_rewrite cfloatToInt;
+    X86_struct_to_register structToReg;
 
     bool returnInArg(TypeFunction* tf)
     {
@@ -168,6 +136,98 @@
         else
             return (rt->ty == Tstruct || rt->ty == Tcomplex64 || rt->ty == Tcomplex80);
     }
+
+    bool passByVal(Type* t)
+    {
+        return t->toBasetype()->ty == Tstruct;
+    }
+
+    void rewriteFunctionType(TypeFunction* tf)
+    {
+        IrFuncTy* fty = tf->fty;
+        Type* rt = fty->ret->type->toBasetype();
+
+        // extern(D)
+        if (tf->linkage == LINKd)
+        {
+            // RETURN VALUE
+
+            // complex {re,im} -> {im,re}
+            if (rt->iscomplex())
+            {
+                fty->ret->rewrite = &swapComplex;
+            }
+
+            // IMPLICIT PARAMETERS
+
+            // mark this/nested params inreg
+            if (fty->arg_this)
+            {
+                fty->arg_this->attrs = llvm::Attribute::InReg;
+            }
+            else if (fty->arg_nest)
+            {
+                fty->arg_nest->attrs = llvm::Attribute::InReg;
+            }
+            // otherwise try to mark the last param inreg
+            else if (!fty->arg_sret && !fty->args.empty())
+            {
+                // The last parameter is passed in EAX rather than being pushed on the stack if the following conditions are met:
+                //   * It fits in EAX.
+                //   * It is not a 3 byte struct.
+                //   * It is not a floating point type.
+
+                IrFuncTyArg* last = fty->args.back();
+                Type* lastTy = last->type->toBasetype();
+                unsigned sz = lastTy->size();
+
+                if (last->byref && !last->isByVal())
+                {
+                    last->attrs = llvm::Attribute::InReg;
+                }
+                else if (!lastTy->isfloating() && (sz == 1 || sz == 2 || sz == 4)) // right?
+                {
+                    // rewrite the struct into an integer to make inreg work
+                    if (lastTy->ty == Tstruct)
+                    {
+                        last->rewrite = &structToReg;
+                        last->ltype = structToReg.type(last->type, last->ltype);
+                        last->byref = false;
+                    }
+                    last->attrs = llvm::Attribute::InReg;
+                }
+            }
+
+            // FIXME: tf->varargs == 1 need to use C calling convention and vararg mechanism to live up to the spec:
+            // "The caller is expected to clean the stack. _argptr is not passed, it is computed by the callee."
+
+            // EXPLICIT PARAMETERS
+
+            // reverse parameter order
+            // for non variadics
+            if (!fty->args.empty() && tf->varargs != 1)
+            {
+                fty->reverseParams = true;
+            }
+        }
+
+        // extern(C) and all others
+        else
+        {
+            // RETURN VALUE
+
+            // cfloat -> i64
+            if (tf->next->toBasetype() == Type::tcomplex32)
+            {
+                fty->ret->rewrite = &cfloatToInt;
+                fty->ret->ltype = LLType::Int64Ty;
+            }
+
+            // IMPLICIT PARAMETERS
+
+            // EXPLICIT PARAMETERS
+        }
+    }
 };
 
 //////////////////////////////////////////////////////////////////////////////
@@ -176,10 +236,10 @@
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
-struct X86_64_cfloat_rewrite : ABIRetRewrite
+struct X86_64_cfloat_rewrite : ABIRewrite
 {
     // {double} -> {float,float}
-    LLValue* get(LLValue* in)
+    LLValue* get(Type*, LLValue* in)
     {
         // extract double
         LLValue* v = gIR->ir->CreateExtractValue(in, 0);
@@ -200,7 +260,7 @@
     }
 
     // {float,float} -> {double}
-    LLValue* put(LLValue* v)
+    LLValue* put(Type*, LLValue* v)
     {
         // extract real
         LLValue* r = gIR->ir->CreateExtractValue(v, 0);
@@ -231,33 +291,41 @@
     }
 
     // {float,float} -> {double}
-    const LLType* type(const LLType* t)
+    const LLType* type(Type*, const LLType* t)
     {
         return LLStructType::get(LLType::DoubleTy, NULL);
     }
-
-    // test if rewrite applies to function
-    bool test(TypeFunction* tf)
-    {
-        return (tf->linkage != LINKd) 
-            && (tf->next->toBasetype() == Type::tcomplex32);
-    }
 };
 
 //////////////////////////////////////////////////////////////////////////////
 
 struct X86_64TargetABI : TargetABI
 {
-    X86_64TargetABI()
-    {
-        retOps.push_back(new X86_64_cfloat_rewrite);
-    }
+    X86_64_cfloat_rewrite cfloat_rewrite;
 
     bool returnInArg(TypeFunction* tf)
     {
         Type* rt = tf->next->toBasetype();
         return (rt->ty == Tstruct);
     }
+
+    bool passByVal(Type* t)
+    {
+        return t->toBasetype()->ty == Tstruct;
+    }
+
+    void rewriteFunctionType(TypeFunction* tf)
+    {
+        IrFuncTy* fty = tf->fty;
+        Type* rt = fty->ret->type->toBasetype();
+
+        // rewrite cfloat return for !extern(D)
+        if (tf->linkage != LINKd && rt == Type::tcomplex32)
+        {
+            fty->ret->rewrite = &cfloat_rewrite;
+            fty->ret->ltype = cfloat_rewrite.type(fty->ret->type, fty->ret->ltype);
+        }
+    }
 };
 
 //////////////////////////////////////////////////////////////////////////////
@@ -269,15 +337,19 @@
 // Some reasonable defaults for when we don't know what ABI to use.
 struct UnknownTargetABI : TargetABI
 {
-    UnknownTargetABI()
+    bool returnInArg(TypeFunction* tf)
     {
-        // Don't push anything into retOps, assume defaults will be fine.
+        return (tf->next->toBasetype()->ty == Tstruct);
     }
 
-    bool returnInArg(TypeFunction* tf)
+    bool passByVal(Type* t)
     {
-        Type* rt = tf->next->toBasetype();
-        return (rt->ty == Tstruct);
+        return t->toBasetype()->ty == Tstruct;
+    }
+
+    void rewriteFunctionType(TypeFunction* t)
+    {
+        // why?
     }
 };
 
--- a/gen/abi.h	Sun Mar 01 22:59:03 2009 +0100
+++ b/gen/abi.h	Tue Mar 03 09:51:15 2009 +0100
@@ -4,6 +4,7 @@
 #include <vector>
 
 struct Type;
+struct IrFuncTyArg;
 namespace llvm
 {
     class Type;
@@ -11,38 +12,27 @@
 }
 
 // return rewrite rule
-struct ABIRetRewrite
+struct ABIRewrite
 {
     // get original value from rewritten one
-    virtual LLValue* get(LLValue* v) = 0;
+    virtual LLValue* get(Type* dty, LLValue* v) = 0;
 
     // rewrite original value
-    virtual LLValue* put(LLValue* v) = 0;
+    virtual LLValue* put(Type* dty, LLValue* v) = 0;
 
     // returns target type of this rewrite
-    virtual const LLType* type(const LLType* t) = 0;
-
-    // test if rewrite applies
-    virtual bool test(TypeFunction* tf) = 0;
+    virtual const LLType* type(Type* dty, const LLType* t) = 0;
 };
 
-
 // interface called by codegen
 struct TargetABI
 {
     static TargetABI* getTarget();
 
-    TargetABI();
-
-    const llvm::Type* getRetType(TypeFunction* tf, const llvm::Type* t);
-    llvm::Value* getRet(TypeFunction* tf, llvm::Value* v);
-    llvm::Value* putRet(TypeFunction* tf, llvm::Value* v);
+    virtual bool returnInArg(TypeFunction* tf) = 0;
+    virtual bool passByVal(Type* t) = 0;
 
-    virtual bool returnInArg(TypeFunction* t) = 0;
-
-protected:
-    std::vector<ABIRetRewrite*> retOps;
-    ABIRetRewrite* findRetRewrite(TypeFunction* tf);
+    virtual void rewriteFunctionType(TypeFunction* t) = 0;
 };
 
 #endif
--- a/gen/functions.cpp	Sun Mar 01 22:59:03 2009 +0100
+++ b/gen/functions.cpp	Tue Mar 03 09:51:15 2009 +0100
@@ -22,136 +22,114 @@
 #include "gen/dvalue.h"
 #include "gen/abi.h"
 
-#include <algorithm>
-
-const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, const LLType* nesttype, bool ismain)
+const llvm::FunctionType* DtoFunctionType(Type* type, Type* thistype, Type* nesttype, bool ismain)
 {
+    // sanity check
     assert(type->ty == Tfunction);
     TypeFunction* f = (TypeFunction*)type;
 
+    // already built ?
     if (type->ir.type != NULL) {
+        assert(f->fty != NULL);
         return llvm::cast<llvm::FunctionType>(type->ir.type->get());
     }
 
-    bool dVararg = false;
-    bool arrayVararg = false;
-    if (f->linkage == LINKd)
+    // create new ir funcTy
+    assert(f->fty == NULL);
+    f->fty = new IrFuncTy();
+
+    // llvm idx counter
+    size_t lidx = 0;
+
+    // main needs a little special handling
+    if (ismain)
+    {
+        f->fty->ret = new IrFuncTyArg(Type::tint32, false);
+    }
+    // sane return value
+    else
     {
-        if (f->varargs == 1)
-            dVararg = true;
-        else if (f->varargs == 2)
-            arrayVararg = true;
+        Type* rt = f->next;
+        unsigned a = 0;
+        // sret return
+        if (gABI->returnInArg(f))
+        {
+            f->fty->arg_sret = new IrFuncTyArg(rt, true, llvm::Attribute::StructRet);
+            rt = Type::tvoid;
+            lidx++;
+        }
+        // sext/zext return
+        else if (unsigned se = DtoShouldExtend(rt))
+        {
+            a = se;
+        }
+        f->fty->ret = new IrFuncTyArg(rt, false, a);
+    }
+    lidx++;
+
+    // member functions
+    if (thistype)
+    {
+        bool toref = (thistype->toBasetype()->ty == Tstruct);
+        f->fty->arg_this = new IrFuncTyArg(thistype, toref);
+        lidx++;
     }
 
-    // return value type
-    const LLType* rettype;
-    const LLType* actualRettype;
-    Type* rt = f->next;
-    bool retinptr = false;
-    bool usesthis = false;
-    bool usesnest = false;
+    // and nested functions
+    else if (nesttype)
+    {
+        f->fty->arg_nest = new IrFuncTyArg(nesttype, false);
+        lidx++;
+    }
 
-    // parameter types
-    std::vector<const LLType*> paramvec;
-
-    // special case main
-    if (ismain)
+    // vararg functions are special too
+    if (f->varargs)
     {
-        rettype = LLType::Int32Ty;
-        actualRettype = rettype;
-        if (Argument::dim(f->parameters) == 0)
+        if (f->linkage == LINKd)
         {
-            const LLType* arrTy = DtoArrayType(LLType::Int8Ty);
-            const LLType* arrArrTy = DtoArrayType(arrTy);
-            paramvec.push_back(arrArrTy);
+            // d style with hidden args
+            // 2 (array) is handled by the frontend
+            if (f->varargs == 1)
+            {
+                // _arguments
+                f->fty->arg_arguments = new IrFuncTyArg(Type::typeinfo->type->arrayOf(), false);
+                lidx++;
+                // _argptr
+                f->fty->arg_argptr = new IrFuncTyArg(Type::tvoid->pointerTo(), false);
+                lidx++;
+            }
         }
-    }
-    // default handling
-    else
-    {
-        assert(rt);
-        if (f->linkage == LINKintrinsic)
+        else if (f->linkage == LINKc)
         {
-            // Intrinsics don't care about ABI
-            Logger::cout() << "Intrinsic returning " << rt->toChars() << '\n';
-            actualRettype = rettype = DtoType(rt);
-            Logger::cout() << "  (LLVM type: " << *rettype << ")\n";
+            f->fty->c_vararg = true;
         }
         else
         {
-            if (gABI->returnInArg(f))
-            {
-                rettype = getPtrToType(DtoType(rt));
-                actualRettype = LLType::VoidTy;
-                f->retInPtr = retinptr = true;
-            }
-            else
-            {
-                rettype = DtoType(rt);
-                // do abi specific transformations
-                actualRettype = gABI->getRetType(f, rettype);
-            }
-
-            // FIXME: should probably be part of the abi
-            if (unsigned ea = DtoShouldExtend(rt))
-            {
-                f->retAttrs |= ea;
-            }
+            type->error(0, "invalid linkage for variadic function");
+            fatal();
         }
     }
 
-    // build up parameter list
-    if (retinptr) {
-        //Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
-        paramvec.push_back(rettype);
-    }
-
-    // this/context param
-    if (thistype) {
-        paramvec.push_back(thistype);
-        usesthis = true;
-    }
-    else if (nesttype) {
-        paramvec.push_back(nesttype);
-        usesnest = true;
-    }
-
-    // dstyle vararg
-    if (dVararg) {
-        paramvec.push_back(DtoType(Type::typeinfo->type->arrayOf())); // _arguments
-        paramvec.push_back(getVoidPtrType()); // _argptr
-    }
-
-    // now that all implicit args are done, store the start of the real args
-    f->firstRealArg = paramvec.size();
+    // if this _Dmain() doesn't have an argument, we force it to have one
+    int nargs = Argument::dim(f->parameters);
 
-    // number of formal params
-    size_t n = Argument::dim(f->parameters);
-
-#if X86_REVERSE_PARAMS
-    // on x86 we need to reverse the formal params in some cases to match the ABI
-    if (global.params.cpu == ARCHx86)
+    if (ismain && nargs == 0)
+    {
+        Type* mainargs = Type::tchar->arrayOf()->arrayOf();
+        f->fty->args.push_back(new IrFuncTyArg(mainargs, false));
+        lidx++;
+    }
+    // add explicit parameters
+    else for (int i = 0; i < nargs; i++)
     {
-        // more than one formal arg,
-        // extern(D) linkage
-        // not a D-style vararg
-        if (n > 1 && f->linkage == LINKd && !dVararg)
-        {
-            f->reverseParams = true;
-        }
-    }
-#endif // X86_REVERSE_PARAMS
+        // get argument
+        Argument* arg = Argument::getNth(f->parameters, i);
 
+        // reference semantics? ref, out and static arrays are
+        bool byref = (arg->storageClass & (STCref|STCout)) || (arg->type->toBasetype()->ty == Tsarray);
 
-    for (int i=0; i < n; ++i) {
-        Argument* arg = Argument::getNth(f->parameters, i);
-        // ensure scalar
-        Type* argT = arg->type->toBasetype();
-        assert(argT);
-
-        bool refOrOut = ((arg->storageClass & STCref) || (arg->storageClass & STCout));
-
-        const LLType* at = DtoType(argT);
+        Type* argtype = arg->type;
+        unsigned a = 0;
 
         // handle lazy args
         if (arg->storageClass & STClazy)
@@ -159,113 +137,51 @@
             Logger::println("lazy param");
             TypeFunction *ltf = new TypeFunction(NULL, arg->type, 0, LINKd);
             TypeDelegate *ltd = new TypeDelegate(ltf);
-            at = DtoType(ltd);
-            paramvec.push_back(at);
+            argtype = ltd;
         }
-        // opaque types need special handling
-        else if (llvm::isa<llvm::OpaqueType>(at)) {
-            Logger::println("opaque param");
-            assert(argT->ty == Tstruct || argT->ty == Tclass);
-            paramvec.push_back(getPtrToType(at));
+        // byval
+        else if (gABI->passByVal(argtype))
+        {
+            if (!byref) a |= llvm::Attribute::ByVal;
+            byref = true;
         }
-        // structs are passed as a reference, but by value
-        else if (argT->ty == Tstruct) {
-            Logger::println("struct param");
-            if (!refOrOut)
-                arg->llvmAttrs |= llvm::Attribute::ByVal;
-            paramvec.push_back(getPtrToType(at));
+        // sext/zext
+        else if (!byref)
+        {
+            a |= DtoShouldExtend(argtype);
         }
-        // static arrays are passed directly by reference
-        else if (argT->ty == Tsarray)
-        {
-            Logger::println("static array param");
-            at = getPtrToType(at);
-            paramvec.push_back(at);
-        }
-        // firstclass ' ref/out ' parameter
-        else if (refOrOut) {
-            Logger::println("ref/out param");
-            at = getPtrToType(at);
-            paramvec.push_back(at);
-        }
-        // firstclass ' in ' parameter
-        else {
-            Logger::println("in param");
-            if (unsigned ea = DtoShouldExtend(argT))
-                arg->llvmAttrs |= ea;
-            paramvec.push_back(at);
-        }
+
+        f->fty->args.push_back(new IrFuncTyArg(argtype, byref, a));
+        lidx++;
+    }
+
+    // let the abi rewrite the types as necesary
+    gABI->rewriteFunctionType(f);
+
+    // build the function type
+    std::vector<const LLType*> argtypes;
+    argtypes.reserve(lidx);
+
+    if (f->fty->arg_sret) argtypes.push_back(f->fty->arg_sret->ltype);
+    if (f->fty->arg_this) argtypes.push_back(f->fty->arg_this->ltype);
+    if (f->fty->arg_nest) argtypes.push_back(f->fty->arg_nest->ltype);
+    if (f->fty->arg_arguments) argtypes.push_back(f->fty->arg_arguments->ltype);
+    if (f->fty->arg_argptr) argtypes.push_back(f->fty->arg_argptr->ltype);
+
+    size_t beg = argtypes.size();
+    size_t nargs2 = f->fty->args.size();
+    for (size_t i = 0; i < nargs2; i++)
+    {
+        argtypes.push_back(f->fty->args[i]->ltype);
     }
 
     // reverse params?
-    if (f->reverseParams)
+    if (f->fty->reverseParams && f->parameters->dim > 1)
     {
-        std::reverse(paramvec.begin() + f->firstRealArg, paramvec.end());
+        std::reverse(argtypes.begin() + beg, argtypes.end());
     }
 
-#if X86_PASS_IN_EAX
-    // pass first param in EAX if it fits, is not floating point and is not a 3 byte struct.
-    // ONLY extern(D) functions !
-    if ((n > 0 || usesthis || usesnest) && f->linkage == LINKd)
-    {
-        // FIXME: Only x86 right now ...
-        if (global.params.cpu == ARCHx86)
-        {
-            int n_inreg = f->reverseParams ? n - 1 : 0;
-            Argument* arg = Argument::getNth(f->parameters, n_inreg);
-
-            // if there is a implicit context parameter, pass it in EAX
-            if (usesthis || usesnest)
-            {
-                f->thisAttrs |= llvm::Attribute::InReg;
-                assert((!arg || (arg->llvmAttrs & llvm::Attribute::InReg) == 0) && "can't have two inreg args!");
-            }
-            // otherwise check the first formal parameter
-            else
-            {
-                Type* t = arg->type->toBasetype();
-
-                // 32bit ints, pointers, classes, static arrays, AAs, ref and out params,
-                // and structs with size <= 4 and != 3
-                // are candidate for being passed in EAX
-                if (
-                    (arg->storageClass & (STCref|STCout))
-                    ||
-                    ((arg->storageClass & STCin) &&
-                     ((t->isscalar() && !t->isfloating()) ||
-                      t->ty == Tclass || t->ty == Tsarray || t->ty == Taarray ||
-                      (t->ty == Tstruct && t->size() != 3)
-                     ) && (t->size() <= PTRSIZE))
-                   )
-                {
-                    arg->llvmAttrs |= llvm::Attribute::InReg;
-                    assert((f->thisAttrs & llvm::Attribute::InReg) == 0 && "can't have two inreg args!");
-
-                    // structs need to go from {...}* byval to i8/i16/i32 inreg
-                    if ((arg->storageClass & STCin) && t->ty == Tstruct)
-                    {
-                        int n_param = f->reverseParams ? f->firstRealArg + n - 1 - n_inreg : f->firstRealArg + n_inreg;
-                        assert(isaPointer(paramvec[n_param]) && (arg->llvmAttrs & llvm::Attribute::ByVal)
-                            && "struct parameter expected to be {...}* byval before inreg is applied");
-                        f->structInregArg = paramvec[n_param]->getContainedType(0);
-                        paramvec[n_param] = LLIntegerType::get(8*t->size());
-                        arg->llvmAttrs &= ~llvm::Attribute::ByVal;
-                    }
-                }
-            }
-        }
-    }
-#endif // X86_PASS_IN_EAX
-
-    // construct function type
-    bool isvararg = !(dVararg || arrayVararg) && f->varargs;
-    llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
-
-    // done
-    f->retInPtr = retinptr;
-    f->usesThis = usesthis;
-    f->usesNest = usesnest;
-
+    llvm::FunctionType* functype = llvm::FunctionType::get(f->fty->ret->ltype, argtypes, f->fty->c_vararg);
     f->ir.type = new llvm::PATypeHolder(functype);
 
     return functype;
@@ -283,10 +199,19 @@
     TypeFunction* f = (TypeFunction*)fdecl->type;
     const llvm::FunctionType* fty = 0;
 
+    // create new ir funcTy
+    assert(f->fty == NULL);
+    f->fty = new IrFuncTy();
+    f->fty->ret = new IrFuncTyArg(Type::tvoid, false);
+
+    f->fty->args.push_back(new IrFuncTyArg(Type::tvoid->pointerTo(), false));
+
     if (fdecl->llvmInternal == LLVMva_start)
         fty = GET_INTRINSIC_DECL(vastart)->getFunctionType();
-    else if (fdecl->llvmInternal == LLVMva_copy)
+    else if (fdecl->llvmInternal == LLVMva_copy) {
         fty = GET_INTRINSIC_DECL(vacopy)->getFunctionType();
+        f->fty->args.push_back(new IrFuncTyArg(Type::tvoid->pointerTo(), false));
+    }
     else if (fdecl->llvmInternal == LLVMva_end)
         fty = GET_INTRINSIC_DECL(vaend)->getFunctionType();
     assert(fty);
@@ -307,13 +232,13 @@
     if (fdecl->type->ir.type != 0)
         return llvm::cast<llvm::FunctionType>(fdecl->type->ir.type->get());
 
-    const LLType* thisty = 0;
-    const LLType* nestty = 0;
+    Type *dthis=0, *dnest=0;
 
     if (fdecl->needThis()) {
         if (AggregateDeclaration* ad = fdecl->isMember2()) {
             Logger::println("isMember = this is: %s", ad->type->toChars());
-            thisty = DtoType(ad->type);
+            dthis = ad->type;
+            const LLType* thisty = DtoType(dthis);
             //Logger::cout() << "this llvm type: " << *thisty << '\n';
             if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->type->ir.type->get()))
                 thisty = getPtrToType(thisty);
@@ -324,10 +249,10 @@
         }
     }
     else if (fdecl->isNested()) {
-        nestty = getPtrToType(LLType::Int8Ty);
+        dnest = Type::tvoid->pointerTo();
     }
 
-    const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, thisty, nestty, fdecl->isMain());
+    const llvm::FunctionType* functype = DtoFunctionType(fdecl->type, dthis, dnest, fdecl->isMain());
 
     return functype;
 }
@@ -414,46 +339,35 @@
 
 static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclaration* fdecl)
 {
-    int llidx = 0;
-    if (f->retInPtr) ++llidx;
-    if (f->usesThis) ++llidx;
-    else if (f->usesNest) ++llidx;
-    if (f->linkage == LINKd && f->varargs == 1)
-        llidx += 2;
-
     int funcNumArgs = func->getArgumentList().size();
 
     LLSmallVector<llvm::AttributeWithIndex, 9> attrs;
     llvm::AttributeWithIndex PAWI;
 
-    // set return value attrs if any
-    if (f->retAttrs)
-    {
-        PAWI.Index = 0;
-        PAWI.Attrs = f->retAttrs;
-        attrs.push_back(PAWI);
+    int idx = 0;
+
+    // handle implicit args
+    #define ADD_PA(X) \
+    if (f->fty->X) { \
+        if (f->fty->X->attrs) { \
+            PAWI.Index = idx; \
+            PAWI.Attrs = f->fty->X->attrs; \
+            attrs.push_back(PAWI); \
+        } \
+        idx++; \
     }
 
-    // set sret param
-    if (f->retInPtr)
-    {
-        PAWI.Index = 1;
-        PAWI.Attrs = llvm::Attribute::StructRet;
-        attrs.push_back(PAWI);
-    }
+    ADD_PA(ret)
+    ADD_PA(arg_sret)
+    ADD_PA(arg_this)
+    ADD_PA(arg_nest)
+    ADD_PA(arg_arguments)
+    ADD_PA(arg_argptr)
 
-    // set this/nest param attrs
-    if (f->thisAttrs)
-    {
-        PAWI.Index = f->retInPtr ? 2 : 1;
-        PAWI.Attrs = f->thisAttrs;
-        attrs.push_back(PAWI);
-    }
+    #undef ADD_PA
 
     // set attrs on the rest of the arguments
     size_t n = Argument::dim(f->parameters);
-    assert(funcNumArgs >= n); // main might mismatch, for the implicit char[][] arg
-
     LLSmallVector<unsigned,8> attrptr(n, 0);
 
     for (size_t k = 0; k < n; ++k)
@@ -461,11 +375,11 @@
         Argument* fnarg = Argument::getNth(f->parameters, k);
         assert(fnarg);
 
-        attrptr[k] = fnarg->llvmAttrs;
+        attrptr[k] = f->fty->args[k]->attrs;
     }
 
     // reverse params?
-    if (f->reverseParams)
+    if (f->fty->reverseParams)
     {
         std::reverse(attrptr.begin(), attrptr.end());
     }
@@ -475,7 +389,7 @@
     {
         if (attrptr[i])
         {
-            PAWI.Index = llidx+i+1;
+            PAWI.Index = idx+i;
             PAWI.Attrs = attrptr[i];
             attrs.push_back(PAWI);
         }
@@ -575,26 +489,26 @@
         // name parameters
         llvm::Function::arg_iterator iarg = func->arg_begin();
 
-        if (f->retInPtr) {
+        if (f->fty->arg_sret) {
             iarg->setName(".sret_arg");
             fdecl->ir.irFunc->retArg = iarg;
             ++iarg;
         }
 
-        if (f->usesThis) {
+        if (f->fty->arg_this) {
             iarg->setName(".this_arg");
             fdecl->ir.irFunc->thisArg = iarg;
             assert(fdecl->ir.irFunc->thisArg);
             ++iarg;
         }
-        else if (f->usesNest) {
+        else if (f->fty->arg_nest) {
             iarg->setName(".nest_arg");
             fdecl->ir.irFunc->nestArg = iarg;
             assert(fdecl->ir.irFunc->nestArg);
             ++iarg;
         }
 
-        if (f->linkage == LINKd && f->varargs == 1) {
+        if (f->fty->arg_argptr) {
             iarg->setName("._arguments");
             fdecl->ir.irFunc->_arguments = iarg;
             ++iarg;
@@ -610,7 +524,7 @@
             if (fdecl->parameters && fdecl->parameters->dim > k)
             {
                 Dsymbol* argsym;
-                if (f->reverseParams)
+                if (f->fty->reverseParams)
                     argsym = (Dsymbol*)fdecl->parameters->data[fdecl->parameters->dim-k-1];
                 else
                     argsym = (Dsymbol*)fdecl->parameters->data[k];
@@ -648,6 +562,8 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
+// FIXME: this isn't too pretty!
+
 void DtoDefineFunction(FuncDeclaration* fd)
 {
     if (fd->ir.defined) return;
@@ -727,7 +643,7 @@
     }
 
     // give the 'this' argument storage and debug info
-    if (f->usesThis)
+    if (f->fty->arg_this)
     {
         LLValue* thisvar = irfunction->thisArg;
         assert(thisvar);
@@ -757,7 +673,8 @@
     // and debug info
     if (fd->parameters)
     {
-        size_t n = fd->parameters->dim;
+        size_t n = f->fty->args.size();
+        assert(n == fd->parameters->dim);
         for (int i=0; i < n; ++i)
         {
             Dsymbol* argsym = (Dsymbol*)fd->parameters->data[i];
@@ -767,20 +684,8 @@
             IrLocal* irloc = vd->ir.irLocal;
             assert(irloc);
 
-            // if it's inreg struct arg, allocate storage
-            if (f->structInregArg && i == (f->reverseParams ? n - 1 : 0))
-            {
-                int n_param = f->reverseParams ? f->firstRealArg + n - 1 - i : f->firstRealArg + i;
-                const LLType* paramty = functype->getParamType(n_param);
-                assert(!f->usesNest && !f->usesThis && 
-                    llvm::isa<LLIntegerType>(paramty) && isaStruct(f->structInregArg)
-                    && "Preconditions for inreg struct arg not met!");
-
-                LLValue* mem = DtoAlloca(f->structInregArg, "inregstructarg");
-                
-                DtoStore(irloc->value, DtoBitCast(mem, getPtrToType(paramty)));
-                irloc->value = mem;
-            }
+            // let the abi transform the argument back first
+            LLValue* argvalue = f->fty->getParam(vd->type, i, irloc->value);
 
         #if DMDV2
             if (vd->nestedrefs.dim)
@@ -794,9 +699,9 @@
             bool refout = vd->storage_class & (STCref | STCout);
             bool lazy = vd->storage_class & STClazy;
 
-            if (!refout && (!DtoIsPassedByRef(vd->type) || lazy))
+            if (!refout && (!f->fty->args[i]->byref || lazy))
             {
-                LLValue* a = irloc->value;
+                LLValue* a = argvalue;
                 LLValue* v = DtoAlloca(a->getType(), vd->ident->toChars());
                 DtoStore(a,v);
                 irloc->value = v;
--- a/gen/functions.h	Sun Mar 01 22:59:03 2009 +0100
+++ b/gen/functions.h	Tue Mar 03 09:51:15 2009 +0100
@@ -1,7 +1,7 @@
 #ifndef LDC_GEN_FUNCTIONS_H
 #define LDC_GEN_FUNCTIONS_H
 
-const llvm::FunctionType* DtoFunctionType(Type* t, const LLType* thistype, const LLType* nesttype, bool ismain = false);
+const llvm::FunctionType* DtoFunctionType(Type* t, Type* thistype, Type* nesttype, bool ismain = false);
 const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl);
 
 const llvm::FunctionType* DtoBaseFunctionType(FuncDeclaration* fdecl);
--- a/gen/statements.cpp	Sun Mar 01 22:59:03 2009 +0100
+++ b/gen/statements.cpp	Tue Mar 03 09:51:15 2009 +0100
@@ -63,7 +63,6 @@
         {
             // sanity check
             IrFunction* f = p->func();
-            assert(f->type->retInPtr);
             assert(f->decl->ir.irFunc->retArg);
 
             // emit dbg line
@@ -94,7 +93,7 @@
             delete e;
 
             // do abi specific transformations on the return value
-            v = gABI->putRet(p->func()->type, v);
+            v = p->func()->type->fty->putRet(exp->type, v);
 
             if (Logger::enabled())
                 Logger::cout() << "return value is '" <<*v << "'\n";
@@ -111,7 +110,7 @@
                     v = llvm::Constant::getNullValue(p->mainFunc->getReturnType());
                 else
                     v = gIR->ir->CreateBitCast(v, p->topfunc()->getReturnType(), "tmp");
-                
+
                 if (Logger::enabled())
                     Logger::cout() << "return value after cast: " << *v << '\n';
             }
--- a/gen/tocall.cpp	Sun Mar 01 22:59:03 2009 +0100
+++ b/gen/tocall.cpp	Tue Mar 03 09:51:15 2009 +0100
@@ -201,11 +201,11 @@
         DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
         args.push_back(argval->getRVal());
 
-        if (fnarg->llvmAttrs)
+        if (tf->fty->args[i]->attrs)
         {
             llvm::AttributeWithIndex Attr;
             Attr.Index = argidx;
-            Attr.Attrs = fnarg->llvmAttrs;
+            Attr.Attrs = tf->fty->args[i]->attrs;
             attrs.push_back(Attr);
         }
 
@@ -213,6 +213,7 @@
     }
 }
 
+// FIXME: this function is a mess !
 
 DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* arguments)
 {
@@ -233,10 +234,10 @@
     TypeFunction* tf = DtoTypeFunction(fnval);
 
     // misc
-    bool retinptr = tf->retInPtr;
-    bool thiscall = tf->usesThis;
+    bool retinptr = tf->fty->arg_sret;
+    bool thiscall = tf->fty->arg_this;
     bool delegatecall = (calleeType->toBasetype()->ty == Tdelegate);
-    bool nestedcall = tf->usesNest;
+    bool nestedcall = tf->fty->arg_nest;
     bool dvarargs = (tf->linkage == LINKd && tf->varargs == 1);
 
     unsigned callconv = DtoCallingConv(loc, tf->linkage);
@@ -261,15 +262,16 @@
     llvm::AttributeWithIndex Attr;
 
     // return attrs
-    if (tf->retAttrs)
+    if (tf->fty->ret->attrs)
     {
         Attr.Index = 0;
-        Attr.Attrs = tf->retAttrs;
+        Attr.Attrs = tf->fty->ret->attrs;
         attrs.push_back(Attr);
     }
 
     // handle implicit arguments
     std::vector<LLValue*> args;
+    args.reserve(tf->fty->args.size());
 
     // return in hidden ptr is first
     if (retinptr)
@@ -325,10 +327,16 @@
         }
 
         // add attributes for context argument
-        if (tf->thisAttrs)
+        if (tf->fty->arg_this && tf->fty->arg_this->attrs)
         {
             Attr.Index = retinptr ? 2 : 1;
-            Attr.Attrs = tf->thisAttrs;
+            Attr.Attrs = tf->fty->arg_this->attrs;
+            attrs.push_back(Attr);
+        }
+        else if (tf->fty->arg_nest && tf->fty->arg_nest->attrs)
+        {
+            Attr.Index = retinptr ? 2 : 1;
+            Attr.Attrs = tf->fty->arg_nest->attrs;
             attrs.push_back(Attr);
         }
     }
@@ -374,20 +382,15 @@
             DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
             LLValue* arg = argval->getRVal();
 
-            int j = tf->reverseParams ? beg + n - i - 1 : beg + i;
+            int j = tf->fty->reverseParams ? beg + n - i - 1 : beg + i;
 
-            // if it's a struct inreg arg, load first to pass as first-class value
-            if (tf->structInregArg && i == (tf->reverseParams ? n - 1 : 0))
-            {
-                assert((fnarg->llvmAttrs & llvm::Attribute::InReg) && isaStruct(tf->structInregArg));
-                arg = DtoBitCast(arg, getPtrToType(callableTy->getParamType(j)));
-                arg = DtoLoad(arg);
-            }
+            // 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))
             {
-            #if 0
+            #if 1
                 if (Logger::enabled())
                 {
                     Logger::cout() << "arg:     " << *arg << '\n';
@@ -398,16 +401,16 @@
             }
 
             // param attrs
-            attrptr[i] = fnarg->llvmAttrs;
+            attrptr[i] = tf->fty->args[i]->attrs;
 
             ++argiter;
             args.push_back(arg);
         }
 
         // reverse the relevant params as well as the param attrs
-        if (tf->reverseParams)
+        if (tf->fty->reverseParams)
         {
-            std::reverse(args.begin() + tf->firstRealArg, args.end());
+            std::reverse(args.begin() + beg, args.end());
             std::reverse(attrptr.begin(), attrptr.end());
         }
 
@@ -475,10 +478,10 @@
             retllval = mem;
         }
     }
-    else
+    else if (!retinptr)
     {
         // do abi specific return value fixups
-        retllval = gABI->getRet(tf, retllval);
+        retllval = tf->fty->getRet(tf->next, retllval);
     }
 
     // repaint the type if necessary
--- a/gen/tollvm.cpp	Sun Mar 01 22:59:03 2009 +0100
+++ b/gen/tollvm.cpp	Tue Mar 03 09:51:15 2009 +0100
@@ -227,7 +227,7 @@
 {
     assert(t->ty == Tdelegate);
     const LLType* i8ptr = getVoidPtrType();
-    const LLType* func = DtoFunctionType(t->nextOf(), NULL, i8ptr);
+    const LLType* func = DtoFunctionType(t->nextOf(), NULL, Type::tvoid->pointerTo());
     const LLType* funcptr = getPtrToType(func);
     return LLStructType::get(i8ptr, funcptr, NULL);
 }
--- a/ir/irfunction.cpp	Sun Mar 01 22:59:03 2009 +0100
+++ b/ir/irfunction.cpp	Tue Mar 03 09:51:15 2009 +0100
@@ -1,6 +1,7 @@
 
 #include "gen/llvm.h"
 #include "gen/tollvm.h"
+#include "gen/abi.h"
 #include "ir/irfunction.h"
 
 #include <sstream>
@@ -9,6 +10,55 @@
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
+IrFuncTyArg::IrFuncTyArg(Type* t, bool bref, unsigned a)
+{
+    type = t;
+    ltype = bref ? DtoType(t->pointerTo()) : DtoType(t);
+    attrs = a;
+    byref = bref;
+    rewrite = NULL;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
+llvm::Value* IrFuncTy::putRet(Type* dty, llvm::Value* val)
+{
+    assert(!arg_sret);
+    if (ret->rewrite)
+        return ret->rewrite->put(dty, val);
+    return val;
+}
+
+llvm::Value* IrFuncTy::getRet(Type* dty, llvm::Value* val)
+{
+    assert(!arg_sret);
+    if (ret->rewrite)
+        return ret->rewrite->get(dty, val);
+    return val;
+}
+
+llvm::Value* IrFuncTy::putParam(Type* dty, int idx, llvm::Value* val)
+{
+    assert(idx >= 0 && idx < args.size() && "invalid putParam");
+    if (args[idx]->rewrite)
+        return args[idx]->rewrite->put(dty, val);
+    return val;
+}
+
+llvm::Value* IrFuncTy::getParam(Type* dty, int idx, llvm::Value* val)
+{
+    assert(idx >= 0 && idx < args.size() && "invalid getParam");
+    if (args[idx]->rewrite)
+        return args[idx]->rewrite->get(dty, val);
+    return val;
+}
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
+
 IrFunction::IrFunction(FuncDeclaration* fd)
 {
     decl = fd;
--- a/ir/irfunction.h	Sun Mar 01 22:59:03 2009 +0100
+++ b/ir/irfunction.h	Tue Mar 03 09:51:15 2009 +0100
@@ -1,6 +1,7 @@
 #ifndef LDC_IR_IRFUNCTION_H
 #define LDC_IR_IRFUNCTION_H
 
+#include "gen/llvm.h"
 #include "ir/ir.h"
 #include "ir/irlandingpad.h"
 
@@ -8,6 +9,66 @@
 #include <stack>
 #include <map>
 
+struct ABIRewrite;
+
+// represents a function type argument
+// both explicit and implicit as well as return values
+struct IrFuncTyArg : IrBase
+{
+    Type* type;
+    const llvm::Type* ltype;
+    unsigned attrs;
+    bool byref;
+
+    ABIRewrite* rewrite;
+
+    bool isInReg() const { return (attrs & llvm::Attribute::InReg) != 0; }
+    bool isSRet() const  { return (attrs & llvm::Attribute::StructRet) != 0; }
+    bool isByVal() const { return (attrs & llvm::Attribute::ByVal) != 0; }
+
+    IrFuncTyArg(Type* t, bool byref, unsigned a = 0);
+};
+
+// represents a function type
+struct IrFuncTy : IrBase
+{
+    // return value
+    IrFuncTyArg* ret;
+
+    // null if not applicable
+    IrFuncTyArg* arg_sret;
+    IrFuncTyArg* arg_this;
+    IrFuncTyArg* arg_nest;
+    IrFuncTyArg* arg_arguments;
+    IrFuncTyArg* arg_argptr;
+
+    // normal explicit arguments
+    LLSmallVector<IrFuncTyArg*, 4> args;
+
+    // C varargs
+    bool c_vararg;
+
+    // range of normal parameters to reverse
+    bool reverseParams;
+
+    IrFuncTy()
+    :   ret(NULL),
+        arg_sret(NULL),
+        arg_this(NULL),
+        arg_nest(NULL),
+        arg_arguments(NULL),
+        arg_argptr(NULL),
+        c_vararg(false),
+        reverseParams(false)
+    {}
+
+    llvm::Value* putRet(Type* dty, llvm::Value* val);
+    llvm::Value* getRet(Type* dty, llvm::Value* val);
+
+    llvm::Value* getParam(Type* dty, int idx, llvm::Value* val);
+    llvm::Value* putParam(Type* dty, int idx, llvm::Value* val);
+};
+
 // represents a function
 struct IrFunction : IrBase
 {