forked from OSchip/llvm-project
[ThinLTO/gold] Perform index-based weak/linkonce resolution
Summary: Invoke the weak/linkonce symbol resolution support (already used by libLTO) that operates via the summary index. This ensures prevailing linkonce are kept, by making them weak, and marks preempted copies as available_externally when possible. With this change, the older support for keeping the prevailing linkonce (by changing their symbol resolution) is removed. Reviewers: mehdi_amini Subscribers: llvm-commits, mehdi_amini Differential Revision: http://reviews.llvm.org/D22302 llvm-svn: 275474
This commit is contained in:
parent
96e881deb5
commit
35e0204eec
|
@ -0,0 +1,37 @@
|
|||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
; Alias are not optimized
|
||||
@linkonceodralias = linkonce_odr alias void (), void ()* @linkonceodrfuncwithalias
|
||||
|
||||
; Alias are not optimized
|
||||
@linkoncealias = linkonce alias void (), void ()* @linkoncefuncwithalias
|
||||
|
||||
; Function with an alias are not optimized
|
||||
define linkonce_odr void @linkonceodrfuncwithalias() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function with an alias are not optimized
|
||||
define linkonce void @linkoncefuncwithalias() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
define linkonce_odr void @linkonceodrfunc() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
define linkonce void @linkoncefunc() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
define weak_odr void @weakodrfunc() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
define weak void @weakfunc() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
|
@ -0,0 +1,87 @@
|
|||
; RUN: opt -module-summary %s -o %t.o
|
||||
; RUN: opt -module-summary %p/Inputs/thinlto_weak_resolution.ll -o %t2.o
|
||||
|
||||
; Verify that prevailing weak for linker symbol is kept.
|
||||
; Note that gold picks the first copy of a function as the prevailing one,
|
||||
; so listing %t.o first is sufficient to ensure that its copies are prevailing.
|
||||
; RUN: %gold -m elf_x86_64 -plugin %llvmshlibdir/LLVMgold.so \
|
||||
; RUN: --plugin-opt=thinlto \
|
||||
; RUN: --plugin-opt=save-temps \
|
||||
; RUN: -shared \
|
||||
; RUN: -o %t3.o %t.o %t2.o
|
||||
|
||||
; RUN: llvm-nm %t3.o | FileCheck %s
|
||||
; CHECK: weakfunc
|
||||
|
||||
; All of the preempted functions should have been eliminated (the plugin will
|
||||
; not link them in).
|
||||
; RUN: llvm-dis %t2.o.opt.bc -o - | FileCheck --check-prefix=OPT2 %s
|
||||
; OPT2-NOT: @
|
||||
|
||||
; RUN: llvm-dis %t.o.opt.bc -o - | FileCheck --check-prefix=OPT %s
|
||||
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
|
||||
define i32 @main() #0 {
|
||||
entry:
|
||||
call void @linkonceodralias()
|
||||
call void @linkoncealias()
|
||||
call void @linkonceodrfuncwithalias()
|
||||
call void @linkoncefuncwithalias()
|
||||
call void @linkonceodrfunc()
|
||||
call void @linkoncefunc()
|
||||
call void @weakodrfunc()
|
||||
call void @weakfunc()
|
||||
call void @linkonceodrfuncInSingleModule()
|
||||
ret i32 0
|
||||
}
|
||||
|
||||
; Alias are resolved
|
||||
; OPT: @linkonceodralias = weak_odr alias void (), void ()* @linkonceodrfuncwithalias
|
||||
@linkonceodralias = linkonce_odr alias void (), void ()* @linkonceodrfuncwithalias
|
||||
|
||||
; Alias are resolved
|
||||
; OPT: @linkoncealias = weak alias void (), void ()* @linkoncefuncwithalias
|
||||
@linkoncealias = linkonce alias void (), void ()* @linkoncefuncwithalias
|
||||
|
||||
; Function with an alias are not optimized
|
||||
; OPT: define linkonce_odr void @linkonceodrfuncwithalias()
|
||||
define linkonce_odr void @linkonceodrfuncwithalias() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; Function with an alias are not optimized
|
||||
; OPT: define linkonce void @linkoncefuncwithalias()
|
||||
define linkonce void @linkoncefuncwithalias() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; OPT: define weak_odr void @linkonceodrfunc()
|
||||
define linkonce_odr void @linkonceodrfunc() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
; OPT: define weak void @linkoncefunc()
|
||||
define linkonce void @linkoncefunc() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
; OPT: define weak_odr void @weakodrfunc()
|
||||
define weak_odr void @weakodrfunc() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
; OPT: define weak void @weakfunc()
|
||||
define weak void @weakfunc() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
; OPT: weak_odr void @linkonceodrfuncInSingleModule()
|
||||
define linkonce_odr void @linkonceodrfuncInSingleModule() #0 {
|
||||
entry:
|
||||
ret void
|
||||
}
|
|
@ -735,16 +735,6 @@ getModuleForFile(LLVMContext &Context, claimed_file &F, const void *View,
|
|||
if (Resolution == LDPR_PREVAILING_DEF_IRONLY_EXP && !Res.IsLinkonceOdr)
|
||||
Resolution = LDPR_PREVAILING_DEF;
|
||||
|
||||
// In ThinLTO mode change all prevailing resolutions to LDPR_PREVAILING_DEF.
|
||||
// For ThinLTO the IR files are compiled through the backend independently,
|
||||
// so we need to ensure that any prevailing linkonce copy will be emitted
|
||||
// into the object file by making it weak. Additionally, we can skip the
|
||||
// IRONLY handling for internalization, which isn't performed in ThinLTO
|
||||
// mode currently anyway.
|
||||
if (options::thinlto && (Resolution == LDPR_PREVAILING_DEF_IRONLY_EXP ||
|
||||
Resolution == LDPR_PREVAILING_DEF_IRONLY))
|
||||
Resolution = LDPR_PREVAILING_DEF;
|
||||
|
||||
GV->setUnnamedAddr(Res.UnnamedAddr);
|
||||
GV->setVisibility(Res.Visibility);
|
||||
|
||||
|
@ -998,6 +988,9 @@ void CodeGen::runLTOPasses() {
|
|||
M->setDataLayout(TM->createDataLayout());
|
||||
|
||||
if (CombinedIndex) {
|
||||
// Apply summary-based LinkOnce/Weak resolution decisions.
|
||||
thinLTOResolveWeakForLinkerModule(*M, *DefinedGlobals);
|
||||
|
||||
// Apply summary-based internalization decisions. Skip if there are no
|
||||
// defined globals from the summary since not only is it unnecessary, but
|
||||
// if this module did not have a summary section the internalizer will
|
||||
|
@ -1322,6 +1315,10 @@ static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) {
|
|||
// are referenced outside of a single IR module.
|
||||
DenseSet<GlobalValue::GUID> Preserve;
|
||||
|
||||
// Keep track of the prevailing copy for each GUID, for use in resolving
|
||||
// weak linkages.
|
||||
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
|
||||
|
||||
ModuleSummaryIndex CombinedIndex;
|
||||
uint64_t NextModuleId = 0;
|
||||
for (claimed_file &F : Modules) {
|
||||
|
@ -1342,19 +1339,27 @@ static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) {
|
|||
|
||||
std::unique_ptr<ModuleSummaryIndex> Index = getModuleSummaryIndexForFile(F);
|
||||
|
||||
// Skip files without a module summary.
|
||||
if (Index)
|
||||
CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
|
||||
|
||||
// Use gold's symbol resolution information to identify symbols referenced
|
||||
// by more than a single IR module (before importing, which is checked
|
||||
// separately).
|
||||
// by more than a single IR module (i.e. referenced by multiple IR modules
|
||||
// or by a non-IR module). Cross references introduced by importing are
|
||||
// checked separately via the export lists. Also track the prevailing copy
|
||||
// for later symbol resolution.
|
||||
for (auto &Sym : F.syms) {
|
||||
ld_plugin_symbol_resolution Resolution =
|
||||
(ld_plugin_symbol_resolution)Sym.resolution;
|
||||
GlobalValue::GUID SymGUID = GlobalValue::getGUID(Sym.name);
|
||||
if (Resolution != LDPR_PREVAILING_DEF_IRONLY)
|
||||
Preserve.insert(GlobalValue::getGUID(Sym.name));
|
||||
Preserve.insert(SymGUID);
|
||||
|
||||
if (Index && (Resolution == LDPR_PREVAILING_DEF ||
|
||||
Resolution == LDPR_PREVAILING_DEF_IRONLY ||
|
||||
Resolution == LDPR_PREVAILING_DEF_IRONLY_EXP))
|
||||
PrevailingCopy[SymGUID] = Index->getGlobalValueSummary(SymGUID);
|
||||
}
|
||||
|
||||
// Skip files without a module summary.
|
||||
if (Index)
|
||||
CombinedIndex.mergeFrom(std::move(Index), ++NextModuleId);
|
||||
}
|
||||
|
||||
// Collect for each module the list of function it defines (GUID ->
|
||||
|
@ -1368,6 +1373,12 @@ static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) {
|
|||
ComputeCrossModuleImport(CombinedIndex, ModuleToDefinedGVSummaries,
|
||||
ImportLists, ExportLists);
|
||||
|
||||
auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
|
||||
const auto &Prevailing = PrevailingCopy.find(GUID);
|
||||
assert(Prevailing != PrevailingCopy.end());
|
||||
return Prevailing->second == S;
|
||||
};
|
||||
|
||||
// Callback for internalization, to prevent internalization of symbols
|
||||
// that were not candidates initially, and those that are being imported
|
||||
// (which introduces new cross references).
|
||||
|
@ -1378,6 +1389,11 @@ static ld_plugin_status thinLTOLink(raw_fd_ostream *ApiFile) {
|
|||
Preserve.count(GUID);
|
||||
};
|
||||
|
||||
thinLTOResolveWeakForLinkerInIndex(
|
||||
CombinedIndex, isPrevailing,
|
||||
[](StringRef ModuleIdentifier, GlobalValue::GUID GUID,
|
||||
GlobalValue::LinkageTypes NewLinkage) {});
|
||||
|
||||
// Use global summary-based analysis to identify symbols that can be
|
||||
// internalized (because they aren't exported or preserved as per callback).
|
||||
// Changes are made in the index, consumed in the ThinLTO backends.
|
||||
|
|
Loading…
Reference in New Issue