changeset 723:55f6c2e454d7

Implemented correct parameter order according to x86-32 ABI documentation. Changed AA types to just a void* .
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Sat, 25 Oct 2008 06:03:28 +0200
parents bd56056a581f
children 6de2ed4f0abe
files dmd/attrib.c dmd/expression.c dmd/mangle.c dmd/mars.h dmd/mtype.c dmd/mtype.h gen/functions.cpp gen/tocall.cpp gen/tollvm.cpp tests/mini/intrinsics.d
diffstat 10 files changed, 199 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/attrib.c	Thu Oct 23 19:42:55 2008 +0200
+++ b/dmd/attrib.c	Sat Oct 25 06:03:28 2008 +0200
@@ -416,6 +416,10 @@
 	case LINKcpp:		p = "C++";		break;
 	case LINKwindows:	p = "Windows";		break;
 	case LINKpascal:	p = "Pascal";		break;
+
+    // LDC
+    case LINKintrinsic: p = "Intrinsic"; break;
+
 	default:
 	    assert(0);
 	    break;
@@ -1003,6 +1007,8 @@
             {
                 fd->llvmInternal = llvm_internal;
                 fd->intrinsicName = arg1str;
+                fd->linkage = LINKintrinsic;
+                ((TypeFunction*)fd->type)->linkage = LINKintrinsic;
             }
             else if (TemplateDeclaration* td = s->isTemplateDeclaration())
             {
--- a/dmd/expression.c	Thu Oct 23 19:42:55 2008 +0200
+++ b/dmd/expression.c	Sat Oct 25 06:03:28 2008 +0200
@@ -684,12 +684,16 @@
 		    //arg->error("cannot modify slice %s", arg->toChars());
 	    }
 
+// LDC we don't want this!
+#if !IN_LLVM
 	    // Convert static arrays to pointers
 	    tb = arg->type->toBasetype();
 	    if (tb->ty == Tsarray)
 	    {
 		arg = arg->checkToPointer();
 	    }
+#endif
+
 
 	    // Convert lazy argument to a delegate
 	    if (p->storageClass & STClazy)
@@ -701,7 +705,8 @@
 	{
 
 	    // If not D linkage, do promotions
-	    if (tf->linkage != LINKd)
+        // LDC: don't do promotions on intrinsics
+	    if (tf->linkage != LINKd && tf->linkage != LINKintrinsic)
 	    {
 		// Promote bytes, words, etc., to ints
 		arg = arg->integralPromotions(sc);
--- a/dmd/mangle.c	Thu Oct 23 19:42:55 2008 +0200
+++ b/dmd/mangle.c	Sat Oct 25 06:03:28 2008 +0200
@@ -104,6 +104,9 @@
 		case LINKd:
 		    break;
 
+        // LDC
+        case LINKintrinsic:
+
 		case LINKc:
 		case LINKwindows:
 		case LINKpascal:
--- a/dmd/mars.h	Thu Oct 23 19:42:55 2008 +0200
+++ b/dmd/mars.h	Sat Oct 25 06:03:28 2008 +0200
@@ -309,6 +309,9 @@
     LINKcpp,
     LINKwindows,
     LINKpascal,
+
+    // LDC
+    LINKintrinsic,
 };
 
 enum DYNCAST
--- a/dmd/mtype.c	Thu Oct 23 19:42:55 2008 +0200
+++ b/dmd/mtype.c	Sat Oct 25 06:03:28 2008 +0200
@@ -2673,6 +2673,8 @@
     this->usesNest = false;
     this->retAttrs = 0;
     this->thisAttrs = 0;
+    this->reverseParams = false;
+    this->reverseIndex = 0;
 }
 
 Type *TypeFunction::syntaxCopy()
@@ -2685,6 +2687,8 @@
     t->usesNest = usesNest;
     t->retAttrs = retAttrs;
     t->thisAttrs = thisAttrs;
+    t->reverseParams = reverseParams;
+    t->reverseIndex = reverseIndex;
     return t;
 }
 
@@ -2794,6 +2798,10 @@
 	case LINKwindows:	mc = 'W';	break;
 	case LINKpascal:	mc = 'V';	break;
 	case LINKcpp:		mc = 'R';	break;
+
+    // LDC
+    case LINKintrinsic: mc = 'Q';   break;
+
 	default:
 	    assert(0);
     }
@@ -2826,6 +2834,10 @@
 	    case LINKwindows:	p = "Windows ";	break;
 	    case LINKpascal:	p = "Pascal ";	break;
 	    case LINKcpp:	p = "C++ ";	break;
+
+        // LDC
+        case LINKintrinsic: p = "Intrinsic"; break;
+
 	    default:
 		assert(0);
 	}
@@ -2861,6 +2873,10 @@
 	    case LINKwindows:	p = "Windows ";	break;
 	    case LINKpascal:	p = "Pascal ";	break;
 	    case LINKcpp:	p = "C++ ";	break;
+
+        // LDC
+        case LINKintrinsic: p = "Intrinsic"; break;
+
 	    default:
 		assert(0);
 	}
--- a/dmd/mtype.h	Thu Oct 23 19:42:55 2008 +0200
+++ b/dmd/mtype.h	Sat Oct 25 06:03:28 2008 +0200
@@ -440,6 +440,9 @@
     bool usesNest;
     unsigned retAttrs;
     unsigned thisAttrs; // also used for nest
+
+    bool reverseParams;
+    size_t reverseIndex;
 };
 
 struct TypeDelegate : Type
--- a/gen/functions.cpp	Thu Oct 23 19:42:55 2008 +0200
+++ b/gen/functions.cpp	Sat Oct 25 06:03:28 2008 +0200
@@ -21,6 +21,8 @@
 #include "gen/classes.h"
 #include "gen/dvalue.h"
 
+#include <algorithm>
+
 const llvm::FunctionType* DtoFunctionType(Type* type, const LLType* thistype, const LLType* nesttype, bool ismain)
 {
     assert(type->ty == Tfunction);
@@ -111,8 +113,23 @@
         // do nothing?
     }
 
+    // number of formal params
     size_t n = Argument::dim(f->parameters);
 
+    // on x86 we need to reverse the formal params in some cases to match the ABI
+    if (global.params.cpu == ARCHx86)
+    {
+        // more than one formal arg,
+        // extern(D) linkage
+        // not a D-style vararg
+        if (n > 1 && f->linkage == LINKd && !typesafeVararg)
+        {
+            f->reverseParams = true;
+            f->reverseIndex = paramvec.size();
+        }
+    }
+
+
     for (int i=0; i < n; ++i) {
         Argument* arg = Argument::getNth(f->parameters, i);
         // ensure scalar
@@ -167,6 +184,12 @@
         }
     }
 
+    // reverse params?
+    if (f->reverseParams)
+    {
+        std::reverse(paramvec.begin() + f->reverseIndex, paramvec.end());
+    }
+
     // construct function type
     bool isvararg = !(typesafeVararg || arrayVararg) && f->varargs;
     llvm::FunctionType* functype = llvm::FunctionType::get(actualRettype, paramvec, isvararg);
@@ -189,6 +212,7 @@
             // otherwise check the first formal parameter
             else
             {
+                int inreg = f->reverseParams ? n - 1 : 0;
                 Argument* arg = Argument::getNth(f->parameters, 0);
                 Type* t = arg->type->toBasetype();
 
@@ -340,6 +364,8 @@
             Logger::println("overloaded intrinsic found");
             fdecl->llvmInternal = LLVMintrinsic;
             DtoOverloadedIntrinsicName(tinst, tempdecl, fdecl->intrinsicName);
+            fdecl->linkage = LINKintrinsic;
+            ((TypeFunction*)fdecl->type)->linkage = LINKintrinsic;
         }
     }
 
