diff gen/functions.cpp @ 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 e177ae483f8e
children 6de2ed4f0abe
line wrap: on
line diff
--- 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;
+        attrptr[k] = fnarg->llvmAttrs;
+    }
 
-        if (PAWI.Attrs)
-            attrs.push_back(PAWI);
+    // reverse params?
+    if (f->reverseParams)
+    {
+        std::reverse(attrptr.begin(), attrptr.end());
     }
 
-    llvm::AttrListPtr palist = llvm::AttrListPtr::get(attrs.begin(), attrs.end());
-    func->setAttributes(palist);
+    // 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());