]> granicus.if.org Git - clang/commitdiff
Put more stuff in the comdat used for variables with static init.
authorRafael Espindola <rafael.espindola@gmail.com>
Thu, 18 Sep 2014 23:41:44 +0000 (23:41 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Thu, 18 Sep 2014 23:41:44 +0000 (23:41 +0000)
Clang can already handle

-------------------------------------------
struct S {
  static const int x;
};
template<typename T> struct U {
  static const int k;
};
template<typename T> const int U<T>::k = T::x;

const int S::x = 42;
extern const int *f();
const int *g() { return &U<S>::k; }
int main() {
  return *f() + U<S>::k;
}

const int *f() { return &U<S>::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

lib/CodeGen/CGDeclCXX.cpp
lib/CodeGen/CodeGenModule.h
lib/CodeGen/ItaniumCXXABI.cpp
lib/CodeGen/TargetInfo.cpp
test/CodeGenCXX/static-data-member.cpp

index 3e5f42e18c221a14fb2ec34efc47cf03cc02c4d6..3f1e4e8d9559f98ee268630e79b609b23e134cf8 100644 (file)
@@ -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<InitSegAttr>();
   CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
                                                           PerformInit);
index b36d4a66cd87f02ae6b87b9b597ee77590cd01f3..a095c9ddbb9711a5589077d159f30d30ab2c648e 100644 (file)
@@ -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; }
 
index 4a24e77139f72bc08fb1ff5ffffb2bbb89911a59..865831fedac277bc441f4899925e4e0db9c38800 100644 (file)
@@ -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);
   }
 
index 9bf1dbbd0d8c58d677476db631a60f9e2bc9ebbc..cca825c1c564f5c583404beeed6f86442a76bf7c 100644 (file)
@@ -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;
index eea979494843b2cbc6040ac1973083b9e82fbbbb..c4ac859e23b240630d2f4ff5b06ca2812d399e82 100644 (file)
@@ -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 <class T> int A<T>::x = foo();
   template struct A<int>;
 
-  // 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]]