mirror of
https://github.com/ldc-developers/ldc.git
synced 2025-04-28 22:21:31 +03:00
Don't forward-declare magic intrinsics mapping to instructions
It's ugly in general, and apparently causes LTO issues on Windows. This required a larger refactoring.
This commit is contained in:
parent
be00cbb189
commit
078f0532ca
6 changed files with 39 additions and 92 deletions
|
@ -51,4 +51,3 @@ extern (C++) LDCPragma DtoGetPragma(Scope* sc, PragmaDeclaration decl, ref const
|
|||
extern (C++) void DtoCheckPragma(PragmaDeclaration decl, Dsymbol sym, LDCPragma llvm_internal, const char* arg1str);
|
||||
extern (C++) bool DtoCheckProfileInstrPragma(Expression arg, ref bool value);
|
||||
extern (C++) bool DtoIsIntrinsic(FuncDeclaration fd);
|
||||
extern (C++) bool DtoIsVaIntrinsic(FuncDeclaration fd);
|
||||
|
|
|
@ -293,37 +293,7 @@ llvm::FunctionType *DtoFunctionType(Type *type, IrFuncTy &irFty, Type *thistype,
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static llvm::FunctionType *DtoVaFunctionType(FuncDeclaration *fdecl) {
|
||||
IrFuncTy &irFty = getIrFunc(fdecl, true)->irFty;
|
||||
if (irFty.funcType) {
|
||||
return irFty.funcType;
|
||||
}
|
||||
|
||||
irFty.ret = new IrFuncTyArg(Type::tvoid, false);
|
||||
|
||||
irFty.args.push_back(new IrFuncTyArg(pointerTo(Type::tvoid), false));
|
||||
|
||||
if (fdecl->llvmInternal == LLVMva_start) {
|
||||
irFty.funcType = GET_INTRINSIC_DECL(vastart)->getFunctionType();
|
||||
} else if (fdecl->llvmInternal == LLVMva_copy) {
|
||||
irFty.funcType = GET_INTRINSIC_DECL(vacopy)->getFunctionType();
|
||||
irFty.args.push_back(new IrFuncTyArg(pointerTo(Type::tvoid), false));
|
||||
} else if (fdecl->llvmInternal == LLVMva_end) {
|
||||
irFty.funcType = GET_INTRINSIC_DECL(vaend)->getFunctionType();
|
||||
}
|
||||
assert(irFty.funcType);
|
||||
|
||||
return irFty.funcType;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
llvm::FunctionType *DtoFunctionType(FuncDeclaration *fdecl) {
|
||||
// handle for C vararg intrinsics
|
||||
if (DtoIsVaIntrinsic(fdecl)) {
|
||||
return DtoVaFunctionType(fdecl);
|
||||
}
|
||||
|
||||
Type *dthis = nullptr, *dnest = nullptr;
|
||||
|
||||
if (fdecl->ident == Id::ensure || fdecl->ident == Id::require) {
|
||||
|
@ -366,25 +336,6 @@ llvm::FunctionType *DtoFunctionType(FuncDeclaration *fdecl) {
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static llvm::Function *DtoDeclareVaFunction(FuncDeclaration *fdecl) {
|
||||
DtoVaFunctionType(fdecl);
|
||||
llvm::Function *func = nullptr;
|
||||
|
||||
if (fdecl->llvmInternal == LLVMva_start) {
|
||||
func = GET_INTRINSIC_DECL(vastart);
|
||||
} else if (fdecl->llvmInternal == LLVMva_copy) {
|
||||
func = GET_INTRINSIC_DECL(vacopy);
|
||||
} else if (fdecl->llvmInternal == LLVMva_end) {
|
||||
func = GET_INTRINSIC_DECL(vaend);
|
||||
}
|
||||
assert(func);
|
||||
|
||||
getIrFunc(fdecl)->setLLVMFunc(func);
|
||||
return func;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void DtoResolveFunction(FuncDeclaration *fdecl, const bool willDeclare) {
|
||||
if ((!global.params.useUnitTests || !fdecl->type) &&
|
||||
fdecl->isUnitTestDeclaration()) {
|
||||
|
@ -412,21 +363,7 @@ void DtoResolveFunction(FuncDeclaration *fdecl, const bool willDeclare) {
|
|||
if (TemplateInstance *tinst = fdecl->parent->isTemplateInstance()) {
|
||||
if (TemplateDeclaration *tempdecl =
|
||||
tinst->tempdecl->isTemplateDeclaration()) {
|
||||
if (tempdecl->llvmInternal == LLVMva_arg) {
|
||||
Logger::println("magic va_arg found");
|
||||
fdecl->llvmInternal = LLVMva_arg;
|
||||
fdecl->ir->setDefined();
|
||||
return; // this gets mapped to an instruction so a declaration makes
|
||||
// no sense
|
||||
}
|
||||
if (tempdecl->llvmInternal == LLVMva_start) {
|
||||
Logger::println("magic va_start found");
|
||||
fdecl->llvmInternal = LLVMva_start;
|
||||
} else if (tempdecl->llvmInternal == LLVMintrinsic) {
|
||||
Logger::println("overloaded intrinsic found");
|
||||
assert(fdecl->llvmInternal == LLVMintrinsic);
|
||||
assert(fdecl->mangleOverride.length);
|
||||
} else if (tempdecl->llvmInternal == LLVMinline_asm) {
|
||||
if (tempdecl->llvmInternal == LLVMinline_asm) {
|
||||
Logger::println("magic inline asm found");
|
||||
TypeFunction *tf = static_cast<TypeFunction *>(fdecl->type);
|
||||
if (tf->parameterList.varargs != VARARGvariadic ||
|
||||
|
@ -436,13 +373,13 @@ void DtoResolveFunction(FuncDeclaration *fdecl, const bool willDeclare) {
|
|||
"variadic with no explicit parameters");
|
||||
fatal();
|
||||
}
|
||||
fdecl->llvmInternal = LLVMinline_asm;
|
||||
assert(fdecl->llvmInternal == LLVMinline_asm);
|
||||
fdecl->ir->setDefined();
|
||||
return; // this gets mapped to a special inline asm call, no point in
|
||||
// going on.
|
||||
} else if (tempdecl->llvmInternal == LLVMinline_ir) {
|
||||
Logger::println("magic inline ir found");
|
||||
fdecl->llvmInternal = LLVMinline_ir;
|
||||
assert(fdecl->llvmInternal == LLVMinline_ir);
|
||||
fdecl->_linkage = LINK::c;
|
||||
Type *type = fdecl->type;
|
||||
assert(type->ty == TY::Tfunction);
|
||||
|
@ -457,6 +394,13 @@ void DtoResolveFunction(FuncDeclaration *fdecl, const bool willDeclare) {
|
|||
}
|
||||
}
|
||||
|
||||
// magic intrinsics are mapped to instructions, no point in fwd-declaring some
|
||||
// non-existing function
|
||||
if (DtoIsMagicIntrinsic(fdecl)) {
|
||||
fdecl->ir->setDefined();
|
||||
return;
|
||||
}
|
||||
|
||||
DtoFunctionType(fdecl);
|
||||
|
||||
IF_LOG Logger::println("DtoResolveFunction(%s): %s", fdecl->toPrettyChars(),
|
||||
|
@ -610,24 +554,19 @@ void DtoDeclareFunction(FuncDeclaration *fdecl, const bool willDefine) {
|
|||
// create IrFunction
|
||||
IrFunction *irFunc = getIrFunc(fdecl, true);
|
||||
|
||||
LLFunction *vafunc = nullptr;
|
||||
if (DtoIsVaIntrinsic(fdecl)) {
|
||||
vafunc = DtoDeclareVaFunction(fdecl);
|
||||
}
|
||||
|
||||
// Calling convention.
|
||||
//
|
||||
// DMD treats _Dmain as having C calling convention and this has been
|
||||
// hardcoded into druntime, even if the frontend type has D linkage (Bugzilla
|
||||
// issue 9028).
|
||||
const bool forceC = vafunc || DtoIsIntrinsic(fdecl) || fdecl->isMain();
|
||||
const bool forceC = DtoIsIntrinsic(fdecl) || fdecl->isMain();
|
||||
|
||||
// mangled name
|
||||
const auto irMangle = getIRMangledName(fdecl, forceC ? LINK::c : f->linkage);
|
||||
|
||||
// construct function
|
||||
LLFunctionType *functype = DtoFunctionType(fdecl);
|
||||
LLFunction *func = vafunc ? vafunc : gIR->module.getFunction(irMangle);
|
||||
LLFunction *func = gIR->module.getFunction(irMangle);
|
||||
if (!func) {
|
||||
// All function declarations are "external" - any other linkage type
|
||||
// is set when actually defining the function, except extern_weak.
|
||||
|
|
|
@ -1576,9 +1576,8 @@ DValue *DtoSymbolAddress(const Loc &loc, Type *type, Declaration *decl) {
|
|||
fatal();
|
||||
}
|
||||
DtoResolveFunction(fdecl);
|
||||
const auto llValue =
|
||||
fdecl->llvmInternal != LLVMva_arg ? DtoCallee(fdecl) : nullptr;
|
||||
return new DFuncValue(fdecl, llValue);
|
||||
assert(!DtoIsMagicIntrinsic(fdecl));
|
||||
return new DFuncValue(fdecl, DtoCallee(fdecl));
|
||||
}
|
||||
|
||||
if (SymbolDeclaration *sdecl = decl->isSymbolDeclaration()) {
|
||||
|
|
|
@ -452,6 +452,7 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s,
|
|||
fatal();
|
||||
}
|
||||
td->llvmInternal = llvm_internal;
|
||||
td->onemember->llvmInternal = llvm_internal;
|
||||
});
|
||||
if (count != 1) {
|
||||
error(s->loc,
|
||||
|
@ -502,6 +503,7 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s,
|
|||
fatal();
|
||||
}
|
||||
td->llvmInternal = llvm_internal;
|
||||
td->onemember->llvmInternal = llvm_internal;
|
||||
});
|
||||
if (count != 1) {
|
||||
error(s->loc,
|
||||
|
@ -515,7 +517,13 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s,
|
|||
case LLVMinline_ir: {
|
||||
DtoCheckInlineIRPragma(ident, s);
|
||||
const int count = applyTemplatePragma(s, [=](TemplateDeclaration *td) {
|
||||
if (!td->onemember) {
|
||||
error(s->loc, "the `%s` pragma template must have exactly one member",
|
||||
ident->toChars());
|
||||
fatal();
|
||||
}
|
||||
td->llvmInternal = llvm_internal;
|
||||
td->onemember->llvmInternal = llvm_internal;
|
||||
});
|
||||
if (count != 1) {
|
||||
error(s->loc,
|
||||
|
@ -570,8 +578,16 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *s,
|
|||
}
|
||||
|
||||
bool DtoIsIntrinsic(FuncDeclaration *fd) {
|
||||
return fd->llvmInternal == LLVMintrinsic || DtoIsMagicIntrinsic(fd);
|
||||
}
|
||||
|
||||
bool DtoIsMagicIntrinsic(FuncDeclaration *fd) {
|
||||
// note: keep in sync with DtoLowerMagicIntrinsic()
|
||||
switch (fd->llvmInternal) {
|
||||
case LLVMintrinsic:
|
||||
case LLVMva_start: // doesn't map to an instruction, but handled as magic intrinsic by LDC
|
||||
case LLVMva_copy: // ditto
|
||||
case LLVMva_arg:
|
||||
case LLVMva_end: // ditto
|
||||
case LLVMalloca:
|
||||
case LLVMfence:
|
||||
case LLVMatomic_store:
|
||||
|
@ -587,15 +603,10 @@ bool DtoIsIntrinsic(FuncDeclaration *fd) {
|
|||
return true;
|
||||
|
||||
default:
|
||||
return DtoIsVaIntrinsic(fd);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool DtoIsVaIntrinsic(FuncDeclaration *fd) {
|
||||
return (fd->llvmInternal == LLVMva_start || fd->llvmInternal == LLVMva_copy ||
|
||||
fd->llvmInternal == LLVMva_end);
|
||||
}
|
||||
|
||||
// pragma(LDC_profile_instr, [true | false])
|
||||
// Return false if an error occurred.
|
||||
bool DtoCheckProfileInstrPragma(Expression *arg, bool &value) {
|
||||
|
|
|
@ -56,4 +56,4 @@ void DtoCheckPragma(PragmaDeclaration *decl, Dsymbol *sym, LDCPragma llvm_intern
|
|||
const char * const arg1str);
|
||||
bool DtoCheckProfileInstrPragma(Expression *arg, bool &value);
|
||||
bool DtoIsIntrinsic(FuncDeclaration *fd);
|
||||
bool DtoIsVaIntrinsic(FuncDeclaration *fd);
|
||||
bool DtoIsMagicIntrinsic(FuncDeclaration *fd);
|
||||
|
|
13
gen/toir.cpp
13
gen/toir.cpp
|
@ -710,7 +710,7 @@ public:
|
|||
auto &PGO = gIR->funcGen().pgo;
|
||||
PGO.setCurrentStmt(e);
|
||||
|
||||
// handle magic inline asm
|
||||
// handle magic intrinsics and inline asm/IR
|
||||
if (auto ve = e->e1->isVarExp()) {
|
||||
if (auto fd = ve->var->isFuncDeclaration()) {
|
||||
if (fd->llvmInternal == LLVMinline_asm) {
|
||||
|
@ -719,6 +719,10 @@ public:
|
|||
if (fd->llvmInternal == LLVMinline_ir) {
|
||||
return DtoInlineIRExpr(e->loc, fd, e->arguments, sretPointer);
|
||||
}
|
||||
|
||||
DValue *result = nullptr;
|
||||
if (DtoLowerMagicIntrinsic(p, fd, e, result))
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -767,13 +771,8 @@ public:
|
|||
|
||||
// get func value if any
|
||||
DFuncValue *dfnval = fnval->isFunc();
|
||||
|
||||
// handle magic intrinsics (mapping to instructions)
|
||||
if (dfnval && dfnval->func) {
|
||||
FuncDeclaration *fndecl = dfnval->func;
|
||||
DValue *result = nullptr;
|
||||
if (DtoLowerMagicIntrinsic(p, fndecl, e, result))
|
||||
return result;
|
||||
assert(!DtoIsMagicIntrinsic(dfnval->func));
|
||||
}
|
||||
|
||||
DValue *result =
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue