From 61a0a7519ee0d26334d30a001501b8c443d36975 Mon Sep 17 00:00:00 2001 From: Rafael Espindola <rafael.espindola@gmail.com> Date: Tue, 5 Nov 2013 21:37:29 +0000 Subject: [PATCH] Produce direct calls instead of alias to linkonce_odr functions. This is a small optimization on linux, but should help more on windows where msvc only outputs one destructor if there would be two identical ones. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@194095 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGCXX.cpp | 39 ++++++++++++++++------------- lib/CodeGen/CodeGenModule.cpp | 15 +++++++++++ lib/CodeGen/CodeGenModule.h | 6 +++++ test/CodeGenCXX/ctor-dtor-alias.cpp | 9 +++---- test/CodeGenCXX/destructors.cpp | 10 +++++--- 5 files changed, 51 insertions(+), 28 deletions(-) diff --git a/lib/CodeGen/CGCXX.cpp b/lib/CodeGen/CGCXX.cpp index 31134be810..15686f7ff6 100644 --- a/lib/CodeGen/CGCXX.cpp +++ b/lib/CodeGen/CGCXX.cpp @@ -112,33 +112,20 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, // support aliases with that linkage, fail. llvm::GlobalValue::LinkageTypes Linkage = getFunctionLinkage(AliasDecl); - llvm::GlobalValue::LinkageTypes TargetLinkage - = getFunctionLinkage(TargetDecl); - - // 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; + llvm::GlobalValue::LinkageTypes TargetLinkage = + getFunctionLinkage(TargetDecl); + // Check if we have it already. StringRef MangledName = getMangledName(AliasDecl); llvm::GlobalValue *Entry = GetGlobalValue(MangledName); if (Entry && !Entry->isDeclaration()) return false; + if (Replacements.count(MangledName)) + return false; // Derive the type for the alias. llvm::PointerType *AliasType @@ -152,6 +139,22 @@ bool CodeGenModule::TryEmitDefinitionAsAlias(GlobalDecl AliasDecl, if (Ref->getType() != AliasType) Aliasee = llvm::ConstantExpr::getBitCast(Ref, AliasType); + // 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; + + assert(Linkage == TargetLinkage); + // Instead of creating as alias to a linkonce_odr, replace all of the uses + // of the aliassee. + if (TargetLinkage == llvm::GlobalValue::LinkOnceODRLinkage) { + Replacements[MangledName] = Aliasee; + return false; + } + } + // Create the alias with no name. llvm::GlobalAlias *Alias = new llvm::GlobalAlias(AliasType, Linkage, "", Aliasee, &getModule()); diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index c34f833269..d7f33c9f1e 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -172,6 +172,20 @@ void CodeGenModule::createCUDARuntime() { CUDARuntime = CreateNVCUDARuntime(*this); } +void CodeGenModule::applyReplacements() { + for (ReplacementsTy::iterator I = Replacements.begin(), + E = Replacements.end(); + I != E; ++I) { + StringRef MangledName = I->first(); + llvm::Constant *Replacement = I->second; + llvm::GlobalValue *Entry = GetGlobalValue(MangledName); + if (!Entry) + continue; + Entry->replaceAllUsesWith(Replacement); + Entry->eraseFromParent(); + } +} + void CodeGenModule::checkAliases() { bool Error = false; for (std::vector<GlobalDecl>::iterator I = Aliases.begin(), @@ -207,6 +221,7 @@ void CodeGenModule::checkAliases() { void CodeGenModule::Release() { EmitDeferred(); + applyReplacements(); checkAliases(); EmitCXXGlobalInitFunc(); EmitCXXGlobalDtorFunc(); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 45a9e20a51..02b9ce6471 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -279,6 +279,9 @@ class CodeGenModule : public CodeGenTypeCache { /// is defined once we get to the end of the of the translation unit. std::vector<GlobalDecl> Aliases; + typedef llvm::StringMap<llvm::TrackingVH<llvm::Constant> > ReplacementsTy; + ReplacementsTy Replacements; + /// DeferredVTables - A queue of (optional) vtables to consider emitting. std::vector<const CXXRecordDecl*> DeferredVTables; @@ -1082,6 +1085,9 @@ private: /// was deferred. void EmitDeferred(); + /// Call replaceAllUsesWith on all pairs in Replacements. + void applyReplacements(); + void checkAliases(); /// EmitDeferredVTables - Emit any vtables which we deferred and diff --git a/test/CodeGenCXX/ctor-dtor-alias.cpp b/test/CodeGenCXX/ctor-dtor-alias.cpp index e658522d79..ff9bd7c5c5 100644 --- a/test/CodeGenCXX/ctor-dtor-alias.cpp +++ b/test/CodeGenCXX/ctor-dtor-alias.cpp @@ -13,12 +13,11 @@ 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. +// test that when the destrucor is linkonce_odr we just replace every use of +// C1 with C2. -// CHECK-DAG: @_ZN5test26foobarIvEC1Ev = alias weak_odr void (%"struct.test2::foobar"*)* @_ZN5test26foobarIvEC2Ev // CHECK-DAG: define linkonce_odr void @_ZN5test26foobarIvEC2Ev( +// CHECK-DAG: call void @_ZN5test26foobarIvEC2Ev void g(); template <typename T> struct foobar { foobar() { g(); } @@ -48,9 +47,7 @@ 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() {} diff --git a/test/CodeGenCXX/destructors.cpp b/test/CodeGenCXX/destructors.cpp index 472a229a9b..887b73fcc5 100644 --- a/test/CodeGenCXX/destructors.cpp +++ b/test/CodeGenCXX/destructors.cpp @@ -9,8 +9,6 @@ // 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 -// CHECK-DAG: @_ZN6test106OptionD1Ev = alias weak_odr void (%"struct.test10::Option"*)* @_ZN6test106OptionD2Ev struct A { int a; @@ -46,6 +44,9 @@ namespace PR7526 { // CHECK: call void @__cxa_call_unexpected allocator::~allocator() throw() { foo(); } + // CHECK-LABEL: define void @_ZN6PR75263fooEv() + // CHECK: call void @_ZN6PR752617allocator_derivedD2Ev + void foo() { allocator_derived ad; } @@ -367,14 +368,15 @@ namespace test9 { namespace test10 { // We used to crash trying to replace _ZN6test106OptionD1Ev with - // _ZN6test106OptionD2Ev twice. For now check that we don't try and produce - // an alias instead (check at the top of the file). + // _ZN6test106OptionD2Ev twice. struct Option { virtual ~Option() {} }; template <class DataType> class opt : public Option {}; template class opt<int>; + // CHECK-LABEL: define zeroext i1 @_ZN6test1016handleOccurrenceEv( bool handleOccurrence() { + // CHECK: call void @_ZN6test106OptionD2Ev( Option x; return true; } -- 2.40.0