-dllimport=defaultLibsOnly: Avoid -linkonce-templates requirement (#3816)

Via a sorts-of '-linkonce-templates light', only defining all *data*
symbols instantiated from druntime/Phobos templates in each
referencing CU.
This commit is contained in:
Martin Kinkelin 2021-09-11 04:53:21 +02:00 committed by GitHub
parent d9b2c936c9
commit 16b9eab374
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 35 additions and 34 deletions

View file

@ -80,9 +80,7 @@ cl::opt<DLLImport, true> dllimport(
"None (default with -link-defaultlib-shared=false)"), "None (default with -link-defaultlib-shared=false)"),
clEnumValN(DLLImport::defaultLibsOnly, "defaultLibsOnly", clEnumValN(DLLImport::defaultLibsOnly, "defaultLibsOnly",
"Only druntime/Phobos symbols (default with " "Only druntime/Phobos symbols (default with "
"-link-defaultlib-shared and -fvisibility=hidden). May " "-link-defaultlib-shared and -fvisibility=hidden)."),
"likely need to be coupled with -linkonce-templates to "
"overcome linker errors wrt. instantiated symbols."),
clEnumValN(DLLImport::all, "all", clEnumValN(DLLImport::all, "all",
"All (default with -link-defaultlib-shared and " "All (default with -link-defaultlib-shared and "
"-fvisibility=public)"))); "-fvisibility=public)")));

View file

@ -598,7 +598,7 @@ void DtoDeclareFunction(FuncDeclaration *fdecl, const bool willDefine) {
bool defineAsAvailableExternally = false; bool defineAsAvailableExternally = false;
if (willDefine) { if (willDefine) {
// will be defined anyway after declaration // will be defined anyway after declaration
} else if (defineOnDeclare(fdecl)) { } else if (defineOnDeclare(fdecl, /*isFunction=*/true)) {
Logger::println("Function is inside a linkonce_odr template, will be " Logger::println("Function is inside a linkonce_odr template, will be "
"defined after declaration."); "defined after declaration.");
if (fdecl->semanticRun < PASSsemantic3done) { if (fdecl->semanticRun < PASSsemantic3done) {

View file

@ -794,14 +794,6 @@ DValue *DtoPaintType(const Loc &loc, DValue *val, Type *to) {
return new DImValue(to, DtoRVal(val)); return new DImValue(to, DtoRVal(val));
} }
/******************************************************************************
* TEMPLATE HELPERS
******************************************************************************/
bool defineOnDeclare(Dsymbol* s) {
return global.params.linkonceTemplates && s->isInstantiated();
}
/****************************************************************************** /******************************************************************************
* PROCESSING QUEUE HELPERS * PROCESSING QUEUE HELPERS
******************************************************************************/ ******************************************************************************/
@ -1680,12 +1672,8 @@ std::string llvmTypeToString(llvm::Type *type) {
} }
// Is the specified symbol defined in the druntime/Phobos libs? // Is the specified symbol defined in the druntime/Phobos libs?
// Note: fuzzy semantics for instantiated symbols, except with // For instantiated symbols: is the template declared in druntime/Phobos?
// -linkonce-templates.
static bool isDefaultLibSymbol(Dsymbol *sym) { static bool isDefaultLibSymbol(Dsymbol *sym) {
if (defineOnDeclare(sym))
return false;
auto mod = sym->getModule(); auto mod = sym->getModule();
if (!mod) if (!mod)
return false; return false;
@ -1705,10 +1693,24 @@ static bool isDefaultLibSymbol(Dsymbol *sym) {
(md->packages.length > 1 && md->packages.ptr[1] == Id::io))); (md->packages.length > 1 && md->packages.ptr[1] == Id::io)));
} }
bool dllimportSymbol(Dsymbol *sym) { bool defineOnDeclare(Dsymbol* sym, bool isFunction) {
if (global.params.linkonceTemplates)
return sym->isInstantiated();
// With -dllimport=defaultLibsOnly, an instantiated data symbol from a
// druntime/Phobos template may be assigned to an arbitrary binary (and culled
// from others via `needsCodegen()`). Define it in each referencing CU and
// never dllimport.
return !isFunction && global.params.dllimport == DLLImport::defaultLibsOnly &&
sym->isInstantiated() && isDefaultLibSymbol(sym);
}
bool dllimportDataSymbol(Dsymbol *sym) {
return sym->isExport() || global.params.dllimport == DLLImport::all || return sym->isExport() || global.params.dllimport == DLLImport::all ||
(global.params.dllimport == DLLImport::defaultLibsOnly && (global.params.dllimport == DLLImport::defaultLibsOnly &&
isDefaultLibSymbol(sym)); // exclude instantiated symbols from druntime/Phobos templates (see
// `defineOnDeclare()`)
!sym->isInstantiated() && isDefaultLibSymbol(sym));
} }
llvm::GlobalVariable *declareGlobal(const Loc &loc, llvm::Module &module, llvm::GlobalVariable *declareGlobal(const Loc &loc, llvm::Module &module,

View file

@ -101,10 +101,6 @@ DValue *DtoCast(const Loc &loc, DValue *val, Type *to);
// otherwise returns a new DValue // otherwise returns a new DValue
DValue *DtoPaintType(const Loc &loc, DValue *val, Type *to); DValue *DtoPaintType(const Loc &loc, DValue *val, Type *to);
/// Returns true if the specified symbol is to be defined on declaration, for
/// -linkonce-templates.
bool defineOnDeclare(Dsymbol *s);
/// Makes sure the declarations corresponding to the given D symbol have been /// Makes sure the declarations corresponding to the given D symbol have been
/// emitted to the currently processed LLVM module. /// emitted to the currently processed LLVM module.
/// ///
@ -245,8 +241,13 @@ LLConstant *toConstantArray(LLType *ct, LLArrayType *at, T *str, size_t len,
llvm::Constant *buildStringLiteralConstant(StringExp *se, bool zeroTerm); llvm::Constant *buildStringLiteralConstant(StringExp *se, bool zeroTerm);
/// Indicates whether the specified symbol is a general dllimport candidate. /// Returns true if the specified symbol is to be defined on declaration,
bool dllimportSymbol(Dsymbol *sym); /// primarily for -linkonce-templates.
bool defineOnDeclare(Dsymbol *sym, bool isFunction);
/// Indicates whether the specified data symbol is a general dllimport
/// candidate.
bool dllimportDataSymbol(Dsymbol *sym);
/// Tries to declare an LLVM global. If a variable with the same mangled name /// Tries to declare an LLVM global. If a variable with the same mangled name
/// already exists, checks if the types match and returns it instead. /// already exists, checks if the types match and returns it instead.

View file

@ -56,7 +56,7 @@ bool IrAggr::useDLLImport() const {
if (!global.params.targetTriple->isOSWindows()) if (!global.params.targetTriple->isOSWindows())
return false; return false;
if (dllimportSymbol(aggrdecl)) { if (dllimportDataSymbol(aggrdecl)) {
// dllimport, unless defined in a root module (=> no extra indirection for // dllimport, unless defined in a root module (=> no extra indirection for
// other root modules, assuming *all* root modules will be linked together // other root modules, assuming *all* root modules will be linked together
// to one or more binaries). // to one or more binaries).
@ -103,7 +103,7 @@ LLConstant *IrAggr::getInitSymbol(bool define) {
init = initGlobal; init = initGlobal;
if (!define) if (!define)
define = defineOnDeclare(aggrdecl); define = defineOnDeclare(aggrdecl, /*isFunction=*/false);
} }
if (define) { if (define) {

View file

@ -73,7 +73,7 @@ LLGlobalVariable *IrClass::getVtblSymbol(bool define) {
/*isConstant=*/true, false, useDLLImport()); /*isConstant=*/true, false, useDLLImport());
if (!define) if (!define)
define = defineOnDeclare(aggrdecl); define = defineOnDeclare(aggrdecl, /*isFunction=*/false);
} }
if (define) { if (define) {
@ -130,7 +130,7 @@ LLGlobalVariable *IrClass::getClassInfoSymbol(bool define) {
} }
if (!define) if (!define)
define = defineOnDeclare(aggrdecl); define = defineOnDeclare(aggrdecl, /*isFunction=*/false);
} }
if (define) { if (define) {
@ -473,7 +473,7 @@ llvm::GlobalVariable *IrClass::getInterfaceVtblSymbol(BaseClass *b,
interfaceVtblMap.insert({{b->sym, interfaces_index}, gvar}); interfaceVtblMap.insert({{b->sym, interfaces_index}, gvar});
if (!define) if (!define)
define = defineOnDeclare(aggrdecl); define = defineOnDeclare(aggrdecl, /*isFunction=*/false);
} }
if (define && !gvar->hasInitializer()) { if (define && !gvar->hasInitializer()) {

View file

@ -27,7 +27,7 @@ llvm::GlobalVariable *IrModule::moduleInfoSymbol() {
const auto irMangle = getIRMangledModuleInfoSymbolName(M); const auto irMangle = getIRMangledModuleInfoSymbolName(M);
const bool useDLLImport = !M->isRoot() && dllimportSymbol(M); const bool useDLLImport = !M->isRoot() && dllimportDataSymbol(M);
moduleInfoVar = declareGlobal(Loc(), gIR->module, moduleInfoVar = declareGlobal(Loc(), gIR->module,
llvm::StructType::create(gIR->context()), llvm::StructType::create(gIR->context()),

View file

@ -57,7 +57,7 @@ LLGlobalVariable* IrStruct::getTypeInfoSymbol(bool define) {
emitTypeInfoMetadata(typeInfo, aggrdecl->type); emitTypeInfoMetadata(typeInfo, aggrdecl->type);
if (!define) if (!define)
define = defineOnDeclare(aggrdecl); define = defineOnDeclare(aggrdecl, /*isFunction=*/false);
} }
if (define) { if (define) {

View file

@ -29,7 +29,7 @@ LLValue *IrGlobal::getValue(bool define) {
declare(); declare();
if (!define) if (!define)
define = defineOnDeclare(V); define = defineOnDeclare(V, /*isFunction=*/false);
} }
if (define) { if (define) {
@ -86,7 +86,7 @@ void IrGlobal::declare() {
// dllimport isn't supported for thread-local globals (MSVC++ neither) // dllimport isn't supported for thread-local globals (MSVC++ neither)
if (!V->isThreadlocal()) { if (!V->isThreadlocal()) {
// implicitly include extern(D) globals with -dllimport // implicitly include extern(D) globals with -dllimport
if (V->isExport() || (V->linkage == LINK::d && dllimportSymbol(V))) { if (V->isExport() || (V->linkage == LINK::d && dllimportDataSymbol(V))) {
const bool isDefinedInRootModule = const bool isDefinedInRootModule =
!(V->storage_class & STCextern) && !V->inNonRoot(); !(V->storage_class & STCextern) && !V->inNonRoot();
if (!isDefinedInRootModule) if (!isDefinedInRootModule)