Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend -linkonce-templates by matching template emission scheme #3600

Merged
merged 5 commits into from
Nov 27, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -167,9 +167,6 @@ script:
- |
if [ "$TRAVIS_CPU_ARCH" = "arm64" ]; then
DMD_TESTSUITE_MAKE_ARGS="-j${PARALLELISM:-3} GDB_FLAGS=OFF" ctest -V -R "dmd-testsuite"
elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
# dmd-testsuite-debug only to reduce time-outs
DMD_TESTSUITE_MAKE_ARGS=-j${PARALLELISM:-3} ctest -V -R "build-run-dmd-testsuite|dmd-testsuite-debug"
else
DMD_TESTSUITE_MAKE_ARGS=-j${PARALLELISM:-3} ctest -V -R "dmd-testsuite"
fi
Expand Down
14 changes: 11 additions & 3 deletions dmd/dsymbolsem.d
Original file line number Diff line number Diff line change
Expand Up @@ -6071,8 +6071,13 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
tempinst.inst.gagged = tempinst.gagged;
}

tempinst.tnext = tempinst.inst.tnext;
tempinst.inst.tnext = tempinst;
// LDC: the tnext linked list is only used by TemplateInstance.needsCodegen(),
// which is skipped with -linkonce-templates
if (!(IN_LLVM && global.params.linkonceTemplates))
{
tempinst.tnext = tempinst.inst.tnext;
tempinst.inst.tnext = tempinst;
}

