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
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);
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; }
// 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);
}
// 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;
-// 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
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]]