Use aliases for more constructors and destructors.

With this patch we produce alias for cases like

template<typename T>
struct foobar {
  foobar() {
  }
};
template struct foobar<void>;

We just have to be careful to produce the same aliases in every TU because
of comdats.

llvm-svn: 194000
This commit is contained in:
Rafael Espindola 2013-11-04 18:38:59 +00:00
parent a6775b622f
commit 3f643bd124
5 changed files with 118 additions and 50 deletions

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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 <typename T> struct foobar {
foobar() {}
};
template struct foobar<void>;
}
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 <typename T> struct foobar {
foobar() { g(); }
};
foobar<void> x;
}
namespace test3 {
// test that these alias are internal.
// CHECK-DAG: @_ZN5test312_GLOBAL__N_11AD1Ev = alias internal void (%"struct.test3::<anonymous namespace>::A"*)* @_ZN5test312_GLOBAL__N_11AD2Ev
// CHECK-DAG: @_ZN5test312_GLOBAL__N_11BD2Ev = alias internal bitcast (void (%"struct.test3::<anonymous namespace>::A"*)* @_ZN5test312_GLOBAL__N_11AD2Ev to void (%"struct.test3::<anonymous namespace>::B"*)*)
// CHECK-DAG: @_ZN5test312_GLOBAL__N_11BD1Ev = alias internal void (%"struct.test3::<anonymous namespace>::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;
}

View File

@ -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(