Skip to content

Commit 377e131

Browse files
committed
[ThinLTO] Only import for non-prevailing interposable global variables
This logic was added in https://reviews.llvm.org/D95943 specifically to handle an issue for non-prevailing global variables. It turns out that it adds a new issue for prevailing glboal variables, since those could be replaced by an available_externally definition and hence incorrectly omitted from the output object file. Limit the import to non-prevailing global variables to fix this, as suggested by @tejohnson. The bulk of the diff is mechanical changes to thread isPrevailing through to where it's needed and ensure it's available before the relevant calls; the actual logic change itself is straightforward. Fixes #61677 Reviewed By: tejohnson Differential Revision: https://reviews.llvm.org/D146876
1 parent 943df86 commit 377e131

File tree

6 files changed

+126
-45
lines changed

6 files changed

+126
-45
lines changed

llvm/include/llvm/Transforms/IPO/FunctionImport.h

+6-2
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,8 @@ class FunctionImportPass : public PassInfoMixin<FunctionImportPass> {
146146
void ComputeCrossModuleImport(
147147
const ModuleSummaryIndex &Index,
148148
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
149+
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
150+
isPrevailing,
149151
StringMap<FunctionImporter::ImportMapTy> &ImportLists,
150152
StringMap<FunctionImporter::ExportSetTy> &ExportLists);
151153

@@ -154,8 +156,10 @@ void ComputeCrossModuleImport(
154156
/// \p ImportList will be populated with a map that can be passed to
155157
/// FunctionImporter::importFunctions() above (see description there).
156158
void ComputeCrossModuleImportForModule(
157-
StringRef ModulePath, const ModuleSummaryIndex &Index,
158-
FunctionImporter::ImportMapTy &ImportList);
159+
StringRef ModulePath,
160+
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
161+
isPrevailing,
162+
const ModuleSummaryIndex &Index, FunctionImporter::ImportMapTy &ImportList);
159163

160164
/// Mark all external summaries in \p Index for import into the given module.
161165
/// Used for distributed builds using a distributed index.

llvm/lib/LTO/LTO.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1553,7 +1553,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
15531553

15541554
if (Conf.OptLevel > 0)
15551555
ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
1556-
ImportLists, ExportLists);
1556+
isPrevailing, ImportLists, ExportLists);
15571557

15581558
// Figure out which symbols need to be internalized. This also needs to happen
15591559
// at -O0 because summary-based DCE is implemented using internalization, and

llvm/lib/LTO/ThinLTOCodeGenerator.cpp

+36-15
Original file line numberDiff line numberDiff line change
@@ -714,15 +714,17 @@ void ThinLTOCodeGenerator::promote(Module &TheModule, ModuleSummaryIndex &Index,
714714
// Compute "dead" symbols, we don't want to import/export these!
715715
computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols);
716716

717+
// Compute prevailing symbols
718+
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
719+
computePrevailingCopies(Index, PrevailingCopy);
720+
717721
// Generate import/export list
718722
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
719723
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
720-
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
724+
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries,
725+
IsPrevailing(PrevailingCopy), ImportLists,
721726
ExportLists);
722727

723-
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
724-
computePrevailingCopies(Index, PrevailingCopy);
725-
726728
// Resolve prevailing symbols
727729
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
728730
resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols,
@@ -764,10 +766,15 @@ void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule,
764766
// Compute "dead" symbols, we don't want to import/export these!
765767
computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols);
766768

769+
// Compute prevailing symbols
770+
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
771+
computePrevailingCopies(Index, PrevailingCopy);
772+
767773
// Generate import/export list
768774
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
769775
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
770-
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
776+
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries,
777+
IsPrevailing(PrevailingCopy), ImportLists,
771778
ExportLists);
772779
auto &ImportList = ImportLists[TheModule.getModuleIdentifier()];
773780