@@ -354,7 +380,7 @@
 
 static void set_param_attrs(TypeFunction* f, llvm::Function* func, FuncDeclaration* fdecl)
 {
-    int llidx = 1;
+    int llidx = 0;
     if (f->retInPtr) ++llidx;
     if (f->usesThis) ++llidx;
     else if (f->usesNest) ++llidx;
@@ -362,9 +388,8 @@
         llidx += 2;
 
     int funcNumArgs = func->getArgumentList().size();
-    std::vector<llvm::AttributeWithIndex> attrs;
-    int k = 0;
 
+    LLSmallVector<llvm::AttributeWithIndex, 9> attrs;
     llvm::AttributeWithIndex PAWI;
 
     // set return value attrs if any
@@ -392,20 +417,38 @@
     }
 
     // set attrs on the rest of the arguments
-    for (; llidx <= funcNumArgs && Argument::dim(f->parameters) > k; ++llidx,++k)
+    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)
     {
         Argument* fnarg = Argument::getNth(f->parameters, k);
         assert(fnarg);
 
-        PAWI.Index = llidx;
-        PAWI.Attrs = fnarg->llvmAttrs;
-
-        if (PAWI.Attrs)
-            attrs.push_back(PAWI);
+        attrptr[k] = fnarg->llvmAttrs;
     }
 
-    llvm::AttrListPtr palist = llvm::AttrListPtr::get(attrs.begin(), attrs.end());
-    func->setAttributes(palist);
+    // reverse params?
+    if (f->reverseParams)
+    {
+        std::reverse(attrptr.begin(), attrptr.end());
+    }
+
+    // build rest of attrs list
+    for (int i = 0; i < n; i++)
+    {
+        if (attrptr[i])
+        {
+            PAWI.Index = llidx+i+1;
+            PAWI.Attrs = attrptr[i];
+            attrs.push_back(PAWI);
+        }
+    }
+
+    llvm::AttrListPtr attrlist = llvm::AttrListPtr::get(attrs.begin(), attrs.end());
+    func->setAttributes(attrlist);
 }
 
 //////////////////////////////////////////////////////////////////////////////////////////
