Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -2290,17 +2290,17 @@ /// as a constant. /// /// If ExcludeCtor is true, the duration when the object's constructor runs -/// will not be considered. The caller will need to verify that the object is -/// not written to during its construction. +/// will not be considered (unless trivial). The caller will need to verify that +/// the object is not written to during its construction. bool CodeGenModule::isTypeConstant(QualType Ty, bool ExcludeCtor) { if (!Ty.isConstant(Context) && !Ty->isReferenceType()) return false; if (Context.getLangOpts().CPlusPlus) { - if (const CXXRecordDecl *Record - = Context.getBaseElementType(Ty)->getAsCXXRecordDecl()) - return ExcludeCtor && !Record->hasMutableFields() && - Record->hasTrivialDestructor(); + if (const CXXRecordDecl *Record = + Context.getBaseElementType(Ty)->getAsCXXRecordDecl()) + return (ExcludeCtor || Record->hasTrivialDefaultConstructor()) && + !Record->hasMutableFields() && Record->hasTrivialDestructor(); } return true; @@ -2372,7 +2372,7 @@ auto *GV = new llvm::GlobalVariable( getModule(), Ty->getElementType(), false, - llvm::GlobalValue::ExternalLinkage, nullptr, MangledName, nullptr, + llvm::GlobalVariable::ExternalLinkage, nullptr, MangledName, nullptr, llvm::GlobalVariable::NotThreadLocal, TargetAddrSpace); // If we already created a global with the same mangled name (but different @@ -2428,6 +2428,29 @@ 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 (GV->hasExternalLinkage() && GV->isConstant() && !GV->hasInitializer() && + !D->hasDefinition() && D->hasInit()) { + bool HasMutableField = false; + if (Context.getLangOpts().CPlusPlus) { + if (const CXXRecordDecl *Record = + Context.getBaseElementType(D->getType())->getAsCXXRecordDecl()) + HasMutableField = Record->hasMutableFields(); + } + + if (D->getType().isConstQualified() && + !HasMutableField & !D->isInline() && !D->hasAttr()) { + const VarDecl *InitDecl; + const Expr *InitExpr = D->getAnyInitializer(InitDecl); + if (InitExpr) { + GV->setLinkage(llvm::GlobalValue::AvailableExternallyLinkage); + GV->setInitializer(EmitConstantInit(*InitDecl)); + } + } + } } auto ExpectedAS = Index: clang/test/CodeGenCXX/cxx11-extern-constexpr.cpp =================================================================== --- /dev/null +++ clang/test/CodeGenCXX/cxx11-extern-constexpr.cpp @@ -0,0 +1,48 @@ +// RUN: %clang_cc1 -std=c++11 %s -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK --check-prefix=CXX11 +// RUN: %clang_cc1 -std=c++1z %s -emit-llvm -o - -triple x86_64-linux-gnu | FileCheck %s --check-prefix=CHECK --check-prefix=CXX17 + +struct Bar { + int b; +}; + +struct MutableBar { + mutable int b; +}; + +struct Foo { + // CXX11: @_ZN3Foo21ConstexprStaticMemberE = available_externally constant i32 42, + // CXX17: @_ZN3Foo21ConstexprStaticMemberE = linkonce_odr constant i32 42, + static constexpr int ConstexprStaticMember = 42; + // CHECK: @_ZN3Foo17ConstStaticMemberE = available_externally constant i32 43, + static const int ConstStaticMember = 43; + + // CXX11: @_ZN3Foo23ConstStaticStructMemberE = available_externally constant %struct.Bar { i32 44 }, + // CXX17: @_ZN3Foo23ConstStaticStructMemberE = linkonce_odr constant %struct.Bar { i32 44 }, + static constexpr Bar ConstStaticStructMember = {44}; + + // CXX11: @_ZN3Foo34ConstexprStaticMutableStructMemberE = external global %struct.MutableBar, + // CXX17: @_ZN3Foo34ConstexprStaticMutableStructMemberE = linkonce_odr global %struct.MutableBar { i32 45 }, + static constexpr MutableBar ConstexprStaticMutableStructMember = {45}; +}; +// CHECK: @_ZL15ConstStaticexpr = internal constant i32 46, +static constexpr int ConstStaticexpr = 46; +// CHECK: @_ZL9ConstExpr = internal constant i32 46, align 4 +static const int ConstExpr = 46; + +// CHECK: @_ZL21ConstexprStaticStruct = internal constant %struct.Bar { i32 47 }, +static constexpr Bar ConstexprStaticStruct = {47}; + +// CHECK: @_ZL28ConstexprStaticMutableStruct = internal global %struct.MutableBar { i32 48 }, +static constexpr MutableBar ConstexprStaticMutableStruct = {48}; + +void use(const int &); +void foo() { + use(Foo::ConstexprStaticMember); + use(Foo::ConstStaticMember); + use(Foo::ConstStaticStructMember.b); + use(Foo::ConstexprStaticMutableStructMember.b); + use(ConstStaticexpr); + use(ConstExpr); + use(ConstexprStaticStruct.b); + use(ConstexprStaticMutableStruct.b); +}