summaryrefslogtreecommitdiffstats
path: root/lib/CodeGen/CodeGenModule.cpp
diff options
context:
space:
mode:
authorMehdi Amini <joker.eph@gmail.com>2017-09-05 03:58:35 +0000
committerMehdi Amini <joker.eph@gmail.com>2017-09-05 03:58:35 +0000
commit75b49839d99f54ef05c79a2a4f14f560a760e8de (patch)
tree10e8c481bd219cd17e377b537689e813cd570752 /lib/CodeGen/CodeGenModule.cpp
parent50f89d67d8772dc6e2e4abb524d8550aacbda89a (diff)
Emit static constexpr member as available_externally definition
By exposing the constant initializer, the optimizer can fold many of these constructs. This is a recommit of r311857 that was reverted in r311898 because an assert was hit when building Chromium. We have to take into account that the GlobalVariable may be first created with a different type than the initializer. This can happen for example when the variable is a struct with tail padding while the initializer does not have padding. In such case, the variable needs to be destroyed an replaced with a new one with the type of the initializer. Differential Revision: https://reviews.llvm.org/D34992 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@312512 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/CodeGen/CodeGenModule.cpp')
-rw-r--r--lib/CodeGen/CodeGenModule.cpp42
1 files changed, 42 insertions, 0 deletions
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index c726d90f2e..b0b5e7d387 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -2437,6 +2437,48 @@ CodeGenModule::GetOrCreateLLVMGlobal(StringRef MangledName,
D->getType().isConstant(Context) &&
isExternallyVisible(D->getLinkageAndVisibility().getLinkage()))
GV->setSection(".cp.rodata");
+
+ // Check if we a have a const declaration with an initializer, we may be
+ // able to emit it as available_externally to expose it's value to the
+ // optimizer.
+ if (Context.getLangOpts().CPlusPlus && GV->hasExternalLinkage() &&
+ D->getType().isConstQualified() && !GV->hasInitializer() &&
+ !D->hasDefinition() && D->hasInit() && !D->hasAttr<DLLImportAttr>()) {
+ const auto *Record =
+ Context.getBaseElementType(D->getType())->getAsCXXRecordDecl();
+ bool HasMutableFields = Record && Record->hasMutableFields();
+ if (!HasMutableFields) {
+ const VarDecl *InitDecl;
+ const Expr *InitExpr = D->getAnyInitializer(InitDecl);
+ if (InitExpr) {
+ ConstantEmitter emitter(*this);
+ llvm::Constant *Init = emitter.tryEmitForInitializer(*InitDecl);
+ if (Init) {
+ auto *InitType = Init->getType();
+ if (GV->getType()->getElementType() != InitType) {
+ // The type of the initializer does not match the definition.
+ // This happens when an initializer has a different type from
+ // the type of the global (because of padding at the end of a
+ // structure for instance).
+ GV->setName(StringRef());
+ // Make a new global with the correct type, this is now guaranteed
+ // to work.
+ auto *NewGV = cast<llvm::GlobalVariable>(
+ GetAddrOfGlobalVar(D, InitType, IsForDefinition));
+
+ // Erase the old global, since it is no longer used.
+ cast<llvm::GlobalValue>(GV)->eraseFromParent();
+ GV = NewGV;
+ } else {
+ GV->setInitializer(Init);
+ GV->setConstant(true);
+ GV->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage);
+ }
+ emitter.finalize(GV);
+ }
+ }
+ }
+ }
}
auto ExpectedAS =