@@ -799,10 +806,15 @@ void ThinLTOCodeGenerator::gatherImportedSummariesForModule(
799806
// Compute "dead" symbols, we don't want to import/export these!
800807
computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols);
801808

809+
// Compute prevailing symbols
810+
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
811+
computePrevailingCopies(Index, PrevailingCopy);
812+
802813
// Generate import/export list
803814
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
804815
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
805-
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
816+
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries,
817+
IsPrevailing(PrevailingCopy), ImportLists,
806818
ExportLists);
807819

808820
llvm::gatherImportedSummariesForModule(
@@ -832,10 +844,15 @@ void ThinLTOCodeGenerator::emitImports(Module &TheModule, StringRef OutputName,
832844
// Compute "dead" symbols, we don't want to import/export these!
833845
computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols);
834846

847+
// Compute prevailing symbols
848+
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
849+
computePrevailingCopies(Index, PrevailingCopy);
850+
835851
// Generate import/export list
836852
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
837853
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
838-
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
854+
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries,
855+
IsPrevailing(PrevailingCopy), ImportLists,
839856
ExportLists);
840857

841858
std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
@@ -874,10 +891,15 @@ void ThinLTOCodeGenerator::internalize(Module &TheModule,
874891
// Compute "dead" symbols, we don't want to import/export these!
875892
computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols);
876893

894+
// Compute prevailing symbols
895+
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
896+
computePrevailingCopies(Index, PrevailingCopy);
897+
877898
// Generate import/export list
878899
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
879900
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
880-
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists,
901+
ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries,
902+
IsPrevailing(PrevailingCopy), ImportLists,
881903
ExportLists);
882904
auto &ExportList = ExportLists[ModuleIdentifier];
883905

