diff --git a/gen/abi-ppc64.cpp b/gen/abi-ppc64.cpp index 9d0fbc61e3..bb77d29572 100644 --- a/gen/abi-ppc64.cpp +++ b/gen/abi-ppc64.cpp @@ -20,6 +20,23 @@ #include "gen/tollvm.h" struct PPC64TargetABI : TargetABI { + llvm::CallingConv::ID callingConv(LINK l) + { + switch (l) + { + case LINKc: + case LINKcpp: + case LINKintrinsic: + case LINKpascal: + case LINKwindows: + return llvm::CallingConv::C; + case LINKd: + case LINKdefault: + return llvm::CallingConv::Fast; + default: + llvm_unreachable("Unhandled D linkage type."); + } + } void newFunctionType(TypeFunction* tf) { diff --git a/gen/abi-win64.cpp b/gen/abi-win64.cpp index 0c10f36a1f..123306441d 100644 --- a/gen/abi-win64.cpp +++ b/gen/abi-win64.cpp @@ -91,6 +91,8 @@ struct Win64TargetABI : TargetABI CfloatToInt cfloatToInt; X87_complex_swap swapComplex; + llvm::CallingConv::ID callingConv(LINK l); + bool returnInArg(TypeFunction* tf); bool passByVal(Type* t); @@ -105,6 +107,23 @@ TargetABI* getWin64TargetABI() return new Win64TargetABI; } +llvm::CallingConv::ID Win64TargetABI::callingConv(LINK l) +{ + switch (l) + { + case LINKc: + case LINKcpp: + case LINKd: + case LINKdefault: + case LINKintrinsic: + case LINKwindows: + return llvm::CallingConv::C; + case LINKpascal: + return llvm::CallingConv::X86_StdCall; + default: + llvm_unreachable("Unhandled D linkage type."); + } +} bool Win64TargetABI::returnInArg(TypeFunction* tf) { diff --git a/gen/abi-x86-64.cpp b/gen/abi-x86-64.cpp index 4e902b64cf..7ac2ae89bf 100644 --- a/gen/abi-x86-64.cpp +++ b/gen/abi-x86-64.cpp @@ -366,6 +366,8 @@ struct X86_64TargetABI : TargetABI { X87_complex_swap swapComplex; CompositeToInt compositeToInt; + llvm::CallingConv::ID callingConv(LINK l); + void newFunctionType(TypeFunction* tf) { funcTypeStack.push_back(FuncTypeData(tf->linkage)); } @@ -414,6 +416,24 @@ TargetABI* getX86_64TargetABI() { } +llvm::CallingConv::ID X86_64TargetABI::callingConv(LINK l) +{ + switch (l) + { + case LINKc: + case LINKcpp: + case LINKd: + case LINKdefault: + case LINKintrinsic: + return llvm::CallingConv::C; + case LINKpascal: + case LINKwindows: // Doesn't really make sense, user should use Win64 target. + return llvm::CallingConv::X86_StdCall; + default: + llvm_unreachable("Unhandled D linkage type."); + } +} + bool X86_64TargetABI::returnInArg(TypeFunction* tf) { assert(linkage() == tf->linkage); Type* rt = tf->next->toBasetype(); diff --git a/gen/abi-x86.cpp b/gen/abi-x86.cpp index b4069f31f6..a2a241e215 100644 --- a/gen/abi-x86.cpp +++ b/gen/abi-x86.cpp @@ -26,6 +26,26 @@ struct X86TargetABI : TargetABI CfloatToInt cfloatToInt; CompositeToInt compositeToInt; + llvm::CallingConv::ID callingConv(LINK l) + { + switch (l) + { + case LINKc: + case LINKcpp: + case LINKintrinsic: + return llvm::CallingConv::C; + case LINKd: + case LINKdefault: + return global.params.targetTriple.isOSWindows() ? + llvm::CallingConv::C : llvm::CallingConv::X86_StdCall; + case LINKpascal: + case LINKwindows: + return llvm::CallingConv::X86_StdCall; + default: + llvm_unreachable("Unhandled D linkage type."); + } + } + bool returnInArg(TypeFunction* tf) { #if DMDV2 diff --git a/gen/abi.cpp b/gen/abi.cpp index 0152a9c9d3..e2f9f3c105 100644 --- a/gen/abi.cpp +++ b/gen/abi.cpp @@ -38,6 +38,24 @@ void ABIRewrite::getL(Type* dty, DValue* v, llvm::Value* lval) // Some reasonable defaults for when we don't know what ABI to use. struct UnknownTargetABI : TargetABI { + llvm::CallingConv::ID callingConv(LINK l) + { + switch (l) + { + case LINKc: + case LINKcpp: + case LINKintrinsic: + case LINKpascal: + case LINKwindows: + return llvm::CallingConv::C; + case LINKd: + case LINKdefault: + return llvm::CallingConv::Fast; + default: + llvm_unreachable("Unhandled D linkage type."); + } + } + bool returnInArg(TypeFunction* tf) { #if DMDV2 @@ -91,6 +109,11 @@ struct IntrinsicABI : TargetABI { RemoveStructPadding remove_padding; + llvm::CallingConv::ID callingConv(LINK l) + { + return llvm::CallingConv::C; + } + bool returnInArg(TypeFunction* tf) { return false; diff --git a/gen/abi.h b/gen/abi.h index ee48205476..e79f20112a 100644 --- a/gen/abi.h +++ b/gen/abi.h @@ -17,6 +17,8 @@ #ifndef LDC_GEN_ABI_H #define LDC_GEN_ABI_H +#include "mars.h" +#include "llvm/CallingConv.h" #include struct Type; @@ -56,6 +58,10 @@ struct TargetABI /// Returns the ABI for intrinsics static TargetABI* getIntrinsic(); + /// Returns the LLVM calling convention to be used for the given D linkage + /// type on the target. + virtual llvm::CallingConv::ID callingConv(enum LINK l) = 0; + /// Called if a new function type is resolved virtual void newFunctionType(TypeFunction* tf) {} diff --git a/gen/functions.cpp b/gen/functions.cpp index 7bac905e05..fe353897db 100644 --- a/gen/functions.cpp +++ b/gen/functions.cpp @@ -779,7 +779,7 @@ void DtoDeclareFunction(FuncDeclaration* fdecl) && !fdecl->isMain() #endif ) - func->setCallingConv(DtoCallingConv(fdecl->loc, f->linkage)); + func->setCallingConv(gABI->callingConv(f->linkage)); else // fall back to C, it should be the right thing to do func->setCallingConv(llvm::CallingConv::C); diff --git a/gen/llvmhelpers.h b/gen/llvmhelpers.h index a3399c4496..e099dcd830 100644 --- a/gen/llvmhelpers.h +++ b/gen/llvmhelpers.h @@ -194,9 +194,6 @@ void tokToIcmpPred(TOK op, bool isUnsigned, llvm::ICmpInst::Predicate* outPred, // gen/tocall.cpp stuff below //////////////////////////////////////////// -/// convert DMD calling conv to LLVM -llvm::CallingConv::ID DtoCallingConv(Loc loc, LINK l); - /// TypeFunction* DtoTypeFunction(DValue* fnval); diff --git a/gen/module.cpp b/gen/module.cpp index 671217bb19..5ffd7e25ed 100644 --- a/gen/module.cpp +++ b/gen/module.cpp @@ -76,7 +76,7 @@ static llvm::Function* build_module_function(const std::string &name, const std: LLFunctionType* fnTy = LLFunctionType::get(LLType::getVoidTy(gIR->context()),argsTy,false); assert(gIR->module->getFunction(name) == NULL); llvm::Function* fn = llvm::Function::Create(fnTy, llvm::GlobalValue::InternalLinkage, name, gIR->module); - fn->setCallingConv(DtoCallingConv(0, LINKd)); + fn->setCallingConv(gABI->callingConv(LINKd)); llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn); IRBuilder<> builder(bb); @@ -89,7 +89,7 @@ static llvm::Function* build_module_function(const std::string &name, const std: for (FuncIterator itr = funcs.begin(), end = funcs.end(); itr != end; ++itr) { llvm::Function* f = (*itr)->ir.irFunc->func; llvm::CallInst* call = builder.CreateCall(f,""); - call->setCallingConv(DtoCallingConv(0, LINKd)); + call->setCallingConv(gABI->callingConv(LINKd)); } // Increment vgate's diff --git a/gen/tocall.cpp b/gen/tocall.cpp index 23233ef960..2b44b69dae 100644 --- a/gen/tocall.cpp +++ b/gen/tocall.cpp @@ -54,42 +54,6 @@ TypeFunction* DtoTypeFunction(DValue* fnval) ////////////////////////////////////////////////////////////////////////////////////////// -llvm::CallingConv::ID DtoCallingConv(Loc loc, LINK l) -{ - llvm::Triple::ArchType const arch = global.params.targetTriple.getArch(); - - if (l == LINKc || l == LINKcpp || l == LINKintrinsic) - return llvm::CallingConv::C; - else if (l == LINKd || l == LINKdefault) - { - //TODO: StdCall is not a good base on Windows due to extra name mangling - // applied there - if (arch == llvm::Triple::x86 || arch == llvm::Triple::x86_64) - { - return global.params.targetTriple.isOSWindows() ? - llvm::CallingConv::C : llvm::CallingConv::X86_StdCall; - } - else - return llvm::CallingConv::Fast; - } - // on the other hand, here, it's exactly what we want!!! TODO: right? - // On Windows 64bit, there is only one calling convention! - else if (l == LINKwindows) - { - return (arch == llvm::Triple::x86_64) ? - llvm::CallingConv::C : llvm::CallingConv::X86_StdCall; - } - else if (l == LINKpascal) - return llvm::CallingConv::X86_StdCall; - else - { - error(loc, "unsupported calling convention"); - fatal(); - } -} - -////////////////////////////////////////////////////////////////////////////////////////// - DValue* DtoVaArg(Loc& loc, Type* type, Expression* valistArg) { DValue* expelem = valistArg->toElem(gIR); @@ -377,7 +341,7 @@ DValue* DtoCallFunction(Loc& loc, Type* resulttype, DValue* fnval, Expressions* bool nestedcall = tf->fty.arg_nest; bool dvarargs = (tf->linkage == LINKd && tf->varargs == 1); - llvm::CallingConv::ID callconv = DtoCallingConv(loc, tf->linkage); + llvm::CallingConv::ID callconv = gABI->callingConv(tf->linkage); // get callee llvm value LLValue* callable = DtoCallableValue(fnval);