From: Rafael Espindola Date: Thu, 18 Sep 2014 23:41:44 +0000 (+0000) Subject: Put more stuff in the comdat used for variables with static init. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8a8794f137331105540836ffc60f1197e1df2c13;p=clang Put more stuff in the comdat used for variables with static init. Clang can already handle ------------------------------------------- struct S { static const int x; }; template struct U { static const int k; }; template const int U::k = T::x; const int S::x = 42; extern const int *f(); const int *g() { return &U::k; } int main() { return *f() + U::k; } const int *f() { return &U::k; } ------------------------------------------- since r217264 which puts the .inint_array section in the same COMDAT as the variable. This patch allows the linker to more easily delete some dead code and data by putting the guard variable and init function in the same COMDAT. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@218089 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp index 3e5f42e18c..3f1e4e8d95 100644 --- a/lib/CodeGen/CGDeclCXX.cpp +++ b/lib/CodeGen/CGDeclCXX.cpp @@ -298,6 +298,11 @@ CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D, llvm::Function *Fn = CreateGlobalInitOrDestructFunction(*this, FTy, FnName.str()); + if (Addr->isWeakForLinker() && supportsCOMDAT()) { + llvm::Comdat *C = TheModule.getOrInsertComdat(Addr->getName()); + Fn->setComdat(C); + } + auto *ISA = D->getAttr(); CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr, PerformInit); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index b36d4a66cd..a095c9ddbb 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -599,6 +599,9 @@ public: DiagnosticsEngine &getDiags() const { return Diags; } const llvm::DataLayout &getDataLayout() const { return TheDataLayout; } const TargetInfo &getTarget() const { return Target; } + const llvm::Triple &getTriple() const; + bool supportsCOMDAT() const; + CGCXXABI &getCXXABI() const { return *ABI; } llvm::LLVMContext &getLLVMContext() { return VMContext; } diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 4a24e77139..865831feda 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -1666,6 +1666,13 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // If the variable is thread-local, so is its guard variable. guard->setThreadLocalMode(var->getThreadLocalMode()); + // The ABI says: It is suggested that it be emitted in the same COMDAT group + // as the associated data object + if (var->isWeakForLinker() && CGM.supportsCOMDAT()) { + llvm::Comdat *C = CGM.getModule().getOrInsertComdat(var->getName()); + guard->setComdat(C); + } + CGM.setStaticLocalDeclGuardAddress(&D, guard); } diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index 9bf1dbbd0d..cca825c1c5 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -6868,6 +6868,14 @@ static bool getTypeString(SmallStringEnc &Enc, const Decl *D, // Driver code //===----------------------------------------------------------------------===// +const llvm::Triple &CodeGenModule::getTriple() const { + return getTarget().getTriple(); +} + +bool CodeGenModule::supportsCOMDAT() const { + return !getTriple().isOSBinFormatMachO(); +} + const TargetCodeGenInfo &CodeGenModule::getTargetCodeGenInfo() { if (TheTargetCodeGenInfo) return *TheTargetCodeGenInfo; diff --git a/test/CodeGenCXX/static-data-member.cpp b/test/CodeGenCXX/static-data-member.cpp index eea9794948..c4ac859e23 100644 --- a/test/CodeGenCXX/static-data-member.cpp +++ b/test/CodeGenCXX/static-data-member.cpp @@ -1,9 +1,13 @@ -// RUN: %clang_cc1 -triple x86_64-apple-darwin10 -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-linux -emit-llvm -o - %s | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | \ +// RUN: FileCheck --check-prefix=MACHO %s // CHECK: @_ZN5test11A1aE = constant i32 10, align 4 // CHECK: @_ZN5test212_GLOBAL__N_11AIiE1xE = internal global i32 0, align 4 // CHECK: @_ZN5test31AIiE1xE = weak_odr global i32 0, align 4 -// CHECK: @_ZGVN5test31AIiE1xE = weak_odr global i64 0 +// CHECK: @_ZGVN5test31AIiE1xE = weak_odr global i64 0, comdat $_ZN5test31AIiE1xE +// MACHO: @_ZGVN5test31AIiE1xE = weak_odr global i64 0 +// MACHO-NOT: comdat // CHECK: _ZN5test51U2k0E = global i32 0 // CHECK: _ZN5test51U2k1E = global i32 0 @@ -60,7 +64,9 @@ namespace test3 { template int A::x = foo(); template struct A; - // CHECK-LABEL: define internal void @__cxx_global_var_init1() + // CHECK-LABEL: define internal void @__cxx_global_var_init1() {{.*}} comdat $_ZN5test31AIiE1xE + // MACHO-LABEL: define internal void @__cxx_global_var_init1() + // MACHO-NOT: comdat // CHECK: [[GUARDBYTE:%.*]] = load i8* bitcast (i64* @_ZGVN5test31AIiE1xE to i8*) // CHECK-NEXT: [[UNINITIALIZED:%.*]] = icmp eq i8 [[GUARDBYTE]], 0 // CHECK-NEXT: br i1 [[UNINITIALIZED]]