@@ -886,9 +908,6 @@ void ThinLTOCodeGenerator::internalize(Module &TheModule,
886908
if (ExportList.empty() && GUIDPreservedSymbols.empty())
887909
return;
888910

889-
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
890-
computePrevailingCopies(Index, PrevailingCopy);
891-
892911
// Resolve prevailing symbols
893912
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
894913
resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols,
@@ -1068,11 +1087,16 @@ void ThinLTOCodeGenerator::run() {
10681087
for (auto GUID : ExportedGUIDs)
10691088
GUIDPreservedSymbols.insert(GUID);
10701089

1090+
// Compute prevailing symbols
1091+
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
1092+
computePrevailingCopies(*Index, PrevailingCopy);
1093+
10711094
// Collect the import/export lists for all modules from the call-graph in the
10721095
// combined index.
10731096
StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount);
10741097
StringMap<FunctionImporter::ExportSetTy> ExportLists(ModuleCount);
1075-
ComputeCrossModuleImport(*Index, ModuleToDefinedGVSummaries, ImportLists,
1098+
ComputeCrossModuleImport(*Index, ModuleToDefinedGVSummaries,
1099+
IsPrevailing(PrevailingCopy), ImportLists,
10761100
ExportLists);
10771101

10781102
// We use a std::map here to be able to have a defined ordering when
@@ -1081,9 +1105,6 @@ void ThinLTOCodeGenerator::run() {
10811105
// on the index, and nuke this map.
10821106
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
10831107

1084-
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
1085-
computePrevailingCopies(*Index, PrevailingCopy);
1086-
10871108
// Resolve prevailing symbols, this has to be computed early because it
10881109
// impacts the caching.
10891110
resolvePrevailingInIndex(*Index, ResolvedODR, GUIDPreservedSymbols,

llvm/lib/Transforms/IPO/FunctionImport.cpp

+52-27
Original file line numberDiff line numberDiff line change
@@ -245,24 +245,25 @@ using EdgeInfo =
245245

246246
} // anonymous namespace
247247

248-
static bool shouldImportGlobal(const ValueInfo &VI,
249-
const GVSummaryMapTy &DefinedGVSummaries) {
248+
static bool shouldImportGlobal(
249+
const ValueInfo &VI, const GVSummaryMapTy &DefinedGVSummaries,
250+
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
251+
isPrevailing) {
250252
const auto &GVS = DefinedGVSummaries.find(VI.getGUID());
251253
if (GVS == DefinedGVSummaries.end())
252254
return true;
253-
// We should not skip import if the module contains a definition with
254-
// interposable linkage type. This is required for correctness in
255-
// the situation with two following conditions:
256-
// * the def with interposable linkage is non-prevailing,
257-
// * there is a prevailing def available for import and marked read-only.
258-
// In this case, the non-prevailing def will be converted to a declaration,
259-
// while the prevailing one becomes internal, thus no definitions will be
260-
// available for linking. In order to prevent undefined symbol link error,
261-
// the prevailing definition must be imported.
255+
// We should not skip import if the module contains a non-prevailing
256+
// definition with interposable linkage type. This is required for correctness
257+
// in the situation where there is a prevailing def available for import and
258+
// marked read-only. In this case, the non-prevailing def will be converted to
259+
// a declaration, while the prevailing one becomes internal, thus no
260+
// definitions will be available for linking. In order to prevent undefined
261+
// symbol link error, the prevailing definition must be imported.
262262
// FIXME: Consider adding a check that the suitable prevailing definition
263263
// exists and marked read-only.
264264
if (VI.getSummaryList().size() > 1 &&
265-
GlobalValue::isInterposableLinkage(GVS->second->linkage()))
265+
GlobalValue::isInterposableLinkage(GVS->second->linkage()) &&
266+
!isPrevailing(VI.getGUID(), GVS->second))
266267
return true;
267268

268269
return false;
@@ -271,11 +272,13 @@ static bool shouldImportGlobal(const ValueInfo &VI,
271272
static void computeImportForReferencedGlobals(
272273
const GlobalValueSummary &Summary, const ModuleSummaryIndex &Index,
273274
const GVSummaryMapTy &DefinedGVSummaries,
275+
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
276+
isPrevailing,
274277
SmallVectorImpl<EdgeInfo> &Worklist,
275278
FunctionImporter::ImportMapTy &ImportList,
276279
StringMap<FunctionImporter::ExportSetTy> *ExportLists) {
277280
for (const auto &VI : Summary.refs()) {
278-
if (!shouldImportGlobal(VI, DefinedGVSummaries)) {
281+
if (!shouldImportGlobal(VI, DefinedGVSummaries, isPrevailing)) {
279282
LLVM_DEBUG(
280283
dbgs() << "Ref ignored! Target already in destination module.\n");
281284
continue;
@@ -348,12 +351,15 @@ getFailureName(FunctionImporter::ImportFailureReason Reason) {
348351
static void computeImportForFunction(
349352
const FunctionSummary &Summary, const ModuleSummaryIndex &Index,
350353
const unsigned Threshold, const GVSummaryMapTy &DefinedGVSummaries,
354+
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
355+
isPrevailing,
351356
SmallVectorImpl<EdgeInfo> &Worklist,
352357
FunctionImporter::ImportMapTy &ImportList,
353358
StringMap<FunctionImporter::ExportSetTy> *ExportLists,
354359
FunctionImporter::ImportThresholdsTy &ImportThresholds) {
355360
computeImportForReferencedGlobals(Summary, Index, DefinedGVSummaries,
356-
Worklist, ImportList, ExportLists);
361+
isPrevailing, Worklist, ImportList,
362+
ExportLists);
357363
static int ImportCount = 0;
358364
for (const auto &Edge : Summary.calls()) {
359365
ValueInfo VI = Edge.first;
@@ -519,8 +525,11 @@ static void computeImportForFunction(
519525
/// as well as the list of "exports", i.e. the list of symbols referenced from
520526
/// another module (that may require promotion).
521527
static void ComputeImportForModule(
522-
const GVSummaryMapTy &DefinedGVSummaries, const ModuleSummaryIndex &Index,
523-
StringRef ModName, FunctionImporter::ImportMapTy &ImportList,
528+
const GVSummaryMapTy &DefinedGVSummaries,
529+
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
530+
isPrevailing,
531+
const ModuleSummaryIndex &Index, StringRef ModName,
532+
FunctionImporter::ImportMapTy &ImportList,
524533
StringMap<FunctionImporter::ExportSetTy> *ExportLists = nullptr) {
525534
// Worklist contains the list of function imported in this module, for which
526535
// we will analyse the callees and may import further down the callgraph.
@@ -546,8 +555,8 @@ static void ComputeImportForModule(
546555
continue;
547556
LLVM_DEBUG(dbgs() << "Initialize import for " << VI << "\n");
548557
computeImportForFunction(*FuncSummary, Index, ImportInstrLimit,
549-
DefinedGVSummaries, Worklist, ImportList,
550-
ExportLists, ImportThresholds);
558+
DefinedGVSummaries, isPrevailing, Worklist,
559+
ImportList, ExportLists, ImportThresholds);
551560
}
552561

553562
// Process the newly imported functions and add callees to the worklist.
@@ -558,11 +567,12 @@ static void ComputeImportForModule(
558567

559568
if (auto *FS = dyn_cast<FunctionSummary>(Summary))
560569
computeImportForFunction(*FS, Index, Threshold, DefinedGVSummaries,
561-
Worklist, ImportList, ExportLists,
570+
isPrevailing, Worklist, ImportList, ExportLists,
562571
ImportThresholds);
563572
else
564573
computeImportForReferencedGlobals(*Summary, Index, DefinedGVSummaries,
565-
Worklist, ImportList, ExportLists);
574+
isPrevailing, Worklist, ImportList,
575+
ExportLists);
566576
}
567577

568578
// Print stats about functions considered but rejected for importing
@@ -653,14 +663,16 @@ checkVariableImport(const ModuleSummaryIndex &Index,
653663
void llvm::ComputeCrossModuleImport(
654664
const ModuleSummaryIndex &Index,
655665
const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
666+
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
667+
isPrevailing,
656668
StringMap<FunctionImporter::ImportMapTy> &ImportLists,
657669
StringMap<FunctionImporter::ExportSetTy> &ExportLists) {
658670
// For each module that has function defined, compute the import/export lists.
659671
for (const auto &DefinedGVSummaries : ModuleToDefinedGVSummaries) {
660672
auto &ImportList = ImportLists[DefinedGVSummaries.first()];
661673
LLVM_DEBUG(dbgs() << "Computing import for Module '"
662674
<< DefinedGVSummaries.first() << "'\n");
663-
ComputeImportForModule(DefinedGVSummaries.second, Index,
675+
ComputeImportForModule(DefinedGVSummaries.second, isPrevailing, Index,
664676
DefinedGVSummaries.first(), ImportList,
665677
&ExportLists);
666678
}
@@ -759,7 +771,10 @@ static void dumpImportListForModule(const ModuleSummaryIndex &Index,
759771

760772
/// Compute all the imports for the given module in the Index.
761773
void llvm::ComputeCrossModuleImportForModule(
762-
StringRef ModulePath, const ModuleSummaryIndex &Index,
774+
StringRef ModulePath,
775+
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
776+
isPrevailing,
777+
const ModuleSummaryIndex &Index,
763778
FunctionImporter::ImportMapTy &ImportList) {
764779
// Collect the list of functions this module defines.
765780
// GUID -> Summary
@@ -768,7 +783,8 @@ void llvm::ComputeCrossModuleImportForModule(
768783

769784
// Compute the import list for this module.
770785
LLVM_DEBUG(dbgs() << "Computing import for Module '" << ModulePath << "'\n");
771-
ComputeImportForModule(FunctionSummaryMap, Index, ModulePath, ImportList);
786+
ComputeImportForModule(FunctionSummaryMap, isPrevailing, Index, ModulePath,
787+
ImportList);
772788

773789
#ifndef NDEBUG
774790
dumpImportListForModule(Index, ModulePath, ImportList);
@@ -1395,7 +1411,9 @@ Expected<bool> FunctionImporter::importFunctions(
13951411
return ImportedCount;
13961412
}
13971413

1398-
static bool doImportingForModule(Module &M) {
1414+
static bool doImportingForModule(
1415+
Module &M, function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
1416+
isPrevailing) {
13991417
if (SummaryFile.empty())
14001418
report_fatal_error("error: -function-import requires -summary-file\n");
14011419
Expected<std::unique_ptr<ModuleSummaryIndex>> IndexPtrOrErr =
@@ -1416,8 +1434,8 @@ static bool doImportingForModule(Module &M) {
14161434
ComputeCrossModuleImportForModuleFromIndex(M.getModuleIdentifier(), *Index,
14171435
ImportList);
14181436
else
1419-
ComputeCrossModuleImportForModule(M.getModuleIdentifier(), *Index,
1420-
ImportList);
1437+
ComputeCrossModuleImportForModule(M.getModuleIdentifier(), isPrevailing,
1438+
*Index, ImportList);
14211439

14221440
// Conservatively mark all internal values as promoted. This interface is
14231441
// only used when doing importing via the function importing pass. The pass
@@ -1458,7 +1476,14 @@ static bool doImportingForModule(Module &M) {
14581476

14591477
PreservedAnalyses FunctionImportPass::run(Module &M,
14601478
ModuleAnalysisManager &AM) {
1461-
if (!doImportingForModule(M))
1479+
// This is only used for testing the function import pass via opt, where we
1480+
// don't have prevailing information from the LTO context available, so just
1481+
// conservatively assume everything is prevailing (which is fine for the very
1482+
// limited use of prevailing checking in this pass).
1483+
auto isPrevailing = [](GlobalValue::GUID, const GlobalValueSummary *) {
1484+
return true;
1485+
};
1486+
if (!doImportingForModule(M, isPrevailing))
14621487
return PreservedAnalyses::all();
14631488

14641489
return PreservedAnalyses::none();
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
; RUN: split-file %s %t
2+
3+
; RUN: opt -module-summary %t/av_ext_def.ll -o %t/av_ext_def.bc
4+
; RUN: opt -module-summary %t/weak_def.ll -o %t/weak_def.bc
5+
; RUN: llvm-lto2 run -o %t/prevailing_import -save-temps %t/av_ext_def.bc %t/weak_def.bc \
6+
; RUN: -r=%t/av_ext_def.bc,ret_av_ext_def,px -r=%t/av_ext_def.bc,def,x \
7+
; RUN: -r=%t/weak_def.bc,ret_weak_def,px -r=%t/weak_def.bc,def,px
8+
; RUN: llvm-dis %t/prevailing_import.2.3.import.bc -o - | FileCheck --match-full-lines --check-prefix=WEAK_DEF %s
9+
; RUN: llvm-nm -jU %t/prevailing_import.2 | FileCheck --match-full-lines --check-prefix=NM %s
10+
11+
;; def should remain weak after function importing in the weak_def module
12+
; WEAK_DEF: @def = weak constant i32 0
13+
14+
;; It should also be defined in the corresponding object file
15+
; NM: def
16+
17+
;--- av_ext_def.ll
18+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
19+
target triple = "x86_64-unknown-linux-gnu"
20+
@def = available_externally constant i32 0
21+
define ptr @ret_av_ext_def() {
22+
ret ptr @def
23+
}
24+
25+
;--- weak_def.ll
26+
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
27+
target triple = "x86_64-unknown-linux-gnu"
28+
@def = weak constant i32 0
29+
define ptr @ret_weak_def() {
30+
ret ptr @def
31+
}

0 commit comments

Comments
 (0)