diff --git a/native/llvm-codegen/README.md b/native/llvm-codegen/README.md index d72aebdfd..70c118202 100644 --- a/native/llvm-codegen/README.md +++ b/native/llvm-codegen/README.md @@ -37,7 +37,7 @@ Repeating `--output` divides the program into that many partitions, which are co WebAssembly code generation differs from LLVM's default pipeline in two ways that do not change its output. The pass that gives multiple-entry loops a single entry runs only on functions whose control flow is irreducible; its reachability analysis grows with the square of a function's block count even when it has nothing to change. Object emission also leaves out the module pass that collects external symbols for assembly declarations, so each function's machine code is freed once it is printed instead of when the whole module is compiled. -`--cache-dir ` names a private directory the caller owns for one helper build. Simplified partitions are stored under the hash of their exact source and objects under the hash of the exact module after importing, each with a trailing digest and published by rename, so a rebuild recompiles only the partitions an edit can affect. The locals ThinLTO promotes for importing are named after their partition rather than a hash of its bitcode, so an edit to one partition leaves the partitions that import from it unchanged. +`--cache-dir ` names a private directory the caller owns for one helper build. Simplified partitions are stored under the hash of their exact source and objects under the hash of the exact module after importing, each with a trailing digest and published by rename, so a rebuild recompiles only the partitions an edit can affect. Partitions drop the names of their struct types before the thin link, which would otherwise number same-named types from different partitions in an order that any edit can shift, changing the module after importing in partitions the edit did not touch. `--import-bitcode `, given once per runtime-pack unit that ships bitcode, imports runtime functions for inlining; scriptc's program builds do not pass it. Small runtime functions reachable from the program's runtime calls are imported as `available_externally` so LLVM can inline them; the runtime objects remain the only definitions. The helper never runs a sanitizer pass, so with import it also drops the emitter's inert `sanitize_address` attributes, which would otherwise block that inlining. Without `--import-bitcode` the module is optimized exactly as emitted. diff --git a/native/llvm-codegen/src/emit.cpp b/native/llvm-codegen/src/emit.cpp index 4e8c7a30c..c087dead8 100644 --- a/native/llvm-codegen/src/emit.cpp +++ b/native/llvm-codegen/src/emit.cpp @@ -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 { - 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 { 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> 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));