mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-12-02 08:26:29 +00:00
[ThinLTO] Fix handling of weak interposable symbols
Summary: Keep aliasees alive if their alias is live, otherwise we end up with an alias to a declaration, which is invalid. This can happen when the aliasee is weak and non-prevailing. This fix exposed the fact that we were then attempting to internalize the weak symbol, which was not exported as it was not prevailing. We should not internalize interposable symbols in general, unless this is the prevailing copy, since it can lead to incorrect inlining and other optimizations. Most of the changes in this patch are due to the restructuring required to pass down the prevailing callback. Finally, while implementing the test cases, I found that in the case of a weak aliasee that is still marked not live because its alias isn't live, after dropping the definition we incorrectly marked the declaration with weak linkage when resolving prevailing symbols in the module. This was due to some special case handling for symbols marked WeakLinkage in the summary located before instead of after a subsequent check for the symbol being a declaration. It turns out that we don't actually need this special case handling any more (looking back at the history, when that was added the code was structured quite differently) - we will correctly mark with weak linkage further below when the definition hasn't been dropped. Fixes PR42542. Reviewers: pcc Subscribers: mehdi_amini, inglorion, steven_wu, dexonsmith, dang, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D66264 llvm-svn: 369766
This commit is contained in:
parent
1ae20d6fd6
commit
c649b1f9bb
@ -59,7 +59,9 @@ void thinLTOResolvePrevailingInIndex(
|
||||
/// must apply the changes to the Module via thinLTOInternalizeModule.
|
||||
void thinLTOInternalizeAndPromoteInIndex(
|
||||
ModuleSummaryIndex &Index,
|
||||
function_ref<bool(StringRef, GlobalValue::GUID)> isExported);
|
||||
function_ref<bool(StringRef, GlobalValue::GUID)> isExported,
|
||||
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
|
||||
isPrevailing);
|
||||
|
||||
/// Computes a unique hash for the Module considering the current list of
|
||||
/// export/import and other global analysis results.
|
||||
|
@ -384,7 +384,9 @@ static bool isWeakObjectWithRWAccess(GlobalValueSummary *GVS) {
|
||||
|
||||
static void thinLTOInternalizeAndPromoteGUID(
|
||||
GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID,
|
||||
function_ref<bool(StringRef, GlobalValue::GUID)> isExported) {
|
||||
function_ref<bool(StringRef, GlobalValue::GUID)> isExported,
|
||||
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
|
||||
isPrevailing) {
|
||||
for (auto &S : GVSummaryList) {
|
||||
if (isExported(S->modulePath(), GUID)) {
|
||||
if (GlobalValue::isLocalLinkage(S->linkage()))
|
||||
@ -393,6 +395,8 @@ static void thinLTOInternalizeAndPromoteGUID(
|
||||
// Ignore local and appending linkage values since the linker
|
||||
// doesn't resolve them.
|
||||
!GlobalValue::isLocalLinkage(S->linkage()) &&
|
||||
(!GlobalValue::isInterposableLinkage(S->linkage()) ||
|
||||
isPrevailing(GUID, S.get())) &&
|
||||
S->linkage() != GlobalValue::AppendingLinkage &&
|
||||
// We can't internalize available_externally globals because this
|
||||
// can break function pointer equality.
|
||||
@ -411,9 +415,12 @@ static void thinLTOInternalizeAndPromoteGUID(
|
||||
// as external and non-exported values as internal.
|
||||
void llvm::thinLTOInternalizeAndPromoteInIndex(
|
||||
ModuleSummaryIndex &Index,
|
||||
function_ref<bool(StringRef, GlobalValue::GUID)> isExported) {
|
||||
function_ref<bool(StringRef, GlobalValue::GUID)> isExported,
|
||||
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
|
||||
isPrevailing) {
|
||||
for (auto &I : Index)
|
||||
thinLTOInternalizeAndPromoteGUID(I.second.SummaryList, I.first, isExported);
|
||||
thinLTOInternalizeAndPromoteGUID(I.second.SummaryList, I.first, isExported,
|
||||
isPrevailing);
|
||||
}
|
||||
|
||||
// Requires a destructor for std::vector<InputModule>.
|
||||
@ -1322,12 +1329,13 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
|
||||
ExportList->second.count(GUID)) ||
|
||||
ExportedGUIDs.count(GUID);
|
||||
};
|
||||
thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported);
|
||||
|
||||
auto isPrevailing = [&](GlobalValue::GUID GUID,
|
||||
const GlobalValueSummary *S) {
|
||||
return ThinLTO.PrevailingModuleForGUID[GUID] == S->modulePath();
|
||||
};
|
||||
thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported,
|
||||
isPrevailing);
|
||||
|
||||
auto recordNewLinkage = [&](StringRef ModuleIdentifier,
|
||||
GlobalValue::GUID GUID,
|
||||
GlobalValue::LinkageTypes NewLinkage) {
|
||||
|
@ -457,10 +457,9 @@ static void resolvePrevailingInIndex(
|
||||
ModuleSummaryIndex &Index,
|
||||
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>>
|
||||
&ResolvedODR,
|
||||
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
|
||||
|
||||
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
|
||||
computePrevailingCopies(Index, PrevailingCopy);
|
||||
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
|
||||
const DenseMap<GlobalValue::GUID, const GlobalValueSummary *>
|
||||
&PrevailingCopy) {
|
||||
|
||||
auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
|
||||
const auto &Prevailing = PrevailingCopy.find(GUID);
|
||||
@ -576,6 +575,8 @@ std::unique_ptr<ModuleSummaryIndex> ThinLTOCodeGenerator::linkCombinedIndex() {
|
||||
static void internalizeAndPromoteInIndex(
|
||||
const StringMap<FunctionImporter::ExportSetTy> &ExportLists,
|
||||
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
|
||||
const DenseMap<GlobalValue::GUID, const GlobalValueSummary *>
|
||||
&PrevailingCopy,
|
||||
ModuleSummaryIndex &Index) {
|
||||
auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
|
||||
const auto &ExportList = ExportLists.find(ModuleIdentifier);
|
||||
@ -584,7 +585,15 @@ static void internalizeAndPromoteInIndex(
|
||||
GUIDPreservedSymbols.count(GUID);
|
||||
};
|
||||
|
||||
thinLTOInternalizeAndPromoteInIndex(Index, isExported);
|
||||
auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
|
||||
const auto &Prevailing = PrevailingCopy.find(GUID);
|
||||
// Not in map means that there was only one copy, which must be prevailing.
|
||||
if (Prevailing == PrevailingCopy.end())
|
||||
return true;
|
||||
return Prevailing->second == S;
|
||||
};
|
||||
|
||||
thinLTOInternalizeAndPromoteInIndex(Index, isExported, isPrevailing);
|
||||
}
|
||||
|
||||
static void computeDeadSymbolsInIndex(
|
||||
@ -629,16 +638,21 @@ void ThinLTOCodeGenerator::promote(Module &TheModule, ModuleSummaryIndex &Index,
|
||||
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
|
||||
ExportLists);
|
||||
|
||||
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
|
||||
computePrevailingCopies(Index, PrevailingCopy);
|
||||
|
||||
// Resolve prevailing symbols
|
||||
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
|
||||
resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols);
|
||||
resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols,
|
||||
PrevailingCopy);
|
||||
|
||||
thinLTOResolvePrevailingInModule(
|
||||
TheModule, ModuleToDefinedGVSummaries[ModuleIdentifier]);
|
||||
|
||||
// Promote the exported values in the index, so that they are promoted
|
||||
// in the module.
|
||||
internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, Index);
|
||||
internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols,
|
||||
PrevailingCopy, Index);
|
||||
|
||||
promoteModule(TheModule, Index);
|
||||
}
|
||||
@ -785,13 +799,18 @@ void ThinLTOCodeGenerator::internalize(Module &TheModule,
|
||||
if (ExportList.empty() && GUIDPreservedSymbols.empty())
|
||||
return;
|
||||
|
||||
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
|
||||
computePrevailingCopies(Index, PrevailingCopy);
|
||||
|
||||
// Resolve prevailing symbols
|
||||
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
|
||||
resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols);
|
||||
resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols,
|
||||
PrevailingCopy);
|
||||
|
||||
// Promote the exported values in the index, so that they are promoted
|
||||
// in the module.
|
||||
internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, Index);
|
||||
internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols,
|
||||
PrevailingCopy, Index);
|
||||
|
||||
promoteModule(TheModule, Index);
|
||||
|
||||
@ -944,14 +963,19 @@ void ThinLTOCodeGenerator::run() {
|
||||
// on the index, and nuke this map.
|
||||
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
|
||||
|
||||
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
|
||||
computePrevailingCopies(*Index, PrevailingCopy);
|
||||
|
||||
// Resolve prevailing symbols, this has to be computed early because it
|
||||
// impacts the caching.
|
||||
resolvePrevailingInIndex(*Index, ResolvedODR, GUIDPreservedSymbols);
|
||||
resolvePrevailingInIndex(*Index, ResolvedODR, GUIDPreservedSymbols,
|
||||
PrevailingCopy);
|
||||
|
||||
// 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.
|
||||
internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, *Index);
|
||||
internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols,
|
||||
PrevailingCopy, *Index);
|
||||
|
||||
// Make sure that every module has an entry in the ExportLists, ImportList,
|
||||
// GVSummary and ResolvedODR maps to enable threaded access to these maps
|
||||
|
@ -764,7 +764,7 @@ void llvm::computeDeadSymbols(
|
||||
}
|
||||
|
||||
// Make value live and add it to the worklist if it was not live before.
|
||||
auto visit = [&](ValueInfo VI) {
|
||||
auto visit = [&](ValueInfo VI, bool IsAliasee) {
|
||||
// FIXME: If we knew which edges were created for indirect call profiles,
|
||||
// we could skip them here. Any that are live should be reached via
|
||||
// other edges, e.g. reference edges. Otherwise, using a profile collected
|
||||
@ -800,12 +800,15 @@ void llvm::computeDeadSymbols(
|
||||
Interposable = true;
|
||||
}
|
||||
|
||||
if (!KeepAliveLinkage)
|
||||
return;
|
||||
if (!IsAliasee) {
|
||||
if (!KeepAliveLinkage)
|
||||
return;
|
||||
|
||||
if (Interposable)
|
||||
report_fatal_error(
|
||||
"Interposable and available_externally/linkonce_odr/weak_odr symbol");
|
||||
if (Interposable)
|
||||
report_fatal_error(
|
||||
"Interposable and available_externally/linkonce_odr/weak_odr "
|
||||
"symbol");
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &S : VI.getSummaryList())
|
||||
@ -821,16 +824,16 @@ void llvm::computeDeadSymbols(
|
||||
// If this is an alias, visit the aliasee VI to ensure that all copies
|
||||
// are marked live and it is added to the worklist for further
|
||||
// processing of its references.
|
||||
visit(AS->getAliaseeVI());
|
||||
visit(AS->getAliaseeVI(), true);
|
||||
continue;
|
||||
}
|
||||
|
||||
Summary->setLive(true);
|
||||
for (auto Ref : Summary->refs())
|
||||
visit(Ref);
|
||||
visit(Ref, false);
|
||||
if (auto *FS = dyn_cast<FunctionSummary>(Summary.get()))
|
||||
for (auto Call : FS->calls())
|
||||
visit(Call.first);
|
||||
visit(Call.first, false);
|
||||
}
|
||||
}
|
||||
Index.setWithGlobalValueDeadStripping();
|
||||
@ -948,23 +951,11 @@ void llvm::thinLTOResolvePrevailingInModule(
|
||||
auto NewLinkage = GS->second->linkage();
|
||||
if (NewLinkage == GV.getLinkage())
|
||||
return;
|
||||
|
||||
// Switch the linkage to weakany if asked for, e.g. we do this for
|
||||
// linker redefined symbols (via --wrap or --defsym).
|
||||
// We record that the visibility should be changed here in `addThinLTO`
|
||||
// as we need access to the resolution vectors for each input file in
|
||||
// order to find which symbols have been redefined.
|
||||
// We may consider reorganizing this code and moving the linkage recording
|
||||
// somewhere else, e.g. in thinLTOResolvePrevailingInIndex.
|
||||
if (NewLinkage == GlobalValue::WeakAnyLinkage) {
|
||||
GV.setLinkage(NewLinkage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (GlobalValue::isLocalLinkage(GV.getLinkage()) ||
|
||||
// In case it was dead and already converted to declaration.
|
||||
GV.isDeclaration())
|
||||
return;
|
||||
|
||||
// Check for a non-prevailing def that has interposable linkage
|
||||
// (e.g. non-odr weak or linkonce). In that case we can't simply
|
||||
// convert to available_externally, since it would lose the
|
||||
|
33
test/LTO/Resolution/X86/not-prevailing-weak-aliasee.ll
Normal file
33
test/LTO/Resolution/X86/not-prevailing-weak-aliasee.ll
Normal file
@ -0,0 +1,33 @@
|
||||
; Test to ensure that non-prevailing weak aliasee is kept as a weak definition
|
||||
; when the alias is not dead.
|
||||
; RUN: opt -module-summary %s -o %t1.bc
|
||||
; RUN: llvm-lto2 run %t1.bc \
|
||||
; RUN: -r=%t1.bc,__a,lx \
|
||||
; RUN: -r=%t1.bc,__b,l \
|
||||
; RUN: -r=%t1.bc,a,plx \
|
||||
; RUN: -r=%t1.bc,b,pl \
|
||||
; RUN: -o %t2.o -save-temps
|
||||
|
||||
; Check that __a is kept as a weak def. __b can be dropped since its alias is
|
||||
; not live and will also be dropped.
|
||||
; RUN: llvm-dis %t2.o.1.1.promote.bc -o - | FileCheck %s
|
||||
; CHECK: define weak hidden void @__a
|
||||
; CHECK: declare hidden void @__b
|
||||
; CHECK: declare void @b
|
||||
|
||||
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
|
||||
target triple = "aarch64-unknown-linux-gnu"
|
||||
|
||||
@a = hidden alias void (), void ()* @__a
|
||||
|
||||
define weak hidden void @__a() {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
@b = hidden alias void (), void ()* @__b
|
||||
|
||||
define weak hidden void @__b() {
|
||||
entry:
|
||||
ret void
|
||||
}
|
6
test/ThinLTO/X86/Inputs/internalize.ll
Normal file
6
test/ThinLTO/X86/Inputs/internalize.ll
Normal file
@ -0,0 +1,6 @@
|
||||
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-apple-macosx10.11.0"
|
||||
|
||||
define weak void @weak_func_nonprevailing() {
|
||||
ret void
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
; RUN: opt -module-summary %s -o %t1.bc
|
||||
; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t1.bc
|
||||
; RUN: opt -module-summary %p/Inputs/internalize.ll -o %t2.bc
|
||||
; Link in %t2.bc first to force its copy of @weak_func_nonprevailing as
|
||||
; prevailing the %t1.bc copy as non-prevailing.
|
||||
; RUN: llvm-lto -thinlto-action=thinlink -o %t.index.bc %t2.bc %t1.bc
|
||||
; RUN: llvm-lto -thinlto-action=internalize -thinlto-index %t.index.bc %t1.bc -o - | llvm-dis -o - | FileCheck %s --check-prefix=REGULAR
|
||||
; RUN: llvm-lto -thinlto-action=internalize -thinlto-index %t.index.bc %t1.bc -o - --exported-symbol=foo | llvm-dis -o - | FileCheck %s --check-prefix=INTERNALIZE
|
||||
|
||||
@ -13,7 +16,10 @@
|
||||
; RUN: llvm-lto2 run %t1.bc -o %t.o -save-temps \
|
||||
; RUN: -r=%t1.bc,_foo,pxl \
|
||||
; RUN: -r=%t1.bc,_bar,pl \
|
||||
; RUN: -r=%t1.bc,_linkonce_func,pl
|
||||
; RUN: -r=%t1.bc,_linkonce_func,pl \
|
||||
; RUN: -r=%t1.bc,_weak_func_prevailing,pl \
|
||||
; RUN: -r=%t1.bc,_alias1,plx \
|
||||
; RUN: -r=%t1.bc,_weak_func_nonprevailing,l
|
||||
; RUN: llvm-dis < %t.o.1.2.internalize.bc | FileCheck %s --check-prefix=INTERNALIZE2
|
||||
|
||||
; Test the enable-lto-internalization option by setting it to false.
|
||||
@ -22,7 +28,10 @@
|
||||
; RUN: llvm-lto2 run %t1.bc -o %t.o -save-temps -enable-lto-internalization=false \
|
||||
; RUN: -r=%t1.bc,_foo,pxl \
|
||||
; RUN: -r=%t1.bc,_bar,pl \
|
||||
; RUN: -r=%t1.bc,_linkonce_func,pl
|
||||
; RUN: -r=%t1.bc,_linkonce_func,pl \
|
||||
; RUN: -r=%t1.bc,_weak_func_prevailing,pl \
|
||||
; RUN: -r=%t1.bc,_alias1,plx \
|
||||
; RUN: -r=%t1.bc,_weak_func_nonprevailing,l
|
||||
; RUN: llvm-dis < %t.o.1.2.internalize.bc | FileCheck %s --check-prefix=INTERNALIZE2-OPTION-DISABLE
|
||||
|
||||
; REGULAR: define void @foo
|
||||
@ -31,15 +40,23 @@
|
||||
; INTERNALIZE: define void @foo
|
||||
; INTERNALIZE: define internal void @bar
|
||||
; INTERNALIZE: define internal void @linkonce_func()
|
||||
; INTERNALIZE: define internal void @weak_func_prevailing()
|
||||
; INTERNALIZE: define weak void @weak_func_nonprevailing()
|
||||
; INTERNALIZE-OPTION-DISABLE: define void @foo
|
||||
; INTERNALIZE-OPTION-DISABLE: define void @bar
|
||||
; INTERNALIZE-OPTION-DISABLE: define weak void @linkonce_func()
|
||||
; INTERNALIZE-OPTION-DISABLE: define weak void @weak_func_prevailing()
|
||||
; INTERNALIZE-OPTION-DISABLE: define weak void @weak_func_nonprevailing()
|
||||
; INTERNALIZE2: define dso_local void @foo
|
||||
; INTERNALIZE2: define internal void @bar
|
||||
; INTERNALIZE2: define internal void @linkonce_func()
|
||||
; INTERNALIZE2: define internal void @weak_func_prevailing()
|
||||
; INTERNALIZE2: define weak dso_local void @weak_func_nonprevailing()
|
||||
; INTERNALIZE2-OPTION-DISABLE: define dso_local void @foo
|
||||
; INTERNALIZE2-OPTION-DISABLE: define dso_local void @bar
|
||||
; INTERNALIZE2-OPTION-DISABLE: define weak dso_local void @linkonce_func()
|
||||
; INTERNALIZE2-OPTION-DISABLE: define weak dso_local void @weak_func_prevailing()
|
||||
; INTERNALIZE2-OPTION-DISABLE: define weak dso_local void @weak_func_nonprevailing()
|
||||
|
||||
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-apple-macosx10.11.0"
|
||||
@ -50,8 +67,20 @@ define void @foo() {
|
||||
}
|
||||
define void @bar() {
|
||||
call void @linkonce_func()
|
||||
call void @weak_func_prevailing()
|
||||
call void @weak_func_nonprevailing()
|
||||
ret void
|
||||
}
|
||||
define linkonce void @linkonce_func() {
|
||||
ret void
|
||||
}
|
||||
define weak void @weak_func_prevailing() {
|
||||
ret void
|
||||
}
|
||||
; Make @weak_func_nonprevailing an aliasee to ensure it is still marked
|
||||
; live and kept as a definition even when non-prevailing. We want to ensure
|
||||
; this definition is not internalized.
|
||||
@alias1 = hidden alias void (), void ()* @weak_func_nonprevailing
|
||||
define weak void @weak_func_nonprevailing() {
|
||||
ret void
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user