Skip to content

Commit 329ba52

Browse files
[LTO][NFC] Free the GlobalResolutions map after final use (#76780)
The GlobalResolutions map was found to contribute ~9% of the peak memory of a large thin link. However, we are essentially done with it when we are about to compute cross module imports, which itself adds to the peak memory due to the import and export lists (there is one use just after importing but it can easily be moved before importing). Move the last use up above importing, and free the GlobalResolutions map after that (and before importing). To help guard against future inadvertent use after it has been released, change it to a std::optional.
1 parent 7837110 commit 329ba52

File tree

2 files changed

+26
-14
lines changed

2 files changed

+26
-14
lines changed

llvm/include/llvm/LTO/LTO.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -404,7 +404,9 @@ class LTO {
404404
};
405405

406406
// Global mapping from mangled symbol names to resolutions.
407-
StringMap<GlobalResolution> GlobalResolutions;
407+
// Make this an optional to guard against accessing after it has been reset
408+
// (to reduce memory after we're done with it).
409+
std::optional<StringMap<GlobalResolution>> GlobalResolutions;
408410

409411
void addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
410412
ArrayRef<SymbolResolution> Res, unsigned Partition,

llvm/lib/LTO/LTO.cpp

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -592,7 +592,9 @@ LTO::LTO(Config Conf, ThinBackend Backend,
592592
unsigned ParallelCodeGenParallelismLevel, LTOKind LTOMode)
593593
: Conf(std::move(Conf)),
594594
RegularLTO(ParallelCodeGenParallelismLevel, this->Conf),
595-
ThinLTO(std::move(Backend)), LTOMode(LTOMode) {}
595+
ThinLTO(std::move(Backend)),
596+
GlobalResolutions(std::make_optional<StringMap<GlobalResolution>>()),
597+
LTOMode(LTOMode) {}
596598

597599
// Requires a destructor for MapVector<BitcodeModule>.
598600
LTO::~LTO() = default;
@@ -610,7 +612,7 @@ void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
610612
assert(ResI != ResE);
611613
SymbolResolution Res = *ResI++;
612614

613-
auto &GlobalRes = GlobalResolutions[Sym.getName()];
615+
auto &GlobalRes = (*GlobalResolutions)[Sym.getName()];
614616
GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr();
615617
if (Res.Prevailing) {
616618
assert(!GlobalRes.Prevailing &&
@@ -1125,7 +1127,7 @@ Error LTO::run(AddStreamFn AddStream, FileCache Cache) {
11251127
// Compute "dead" symbols, we don't want to import/export these!
11261128
DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
11271129
DenseMap<GlobalValue::GUID, PrevailingType> GUIDPrevailingResolutions;
1128-
for (auto &Res : GlobalResolutions) {
1130+
for (auto &Res : *GlobalResolutions) {
11291131
// Normally resolution have IR name of symbol. We can do nothing here
11301132
// otherwise. See comments in GlobalResolution struct for more details.
11311133
if (Res.second.IRName.empty())
@@ -1169,6 +1171,8 @@ Error LTO::run(AddStreamFn AddStream, FileCache Cache) {
11691171

11701172
Error Result = runRegularLTO(AddStream);
11711173
if (!Result)
1174+
// This will reset the GlobalResolutions optional once done with it to
1175+
// reduce peak memory before importing.
11721176
Result = runThinLTO(AddStream, Cache, GUIDPreservedSymbols);
11731177

11741178
if (StatsFile)
@@ -1273,8 +1277,8 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
12731277
// This returns true when the name is local or not defined. Locals are
12741278
// expected to be handled separately.
12751279
auto IsVisibleToRegularObj = [&](StringRef name) {
1276-
auto It = GlobalResolutions.find(name);
1277-
return (It == GlobalResolutions.end() || It->second.VisibleOutsideSummary);
1280+
auto It = GlobalResolutions->find(name);
1281+
return (It == GlobalResolutions->end() || It->second.VisibleOutsideSummary);
12781282
};
12791283

12801284
// If allowed, upgrade public vcall visibility metadata to linkage unit
@@ -1291,7 +1295,7 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
12911295
return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
12921296

12931297
if (!Conf.CodeGenOnly) {
1294-
for (const auto &R : GlobalResolutions) {
1298+
for (const auto &R : *GlobalResolutions) {
12951299
GlobalValue *GV =
12961300
RegularLTO.CombinedModule->getNamedValue(R.second.IRName);
12971301
if (!R.second.isPrevailingIRSymbol())
@@ -1708,8 +1712,8 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
17081712
// This returns true when the name is local or not defined. Locals are
17091713
// expected to be handled separately.
17101714
auto IsVisibleToRegularObj = [&](StringRef name) {
1711-
auto It = GlobalResolutions.find(name);
1712-
return (It == GlobalResolutions.end() ||
1715+
auto It = GlobalResolutions->find(name);
1716+
return (It == GlobalResolutions->end() ||
17131717
It->second.VisibleOutsideSummary);
17141718
};
17151719

@@ -1739,15 +1743,11 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
17391743
ContextDisambiguation.run(ThinLTO.CombinedIndex, isPrevailing);
17401744
}
17411745

1742-
if (Conf.OptLevel > 0)
1743-
ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
1744-
isPrevailing, ImportLists, ExportLists);
1745-
17461746
// Figure out which symbols need to be internalized. This also needs to happen
17471747
// at -O0 because summary-based DCE is implemented using internalization, and
17481748
// we must apply DCE consistently with the full LTO module in order to avoid
17491749
// undefined references during the final link.
1750-
for (auto &Res : GlobalResolutions) {
1750+
for (auto &Res : *GlobalResolutions) {
17511751
// If the symbol does not have external references or it is not prevailing,
17521752
// then not need to mark it as exported from a ThinLTO partition.
17531753
if (Res.second.Partition != GlobalResolution::External ||
@@ -1760,6 +1760,16 @@ Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
17601760
ExportedGUIDs.insert(GUID);
17611761
}
17621762

1763+
// Reset the GlobalResolutions to deallocate the associated memory, as there
1764+
// are no further accesses. We specifically want to do this before computing
1765+
// cross module importing, which adds to peak memory via the computed import
1766+
// and export lists.
1767+
GlobalResolutions.reset();
1768+
1769+
if (Conf.OptLevel > 0)
1770+
ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
1771+
isPrevailing, ImportLists, ExportLists);
1772+
17631773
// Any functions referenced by the jump table in the regular LTO object must
17641774
// be exported.
17651775
for (auto &Def : ThinLTO.CombinedIndex.cfiFunctionDefs())

0 commit comments

Comments
 (0)