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;

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

#ifdef TU2
const int *f() { return &U<S>::k; }
#endif
-------------------------------------------

since r217264 which puts the .inint_array section in the same COMDAT
as the variable.

The attached 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.

One thing we have to decide is what to do about MachO. Should we omit
the comdats from the IR for MachO or have llvm ignore it?

Cheers,
Rafael
diff --git a/lib/CodeGen/CGDeclCXX.cpp b/lib/CodeGen/CGDeclCXX.cpp
index 3e5f42e..a03bdc8 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()) {
+    llvm::Comdat *C = TheModule.getOrInsertComdat(Addr->getName());
+    Fn->setComdat(C);
+  }
+
   auto *ISA = D->getAttr<InitSegAttr>();
   CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D, Addr,
                                                           PerformInit);
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index 038d890..78ada2c 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()) {
+      llvm::Comdat *C = CGM.getModule().getOrInsertComdat(var->getName());
+      guard->setComdat(C);
+    }
+
     CGM.setStaticLocalDeclGuardAddress(&D, guard);
   }
 
diff --git a/test/CodeGenCXX/static-data-member.cpp b/test/CodeGenCXX/static-data-member.cpp
index eea9794..da9652a 100644
--- a/test/CodeGenCXX/static-data-member.cpp
+++ b/test/CodeGenCXX/static-data-member.cpp
@@ -1,9 +1,9 @@
-// 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
 
 // 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
 
 // CHECK: _ZN5test51U2k0E = global i32 0
 // CHECK: _ZN5test51U2k1E = global i32 0
@@ -60,7 +60,7 @@ 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
   // CHECK:      [[GUARDBYTE:%.*]] = load i8* bitcast (i64* @_ZGVN5test31AIiE1xE to i8*)
   // CHECK-NEXT: [[UNINITIALIZED:%.*]] = icmp eq i8 [[GUARDBYTE]], 0
   // CHECK-NEXT: br i1 [[UNINITIALIZED]]
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to