Drop struct type names before the thin link instead of renaming promoted locals

The partitions of a program build have no locals for ThinLTO to promote:
symbols that other partitions refer to are already hidden. What changed
the modules after importing, and with them the object cache keys, of
partitions an edit did not touch was the numbering of struct types. Every
partition declares the program's types under the same names, and the thin
link loads the importing partition and the partitions it imports from into
one context, which tells same-named types apart by appending a counter
that runs across the whole link. An edit that adds a type anywhere shifted
the counter.

Partitions now drop the names of their struct types before their summary
is written; importing matches unnamed types by their bodies. The
promoted-locals option, the per-partition source file name and the
partition index in the summary key are removed.
This commit is contained in:
Chris Tate
2026-10-24 17:47:58 -05:00
parent 9e4f1253c6
commit 65555dace3
2 changed files with 14 additions and 33 deletions
+13 -32
View File
@@ -170,33 +170,18 @@ void limitProfileImports() {
(void)Limited;
}
// ThinLTO renames the locals it promotes so that the code other partitions
// import can refer to them: switch tables, constants and the other private
// symbols optimization creates. By default the new name carries a hash of
// the defining partition's whole bitcode, so an edit anywhere in a partition
// renames them in every partition that imports from it, and those partitions
// miss the object cache although their own code is unchanged. Named after
// the partition instead (PartitionSourceName), they keep their names while
// the partition changes. The option is process-wide; the helper sets it once.
void stablePromotedNames() {
static const bool Set = [] {
StringRef Name = "use-source-filename-for-promoted-locals";
if (cl::Option *Option = cl::getRegisteredOptions().lookup(Name))
Option->addOccurrence(0, Name, "true");
return true;
}();
(void)Set;
}
// Gives a partition's module its own source file name, which the names of
// the locals ThinLTO promotes derive from (stablePromotedNames). It runs
// after the pre-link optimization, so profile annotation still matches the
// program's local functions under their source path.
struct PartitionSourceName : PassInfoMixin<PartitionSourceName> {
explicit PartitionSourceName(std::string Name) : Name(std::move(Name)) {}
std::string Name;
// Drops the names of a partition's struct types before its summary is
// written. Every partition declares the program's types under the same
// names, and a thin link loads the importing partition and the partitions
// it imports from into one context, which tells same-named types apart by
// appending a counter that runs across the whole link. An edit that adds a
// type anywhere shifts the counter, so the module after importing, the
// object cache key, changed in partitions whose code had not. Unnamed types
// carry no such suffix; importing still matches them by their bodies.
struct UnnameStructTypes : PassInfoMixin<UnnameStructTypes> {
PreservedAnalyses run(Module &M, ModuleAnalysisManager &) {
M.setSourceFileName(Name);
for (StructType *Type : M.getIdentifiedStructTypes())
Type->setName("");
return PreservedAnalyses::all();
}
static bool isRequired() { return true; }
@@ -591,12 +576,8 @@ compileOptimizedPartitions(const EmitOptions &Options,
size_t Count = Plan.Modules.size();
std::vector<std::unique_ptr<MemoryBuffer>> Summaries(Count);
SharedFailure Failures;
stablePromotedNames();
forEachPartition(Count, [&](size_t I) {
// The partition's index names its promoted locals, so it keys the
// summary with the partition's source.
std::string Key =
hashParts({Salt, "summary", std::to_string(I), Plan.Modules[I]});
std::string Key = hashParts({Salt, "summary", Plan.Modules[I]});
if ((Summaries[I] = Cache.lookup(Key, "bc")))
return;
std::string LookupError;
@@ -629,7 +610,7 @@ compileOptimizedPartitions(const EmitOptions &Options,
// link; the post-link optimization reads the annotated weights.
Pipeline P(*Machine, Level, profileOptions(Options));
ModulePassManager MPM = P.PB.buildThinLTOPreLinkDefaultPipeline(Level);
MPM.addPass(PartitionSourceName("scriptc-partition-" + std::to_string(I)));
MPM.addPass(UnnameStructTypes());
MPM.addPass(BitcodeWriterPass(Stream, /*ShouldPreserveUseListOrder=*/false,
/*EmitSummaryIndex=*/true,
/*EmitModuleHash=*/true));