Use a trivial comdat for inline ctor/dtor when not using C5/D5.

When combined with llvm not producing implicit comdats, not doing this would
cause code bloat on ELF and link errors on COFF.

llvm-svn: 226211
This commit is contained in:
Rafael Espindola 2015-01-15 21:36:08 +00:00
parent c59328e627
commit dbee8a7a7a
4 changed files with 20 additions and 9 deletions

View File

@ -1953,6 +1953,13 @@ static bool shouldBeInCOMDAT(CodeGenModule &CGM, const Decl &D) {
llvm_unreachable("No such linkage"); llvm_unreachable("No such linkage");
} }
void CodeGenModule::maybeSetTrivialComdat(const Decl &D,
llvm::GlobalObject &GO) {
if (!shouldBeInCOMDAT(*this, D))
return;
GO.setComdat(TheModule.getOrInsertComdat(GO.getName()));
}
void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) { void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
llvm::Constant *Init = nullptr; llvm::Constant *Init = nullptr;
QualType ASTTy = D->getType(); QualType ASTTy = D->getType();
@ -2096,8 +2103,7 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
setTLSMode(GV, *D); setTLSMode(GV, *D);
} }
if (shouldBeInCOMDAT(*this, *D)) maybeSetTrivialComdat(*D, *GV);
GV->setComdat(TheModule.getOrInsertComdat(GV->getName()));
// Emit the initializer function if necessary. // Emit the initializer function if necessary.
if (NeedsGlobalCtor || NeedsGlobalDtor) if (NeedsGlobalCtor || NeedsGlobalDtor)
@ -2433,8 +2439,7 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
MaybeHandleStaticInExternC(D, Fn); MaybeHandleStaticInExternC(D, Fn);
if (shouldBeInCOMDAT(*this, *D)) maybeSetTrivialComdat(*D, *Fn);
Fn->setComdat(TheModule.getOrInsertComdat(Fn->getName()));
CodeGenFunction(*this).GenerateCode(D, Fn, FI); CodeGenFunction(*this).GenerateCode(D, Fn, FI);

View File

@ -606,6 +606,7 @@ public:
const TargetInfo &getTarget() const { return Target; } const TargetInfo &getTarget() const { return Target; }
const llvm::Triple &getTriple() const; const llvm::Triple &getTriple() const;
bool supportsCOMDAT() const; bool supportsCOMDAT() const;
void maybeSetTrivialComdat(const Decl &D, llvm::GlobalObject &GO);
CGCXXABI &getCXXABI() const { return *ABI; } CGCXXABI &getCXXABI() const { return *ABI; }
llvm::LLVMContext &getLLVMContext() { return VMContext; } llvm::LLVMContext &getLLVMContext() { return VMContext; }

View File

@ -3202,5 +3202,7 @@ void ItaniumCXXABI::emitCXXStructor(const CXXMethodDecl *MD,
getMangleContext().mangleCXXCtorComdat(CD, Out); getMangleContext().mangleCXXCtorComdat(CD, Out);
llvm::Comdat *C = CGM.getModule().getOrInsertComdat(Out.str()); llvm::Comdat *C = CGM.getModule().getOrInsertComdat(Out.str());
Fn->setComdat(C); Fn->setComdat(C);
} else {
CGM.maybeSetTrivialComdat(*MD, *Fn);
} }
} }

View File

@ -22,7 +22,10 @@ namespace test1 {
// CHECK1-NOT: comdat // CHECK1-NOT: comdat
// COFF doesn't support comdats with arbitrary names (C5/D5). // COFF doesn't support comdats with arbitrary names (C5/D5).
// COFF-NOT: comdat // COFF: define weak_odr {{.*}} void @_ZN5test16foobarIvEC2Ev({{.*}} comdat align
// COFF: define weak_odr {{.*}} void @_ZN5test16foobarIvEC1Ev({{.*}} comdat align
// COFF: define weak_odr {{.*}} void @_ZN5test16foobarIvED2Ev({{.*}} comdat align
// COFF: define weak_odr {{.*}} void @_ZN5test16foobarIvED0Ev({{.*}} comdat align
template <typename T> template <typename T>
struct foobar { struct foobar {
@ -39,7 +42,7 @@ namespace test2 {
// CHECK1: define internal void @__cxx_global_var_init() // CHECK1: define internal void @__cxx_global_var_init()
// CHECK1: call void @_ZN5test26foobarIvEC2Ev // CHECK1: call void @_ZN5test26foobarIvEC2Ev
// CHECK1: define linkonce_odr void @_ZN5test26foobarIvEC2Ev( // CHECK1: define linkonce_odr void @_ZN5test26foobarIvEC2Ev({{.*}} comdat align
void g(); void g();
template <typename T> struct foobar { template <typename T> struct foobar {
foobar() { g(); } foobar() { g(); }
@ -72,13 +75,13 @@ namespace test4 {
// CHECK1: define internal void @__cxx_global_var_init2() // CHECK1: define internal void @__cxx_global_var_init2()
// CHECK1: call i32 @__cxa_atexit{{.*}}_ZN5test41AD2Ev // CHECK1: call i32 @__cxa_atexit{{.*}}_ZN5test41AD2Ev
// CHECK1: define linkonce_odr void @_ZN5test41AD2Ev( // CHECK1: define linkonce_odr void @_ZN5test41AD2Ev({{.*}} comdat align
// test that we don't do this optimization at -O0 so that the debugger can // test that we don't do this optimization at -O0 so that the debugger can
// see both destructors. // see both destructors.
// NOOPT: define internal void @__cxx_global_var_init2() // NOOPT: define internal void @__cxx_global_var_init2()
// NOOPT: call i32 @__cxa_atexit{{.*}}@_ZN5test41BD2Ev // NOOPT: call i32 @__cxa_atexit{{.*}}@_ZN5test41BD2Ev
// NOOPT: define linkonce_odr void @_ZN5test41BD2Ev // NOOPT: define linkonce_odr void @_ZN5test41BD2Ev({{.*}} comdat align
struct A { struct A {
virtual ~A() {} virtual ~A() {}
}; };
@ -93,7 +96,7 @@ namespace test5 {
// CHECK2: define internal void @__cxx_global_var_init3() // CHECK2: define internal void @__cxx_global_var_init3()
// CHECK2: call i32 @__cxa_atexit{{.*}}_ZN5test51AD2Ev // CHECK2: call i32 @__cxa_atexit{{.*}}_ZN5test51AD2Ev
// CHECK2: define linkonce_odr void @_ZN5test51AD2Ev( // CHECK2: define linkonce_odr void @_ZN5test51AD2Ev({{.*}} comdat align
struct A { struct A {
virtual ~A() {} virtual ~A() {}
}; };