@@ -503,13 +546,13 @@
     {
         // name parameters
         llvm::Function::arg_iterator iarg = func->arg_begin();
-        int k = 0;
+
         if (f->retInPtr) {
             iarg->setName(".sretarg");
             fdecl->ir.irFunc->retArg = iarg;
             ++iarg;
         }
-        
+
         if (f->usesThis) {
             iarg->setName("this");
             fdecl->ir.irFunc->thisArg = iarg;
@@ -532,17 +575,26 @@
             ++iarg;
         }
 
+        int k = 0;
+
         for (; iarg != func->arg_end(); ++iarg)
         {
             if (fdecl->parameters && fdecl->parameters->dim > k)
             {
-                Dsymbol* argsym = (Dsymbol*)fdecl->parameters->data[k++];
+                Dsymbol* argsym;
+                if (f->reverseParams)
+                    argsym = (Dsymbol*)fdecl->parameters->data[fdecl->parameters->dim-k-1];
+                else
+                    argsym = (Dsymbol*)fdecl->parameters->data[k];
+
                 VarDeclaration* argvd = argsym->isVarDeclaration();
                 assert(argvd);
                 assert(!argvd->ir.irLocal);
                 argvd->ir.irLocal = new IrLocal(argvd);
                 argvd->ir.irLocal->value = iarg;
                 iarg->setName(argvd->ident->toChars());
+
+                k++;
             }
             else
             {
@@ -902,7 +954,7 @@
     DValue* arg = argexp->toElem(gIR);
 
     // ref/out arg
-    if (fnarg && ((fnarg->storageClass & STCref) || (fnarg->storageClass & STCout)))
+    if (fnarg && (fnarg->storageClass & (STCref | STCout)))
     {
         if (arg->isVar() || arg->isLRValue())
             arg = new DImValue(argexp->type, arg->getLVal());
--- a/gen/tocall.cpp	Thu Oct 23 19:42:55 2008 +0200
+++ b/gen/tocall.cpp	Sat Oct 25 06:03:28 2008 +0200
@@ -34,7 +34,7 @@
 
 unsigned DtoCallingConv(LINK l)
 {
-    if (l == LINKc || l == LINKcpp)
+    if (l == LINKc || l == LINKcpp || l == LINKintrinsic)
         return llvm::CallingConv::C;
     else if (l == LINKd || l == LINKdefault)
     {
@@ -111,7 +111,7 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
-void DtoBuildDVarArgList(std::vector<LLValue*>& args, llvm::AttrListPtr& palist, TypeFunction* tf, Expressions* arguments, size_t argidx)
+void DtoBuildDVarArgList(std::vector<LLValue*>& args, std::vector<llvm::AttributeWithIndex>& attrs, TypeFunction* tf, Expressions* arguments, size_t argidx)
 {
     Logger::println("doing d-style variadic arguments");
 
@@ -195,7 +195,12 @@
         args.push_back(argval->getRVal());
 
         if (fnarg->llvmAttrs)
-            palist = palist.addAttr(argidx, fnarg->llvmAttrs);
+        {
+            llvm::AttributeWithIndex Attr;
+            Attr.Index = argidx;
+            Attr.Attrs = fnarg->llvmAttrs;
+            attrs.push_back(Attr);
+        }
 
         ++argidx;
     }
@@ -234,6 +239,11 @@
     const LLFunctionType* callableTy = DtoExtractFunctionType(callable->getType());
     assert(callableTy);
 
+    if (Logger::enabled())
+    {
+        Logger::cout() << "callable: " << *callable << '\n';
+    }
+
     // get n arguments
     size_t n_arguments = arguments ? arguments->dim : 0;
 
@@ -242,11 +252,16 @@
     LLFunctionType::param_iterator argiter = argbegin;
 
     // parameter attributes
-    llvm::AttrListPtr palist;
+    std::vector<llvm::AttributeWithIndex> attrs;
+    llvm::AttributeWithIndex Attr;
 
     // return attrs
     if (tf->retAttrs)
-        palist = palist.addAttr(0, tf->retAttrs);
+    {
+        Attr.Index = 0;
+        Attr.Attrs = tf->retAttrs;
+        attrs.push_back(Attr);
+    }
 
     // handle implicit arguments
     std::vector<LLValue*> args;
@@ -259,7 +274,9 @@
         args.push_back(retvar);
 
         // add attrs for hidden ptr
-        palist = palist.addAttr(1, llvm::Attribute::StructRet);
+        Attr.Index = 1;
+        Attr.Attrs = llvm::Attribute::StructRet;
+        attrs.push_back(Attr);
     }
 
     // then comes a context argument...
@@ -304,7 +321,11 @@
 
         // add attributes for context argument
         if (tf->thisAttrs)
-            palist = palist.addAttr(retinptr?2:1, tf->thisAttrs);
+        {
+            Attr.Index = retinptr ? 2 : 1;
+            Attr.Attrs = tf->thisAttrs;
+            attrs.push_back(Attr);
+        }
     }
 
     // handle the rest of the arguments based on param passing style
@@ -326,33 +347,83 @@
     // d style varargs needs a few more hidden arguments as well as special passing
     else if (dvarargs)
     {
-        DtoBuildDVarArgList(args, palist, tf, arguments, argiter-argbegin+1);
+        DtoBuildDVarArgList(args, attrs, tf, arguments, argiter-argbegin+1);
     }
 
     // otherwise we're looking at a normal function call
+    // or a C style vararg call
     else
     {
         Logger::println("doing normal arguments");
-        for (int i=0; i<n_arguments; i++) {
-            int j = argiter-argbegin;
+
+        size_t n = Argument::dim(tf->parameters);
+
+        LLSmallVector<unsigned, 10> attrptr(n, 0);
+
+        // do formal params
+        int beg = argiter-argbegin;
+        for (int i=0; i<n; i++)
+        {
             Argument* fnarg = Argument::getNth(tf->parameters, i);
+            assert(fnarg);
             DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
             LLValue* arg = argval->getRVal();
-            if (fnarg) // can fnarg ever be null in this block?
+
+            int j = tf->reverseParams ? beg + n - i - 1 : beg + i;
+
+            // parameter type mismatch, this is hard to get rid of
+            if (arg->getType() != callableTy->getParamType(j))
             {
+            #if 0
                 if (Logger::enabled())
                 {
                     Logger::cout() << "arg:     " << *arg << '\n';
                     Logger::cout() << "expects: " << *callableTy->getParamType(j) << '\n';
                 }
-                if (arg->getType() != callableTy->getParamType(j))
-                    arg = DtoBitCast(arg, callableTy->getParamType(j));
-                if (fnarg->llvmAttrs)
-                    palist = palist.addAttr(j+1, fnarg->llvmAttrs);
+            #endif
+                arg = DtoBitCast(arg, callableTy->getParamType(j));
             }
+
+            // param attrs
+            attrptr[i] = fnarg->llvmAttrs;
+
             ++argiter;
             args.push_back(arg);
         }
+
+        // reverse the relevant params as well as the param attrs
+        if (tf->reverseParams)
+        {
+            std::reverse(args.begin() + tf->reverseIndex, args.end());
+            std::reverse(attrptr.begin(), attrptr.end());
+        }
+
+        // add attributes
+        for (int i = 0; i < n; i++)
+        {
+            if (attrptr[i])
+            {
+                Attr.Index = beg + i + 1;
+                Attr.Attrs = attrptr[i];
+                attrs.push_back(Attr);
+            }
+        }
+
+        // do C varargs
+        if (n_arguments > n)
+        {
+            for (int i=n; i<n_arguments; i++)
+            {
+                Argument* fnarg = Argument::getNth(tf->parameters, i);
+                DValue* argval = DtoArgument(fnarg, (Expression*)arguments->data[i]);
+                LLValue* arg = argval->getRVal();
+
+                // FIXME: do we need any param attrs here ?
+
+                ++argiter;
+                args.push_back(arg);
+            }
+        }
     }
 
     #if 0
@@ -405,17 +476,18 @@
     }
 
     // set calling convention and parameter attributes
+    llvm::AttrListPtr attrlist = llvm::AttrListPtr::get(attrs.begin(), attrs.end());
     if (dfnval && dfnval->func)
     {
         LLFunction* llfunc = llvm::dyn_cast<LLFunction>(dfnval->val);
-        if (llfunc && llfunc->isIntrinsic())
-            palist = llvm::Intrinsic::getAttributes((llvm::Intrinsic::ID)llfunc->getIntrinsicID());
+        if (llfunc && llfunc->isIntrinsic()) // override intrinsic attrs
+            attrlist = llvm::Intrinsic::getAttributes((llvm::Intrinsic::ID)llfunc->getIntrinsicID());
         else
             call->setCallingConv(callconv);
     }
     else
         call->setCallingConv(callconv);
-    call->setAttributes(palist);
+    call->setAttributes(attrlist);
 
     return new DImValue(resulttype, retllval);
 }
--- a/gen/tollvm.cpp	Thu Oct 23 19:42:55 2008 +0200
+++ b/gen/tollvm.cpp	Sat Oct 25 06:03:28 2008 +0200
@@ -163,11 +163,15 @@
 
     // associative arrays
     case Taarray:
+    #if 1
+        return getVoidPtrType();
+    #else
     {
         TypeAArray* taa = (TypeAArray*)t;
         // aa key/val can't be void
         return getPtrToType(LLStructType::get(DtoType(taa->key), DtoType(taa->next), 0));
     }
+    #endif
 
 /*
     Not needed atm as VarDecls for tuples are rewritten as a string of 
--- a/tests/mini/intrinsics.d	Thu Oct 23 19:42:55 2008 +0200
+++ b/tests/mini/intrinsics.d	Sat Oct 25 06:03:28 2008 +0200
@@ -21,7 +21,7 @@
 
     real r;
     printf("Enter real: ");
-    //scanf("%lf", &d);
+    //scanf("%llf", &r);
     r = 3.2311167891231231234754764576;
     version(X86)
     {