Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -406,6 +406,10 @@ bool isTriviallyRecursive(const FunctionDecl *F); bool shouldEmitFunction(GlobalDecl GD); + bool shouldEmitGlobalVariable(const VarDecl *D); + /// \brief Return true if this global variable has a constant initializer that + /// can be emitted with available externally linkage. + bool canEmitGlobalAsAvailableExternally(const VarDecl *D); /// @name Cache for Blocks Runtime Globals /// @{ Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -1254,6 +1254,19 @@ return !isTriviallyRecursive(F); } +bool CodeGenModule::canEmitGlobalAsAvailableExternally(const VarDecl *D) { + return D->hasInit() && !D->hasDefinition(Context) && + !D->getType().isVolatileQualified() && + isTypeConstant(D->getType(), /*ExcludeCtor=*/true); +} + +bool CodeGenModule::shouldEmitGlobalVariable(const VarDecl *D) { + if (canEmitGlobalAsAvailableExternally(D)) + return CodeGenOpts.OptimizationLevel != 0; + + return true; +} + /// If the type for the method's class was generated by /// CGDebugInfo::createContextChain(), the cache contains only a /// limited DIType without any declarations. Since EmitFunctionStart() @@ -1304,8 +1317,13 @@ return EmitGlobalFunctionDefinition(GD, GV); } - if (const VarDecl *VD = dyn_cast(D)) + if (const VarDecl *VD = dyn_cast(D)) { + // At -O0, don't generate IR for vars with available_externally linkage. + if (!shouldEmitGlobalVariable(VD)) + return; + return EmitGlobalVarDefinition(VD); + } llvm_unreachable("Invalid argument to EmitGlobalDefinition()"); } @@ -1573,6 +1591,15 @@ D->isStaticDataMember() && D->hasInit() && !D->isThisDeclarationADefinition()) EmitGlobalVarDefinition(D); + + // If the variable has an initializer but no definition we can emit it with + // available_externally linkage. + if (canEmitGlobalAsAvailableExternally(D)) { + assert(GetLLVMLinkageVarDefinition(D, /*isConstant=*/true) == + llvm::GlobalValue::AvailableExternallyLinkage && + "Global variable should be available_externally!"); + addDeferredDeclToEmit(GV, D); + } } if (AddrSpace != Ty->getAddressSpace()) @@ -1874,6 +1901,13 @@ llvm::GlobalValue::LinkageTypes CodeGenModule::GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant) { + // Check for definitionless vars. We can emit them with available_externally + // linkage. We check this before calling GetGVALinkageForVariable because it + // can happen for explicit template instantiations that would cause an + // assertion failure otherwise. + if (canEmitGlobalAsAvailableExternally(D)) + return llvm::GlobalValue::AvailableExternallyLinkage; + GVALinkage Linkage = getContext().GetGVALinkageForVariable(D); if (Linkage == GVA_Internal) return llvm::Function::InternalLinkage; Index: test/CodeGenCXX/constexpr-available-externally.cpp =================================================================== --- /dev/null +++ test/CodeGenCXX/constexpr-available-externally.cpp @@ -0,0 +1,78 @@ +// RUN: %clang_cc1 -emit-llvm -O1 -std=c++11 -disable-llvm-optzns -o - %s | FileCheck %s + +// PR17612 +// CHECK: @_ZN6Object3fooE = available_externally constant %struct.Literal { i32 1 } +// CHECK: @_ZN6Object3barE = available_externally constant i32 42 +// CHECK: @_ZN3tplIiE4nposE = available_externally constant i32 -1 +// CHECK: @_ZN6Holder11threadlocalE = available_externally thread_local constant i32 1 +// CHECK-NOT: @_ZN1S1nE = available_externally +// CHECK-NOT: @_ZN1B1aE = available_externally +// CHECK-NOT: @_ZN3foo1XE = available_externally + +struct Literal { + int i; + constexpr Literal(int i) : i(i) {} +}; + +struct Object { + static constexpr Literal foo = Literal(1); + static const int bar = 42; +}; + +void bar(const int &); + +int f() { + Literal l = Object::foo; + bar(Object::bar); + return l.i; + +// CHECK-LABEL: @_Z1fv +// CHECK: call void @llvm.memcpy{{[^(]*}}(i8* %{{[^,]*}}, i8* bitcast (%struct.Literal* @_ZN6Object3fooE to i8*) +// CHECK: call void @_Z3barRKi(i32* @_ZN6Object3barE) +} + +template +struct tpl { + static const T npos = -1; +}; + +template struct tpl; + +void g() { + bar(tpl::npos); +// CHECK-LABEL: @_Z1gv +// CHECK: call void @_Z3barRKi(i32* @_ZN3tplIiE4nposE) +} + +constexpr int constone() { return 1; } +struct Holder { + static const int thread_local threadlocal = constone(); +}; +const int *h() { + return &Holder::threadlocal; +} + +struct S { + static constexpr volatile int n = 0; +}; +const volatile void *j() { + return &S::n; +} + +struct A { + mutable int n; +}; +struct B { + static constexpr A a = { 0 }; +}; +const void *k() { + return &B::a; +} + +struct foo { + static const int X = 1; + void bar(); +}; +void f(foo *x) { + x->bar(); +}