changeset 55:0ccfae271c45 trunk

[svn r59] Added support for C-style variadic functions. Currently only works on x86, x86-64 va_arg is broken in LLVM 2.1. PPC and PPC64 unknown. Updates to runtime. Rebuild!
author lindquist
date Wed, 24 Oct 2007 22:18:06 +0200
parents 28e99b04a132
children 3a784f7790d6
files dmd/attrib.c dmd/dsymbol.c dmd/mars.c gen/enums.h gen/toir.c gen/tollvm.c gen/toobj.c lphobos/build.sh lphobos/llvm/intrinsic.d lphobos/llvm/va_list.d lphobos/llvmsupport.d lphobos/std/c/stdarg.d test/vararg1.d
diffstat 13 files changed, 325 insertions(+), 115 deletions(-) [+]
line wrap: on
line diff
--- a/dmd/attrib.c	Wed Oct 24 01:37:34 2007 +0200
+++ b/dmd/attrib.c	Wed Oct 24 22:18:06 2007 +0200
@@ -29,8 +29,10 @@
 #include "aggregate.h"
 #include "module.h"
 #include "parse.h"
+#include "template.h"
 
 #include "../gen/enums.h"
+#include "../gen/logger.h"
 
 extern void obj_includelib(char *name);
 
@@ -752,9 +754,9 @@
 #if IN_LLVM
     int llvm_internal = 0;
     char* llvm_str1 = NULL;
-    
+
 #endif
-    
+
     //printf("\tPragmaDeclaration::semantic '%s'\n",toChars());
     if (ident == Id::msg)
     {
@@ -873,6 +875,18 @@
                     llvm_internal = LLVMbind;
                     assert(args->dim == 2);
                 }
+                else if (strcmp(str,"va_start")==0) {
+                    llvm_internal = LLVMva_start;
+                    assert(args->dim == 1);
+                }
+                else if (strcmp(str,"va_arg")==0) {
+                    llvm_internal = LLVMva_arg;
+                    assert(args->dim == 1);
+                }
+                else if (strcmp(str,"va_intrinsic")==0) {
+                    llvm_internal = LLVMva_intrinsic;
+                    assert(args->dim == 2);
+                }
                 else {
                     error("unknown pragma command: %s", str);
                 }
@@ -886,6 +900,7 @@
             case LLVMintrinsic:
             case LLVMmangle:
             case LLVMbind:
+            case LLVMva_intrinsic:
                 e = (Expression *)args->data[1];
                 e = e->semantic(sc);
                 e = e->optimize(WANTvalue);
@@ -897,6 +912,8 @@
                 break;
             
             case LLVMnull:
+            case LLVMva_arg:
+            case LLVMva_start:
                 break;
             
             default:
@@ -923,6 +940,7 @@
             {
             case LLVMintrinsic:
             case LLVMmangle:
+            case LLVMva_intrinsic:
                 if (FuncDeclaration* fd = s->isFuncDeclaration()) {
                     fd->llvmInternal = llvm_internal;
                     fd->llvmInternal1 = llvm_str1;
@@ -932,7 +950,7 @@
                     assert(0);
                 }
                 break;
-            
+
             case LLVMnull:
                 if (StaticCtorDeclaration* sd = s->isStaticCtorDeclaration()) {
                     sd->llvmInternal = llvm_internal;
@@ -942,7 +960,7 @@
                     assert(0);
                 }
                 break;
-            
+
             case LLVMbind:
                 if (VarDeclaration* vd = s->isVarDeclaration()) {
                     vd->llvmInternal = llvm_internal;
@@ -953,7 +971,23 @@
                     assert(0);
                 }
                 break;
-            
+
+            case LLVMva_start:
+            case LLVMva_arg:
+                if (TemplateDeclaration* td = s->isTemplateDeclaration()) {
+                    td->llvmInternal = llvm_internal;
+                    assert(td->parameters->dim == 1);
+                    assert(!td->overnext);
+                    assert(!td->overroot);
+                    assert(td->onemember);
+                    Logger::println("template->onemember = %s", td->onemember->toChars());
+                }
+                else {
+                    error("can only be used on templates");
+                    assert(0);
+                }
+                break;
+
             default:
                 assert(0 && "invalid LLVM_internal pragma got through :/");
             }
--- a/dmd/dsymbol.c	Wed Oct 24 01:37:34 2007 +0200
+++ b/dmd/dsymbol.c	Wed Oct 24 22:18:06 2007 +0200
@@ -47,6 +47,7 @@
     this->llvmInternal1 = NULL;
     this->llvmInternal2 = NULL;
     this->llvmValue = NULL;
