mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-05-04 00:55:49 +03:00
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:
parent
e05a5c6f22
commit
2d3de4a3d4
4 changed files with 65 additions and 28 deletions
|
@ -36,8 +36,6 @@ struct X86TargetABI : TargetABI
|
||||||
return llvm::CallingConv::C;
|
return llvm::CallingConv::C;
|
||||||
case LINKd:
|
case LINKd:
|
||||||
case LINKdefault:
|
case LINKdefault:
|
||||||
return global.params.targetTriple.isOSWindows() ?
|
|
||||||
llvm::CallingConv::C : llvm::CallingConv::X86_StdCall;
|
|
||||||
case LINKpascal:
|
case LINKpascal:
|
||||||
case LINKwindows:
|
case LINKwindows:
|
||||||
return llvm::CallingConv::X86_StdCall;
|
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)
|
bool returnInArg(TypeFunction* tf)
|
||||||
{
|
{
|
||||||
#if DMDV2
|
#if DMDV2
|
||||||
|
|
10
gen/abi.h
10
gen/abi.h
|
@ -60,7 +60,15 @@ struct TargetABI
|
||||||
|
|
||||||
/// Returns the LLVM calling convention to be used for the given D linkage
|
/// Returns the LLVM calling convention to be used for the given D linkage
|
||||||
/// type on the target.
|
/// 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
|
/// Called if a new function type is resolved
|
||||||
virtual void newFunctionType(TypeFunction* tf) {}
|
virtual void newFunctionType(TypeFunction* tf) {}
|
||||||
|
|
|
@ -741,48 +741,52 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
|
||||||
fdecl->ir.irFunc = new IrFunction(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;
|
LLFunction* vafunc = 0;
|
||||||
if (fdecl->isVaIntrinsic())
|
if (fdecl->isVaIntrinsic())
|
||||||
vafunc = DtoDeclareVaFunction(fdecl);
|
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
|
// construct function
|
||||||
LLFunctionType* functype = DtoFunctionType(fdecl);
|
LLFunctionType* functype = DtoFunctionType(fdecl);
|
||||||
LLFunction* func = vafunc ? vafunc : gIR->module->getFunction(mangled_name);
|
LLFunction* func = vafunc ? vafunc : gIR->module->getFunction(mangledName);
|
||||||
if (!func) {
|
if (!func) {
|
||||||
if(fdecl->llvmInternal == LLVMinline_ir)
|
if(fdecl->llvmInternal == LLVMinline_ir)
|
||||||
func = DtoInlineIRFunction(fdecl);
|
func = DtoInlineIRFunction(fdecl);
|
||||||
else
|
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) {
|
} else if (func->getFunctionType() != functype) {
|
||||||
error(fdecl->loc, "Function type does not match previously declared function with the same mangled name: %s", fdecl->mangle());
|
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())
|
if (Logger::enabled())
|
||||||
Logger::cout() << "func = " << *func << std::endl;
|
Logger::cout() << "func = " << *func << std::endl;
|
||||||
|
|
||||||
// add func to IRFunc
|
// add func to IRFunc
|
||||||
fdecl->ir.irFunc->func = func;
|
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
|
// parameter attributes
|
||||||
if (!fdecl->isIntrinsic()) {
|
if (!fdecl->isIntrinsic()) {
|
||||||
set_param_attrs(f, func, fdecl);
|
set_param_attrs(f, func, fdecl);
|
||||||
|
|
|
@ -74,15 +74,18 @@ static llvm::Function* build_module_function(const std::string &name, const std:
|
||||||
|
|
||||||
std::vector<LLType*> argsTy;
|
std::vector<LLType*> argsTy;
|
||||||
LLFunctionType* fnTy = LLFunctionType::get(LLType::getVoidTy(gIR->context()),argsTy,false);
|
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));
|
fn->setCallingConv(gABI->callingConv(LINKd));
|
||||||
|
|
||||||
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn);
|
llvm::BasicBlock* bb = llvm::BasicBlock::Create(gIR->context(), "entry", fn);
|
||||||
IRBuilder<> builder(bb);
|
IRBuilder<> builder(bb);
|
||||||
|
|
||||||
// debug info
|
// debug info
|
||||||
DtoDwarfSubProgramInternal(name.c_str(), name.c_str());
|
DtoDwarfSubProgramInternal(name.c_str(), symbolName.c_str());
|
||||||
|
|
||||||
// Call ctor's
|
// Call ctor's
|
||||||
typedef std::list<FuncDeclaration*>::const_iterator FuncIterator;
|
typedef std::list<FuncDeclaration*>::const_iterator FuncIterator;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue