-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)"),
clEnumValN(DLLImport::defaultLibsOnly, "defaultLibsOnly",
"Only druntime/Phobos symbols (default with "
"-link-defaultlib-shared and -fvisibility=hidden). May "
"likely need to be coupled with -linkonce-templates to "
"overcome linker errors wrt. instantiated symbols."),
"-link-defaultlib-shared and -fvisibility=hidden)."),
clEnumValN(DLLImport::all, "all",
"All (default with -link-defaultlib-shared and "
"-fvisibility=public)")));

View file

@ -598,7 +598,7 @@ void DtoDeclareFunction(FuncDeclaration *fdecl, const bool willDefine) {
bool defineAsAvailableExternally = false;
if (willDefine) {
// 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 "
"defined after declaration.");
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));
}
/******************************************************************************
* TEMPLATE HELPERS
******************************************************************************/
bool defineOnDeclare(Dsymbol* s) {
return global.params.linkonceTemplates && s->isInstantiated();
}
/******************************************************************************
* PROCESSING QUEUE HELPERS
******************************************************************************/
@ -1680,12 +1672,8 @@ std::string llvmTypeToString(llvm::Type *type) {
}
// Is the specified symbol defined in the druntime/Phobos libs?
// Note: fuzzy semantics for instantiated symbols, except with
// -linkonce-templates.
// For instantiated symbols: is the template declared in druntime/Phobos?
static bool isDefaultLibSymbol(Dsymbol *sym) {
if (defineOnDeclare(sym))
return false;
auto mod = sym->getModule();
if (!mod)
return false;
@ -1705,10 +1693,24 @@ static bool isDefaultLibSymbol(Dsymbol *sym) {
(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 ||
(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,

View file

@ -101,10 +101,6 @@ DValue *DtoCast(const Loc &loc, DValue *val, Type *to);
// otherwise returns a new DValue
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
/// 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);
/// Indicates whether the specified symbol is a general dllimport candidate.
bool dllimportSymbol(Dsymbol *sym);
/// Returns true if the specified symbol is to be defined on declaration,
/// 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
/// 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())
return false;
if (dllimportSymbol(aggrdecl)) {
if (dllimportDataSymbol(aggrdecl)) {
// dllimport, unless defined in a root module (=> no extra indirection for
// other root modules, assuming *all* root modules will be linked together
// to one or more binaries).
@ -103,7 +103,7 @@ LLConstant *IrAggr::getInitSymbol(bool define) {
init = initGlobal;
if (!define)
define = defineOnDeclare(aggrdecl);
define = defineOnDeclare(aggrdecl, /*isFunction=*/false);
}
if (define) {

View file

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

View file

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

View file

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

View file

@ -29,7 +29,7 @@ LLValue *IrGlobal::getValue(bool define) {
declare();
if (!define)
define = defineOnDeclare(V);
define = defineOnDeclare(V, /*isFunction=*/false);
}
if (define) {
@ -86,7 +86,7 @@ void IrGlobal::declare() {
// dllimport isn't supported for thread-local globals (MSVC++ neither)
if (!V->isThreadlocal()) {
// 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 =
!(V->storage_class & STCextern) && !V->inNonRoot();
if (!isDefinedInRootModule)