From 3f643bd1248b77f5e87af2f7ee5e4f0881729e93 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Mon, 4 Nov 2013 18:38:59 +0000 Subject: [PATCH] Use aliases for more constructors and destructors. With this patch we produce alias for cases like template struct foobar { foobar() { } }; template struct foobar; We just have to be careful to produce the same aliases in every TU because of comdats. llvm-svn: 194000 --- clang/lib/CodeGen/CGCXX.cpp | 85 +++++++++++++---------- clang/lib/CodeGen/CGVTables.cpp | 4 -- clang/lib/CodeGen/CodeGenModule.h | 3 +- clang/test/CodeGenCXX/ctor-dtor-alias.cpp | 62 +++++++++++++++++ clang/test/CodeGenCXX/destructors.cpp | 14 ++-- 5 files changed, 118 insertions(+), 50 deletions(-) create mode 100644 clang/test/CodeGenCXX/ctor-dtor-alias.cpp diff --git a/clang/lib/CodeGen/CGCXX.cpp b/clang/lib/CodeGen/CGCXX.cpp index 7dd850be0bdd..25f3e6f4daa3 100644 --- a/clang/lib/CodeGen/CGCXX.cpp +++ b/clang/lib/CodeGen/CGCXX.cpp @@ -95,12 +95,16 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) { return true; return TryEmitDefinitionAsAlias(GlobalDecl(D, Dtor_Base), - GlobalDecl(BaseD, Dtor_Base)); + GlobalDecl(BaseD, Dtor_Base), + false); } /// Try to emit a definition as a global alias for another definition. +/// If \p InEveryTU is true, we know that an equivalent alias can be produced +/// in every translation unit. bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, - GlobalDecl TargetDecl) { + GlobalDecl TargetDecl, + bool InEveryTU) { if (!getCodeGenOpts().CXXCtorDtorAliases) return true; @@ -108,34 +112,34 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, // support aliases with that linkage, fail. llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl); - switch (Linkage) { - // We can definitely emit aliases to definitions with external linkage. - case llvm::GlobalValue::ExternalLinkage: - case llvm::GlobalValue::ExternalWeakLinkage: - break; - - // Same with local linkage. - case llvm::GlobalValue::InternalLinkage: - case llvm::GlobalValue::PrivateLinkage: - case llvm::GlobalValue::LinkerPrivateLinkage: - break; - - // We should try to support linkonce linkages. - case llvm::GlobalValue::LinkOnceAnyLinkage: - case llvm::GlobalValue::LinkOnceODRLinkage: - return true; - - // Other linkages will probably never be supported. - default: - return true; - } - llvm::GlobalValue::LinkageTypes TargetLinkage = getFunctionLinkage(TargetDecl); - if (llvm::GlobalValue::isWeakForLinker(TargetLinkage)) + // Don't create an alias to a linker weak symbol unless we know we can do + // that in every TU. This avoids producing different COMDATs in different + // TUs. + if (llvm::GlobalValue::isWeakForLinker(TargetLinkage)) { + if (!InEveryTU) + return true; + + // In addition to making sure we produce it in every TU, we have to make + // sure llvm keeps it. + // FIXME: Instead of outputting an alias we could just replace every use of + // AliasDecl with TargetDecl. + assert(Linkage == TargetLinkage); + Linkage = llvm::GlobalValue::WeakODRLinkage; + } + + // We can't use an alias if the linkage is not valid for one. + if (!llvm::GlobalAlias::isValidLinkage(Linkage)) return true; + // Check if we have it already. + StringRef MangledName = getMangledName(AliasDecl); + llvm::GlobalValue *Entry = GetGlobalValue(MangledName); + if (Entry && !Entry->isDeclaration()) + return false; + // Derive the type for the alias. llvm::PointerType *AliasType = getTypes().GetFunctionType(AliasDecl)->getPointerTo(); @@ -153,10 +157,7 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule()); // Switch any previous uses to the alias. - StringRef MangledName = getMangledName(AliasDecl); - llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry) { - assert(Entry->isDeclaration() && "definition already exists for alias"); assert(Entry->getType() == AliasType && "declaration exists with different type"); Alias->takeName(Entry); @@ -177,11 +178,14 @@ void CodeGenModule::EmitCXXConstructor(const CXXConstructorDecl *ctor, // The complete constructor is equivalent to the base constructor // for classes with no virtual bases. Try to emit it as an alias. if (getTarget().getCXXABI().hasConstructorVariants() && - ctorType == Ctor_Complete && !ctor->getParent()->getNumVBases() && - !TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete), - GlobalDecl(ctor, Ctor_Base))) - return; + (ctorType == Ctor_Complete || ctorType == Ctor_Base)) { + bool ProducedAlias = + !TryEmitDefinitionAsAlias(GlobalDecl(ctor, Ctor_Complete), + GlobalDecl(ctor, Ctor_Base), true); + if (ctorType == Ctor_Complete && ProducedAlias) + return; + } const CGFunctionInfo &fnInfo = getTypes().arrangeCXXConstructorDeclaration(ctor, ctorType); @@ -218,11 +222,18 @@ void CodeGenModule::EmitCXXDestructor(const CXXDestructorDecl *dtor, CXXDtorType dtorType) { // The complete destructor is equivalent to the base destructor for // classes with no virtual bases, so try to emit it as an alias. - if (dtorType == Dtor_Complete && - !dtor->getParent()->getNumVBases() && - !TryEmitDefinitionAsAlias(GlobalDecl(dtor, Dtor_Complete), - GlobalDecl(dtor, Dtor_Base))) - return; + if (!dtor->getParent()->getNumVBases() && + (dtorType == Dtor_Complete || dtorType == Dtor_Base)) { + bool ProducedAlias = + !TryEmitDefinitionAsAlias(GlobalDecl(dtor, Dtor_Complete), + GlobalDecl(dtor, Dtor_Base), true); + if (ProducedAlias) { + if (dtorType == Dtor_Complete) + return; + if (dtor->isVirtual()) + getVTables().EmitThunks(GlobalDecl(dtor, Dtor_Complete)); + } + } // The base destructor is equivalent to the base destructor of its // base class if there is exactly one non-virtual base class with a diff --git a/clang/lib/CodeGen/CGVTables.cpp b/clang/lib/CodeGen/CGVTables.cpp index 0956fee037a6..996bd905f67c 100644 --- a/clang/lib/CodeGen/CGVTables.cpp +++ b/clang/lib/CodeGen/CGVTables.cpp @@ -387,10 +387,6 @@ void CodeGenVTables::emitThunk(GlobalDecl GD, const ThunkInfo &Thunk, return; } - // If a function has a body, it should have available_externally linkage. - assert(ThunkFn->hasAvailableExternallyLinkage() && - "Function should have available_externally linkage!"); - // Change the linkage. CGM.setFunctionLinkage(GD, ThunkFn); return; diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 25aaae61e482..249ad3317594 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -1034,7 +1034,8 @@ private: // C++ related functions. - bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target); + bool TryEmitDefinitionAsAlias(GlobalDecl Alias, GlobalDecl Target, + bool InEveryTU); bool TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D); void EmitNamespace(const NamespaceDecl *D); diff --git a/clang/test/CodeGenCXX/ctor-dtor-alias.cpp b/clang/test/CodeGenCXX/ctor-dtor-alias.cpp new file mode 100644 index 000000000000..e658522d799a --- /dev/null +++ b/clang/test/CodeGenCXX/ctor-dtor-alias.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 %s -triple x86_64-linux -emit-llvm -o - -mconstructor-aliases | FileCheck %s + +namespace test1 { +// test that we produce an alias when the destructor is weak_odr + +// CHECK-DAG: @_ZN5test16foobarIvEC1Ev = alias weak_odr void (%"struct.test1::foobar"*)* @_ZN5test16foobarIvEC2Ev +// CHECK-DAG: define weak_odr void @_ZN5test16foobarIvEC2Ev( +template struct foobar { + foobar() {} +}; + +template struct foobar; +} + +namespace test2 { +// test that we produce an alias when the destrucor is linkonce_odr. Note that +// the alias itself is weak_odr to make sure we don't get a translation unit +// with just _ZN5test26foobarIvEC2Ev in it. + +// CHECK-DAG: @_ZN5test26foobarIvEC1Ev = alias weak_odr void (%"struct.test2::foobar"*)* @_ZN5test26foobarIvEC2Ev +// CHECK-DAG: define linkonce_odr void @_ZN5test26foobarIvEC2Ev( +void g(); +template struct foobar { + foobar() { g(); } +}; +foobar x; +} + +namespace test3 { +// test that these alias are internal. + +// CHECK-DAG: @_ZN5test312_GLOBAL__N_11AD1Ev = alias internal void (%"struct.test3::::A"*)* @_ZN5test312_GLOBAL__N_11AD2Ev +// CHECK-DAG: @_ZN5test312_GLOBAL__N_11BD2Ev = alias internal bitcast (void (%"struct.test3::::A"*)* @_ZN5test312_GLOBAL__N_11AD2Ev to void (%"struct.test3::::B"*)*) +// CHECK-DAG: @_ZN5test312_GLOBAL__N_11BD1Ev = alias internal void (%"struct.test3::::B"*)* @_ZN5test312_GLOBAL__N_11BD2Ev +// CHECK-DAG: define internal void @_ZN5test312_GLOBAL__N_11AD2Ev( +namespace { +struct A { + ~A() {} +}; + +struct B : public A {}; +} + +B x; +} + +namespace test4 { + // Test that we don't produce aliases from B to A. We cannot because we cannot + // guarantee that they will be present in every TU. + + // CHECK-DAG: @_ZN5test41BD1Ev = alias weak_odr void (%"struct.test4::B"*)* @_ZN5test41BD2Ev + // CHECK-DAG: define linkonce_odr void @_ZN5test41BD2Ev( + // CHECK-DAG: @_ZN5test41AD1Ev = alias weak_odr void (%"struct.test4::A"*)* @_ZN5test41AD2Ev + // CHECK-DAG: define linkonce_odr void @_ZN5test41AD2Ev( + struct A { + virtual ~A() {} + }; + struct B : public A{ + ~B() {} + }; + B X; +} diff --git a/clang/test/CodeGenCXX/destructors.cpp b/clang/test/CodeGenCXX/destructors.cpp index de73fcce3a42..0030aae92edd 100644 --- a/clang/test/CodeGenCXX/destructors.cpp +++ b/clang/test/CodeGenCXX/destructors.cpp @@ -9,6 +9,7 @@ // CHECK-DAG: @_ZN5test312_GLOBAL__N_11DD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11DD2Ev // CHECK-DAG: @_ZN5test312_GLOBAL__N_11DD2Ev = alias internal bitcast {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev // CHECK-DAG: @_ZN5test312_GLOBAL__N_11CD1Ev = alias internal {{.*}} @_ZN5test312_GLOBAL__N_11CD2Ev +// CHECK-DAG: @_ZN6PR752617allocator_derivedD1Ev = alias weak_odr void (%"struct.PR7526::allocator_derived"*)* @_ZN6PR752617allocator_derivedD2Ev struct A { int a; @@ -44,9 +45,6 @@ namespace PR7526 { // CHECK: call void @__cxa_call_unexpected allocator::~allocator() throw() { foo(); } - // CHECK-LABEL: define linkonce_odr void @_ZN6PR752617allocator_derivedD1Ev(%"struct.PR7526::allocator_derived"* %this) unnamed_addr - // CHECK-NOT: call void @__cxa_call_unexpected - // CHECK: } void foo() { allocator_derived ad; } @@ -396,6 +394,11 @@ namespace test9 { // CHECK: call void @_ZN5test31AD2Ev( // CHECK: ret void + // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev( + // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 + // CHECK: call void @_ZN5test312_GLOBAL__N_11CD1Ev( + // CHECK: ret void + // CHECK: declare void @_ZN5test31BD2Ev( // CHECK: declare void @_ZN5test31AD2Ev( @@ -408,11 +411,6 @@ namespace test9 { // CHECK: call void @_ZdlPv({{.*}}) [[NUW]] // CHECK: resume { i8*, i32 } - // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD1Ev( - // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 - // CHECK: call void @_ZN5test312_GLOBAL__N_11CD1Ev( - // CHECK: ret void - // CHECK-LABEL: define internal void @_ZThn8_N5test312_GLOBAL__N_11CD0Ev( // CHECK: getelementptr inbounds i8* {{.*}}, i64 -8 // CHECK: call void @_ZN5test312_GLOBAL__N_11CD0Ev(