Fix ABI on Win32.

We can't simply use the C calling convention, as the D(MD)
ABI is callee-pop, and this is hardcoded in naked functions
with stack parameters.

The \1 "trick" is normally used to avoid prefixes added by
LLVM; on the 3.2 release, a patch is needed to make it work
for the @<n> stdcall suffixes as well.
This commit is contained in:
David Nadlinger 2013-02-20 19:39:01 +01:00
parent e05a5c6f22
commit 2d3de4a3d4
4 changed files with 65 additions and 28 deletions

View file

@ -36,8 +36,6 @@ struct X86TargetABI : TargetABI
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;
@ -46,6 +44,30 @@ struct X86TargetABI : TargetABI
}
}
std::string mangleForLLVM(llvm::StringRef name, LINK l)
{
switch (l)
{
case LINKc:
case LINKcpp:
case LINKintrinsic:
case LINKpascal:
case LINKwindows:
return name;
case LINKd:
case LINKdefault:
if (global.params.targetTriple.isOSWindows())
{
// Prepend a 0x1 byte to keep LLVM from adding the usual
// "@<paramsize>" stdcall suffix.
return ("\1_" + name).str();
}
return name;
default:
llvm_unreachable("Unhandled D linkage type.");
}
}
bool returnInArg(TypeFunction* tf)
{
#if DMDV2

View file

@ -60,7 +60,15 @@ struct TargetABI
/// 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;
virtual llvm::CallingConv::ID callingConv(LINK l) = 0;
/// Applies any rewrites that might be required to accurately reproduce the
/// passed function name on LLVM given a specific calling convention.
///
/// Using this function at a stage where the name could be user-visible is
/// almost certainly a mistake; it is intended to e.g. prepend '\1' where
/// disabling the LLVM-internal name mangling/postprocessing is required.
virtual std::string mangleForLLVM(llvm::StringRef name, LINK l) { return name; }
/// Called if a new function type is resolved
virtual void newFunctionType(TypeFunction* tf) {}

View file

@ -741,48 +741,52 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
fdecl->ir.irFunc = new IrFunction(fdecl);
}
// mangled name
const char* mangled_name;
if (fdecl->llvmInternal == LLVMintrinsic)
mangled_name = fdecl->intrinsicName.c_str();
else
mangled_name = fdecl->mangle();
LLFunction* vafunc = 0;
if (fdecl->isVaIntrinsic())
vafunc = DtoDeclareVaFunction(fdecl);
// calling convention
LINK link = f->linkage;
if (vafunc || fdecl->llvmInternal == LLVMintrinsic
#if DMDV2
// DMD treats _Dmain as having C calling convention and this has been
// hardcoded into druntime, even if the frontend type has D linkage.
// See Bugzilla issue 9028.
|| fdecl->isMain()
#endif
)
{
link = LINKc;
}
// mangled name
std::string mangledName;
if (fdecl->llvmInternal == LLVMintrinsic)
mangledName = fdecl->intrinsicName;
else
mangledName = fdecl->mangle();
mangledName = gABI->mangleForLLVM(mangledName, link);
// construct function
LLFunctionType* functype = DtoFunctionType(fdecl);
LLFunction* func = vafunc ? vafunc : gIR->module->getFunction(mangled_name);
LLFunction* func = vafunc ? vafunc : gIR->module->getFunction(mangledName);
if (!func) {
if(fdecl->llvmInternal == LLVMinline_ir)
func = DtoInlineIRFunction(fdecl);
else
func = LLFunction::Create(functype, DtoLinkage(fdecl), mangled_name, gIR->module);
func = LLFunction::Create(functype, DtoLinkage(fdecl), mangledName, gIR->module);
} else if (func->getFunctionType() != functype) {
error(fdecl->loc, "Function type does not match previously declared function with the same mangled name: %s", fdecl->mangle());
}
func->setCallingConv(gABI->callingConv(link));
if (Logger::enabled())
Logger::cout() << "func = " << *func << std::endl;
// add func to IRFunc
fdecl->ir.irFunc->func = func;
// calling convention
if (!vafunc && fdecl->llvmInternal != LLVMintrinsic
#if DMDV2
// DMD treats _Dmain as having C calling convention and this has been
// hardcoded into druntime, even if the frontend type has D linkage.
// See Bugzilla issue 9028.
&& !fdecl->isMain()
#endif
)
func->setCallingConv(gABI->callingConv(f->linkage));
else // fall back to C, it should be the right thing to do
func->setCallingConv(llvm::CallingConv::C);
// parameter attributes
if (!fdecl->isIntrinsic()) {
set_param_attrs(f, func, fdecl);

View file

@ -74,15 +74,18 @@ static llvm::Function* build_module_function(const std::string &name, const std:
std::vector<LLType*> argsTy;
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);
std::string const symbolName = gABI->mangleForLLVM(name, LINKd);
assert(gIR->module->getFunction(symbolName) == NULL);
llvm::Function* fn = llvm::Function::Create(fnTy,
llvm::GlobalValue::InternalLinkage, symbolName, gIR->module);
fn->setCallingConv(gABI->callingConv(LINKd));
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn);
IRBuilder<> builder(bb);
// debug info
DtoDwarfSubProgramInternal(name.c_str(), name.c_str());
DtoDwarfSubProgramInternal(name.c_str(), symbolName.c_str());
// Call ctor's
typedef std::list<FuncDeclaration*>::const_iterator FuncIterator;