summaryrefslogtreecommitdiff
path: root/lib/CodeGen/CodeGenModule.cpp
diff options
context:
space:
mode:
authorHans Wennborg <hans@hanshq.net>2015-01-10 01:19:48 +0000
committerHans Wennborg <hans@hanshq.net>2015-01-10 01:19:48 +0000
commitafe88a16c63ece9ce3715c3acbbabd83a488921f (patch)
treec8274af5e61df2facf88ee8a955235d4f9b65fc8 /lib/CodeGen/CodeGenModule.cpp
parent9017269b38fe5d47f2e27633e94f682a045e65b3 (diff)
downloadclang-afe88a16c63ece9ce3715c3acbbabd83a488921f.tar.gz
Don't emit implicit template instantiations eagerly (PR21718)
Their linkage can change if they are later explicitly instantiated. We would previously emit such functions eagerly (as opposed to lazily on first use) if they have a 'dllexport' or 'used' attribute, and fail an assert when hitting the explicit instantiation. This is achieved by replacing the old CodeGenModule::MayDeferGeneration() method with two new ones: MustBeEmitted() and MayBeEmittedEagerly(). Differential Revision: http://reviews.llvm.org/D6674 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@225570 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CodeGenModule.cpp')
-rw-r--r--lib/CodeGen/CodeGenModule.cpp46
1 files changed, 32 insertions, 14 deletions
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 25aaa30855..a863591aa0 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -1102,14 +1102,18 @@ void CodeGenModule::EmitDeferred() {
llvm::GlobalValue *GV = G.GV;
DeferredDeclsToEmit.pop_back();
- assert(GV == GetGlobalValue(getMangledName(D)));
+ assert(!GV || GV == GetGlobalValue(getMangledName(D)));
+ if (!GV)
+ GV = GetGlobalValue(getMangledName(D));
+
+
// Check to see if we've already emitted this. This is necessary
// for a couple of reasons: first, decls can end up in the
// deferred-decls queue multiple times, and second, decls can end
// up with definitions in unusual ways (e.g. by an extern inline
// function acquiring a strong function redefinition). Just
// ignore these cases.
- if(!GV->isDeclaration())
+ if (GV && !GV->isDeclaration())
continue;
// Otherwise, emit the definition and move on to the next one.
@@ -1234,12 +1238,22 @@ bool CodeGenModule::isInSanitizerBlacklist(llvm::GlobalVariable *GV,
return false;
}
-bool CodeGenModule::MayDeferGeneration(const ValueDecl *Global) {
+bool CodeGenModule::MustBeEmitted(const ValueDecl *Global) {
// Never defer when EmitAllDecls is specified.
if (LangOpts.EmitAllDecls)
- return false;
+ return true;
+
+ return getContext().DeclMustBeEmitted(Global);
+}
- return !getContext().DeclMustBeEmitted(Global);
+bool CodeGenModule::MayBeEmittedEagerly(const ValueDecl *Global) {
+ if (const auto *FD = dyn_cast<FunctionDecl>(Global))
+ if (FD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
+ // Implicit template instantiations may change linkage if they are later
+ // explicitly instantiated, so they should not be emitted eagerly.
+ return false;
+
+ return true;
}
llvm::Constant *CodeGenModule::GetAddrOfUuidDescriptor(
@@ -1348,9 +1362,10 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
return;
}
- // Defer code generation when possible if this is a static definition, inline
- // function etc. These we only want to emit if they are used.
- if (!MayDeferGeneration(Global)) {
+ // Defer code generation to first use when possible, e.g. if this is an inline
+ // function. If the global must always be emitted, do it eagerly if possible
+ // to benefit from cache locality.
+ if (MustBeEmitted(Global) && MayBeEmittedEagerly(Global)) {
// Emit the definition if it can't be deferred.
EmitGlobalDefinition(GD);
return;
@@ -1363,13 +1378,16 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
DelayedCXXInitPosition[Global] = CXXGlobalInits.size();
CXXGlobalInits.push_back(nullptr);
}
-
- // If the value has already been used, add it directly to the
- // DeferredDeclsToEmit list.
+
StringRef MangledName = getMangledName(GD);
- if (llvm::GlobalValue *GV = GetGlobalValue(MangledName))
+ if (llvm::GlobalValue *GV = GetGlobalValue(MangledName)) {
+ // The value has already been used and should therefore be emitted.
addDeferredDeclToEmit(GV, GD);
- else {
+ } else if (MustBeEmitted(Global)) {
+ // The value must be emitted, but cannot be emitted eagerly.
+ assert(!MayBeEmittedEagerly(Global));
+ addDeferredDeclToEmit(/*GV=*/nullptr, GD);
+ } else {
// Otherwise, remember that we saw a deferred decl with this name. The
// first use of the mangled name will cause it to move into
// DeferredDeclsToEmit.
@@ -1843,7 +1861,7 @@ CodeGenModule::CreateRuntimeVariable(llvm::Type *Ty,
void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
assert(!D->getInit() && "Cannot emit definite definitions here!");
- if (MayDeferGeneration(D)) {
+ if (!MustBeEmitted(D)) {
// If we have not seen a reference to this variable yet, place it
// into the deferred declarations table to be emitted if needed
// later.