Mercurial > projects > ldc
diff gen/toir.c @ 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 | a9d29e9f1fed |
line wrap: on
line diff
--- 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);