/* A module can have explicit template instance and its alias
* in module scope (e,g, `alias Base64 = Base64Impl!('+', '/');`).
Expand Down Expand Up @@ -6156,7 +6161,10 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
scope v = new InstMemberWalker(tempinst.inst);
tempinst.inst.accept(v);

if (tempinst.minst) // if inst was not speculative
// LDC: if `inst` was speculative, it was already appended to a root
// module - unless using -linkonce-templates
if ((IN_LLVM && global.params.linkonceTemplates) ||
tempinst.minst) // if inst was not speculative
{
/* Add 'inst' once again to the root module members[], then the
* instance members will get codegen chances.
Expand Down
24 changes: 24 additions & 0 deletions dmd/dtemplate.d
Original file line number Diff line number Diff line change
Expand Up @@ -6190,6 +6190,11 @@ extern (C++) class TemplateInstance : ScopeDsymbol
*/
final bool needsCodegen()
{
version (IN_LLVM)
{
assert(!global.params.linkonceTemplates);
}

// Now -allInst is just for the backward compatibility.
if (global.params.allInst)
{
Expand Down Expand Up @@ -7309,6 +7314,25 @@ extern (C++) class TemplateInstance : ScopeDsymbol
{
Module mi = minst; // instantiated . inserted module

version (IN_LLVM)
{
if (global.params.linkonceTemplates)
{
// Skip if it's not a root module.
if (!mi || !mi.isRoot())
return null;

// Skip if the primary instance has already been assigned to a root
// module.
if (inst.memberOf)
return null;

// Okay, this is the primary instance to be assigned to a root
// module and getting semantic3.
assert(this is inst);
}
}

if (global.params.useUnitTests)
{
// Turn all non-root instances to speculative
Expand Down
2 changes: 2 additions & 0 deletions dmd/globals.d
Original file line number Diff line number Diff line change
Expand Up @@ -341,6 +341,8 @@ version (IN_LLVM)
uint hashThreshold; // MD5 hash symbols larger than this threshold (0 = no hashing)

bool outputSourceLocations; // if true, output line tables.

bool linkonceTemplates; // -linkonce-templates
} // IN_LLVM
}

Expand Down
2 changes: 2 additions & 0 deletions dmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,8 @@ struct Param
unsigned hashThreshold; // MD5 hash symbols larger than this threshold (0 = no hashing)

bool outputSourceLocations; // if true, output line tables.

bool linkonceTemplates; // -linkonce-templates
#endif
};

Expand Down
3 changes: 2 additions & 1 deletion driver/cl_options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -487,8 +487,9 @@ cl::opt<uint32_t, true> hashThreshold(
"hash-threshold", cl::ZeroOrMore, cl::location(global.params.hashThreshold),
cl::desc("Hash symbol names longer than this threshold (experimental)"));

cl::opt<bool> linkonceTemplates(
static cl::opt<bool, true> linkonceTemplates(
"linkonce-templates", cl::ZeroOrMore,
cl::location(global.params.linkonceTemplates),
cl::desc(
"Use linkonce_odr linkage for template symbols instead of weak_odr"));

Expand Down
1 change: 0 additions & 1 deletion driver/cl_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ extern cl::opt<bool> m64bits;
extern cl::opt<std::string> mTargetTriple;
extern cl::opt<std::string> mABI;
extern FloatABI::Type floatABI;
extern cl::opt<bool> linkonceTemplates;
extern cl::opt<bool> disableLinkerStripDead;
extern cl::opt<unsigned char> defaultToHiddenVisibility;
extern cl::opt<bool> noPLT;
Expand Down
5 changes: 3 additions & 2 deletions driver/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,9 @@ void parseCommandLine(Strings &sourceFiles) {
global.params.output_mlir = opts::output_mlir ? OUTPUTFLAGset : OUTPUTFLAGno;
global.params.output_s = opts::output_s ? OUTPUTFLAGset : OUTPUTFLAGno;

templateLinkage = opts::linkonceTemplates ? LLGlobalValue::LinkOnceODRLinkage
: LLGlobalValue::WeakODRLinkage;
templateLinkage = global.params.linkonceTemplates
? LLGlobalValue::LinkOnceODRLinkage
: LLGlobalValue::WeakODRLinkage;

if (global.params.run || !runargs.empty()) {
// FIXME: how to properly detect the presence of a PositionalEatsArgs
Expand Down
2 changes: 1 addition & 1 deletion gen/declarations.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,7 +324,7 @@ class CodegenVisitor : public Visitor {
}

// FIXME: This is #673 all over again.
if (!decl->needsCodegen()) {
if (!global.params.linkonceTemplates && !decl->needsCodegen()) {
Logger::println("Does not need codegen, skipping.");
return;
}
Expand Down
10 changes: 5 additions & 5 deletions gen/function-inlining.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,21 +72,21 @@ bool isInlineCandidate(FuncDeclaration &fdecl) {

} // end anonymous namespace

bool alreadyOrWillBeDefined(FuncDeclaration &fdecl) {
bool skipCodegen(FuncDeclaration &fdecl) {
if (fdecl.isFuncLiteralDeclaration()) // emitted into each referencing CU
return true;
return false;

for (FuncDeclaration *f = &fdecl; f;) {
if (!f->isInstantiated() && f->inNonRoot()) {
return false;
if (f->inNonRoot()) { // false if instantiated
return true;
}
if (f->isNested()) {
f = f->toParent2()->isFuncDeclaration();
} else {
break;
}
}
return true;
return false;
}

bool defineAsExternallyAvailable(FuncDeclaration &fdecl) {
Expand Down
4 changes: 2 additions & 2 deletions gen/function-inlining.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@
class FuncDeclaration;

/// Check whether the frontend knows that the function is already defined
/// in some other module (see DMD's FuncDeclaration::toObjFile).
bool alreadyOrWillBeDefined(FuncDeclaration &fdecl);
/// in some other module (see DMD's `FuncDeclaration_toObjFile()`).
bool skipCodegen(FuncDeclaration &fdecl);

/// Returns whether `fdecl` should be emitted with externally_available
/// linkage to make it available for inlining.
Expand Down
31 changes: 23 additions & 8 deletions gen/functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -575,10 +575,26 @@ void DtoDeclareFunction(FuncDeclaration *fdecl, const bool willDefine) {
// Check if fdecl should be defined too for cross-module inlining.
// If true, semantic is fully done for fdecl which is needed for some code
// below (e.g. code that uses fdecl->vthis).
const bool defineAtEnd = !willDefine && defineAsExternallyAvailable(*fdecl);
if (defineAtEnd) {
IF_LOG Logger::println(
"Function is an externally_available inline candidate.");
bool defineAtEnd = false;
bool defineAsAvailableExternally = false;
if (willDefine) {
// will be defined anyway after declaration
} else if (defineOnDeclare(fdecl)) {
Logger::println("Function is inside a linkonce_odr template, will be "
"defined after declaration.");
if (fdecl->semanticRun < PASSsemantic3done) {
// this can e.g. happen for special __xtoHash member functions
Logger::println("Function hasn't had sema3 run yet, running it now.");
const bool semaSuccess = fdecl->functionSemantic3();
assert(semaSuccess);
Module::runDeferredSemantic3();
}
defineAtEnd = true;
} else if (defineAsExternallyAvailable(*fdecl)) {
Logger::println("Function is an externally_available inline candidate, "
"will be defined after declaration.");
defineAtEnd = true;
defineAsAvailableExternally = true;
}

// get TypeFunction*
Expand Down Expand Up @@ -768,9 +784,8 @@ void DtoDeclareFunction(FuncDeclaration *fdecl, const bool willDefine) {

// Now that this function is declared, also define it if needed.
if (defineAtEnd) {
IF_LOG Logger::println(
"Function is an externally_available inline candidate: define it now.");
DtoDefineFunction(fdecl, /*linkageAvailableExternally=*/true);
IF_LOG Logger::println("Define function after declaration:");
DtoDefineFunction(fdecl, defineAsAvailableExternally);
}
}

Expand Down Expand Up @@ -1038,7 +1053,7 @@ void DtoDefineFunction(FuncDeclaration *fd, bool linkageAvailableExternally) {
}
}

if (!linkageAvailableExternally && !alreadyOrWillBeDefined(*fd)) {
if (!linkageAvailableExternally && skipCodegen(*fd)) {
IF_LOG Logger::println("Skipping '%s'.", fd->toPrettyChars());
return;
}
Expand Down
13 changes: 2 additions & 11 deletions gen/llvmhelpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -795,17 +795,8 @@ DValue *DtoPaintType(Loc &loc, DValue *val, Type *to) {
* TEMPLATE HELPERS
******************************************************************************/

TemplateInstance *DtoIsTemplateInstance(Dsymbol *s) {
if (!s) {
return nullptr;
}
if (s->isTemplateInstance() && !s->isTemplateMixin()) {
return s->isTemplateInstance();
}
if (s->parent) {
return DtoIsTemplateInstance(s->parent);
}
return nullptr;
bool defineOnDeclare(Dsymbol* s) {
return global.params.linkonceTemplates && s->isInstantiated();
}

/******************************************************************************
Expand Down
5 changes: 3 additions & 2 deletions gen/llvmhelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,9 @@ DValue *DtoCast(Loc &loc, DValue *val, Type *to);
// otherwise returns a new DValue
DValue *DtoPaintType(Loc &loc, DValue *val, Type *to);

// is template instance check, returns module where instantiated
TemplateInstance *DtoIsTemplateInstance(Dsymbol *s);
/// 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.
Expand Down
2 changes: 1 addition & 1 deletion gen/modules.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -608,7 +608,7 @@ void codegenModule(IRState *irs, Module *m) {

// process module members
// NOTE: m->members may grow during codegen
for (unsigned k = 0; k < m->members->length; k++) {
for (d_size_t k = 0; k < m->members->length; k++) {
Dsymbol *dsym = (*m->members)[k];
assert(dsym);
Declaration_codegen(dsym);
Expand Down
6 changes: 3 additions & 3 deletions gen/naked.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ void DtoDefineNakedFunction(FuncDeclaration *fd) {
asmstr << "\t.section\t__TEXT,__text,regular,pure_instructions"
<< std::endl;
asmstr << "\t.globl\t" << mangle << std::endl;
if (DtoIsTemplateInstance(fd)) {
if (fd->isInstantiated()) {
asmstr << "\t.weak_definition\t" << mangle << std::endl;
}
asmstr << "\t.p2align\t4, 0x90" << std::endl;
Expand Down Expand Up @@ -198,7 +198,7 @@ void DtoDefineNakedFunction(FuncDeclaration *fd) {
asmstr << "\t.type\t32;" << std::endl;
asmstr << "\t.endef" << std::endl;

if (DtoIsTemplateInstance(fd)) {
if (fd->isInstantiated()) {
asmstr << "\t.section\t.text,\"xr\",discard," << mangle << std::endl;
} else {
asmstr << "\t.text" << std::endl;
Expand All @@ -207,7 +207,7 @@ void DtoDefineNakedFunction(FuncDeclaration *fd) {
asmstr << "\t.p2align\t4, 0x90" << std::endl;
asmstr << mangle << ":" << std::endl;
} else {
if (DtoIsTemplateInstance(fd)) {
if (fd->isInstantiated()) {
asmstr << "\t.section\t.text." << mangle << ",\"axG\",@progbits,"
<< mangle << ",comdat" << std::endl;
asmstr << "\t.weak\t" << mangle << std::endl;
Expand Down
4 changes: 0 additions & 4 deletions gen/rttibuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,6 @@ void RTTIBuilder::push_null_vp() { push(getNullValue(getVoidPtrType())); }

void RTTIBuilder::push_typeinfo(Type *t) { push(DtoTypeInfoOf(t)); }

void RTTIBuilder::push_classinfo(ClassDeclaration *cd) {
push(getIrAggr(cd)->getClassInfoSymbol());
}

void RTTIBuilder::push_string(const char *str) { push(DtoConstString(str)); }

void RTTIBuilder::push_null_void_array() {
Expand Down
1 change: 0 additions & 1 deletion gen/rttibuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ class RTTIBuilder {
void push_size_as_vp(uint64_t s);
void push_string(const char *str);
void push_typeinfo(Type *t);
void push_classinfo(ClassDeclaration *cd);

/// pushes the function pointer or a null void* if it cannot.
void push_funcptr(FuncDeclaration *fd, Type *castto = nullptr);
Expand Down
6 changes: 3 additions & 3 deletions gen/runtime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -105,10 +105,10 @@ static void checkForImplicitGCCall(const Loc &loc, const char *name) {
////////////////////////////////////////////////////////////////////////////////

bool initRuntime() {
Logger::println("*** Initializing D runtime declarations ***");
LOG_SCOPE;

if (!M) {
Logger::println("*** Initializing D runtime declarations ***");
LOG_SCOPE;

buildRuntimeModule();
}

Expand Down
15 changes: 8 additions & 7 deletions gen/tollvm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -215,16 +215,17 @@ LLValue *DtoDelegateEquals(TOK op, LLValue *lhs, LLValue *rhs) {
////////////////////////////////////////////////////////////////////////////////

LinkageWithCOMDAT DtoLinkage(Dsymbol *sym) {
// Function (incl. delegate) literals are emitted into each referencing
// compilation unit; use template linkage to prevent conflicts.
auto linkage = (sym->isFuncLiteralDeclaration() || DtoIsTemplateInstance(sym))
? templateLinkage
: LLGlobalValue::ExternalLinkage;

// If @(ldc.attributes.weak) is applied, override the linkage to WeakAny
LLGlobalValue::LinkageTypes linkage;
if (hasWeakUDA(sym)) {
linkage = LLGlobalValue::WeakAnyLinkage;
}
// Function (incl. delegate) literals are emitted into each referencing
// compilation unit; use template linkage to prevent conflicts.
else if (sym->isFuncLiteralDeclaration() || sym->isInstantiated()) {
linkage = templateLinkage;
} else {
linkage = LLGlobalValue::ExternalLinkage;
}

return {linkage, needsCOMDAT()};
}
Expand Down
6 changes: 3 additions & 3 deletions gen/typinf.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -290,7 +290,7 @@ class DefineVisitor : public Visitor {
RTTIBuilder b(getInterfaceTypeInfoType());

// TypeInfo base
b.push_classinfo(tc->sym);
b.push_typeinfo(tc);

// finish
b.finalize(gvar);
Expand Down Expand Up @@ -508,10 +508,10 @@ LLGlobalVariable *DtoResolveTypeInfo(TypeInfoDeclaration *tid) {
assert(!gIR->dcomputetarget);

if (!tid->ir->isResolved()) {
tid->ir->setResolved();

DeclareOrDefineVisitor v;
tid->accept(&v);

tid->ir->setResolved();
}

return llvm::cast<LLGlobalVariable>(getIrValue(tid));
Expand Down
3 changes: 3 additions & 0 deletions ir/iraggr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,9 @@ LLConstant *IrAggr::getInitSymbol(bool define) {
initGlobal->setAlignment(LLMaybeAlign(DtoAlignment(type)));

init = initGlobal;

if (!define)
define = defineOnDeclare(aggrdecl);
}

if (define) {
Expand Down
Loading