Only non-typesafe variadics need to take LLVM varargs (#2127)

* gen/functions: Re-clang-format, minor style cleanup [nfc]

* Only non-typesafe variadics need to take LLVM varargs

GitHub: Fixes #2121.
This commit is contained in:
David Nadlinger 2017-05-22 08:37:05 +01:00 committed by Nicholas Wilson
parent ebfdc25323
commit c9112f3daf
3 changed files with 34 additions and 37 deletions

View file

@ -123,20 +123,14 @@ llvm::FunctionType *DtoFunctionType(Type *type, IrFuncTy &irFty, Type *thistype,
++nextLLArgIdx; ++nextLLArgIdx;
} }
// vararg functions are special too // Non-typesafe variadics (both C and D styles) are also variadics on the LLVM
if (f->varargs) { // level.
if (f->linkage == LINKd) { const bool isLLVMVariadic = (f->varargs == 1);
// d style with hidden args if (isLLVMVariadic && f->linkage == LINKd) {
// 2 (array) is handled by the frontend // Add extra `_arguments` parameter for D-style variadic functions.
if (f->varargs == 1) { newIrFty.arg_arguments =
// _arguments new IrFuncTyArg(Type::dtypeinfo->type->arrayOf(), false);
newIrFty.arg_arguments = ++nextLLArgIdx;
new IrFuncTyArg(Type::dtypeinfo->type->arrayOf(), false);
++nextLLArgIdx;
}
}
newIrFty.c_vararg = true;
} }
// if this _Dmain() doesn't have an argument, we force it to have one // if this _Dmain() doesn't have an argument, we force it to have one
@ -226,7 +220,7 @@ llvm::FunctionType *DtoFunctionType(Type *type, IrFuncTy &irFty, Type *thistype,
} }
irFty.funcType = irFty.funcType =
LLFunctionType::get(irFty.ret->ltype, argtypes, irFty.c_vararg); LLFunctionType::get(irFty.ret->ltype, argtypes, isLLVMVariadic);
IF_LOG Logger::cout() << "Final function type: " << *irFty.funcType << "\n"; IF_LOG Logger::cout() << "Final function type: " << *irFty.funcType << "\n";
@ -518,15 +512,13 @@ void DtoDeclareFunction(FuncDeclaration *fdecl) {
vafunc = DtoDeclareVaFunction(fdecl); vafunc = DtoDeclareVaFunction(fdecl);
} }
// calling convention // Calling convention.
LINK link = f->linkage; //
if (vafunc || DtoIsIntrinsic(fdecl) // DMD treats _Dmain as having C calling convention and this has been
// DMD treats _Dmain as having C calling convention and this has been // hardcoded into druntime, even if the frontend type has D linkage (Bugzilla
// hardcoded into druntime, even if the frontend type has D linkage. // issue 9028).
// See Bugzilla issue 9028. const bool forceC = vafunc || DtoIsIntrinsic(fdecl) || fdecl->isMain();
|| fdecl->isMain()) { const auto link = forceC ? LINKc : f->linkage;
link = LINKc;
}
// mangled name // mangled name
std::string mangledName = getMangledName(fdecl, link); std::string mangledName = getMangledName(fdecl, link);
@ -540,8 +532,9 @@ void DtoDeclareFunction(FuncDeclaration *fdecl) {
func = LLFunction::Create(functype, llvm::GlobalValue::ExternalLinkage, func = LLFunction::Create(functype, llvm::GlobalValue::ExternalLinkage,
mangledName, &gIR->module); mangledName, &gIR->module);
} else if (func->getFunctionType() != functype) { } else if (func->getFunctionType() != functype) {
error(fdecl->loc, "Function type does not match previously declared " error(fdecl->loc,
"function with the same mangled name: %s", "Function type does not match previously declared "
"function with the same mangled name: %s",
mangleExact(fdecl)); mangleExact(fdecl));
fatal(); fatal();
} }
@ -793,8 +786,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
llvm::Function *func = getIrFunc(fd)->getLLVMFunc(); llvm::Function *func = getIrFunc(fd)->getLLVMFunc();
assert(nullptr != func); assert(nullptr != func);
if (!linkageAvailableExternally && if (!linkageAvailableExternally &&
(func->getLinkage() == (func->getLinkage() == llvm::GlobalValue::AvailableExternallyLinkage)) {
llvm::GlobalValue::AvailableExternallyLinkage)) {
// Fix linkage // Fix linkage
const auto lwc = lowerFuncLinkage(fd); const auto lwc = lowerFuncLinkage(fd);
setLinkage(lwc, func); setLinkage(lwc, func);
@ -817,8 +809,9 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
// This function failed semantic3() with errors but the errors were gagged. // This function failed semantic3() with errors but the errors were gagged.
// In contrast to DMD we immediately bail out here, since other parts of // In contrast to DMD we immediately bail out here, since other parts of
// the codegen expect irFunc to be set for defined functions. // the codegen expect irFunc to be set for defined functions.
error(fd->loc, "Internal Compiler Error: function not fully analyzed; " error(fd->loc,
"previous unreported errors compiling %s?", "Internal Compiler Error: function not fully analyzed; "
"previous unreported errors compiling %s?",
fd->toPrettyChars()); fd->toPrettyChars());
fatal(); fatal();
} }
@ -878,8 +871,9 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
assert(fd->ident != Id::empty); assert(fd->ident != Id::empty);
if (fd->semanticRun != PASSsemantic3done) { if (fd->semanticRun != PASSsemantic3done) {
error(fd->loc, "Internal Compiler Error: function not fully analyzed; " error(fd->loc,
"previous unreported errors compiling %s?", "Internal Compiler Error: function not fully analyzed; "
"previous unreported errors compiling %s?",
fd->toPrettyChars()); fd->toPrettyChars());
fatal(); fatal();
} }
@ -1063,8 +1057,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
gIR->scopebb()); gIR->scopebb());
// copy _arguments to a memory location // copy _arguments to a memory location
irFunc->_arguments = irFunc->_arguments = DtoAllocaDump(irFunc->_arguments, 0, "_arguments_mem");
DtoAllocaDump(irFunc->_arguments, 0, "_arguments_mem");
// Push cleanup block that calls va_end to match the va_start call. // Push cleanup block that calls va_end to match the va_start call.
{ {

View file

@ -101,9 +101,6 @@ struct IrFuncTy {
using ArgList = std::vector<IrFuncTyArg *>; using ArgList = std::vector<IrFuncTyArg *>;
ArgList args; ArgList args;
// C varargs
bool c_vararg = false;
// range of normal parameters to reverse // range of normal parameters to reverse
bool reverseParams = false; bool reverseParams = false;

7
tests/codegen/varargs.d Normal file
View file

@ -0,0 +1,7 @@
// RUN: %ldc -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
// Make sure typesafe variadics are not lowered to LLVM variadics.
void typesafe(size_t[2] a...) {}
// CHECK: define{{.*}}typesafe
// CHECK-NOT: ...
// CHECK-SAME: {