+    this->llvmDModule = NULL;
 }
 
 Dsymbol::Dsymbol(Identifier *ident)
--- a/dmd/mars.c	Wed Oct 24 01:37:34 2007 +0200
+++ b/dmd/mars.c	Wed Oct 24 22:18:06 2007 +0200
@@ -15,6 +15,7 @@
 #include <assert.h>
 #include <limits.h>
 #include <string>
+#include <vaarg.h>
 
 #if _WIN32
 #include <windows.h>
@@ -667,6 +668,10 @@
             global.params.llvmArch = const_cast<char*>(e->Name);
             if (global.params.verbose || very_verbose)
             printf("Default target found: %s\n", global.params.llvmArch);
+            if (very_verbose) {
+                int X = sizeof(va_list);
+                printf("valist.sizeof = %d\n", X);
+            }
         }
     }
 
--- a/gen/enums.h	Wed Oct 24 01:37:34 2007 +0200
+++ b/gen/enums.h	Wed Oct 24 22:18:06 2007 +0200
@@ -5,4 +5,7 @@
     LLVMmangle,
     LLVMintrinsic,
     LLVMbind,
+    LLVMva_arg,
+    LLVMva_start,
+    LLVMva_intrinsic
 };
--- a/gen/toir.c	Wed Oct 24 01:37:34 2007 +0200
+++ b/gen/toir.c	Wed Oct 24 22:18:06 2007 +0200
@@ -210,12 +210,12 @@
     else if (FuncDeclaration* fdecl = var->isFuncDeclaration())
     {
         Logger::println("FuncDeclaration");
-        if (fdecl->llvmValue == 0) {
+        if (fdecl->llvmInternal != LLVMva_arg && fdecl->llvmValue == 0)
             fdecl->toObjFile();
-        }
         e->val = fdecl->llvmValue;
         e->type = elem::FUNC;
         e->funcdecl = fdecl;
+        return e;
     }
     else if (SymbolDeclaration* sdecl = var->isSymbolDeclaration())
     {
@@ -971,21 +971,21 @@
 {
     Logger::print("CallExp::toElem: %s\n", toChars());
     LOG_SCOPE;
+
     elem* e = new elem;
     elem* fn = e1->toElem(p);
-    LINK dlink = LINKdefault;
+
+    TypeFunction* tf = 0;
+    Type* e1type = LLVM_DtoDType(e1->type);
 
     bool delegateCall = false;
     llvm::Value* zero = llvm::ConstantInt::get(llvm::Type::Int32Ty,0,false);
     llvm::Value* one = llvm::ConstantInt::get(llvm::Type::Int32Ty,1,false);
+    LINK dlink = LINKdefault;
 
     // hidden struct return parameter handling
     bool retinptr = false;
 
-    TypeFunction* tf = 0;
-
-    Type* e1type = LLVM_DtoDType(e1->type);
-
     // regular functions
     if (e1type->ty == Tfunction) {
         tf = (TypeFunction*)e1type;
@@ -1012,7 +1012,38 @@
         assert(tf);
     }
 
+    // va args
+    bool va_magic = false;
+    bool va_intrinsic = false;
+    if (fn->funcdecl) {
+        if (fn->funcdecl->llvmInternal == LLVMva_intrinsic) {
+            va_magic = true;
+            va_intrinsic = true;
+        }
+        else if (fn->funcdecl->llvmInternal == LLVMva_start) {
+            va_magic = true;
+        }
+        else if (fn->funcdecl->llvmInternal == LLVMva_arg) {
+            Argument* fnarg = Argument::getNth(tf->parameters, 0);
+            Expression* exp = (Expression*)arguments->data[0];
+            elem* expelem = exp->toElem(p);
+            assert(expelem->mem);
+            elem* e = new elem;
+            Type* t = LLVM_DtoDType(type);
+            const llvm::Type* llt = LLVM_DtoType(type);
+            if (LLVM_DtoIsPassedByRef(t))
+                llt = llvm::PointerType::get(llt);
+            e->type = elem::VAL;
+            e->val = p->ir->CreateVAArg(expelem->mem,llt,"tmp");
+            delete expelem;
+            return e;
+        }
+    }
+
+    // args
     size_t n = arguments->dim;
+    if (fn->funcdecl && fn->funcdecl->llvmInternal == LLVMva_start)
+        n = 1;
     if (fn->arg || delegateCall) n++;
     if (retinptr) n++;
 
@@ -1113,11 +1144,26 @@
 
     Logger::println("regular arguments");
 
+    // va arg function special argument passing
+    if (va_magic) {
+        size_t n = va_intrinsic ? arguments->dim : 1;
+        for (int i=0; i<n; i++,j++)
+        {
+            Argument* fnarg = Argument::getNth(tf->parameters, i);
+            Expression* exp = (Expression*)arguments->data[i];
+            elem* expelem = exp->toElem(p);
+            assert(expelem->mem);
+            llargs[j] = p->ir->CreateBitCast(expelem->mem, llvm::PointerType::get(llvm::Type::Int8Ty), "tmp");
+            delete expelem;
+        }
+    }
     // regular arguments
-    for (int i=0; i<arguments->dim; i++,j++)
-    {
-        Argument* fnarg = Argument::getNth(tf->parameters, i);
-        llargs[j] = LLVM_DtoArgument(llfnty->getParamType(j), fnarg, (Expression*)arguments->data[i]);
+    else {
+        for (int i=0; i<arguments->dim; i++,j++)
+        {
+            Argument* fnarg = Argument::getNth(tf->parameters, i);
+            llargs[j] = LLVM_DtoArgument(llfnty->getParamType(j), fnarg, (Expression*)arguments->data[i]);
+        }
     }
 
     // void returns cannot not be named
@@ -1131,7 +1177,7 @@
         Logger::cout() << *llargs[i] << '\n';
     }
 
-    //Logger::cout() << "Calling: " << *funcval->getType() << '\n';
+    Logger::cout() << "Calling: " << *funcval->getType() << '\n';
 
     // call the function
     llvm::CallInst* call = new llvm::CallInst(funcval, llargs.begin(), llargs.end(), varname, p->scopebb());
@@ -1141,7 +1187,7 @@
         e->val = call;
 
     // set calling convention
-    if ((fn->funcdecl && (fn->funcdecl->llvmInternal != LLVMintrinsic)) || delegateCall)
+    if ((fn->funcdecl && (fn->funcdecl->llvmInternal != LLVMintrinsic && fn->funcdecl->llvmInternal != LLVMva_start)) || delegateCall)
         call->setCallingConv(LLVM_DtoCallingConv(dlink));
     else if (fn->callconv != (unsigned)-1)
         call->setCallingConv(fn->callconv);
--- a/gen/tollvm.c	Wed Oct 24 01:37:34 2007 +0200
+++ b/gen/tollvm.c	Wed Oct 24 22:18:06 2007 +0200
@@ -221,8 +221,39 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
+static const llvm::FunctionType* LLVM_DtoVaFunctionType(FuncDeclaration* fdecl)
+{
+    TypeFunction* f = (TypeFunction*)fdecl->type;
+    assert(f != 0);
+
+    const llvm::PointerType* i8pty = llvm::PointerType::get(llvm::Type::Int8Ty);
+    std::vector<const llvm::Type*> args;
+
+    if (fdecl->llvmInternal == LLVMva_start) {
+        args.push_back(i8pty);
+    }
+    else if (fdecl->llvmInternal == LLVMva_intrinsic) {
+        size_t n = Argument::dim(f->parameters);
+        for (size_t i=0; i<n; ++i) {
+            args.push_back(i8pty);
+        }
+    }
+    else
+    assert(0);
+
+    const llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::VoidTy, args, false);
+    f->llvmType = fty;
+    return fty;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
 const llvm::FunctionType* LLVM_DtoFunctionType(FuncDeclaration* fdecl)
 {
+    if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
+        return LLVM_DtoVaFunctionType(fdecl);
+    }
+
     TypeFunction* f = (TypeFunction*)fdecl->type;
     assert(f != 0);
 
@@ -260,73 +291,79 @@
     // parameter types
     std::vector<const llvm::Type*> paramvec;
 
-    if (retinptr) {
-        Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
-        paramvec.push_back(rettype);
+    if (fdecl->llvmInternal == LLVMva_start) {
+        paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
     }
-
-    if (fdecl->needThis()) {
-        if (AggregateDeclaration* ad = fdecl->isMember()) {
-            Logger::print("isMember = this is: %s\n", ad->type->toChars());
-            const llvm::Type* thisty = LLVM_DtoType(ad->type);
-            Logger::cout() << "this llvm type: " << *thisty << '\n';
-            if (llvm::isa<llvm::StructType>(thisty) || thisty == gIR->topstruct().recty.get())
-                thisty = llvm::PointerType::get(thisty);
-            paramvec.push_back(thisty);
-            usesthis = true;
+    else {
+        if (retinptr) {
+            Logger::cout() << "returning through pointer parameter: " << *rettype << '\n';
+            paramvec.push_back(rettype);
         }
-        else
-        assert(0);
-    }
-    else if (fdecl->isNested()) {
-        paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
-        usesthis = true;
-    }
 
-    size_t n = Argument::dim(f->parameters);
-    for (int i=0; i < n; ++i) {
-        Argument* arg = Argument::getNth(f->parameters, i);
-        // ensure scalar
-        Type* argT = LLVM_DtoDType(arg->type);
-        assert(argT);
-
-        if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
-            //assert(arg->vardecl);
-            //arg->vardecl->refparam = true;
-        }
-        else
-            arg->llvmCopy = true;
-
-        const llvm::Type* at = LLVM_DtoType(argT);
-        if (llvm::isa<llvm::StructType>(at)) {
-            Logger::println("struct param");
-            paramvec.push_back(llvm::PointerType::get(at));
-        }
-        else if (llvm::isa<llvm::ArrayType>(at)) {
-            Logger::println("sarray param");
-            assert(argT->ty == Tsarray);
-            //paramvec.push_back(llvm::PointerType::get(at->getContainedType(0)));
-            paramvec.push_back(llvm::PointerType::get(at));
-        }
-        else if (llvm::isa<llvm::OpaqueType>(at)) {
-            Logger::println("opaque param");
-            if (argT->ty == Tstruct || argT->ty == Tclass)
-                paramvec.push_back(llvm::PointerType::get(at));
+        if (fdecl->needThis()) {
+            if (AggregateDeclaration* ad = fdecl->isMember()) {
+                Logger::print("isMember = this is: %s\n", ad->type->toChars());
+                const llvm::Type* thisty = LLVM_DtoType(ad->type);
+                Logger::cout() << "this llvm type: " << *thisty << '\n';
+                if (llvm::isa<llvm::StructType>(thisty) || thisty == gIR->topstruct().recty.get())
+                    thisty = llvm::PointerType::get(thisty);
+                paramvec.push_back(thisty);
+                usesthis = true;
+            }
             else
             assert(0);
         }
-        /*if (llvm::isa<llvm::StructType>(at) || argT->ty == Tstruct || argT->ty == Tsarray) {
-            paramvec.push_back(llvm::PointerType::get(at));
-        }*/
-        else {
-            if (!arg->llvmCopy) {
-                Logger::println("ref param");
-                at = llvm::PointerType::get(at);
+        else if (fdecl->isNested()) {
+            paramvec.push_back(llvm::PointerType::get(llvm::Type::Int8Ty));
+            usesthis = true;
+        }
+
+        size_t n = Argument::dim(f->parameters);
+
+        for (int i=0; i < n; ++i) {
+            Argument* arg = Argument::getNth(f->parameters, i);
+            // ensure scalar
+            Type* argT = LLVM_DtoDType(arg->type);
+            assert(argT);
+
+            if ((arg->storageClass & STCref) || (arg->storageClass & STCout)) {
+                //assert(arg->vardecl);
+                //arg->vardecl->refparam = true;
+            }
+            else
+                arg->llvmCopy = true;
+
+            const llvm::Type* at = LLVM_DtoType(argT);
+            if (llvm::isa<llvm::StructType>(at)) {
+                Logger::println("struct param");
+                paramvec.push_back(llvm::PointerType::get(at));
             }
+            else if (llvm::isa<llvm::ArrayType>(at)) {
+                Logger::println("sarray param");
+                assert(argT->ty == Tsarray);
+                //paramvec.push_back(llvm::PointerType::get(at->getContainedType(0)));
+                paramvec.push_back(llvm::PointerType::get(at));
+            }
+            else if (llvm::isa<llvm::OpaqueType>(at)) {
+                Logger::println("opaque param");
+                if (argT->ty == Tstruct || argT->ty == Tclass)
+                    paramvec.push_back(llvm::PointerType::get(at));
+                else
+                assert(0);
+            }
+            /*if (llvm::isa<llvm::StructType>(at) || argT->ty == Tstruct || argT->ty == Tsarray) {
+                paramvec.push_back(llvm::PointerType::get(at));
+            }*/
             else {
-                Logger::println("in param");
+                if (!arg->llvmCopy) {
+                    Logger::println("ref param");
+                    at = llvm::PointerType::get(at);
+                }
+                else {
+                    Logger::println("in param");
+                }
+                paramvec.push_back(at);
             }
-            paramvec.push_back(at);
         }
     }
 
@@ -931,10 +968,44 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////
 
+static llvm::Function* LLVM_DtoDeclareVaFunction(FuncDeclaration* fdecl)
+{
+    TypeFunction* f = (TypeFunction*)LLVM_DtoDType(fdecl->type);
+    const llvm::FunctionType* fty = LLVM_DtoVaFunctionType(fdecl);
+    llvm::Constant* fn = 0;
+
+    if (fdecl->llvmInternal == LLVMva_start) {
+        fn = gIR->module->getOrInsertFunction("llvm.va_start", fty);
+        assert(fn);
+    }
+    else if (fdecl->llvmInternal == LLVMva_intrinsic) {
+        fn = gIR->module->getOrInsertFunction(fdecl->llvmInternal1, fty);
+        assert(fn);
+    }
+    else
+    assert(0);
+
+    llvm::Function* func = llvm::cast_or_null<llvm::Function>(fn);
+    assert(func);
+    assert(func->isIntrinsic());
+    fdecl->llvmValue = func;
+    return func;
+}
+
+//////////////////////////////////////////////////////////////////////////////////////////
+
 llvm::Function* LLVM_DtoDeclareFunction(FuncDeclaration* fdecl)
 {
+    if ((fdecl->llvmInternal == LLVMva_start) || (fdecl->llvmInternal == LLVMva_intrinsic)) {
+        return LLVM_DtoDeclareVaFunction(fdecl);
+    }
+
     // mangled name
-    char* mangled_name = (fdecl->llvmInternal == LLVMintrinsic) ? fdecl->llvmInternal1 : fdecl->mangle();
+    char* mangled_name;
+    if (fdecl->llvmInternal == LLVMintrinsic)
+        mangled_name = fdecl->llvmInternal1;
+    else
+        mangled_name = fdecl->mangle();
 
     // unit test special handling
     if (fdecl->isUnitTestDeclaration())
--- a/gen/toobj.c	Wed Oct 24 01:37:34 2007 +0200
+++ b/gen/toobj.c	Wed Oct 24 22:18:06 2007 +0200
@@ -646,8 +646,31 @@
         return;
     }
 
+    Type* t = LLVM_DtoDType(type);
+    TypeFunction* f = (TypeFunction*)t;
+
+    bool declareOnly = false;
+    if (TemplateInstance* tinst = parent->isTemplateInstance()) {
+        TemplateDeclaration* tempdecl = tinst->tempdecl;
+        if (tempdecl->llvmInternal == LLVMva_start)
+        {
+            Logger::println("magic va_start found");
+            llvmInternal = LLVMva_start;
+            declareOnly = true;
+        }
+        else if (tempdecl->llvmInternal == LLVMva_arg)
+        {
+            Logger::println("magic va_arg found");
+            llvmInternal = LLVMva_arg;
+            return;
+        }
+    }
+
     llvm::Function* func = LLVM_DtoDeclareFunction(this);
 
+    if (declareOnly)
+        return;
+
     if (!gIR->structs.empty() && gIR->topstruct().queueFuncs) {
         if (!llvmQueued) {
             Logger::println("queueing %s", toChars());
@@ -657,8 +680,6 @@
         return; // we wait with the definition as they might invoke a virtual method and the vtable is not yet complete
     }
 
-    Type* t = LLVM_DtoDType(type);
-    TypeFunction* f = (TypeFunction*)t;
     assert(f->llvmType);
     const llvm::FunctionType* functype = llvm::cast<llvm::FunctionType>(llvmValue->getType()->getContainedType(0));
 
--- a/lphobos/build.sh	Wed Oct 24 01:37:34 2007 +0200
+++ b/lphobos/build.sh	Wed Oct 24 22:18:06 2007 +0200
@@ -25,6 +25,10 @@
 rebuild typeinfos.d -c -oqobj -dc=llvmdc-posix || exit 1
 llvm-link -f -o=../lib/llvmdcore.bc `ls obj/typeinfo.*.bc` ../lib/llvmdcore.bc || exit 1
 
+echo "compiling llvm runtime support"
+rebuild llvmsupport.d -c -oqobj -dc=llvmdc-posix || exit
+llvm-link -f -o=../lib/llvmdcore.bc `ls obj/llvm.*.bc` ../lib/llvmdcore.bc || exit 1
+
 echo "optimizing"
 opt -f -std-compile-opts -o=../lib/llvmdcore.bc ../lib/llvmdcore.bc || exit 1
 
--- a/lphobos/llvm/intrinsic.d	Wed Oct 24 01:37:34 2007 +0200
+++ b/lphobos/llvm/intrinsic.d	Wed Oct 24 22:18:06 2007 +0200
@@ -1,15 +1,5 @@
 module llvm.intrinsic;
 
-// variable argument handling intrinsics
-pragma(LLVM_internal, "intrinsic", "llvm.va_start")
-    void llvm_va_start(void* args);
-
-pragma(LLVM_internal, "intrinsic", "llvm.va_end")
-    void llvm_va_end(void* args);
-
-pragma(LLVM_internal, "intrinsic", "llvm.va_copy")
-    void llvm_va_copy(void* dst, void* src);
-
 // code generator intrinsics
 /*
 pragma(LLVM_internal, "intrinsic", "llvm.returnaddress")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/llvm/va_list.d	Wed Oct 24 22:18:06 2007 +0200
@@ -0,0 +1,25 @@
+module llvm.va_list;
+
+alias void* va_list;
+
+/*
+
+version(X86)
+{
+    alias void* va_list;
+}
+else version(X86_64)
+{
+    struct X86_64_va_list
+    {
+        uint gp_offset;
+        uint fp_offset;
+        void* overflow_arg_area;
+        void* reg_save_area;
+    }
+    alias X86_64_va_list va_list;
+}
+else
+static assert("only x86 and x86-64 support va_list");
+
+*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/lphobos/llvmsupport.d	Wed Oct 24 22:18:06 2007 +0200
@@ -0,0 +1,5 @@
+module llvmsupport;
+
+import
+llvm.intrinsic,
+llvm.va_list;
--- a/lphobos/std/c/stdarg.d	Wed Oct 24 01:37:34 2007 +0200
+++ b/lphobos/std/c/stdarg.d	Wed Oct 24 22:18:06 2007 +0200
@@ -1,7 +1,7 @@
 
 /**
  * C's &lt;stdarg.h&gt;
- * Authors: Hauke Duden and Walter Bright, Digital Mars, www.digitalmars.com
+ * Authors: Hauke Duden, Walter Bright and Tomas Lindquist Olsen, Digital Mars, www.digitalmars.com
  * License: Public Domain
  * Macros:
  *	WIKI=Phobos/StdCStdarg
@@ -11,32 +11,16 @@
 
 module std.c.stdarg;
 
-alias void* va_list;
+public import llvm.va_list;
 
-template va_start(T)
-{
-    void va_start(out va_list ap, inout T parmn)
-    {
-	ap = cast(va_list)(cast(void*)&parmn + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1)));
-    }
-}
+pragma(LLVM_internal, "va_start")
+    void va_start(T)(va_list ap, ref T);
 
-template va_arg(T)
-{
-    T va_arg(inout va_list ap)
-    {
-	T arg = *cast(T*)ap;
-	ap = cast(va_list)(cast(void*)ap + ((T.sizeof + int.sizeof - 1) & ~(int.sizeof - 1)));
-	return arg;
-    }
-}
+pragma(LLVM_internal, "va_arg")
+    T va_arg(T)(va_list ap);
 
-void va_end(va_list ap)
-{
-
-}
+pragma(LLVM_internal, "va_intrinsic", "llvm.va_end")
+    void va_end(va_list args);
 
-void va_copy(out va_list dest, va_list src)
-{
-    dest = src;
-}
+pragma(LLVM_internal, "va_intrinsic", "llvm.va_copy")
+    void va_copy(va_list dst, va_list src);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/vararg1.d	Wed Oct 24 22:18:06 2007 +0200
@@ -0,0 +1,21 @@
+module vararg1;
+
+import std.c.stdarg;
+
+extern(C) int add(int n, ...)
+{
+    va_list ap=void;
+    va_start(ap, n);
+    int r;
+    //for (int i=0; i<n; i++)
+    //    r += va_arg!(int)(ap);
+    r = va_arg!(int)(ap);
+    va_end(ap);
+    return r;
+}
+
+void main()
+{
+    int i = add(4,1,2,3,4);
+    assert(i == 10);
+}