From 7cb1b304f8f66c2bd15b70db9f723bcf9e70109a Mon Sep 17 00:00:00 2001 From: Mehdi Amini Date: Tue, 5 Sep 2017 03:58:35 +0000 Subject: 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 llvm-svn: 312512 --- clang/lib/CodeGen/CodeGenModule.cpp | 42 +++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) (limited to 'clang/lib/CodeGen/CodeGenModule.cpp') diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index c726d90f2e3..b0b5e7d387f 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/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()) { + 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( + GetAddrOfGlobalVar(D, InitType, IsForDefinition)); + + // Erase the old global, since it is no longer used. + cast(GV)->eraseFromParent(); + GV = NewGV; + } else { + GV->setInitializer(Init); + GV->setConstant(true); + GV->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage); + } + emitter.finalize(GV); + } + } + } + } } auto ExpectedAS = -- cgit v1.2.3