[LLD][COFF] Add more --time-trace tags for ThinLTO linking (#156471)

In order to better see what's going on during ThinLTO linking, this PR
adds more profile tags when using `--time-trace` on a `lld-link.exe`
invocation.

After PR, linking `clang.exe`:

<img width="3839" height="2026" alt="Capture d’écran 2025-09-02 082021"
src="https://github.com/user-attachments/assets/bf0c85ba-2f85-4bbf-a5c1-800039b56910"
/>

Linking a custom (Unreal Engine game) binary gives a completly
different picture, probably because of using Unity files, and the sheer
amount of input files (here, providing over 60 GB of .OBJs/.LIBs).

<img width="1940" height="1008" alt="Capture d’écran 2025-09-02 102048"
src="https://github.com/user-attachments/assets/60b28630-7995-45ce-9e8c-13f3cb5312e0"
/>
This commit is contained in:
Alexandre Ganea 2025-09-05 15:28:19 -04:00 committed by GitHub
parent a549e73cad
commit 5cda2424c8
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 170 additions and 111 deletions

View File

@ -26,6 +26,7 @@
#include "llvm/Support/Caching.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <cstddef>
#include <memory>
@ -176,6 +177,7 @@ void BitcodeCompiler::add(BitcodeFile &f) {
// Merge all the bitcode files we have seen, codegen the result
// and return the resulting objects.
std::vector<InputFile *> BitcodeCompiler::compile() {
llvm::TimeTraceScope timeScope("Bitcode compile");
unsigned maxTasks = ltoObj->getMaxTasks();
buf.resize(maxTasks);
files.resize(maxTasks);

View File

@ -1437,11 +1437,13 @@ void SymbolTable::compileBitcodeFiles() {
if (bitcodeFileInstances.empty())
return;
llvm::TimeTraceScope timeScope("Compile bitcode");
ScopedTimer t(ctx.ltoTimer);
lto.reset(new BitcodeCompiler(ctx));
for (BitcodeFile *f : bitcodeFileInstances)
lto->add(*f);
{
llvm::TimeTraceScope addScope("Add bitcode file instances");
for (BitcodeFile *f : bitcodeFileInstances)
lto->add(*f);
}
for (InputFile *newObj : lto->compile()) {
ObjFile *obj = cast<ObjFile>(newObj);
obj->parse();

View File

@ -43,6 +43,7 @@
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TimeProfiler.h"
#include <algorithm>
#include <cassert>
@ -1052,6 +1053,7 @@ void MetadataLoader::MetadataLoaderImpl::callMDTypeCallback(Metadata **Val,
/// Parse a METADATA_BLOCK. If ModuleLevel is true then we are parsing
/// module level metadata.
Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
llvm::TimeTraceScope timeScope("Parse metadata");
if (!ModuleLevel && MetadataList.hasFwdRefs())
return error("Invalid metadata: fwd refs into function blocks");

View File

@ -48,6 +48,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/NVPTXAddrSpace.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/TargetParser/Triple.h"
#include <cstdint>
#include <cstring>
@ -5256,6 +5257,7 @@ bool llvm::UpgradeDebugInfo(Module &M) {
if (DisableAutoUpgradeDebugInfo)
return false;
llvm::TimeTraceScope timeScope("Upgrade debug info");
// We need to get metadata before the module is verified (i.e., getModuleFlag
// makes assumptions that we haven't verified yet). Carefully extract the flag
// from the metadata.

View File

@ -36,6 +36,7 @@
#include "llvm/IR/Module.h"
#include "llvm/IR/PassManager.h"
#include "llvm/Support/Casting.h"
#include "llvm/Support/TimeProfiler.h"
#include <algorithm>
#include <cassert>
#include <optional>
@ -563,6 +564,7 @@ bool llvm::stripDebugInfo(Function &F) {
}
bool llvm::StripDebugInfo(Module &M) {
llvm::TimeTraceScope timeScope("Strip debug info");
bool Changed = false;
for (NamedMDNode &NMD : llvm::make_early_inc_range(M.named_metadata())) {

View File

@ -44,6 +44,7 @@
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/RandomNumberGenerator.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/VersionTuple.h"
#include <cassert>
#include <cstdint>
@ -478,6 +479,7 @@ Error Module::materializeAll() {
}
Error Module::materializeMetadata() {
llvm::TimeTraceScope timeScope("Materialize metadata");
if (!Materializer)
return Error::success();
return Materializer->materializeMetadata();

View File

@ -119,6 +119,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/ModRef.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <cassert>
@ -399,6 +400,7 @@ public:
bool hasBrokenDebugInfo() const { return BrokenDebugInfo; }
bool verify(const Function &F) {
llvm::TimeTraceScope timeScope("Verifier");
assert(F.getParent() == &M &&
"An instance of this class only works with a specific module!");
@ -2822,6 +2824,7 @@ static Instruction *getSuccPad(Instruction *Terminator) {
}
void Verifier::verifySiblingFuncletUnwinds() {
llvm::TimeTraceScope timeScope("Verifier verify sibling funclet unwinds");
SmallPtrSet<Instruction *, 8> Visited;
SmallPtrSet<Instruction *, 8> Active;
for (const auto &Pair : SiblingFuncletInfo) {

View File

@ -631,6 +631,7 @@ LTO::~LTO() = default;
void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
ArrayRef<SymbolResolution> Res,
unsigned Partition, bool InSummary) {
llvm::TimeTraceScope timeScope("LTO add module to global resolution");
auto *ResI = Res.begin();
auto *ResE = Res.end();
(void)ResE;
@ -731,6 +732,7 @@ static void writeToResolutionFile(raw_ostream &OS, InputFile *Input,
Error LTO::add(std::unique_ptr<InputFile> Input,
ArrayRef<SymbolResolution> Res) {
llvm::TimeTraceScope timeScope("LTO add input", Input->getName());
assert(!CalledGetMaxTasks);
if (Conf.ResolutionFile)
@ -756,6 +758,7 @@ Error LTO::add(std::unique_ptr<InputFile> Input,
Expected<ArrayRef<SymbolResolution>>
LTO::addModule(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
unsigned ModI, ArrayRef<SymbolResolution> Res) {
llvm::TimeTraceScope timeScope("LTO add module", Input.getName());
Expected<BitcodeLTOInfo> LTOInfo = Input.Mods[ModI].getLTOInfo();
if (!LTOInfo)
return LTOInfo.takeError();
@ -850,6 +853,7 @@ Expected<
LTO::addRegularLTO(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
ArrayRef<SymbolResolution> Res) {
llvm::TimeTraceScope timeScope("LTO add regular LTO");
RegularLTOState::AddedModule Mod;
Expected<std::unique_ptr<Module>> MOrErr =
BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true,
@ -1024,6 +1028,7 @@ LTO::addRegularLTO(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod,
bool LivenessFromIndex) {
llvm::TimeTraceScope timeScope("LTO link regular LTO");
std::vector<GlobalValue *> Keep;
for (GlobalValue *GV : Mod.Keep) {
if (LivenessFromIndex && !ThinLTO.CombinedIndex.isGUIDLive(GV->getGUID())) {
@ -1063,6 +1068,7 @@ Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod,
Expected<ArrayRef<SymbolResolution>>
LTO::addThinLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
ArrayRef<SymbolResolution> Res) {
llvm::TimeTraceScope timeScope("LTO add thin LTO");
ArrayRef<SymbolResolution> ResTmp = Res;
for (const InputFile::Symbol &Sym : Syms) {
assert(!ResTmp.empty());
@ -1252,6 +1258,7 @@ Error LTO::run(AddStreamFn AddStream, FileCache Cache) {
void lto::updateMemProfAttributes(Module &Mod,
const ModuleSummaryIndex &Index) {
llvm::TimeTraceScope timeScope("LTO update memprof attributes");
if (Index.withSupportsHotColdNew())
return;
@ -1282,6 +1289,7 @@ void lto::updateMemProfAttributes(Module &Mod,
}
Error LTO::runRegularLTO(AddStreamFn AddStream) {
llvm::TimeTraceScope timeScope("Run regular LTO");
// Setup optimization remarks.
auto DiagFileOrErr = lto::setupLLVMOptimizationRemarks(
RegularLTO.CombinedModule->getContext(), Conf.RemarksFilename,
@ -1294,10 +1302,12 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
// Finalize linking of regular LTO modules containing summaries now that
// we have computed liveness information.
for (auto &M : RegularLTO.ModsWithSummaries)
if (Error Err = linkRegularLTO(std::move(M),
/*LivenessFromIndex=*/true))
return Err;
{
llvm::TimeTraceScope timeScope("Link regular LTO");
for (auto &M : RegularLTO.ModsWithSummaries)
if (Error Err = linkRegularLTO(std::move(M), /*LivenessFromIndex=*/true))
return Err;
}
// Ensure we don't have inconsistently split LTO units with type tests.
// FIXME: this checks both LTO and ThinLTO. It happens to work as we take
@ -1526,6 +1536,9 @@ public:
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, BitcodeModule> &ModuleMap) {
auto ModuleID = BM.getModuleIdentifier();
llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (in-process)",
ModuleID);
auto RunThinBackend = [&](AddStreamFn AddStream) {
LTOLLVMContext BackendContext(Conf);
Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(BackendContext);
@ -1536,9 +1549,6 @@ public:
ImportList, DefinedGlobals, &ModuleMap,
Conf.CodeGenOnly);
};
auto ModuleID = BM.getModuleIdentifier();
if (ShouldEmitIndexFiles) {
if (auto E = emitFiles(ImportList, ModuleID, ModuleID.str()))
return E;
@ -1639,6 +1649,9 @@ public:
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, BitcodeModule> &ModuleMap) override {
auto ModuleID = BM.getModuleIdentifier();
llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (first round)",
ModuleID);
auto RunThinBackend = [&](AddStreamFn CGAddStream,
AddStreamFn IRAddStream) {
LTOLLVMContext BackendContext(Conf);
@ -1650,8 +1663,6 @@ public:
ImportList, DefinedGlobals, &ModuleMap,
Conf.CodeGenOnly, IRAddStream);
};
auto ModuleID = BM.getModuleIdentifier();
// Like InProcessThinBackend, we produce index files as needed for
// FirstRoundThinBackend. However, these files are not generated for
// SecondRoundThinBackend.
@ -1735,6 +1746,9 @@ public:
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, BitcodeModule> &ModuleMap) override {
auto ModuleID = BM.getModuleIdentifier();
llvm::TimeTraceScope timeScope("Run ThinLTO backend thread (second round)",
ModuleID);
auto RunThinBackend = [&](AddStreamFn AddStream) {
LTOLLVMContext BackendContext(Conf);
std::unique_ptr<Module> LoadedModule =
@ -1744,8 +1758,6 @@ public:
ImportList, DefinedGlobals, &ModuleMap,
/*CodeGenOnly=*/true);
};
auto ModuleID = BM.getModuleIdentifier();
if (!Cache.isValid() || !CombinedIndex.modulePaths().count(ModuleID) ||
all_of(CombinedIndex.getModuleHash(ModuleID),
[](uint32_t V) { return V == 0; }))
@ -1915,6 +1927,7 @@ ThinBackend lto::createWriteIndexesThinBackend(
Error LTO::runThinLTO(AddStreamFn AddStream, FileCache Cache,
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) {
llvm::TimeTraceScope timeScope("Run ThinLTO");
LLVM_DEBUG(dbgs() << "Running ThinLTO\n");
ThinLTO.CombinedIndex.releaseTemporaryMemory();
timeTraceProfilerBegin("ThinLink", StringRef(""));

View File

@ -366,6 +366,7 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod,
bool IsThinLTO, ModuleSummaryIndex *ExportSummary,
const ModuleSummaryIndex *ImportSummary,
const std::vector<uint8_t> &CmdArgs) {
llvm::TimeTraceScope timeScope("opt");
if (EmbedBitcode == LTOBitcodeEmbedding::EmbedPostMergePreOptimized) {
// FIXME: the motivation for capturing post-merge bitcode and command line
// is replicating the compilation environment from bitcode, without needing
@ -399,6 +400,7 @@ bool lto::opt(const Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod,
static void codegen(const Config &Conf, TargetMachine *TM,
AddStreamFn AddStream, unsigned Task, Module &Mod,
const ModuleSummaryIndex &CombinedIndex) {
llvm::TimeTraceScope timeScope("codegen");
if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod))
return;
@ -552,6 +554,7 @@ Error lto::finalizeOptimizationRemarks(
Error lto::backend(const Config &C, AddStreamFn AddStream,
unsigned ParallelCodeGenParallelismLevel, Module &Mod,
ModuleSummaryIndex &CombinedIndex) {
llvm::TimeTraceScope timeScope("LTO backend");
Expected<const Target *> TOrErr = initAndLookupTarget(C, Mod);
if (!TOrErr)
return TOrErr.takeError();
@ -577,6 +580,7 @@ Error lto::backend(const Config &C, AddStreamFn AddStream,
static void dropDeadSymbols(Module &Mod, const GVSummaryMapTy &DefinedGlobals,
const ModuleSummaryIndex &Index) {
llvm::TimeTraceScope timeScope("Drop dead symbols");
std::vector<GlobalValue*> DeadGVs;
for (auto &GV : Mod.global_values())
if (GlobalValueSummary *GVS = DefinedGlobals.lookup(GV.getGUID()))
@ -603,6 +607,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,
MapVector<StringRef, BitcodeModule> *ModuleMap,
bool CodeGenOnly, AddStreamFn IRAddStream,
const std::vector<uint8_t> &CmdArgs) {
llvm::TimeTraceScope timeScope("Thin backend", Mod.getModuleIdentifier());
Expected<const Target *> TOrErr = initAndLookupTarget(Conf, Mod);
if (!TOrErr)
return TOrErr.takeError();
@ -679,6 +684,7 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,
return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile));
auto ModuleLoader = [&](StringRef Identifier) {
llvm::TimeTraceScope moduleLoaderScope("Module loader", Identifier);
assert(Mod.getContext().isODRUniquingDebugTypes() &&
"ODR Type uniquing should be enabled on the context");
if (ModuleMap) {
@ -712,10 +718,13 @@ Error lto::thinBackend(const Config &Conf, unsigned Task, AddStreamFn AddStream,
return MOrErr;
};
FunctionImporter Importer(CombinedIndex, ModuleLoader,
ClearDSOLocalOnDeclarations);
if (Error Err = Importer.importFunctions(Mod, ImportList).takeError())
return Err;
{
llvm::TimeTraceScope importScope("Import functions");
FunctionImporter Importer(CombinedIndex, ModuleLoader,
ClearDSOLocalOnDeclarations);
if (Error Err = Importer.importFunctions(Mod, ImportList).takeError())
return Err;
}
// Do this after any importing so that imported code is updated.
updateMemProfAttributes(Mod, CombinedIndex);

View File

@ -40,6 +40,7 @@
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Transforms/IPO/Internalize.h"
#include "llvm/Transforms/Utils/Cloning.h"
@ -1550,6 +1551,7 @@ void llvm::computeDeadSymbolsWithConstProp(
const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols,
function_ref<PrevailingType(GlobalValue::GUID)> isPrevailing,
bool ImportEnabled) {
llvm::TimeTraceScope timeScope("Drop dead symbols and propagate attributes");
computeDeadSymbolsAndUpdateIndirectCalls(Index, GUIDPreservedSymbols,
isPrevailing);
if (ImportEnabled)
@ -1664,6 +1666,7 @@ bool llvm::convertToDeclaration(GlobalValue &GV) {
void llvm::thinLTOFinalizeInModule(Module &TheModule,
const GVSummaryMapTy &DefinedGlobals,
bool PropagateAttrs) {
llvm::TimeTraceScope timeScope("ThinLTO finalize in module");
DenseSet<Comdat *> NonPrevailingComdats;
auto FinalizeInModule = [&](GlobalValue &GV, bool Propagate = false) {
// See if the global summary analysis computed a new resolved linkage.
@ -1791,6 +1794,7 @@ void llvm::thinLTOFinalizeInModule(Module &TheModule,
/// Run internalization on \p TheModule based on symmary analysis.
void llvm::thinLTOInternalizeModule(Module &TheModule,
const GVSummaryMapTy &DefinedGlobals) {
llvm::TimeTraceScope timeScope("ThinLTO internalize module");
// Declare a callback for the internalize pass that will ask for every
// candidate GlobalValue if it can be internalized or not.
auto MustPreserveGV = [&](const GlobalValue &GV) -> bool {
@ -1885,6 +1889,7 @@ Expected<bool> FunctionImporter::importFunctions(
// Do the actual import of functions now, one Module at a time
for (const auto &ModName : ImportList.getSourceModules()) {
llvm::TimeTraceScope timeScope("Import", ModName);
// Get the module for the import
Expected<std::unique_ptr<Module>> SrcModuleOrErr = ModuleLoader(ModName);
if (!SrcModuleOrErr)
@ -1900,102 +1905,114 @@ Expected<bool> FunctionImporter::importFunctions(
// Find the globals to import
SetVector<GlobalValue *> GlobalsToImport;
for (Function &F : *SrcModule) {
if (!F.hasName())
continue;
auto GUID = F.getGUID();
auto MaybeImportType = ImportList.getImportType(ModName, GUID);
bool ImportDefinition = MaybeImportType == GlobalValueSummary::Definition;
{
llvm::TimeTraceScope functionsScope("Functions");
for (Function &F : *SrcModule) {
if (!F.hasName())
continue;
auto GUID = F.getGUID();
auto MaybeImportType = ImportList.getImportType(ModName, GUID);
bool ImportDefinition =
MaybeImportType == GlobalValueSummary::Definition;
LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
<< " importing function"
<< (ImportDefinition
? " definition "
: (MaybeImportType ? " declaration " : " "))
<< GUID << " " << F.getName() << " from "
<< SrcModule->getSourceFileName() << "\n");
if (ImportDefinition) {
if (Error Err = F.materialize())
return std::move(Err);
// MemProf should match function's definition and summary,
// 'thinlto_src_module' is needed.
if (EnableImportMetadata || EnableMemProfContextDisambiguation) {
// Add 'thinlto_src_module' and 'thinlto_src_file' metadata for
// statistics and debugging.
F.setMetadata(
"thinlto_src_module",
MDNode::get(DestModule.getContext(),
{MDString::get(DestModule.getContext(),
SrcModule->getModuleIdentifier())}));
F.setMetadata(
"thinlto_src_file",
MDNode::get(DestModule.getContext(),
{MDString::get(DestModule.getContext(),
SrcModule->getSourceFileName())}));
}
GlobalsToImport.insert(&F);
}
}
for (GlobalVariable &GV : SrcModule->globals()) {
if (!GV.hasName())
continue;
auto GUID = GV.getGUID();
auto MaybeImportType = ImportList.getImportType(ModName, GUID);
bool ImportDefinition = MaybeImportType == GlobalValueSummary::Definition;
LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
<< " importing global"
<< (ImportDefinition
? " definition "
: (MaybeImportType ? " declaration " : " "))
<< GUID << " " << GV.getName() << " from "
<< SrcModule->getSourceFileName() << "\n");
if (ImportDefinition) {
if (Error Err = GV.materialize())
return std::move(Err);
ImportedGVCount += GlobalsToImport.insert(&GV);
}
}
for (GlobalAlias &GA : SrcModule->aliases()) {
if (!GA.hasName() || isa<GlobalIFunc>(GA.getAliaseeObject()))
continue;
auto GUID = GA.getGUID();
auto MaybeImportType = ImportList.getImportType(ModName, GUID);
bool ImportDefinition = MaybeImportType == GlobalValueSummary::Definition;
LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
<< " importing alias"
<< (ImportDefinition
? " definition "
: (MaybeImportType ? " declaration " : " "))
<< GUID << " " << GA.getName() << " from "
<< SrcModule->getSourceFileName() << "\n");
if (ImportDefinition) {
if (Error Err = GA.materialize())
return std::move(Err);
// Import alias as a copy of its aliasee.
GlobalObject *GO = GA.getAliaseeObject();
if (Error Err = GO->materialize())
return std::move(Err);
auto *Fn = replaceAliasWithAliasee(SrcModule.get(), &GA);
LLVM_DEBUG(dbgs() << "Is importing aliasee fn " << GO->getGUID() << " "
<< GO->getName() << " from "
LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
<< " importing function"
<< (ImportDefinition
? " definition "
: (MaybeImportType ? " declaration " : " "))
<< GUID << " " << F.getName() << " from "
<< SrcModule->getSourceFileName() << "\n");
if (EnableImportMetadata || EnableMemProfContextDisambiguation) {
// Add 'thinlto_src_module' and 'thinlto_src_file' metadata for
// statistics and debugging.
Fn->setMetadata(
"thinlto_src_module",
MDNode::get(DestModule.getContext(),
{MDString::get(DestModule.getContext(),
SrcModule->getModuleIdentifier())}));
Fn->setMetadata(
"thinlto_src_file",
MDNode::get(DestModule.getContext(),
{MDString::get(DestModule.getContext(),
SrcModule->getSourceFileName())}));
if (ImportDefinition) {
if (Error Err = F.materialize())
return std::move(Err);
// MemProf should match function's definition and summary,
// 'thinlto_src_module' is needed.
if (EnableImportMetadata || EnableMemProfContextDisambiguation) {
// Add 'thinlto_src_module' and 'thinlto_src_file' metadata for
// statistics and debugging.
F.setMetadata(
"thinlto_src_module",
MDNode::get(DestModule.getContext(),
{MDString::get(DestModule.getContext(),
SrcModule->getModuleIdentifier())}));
F.setMetadata(
"thinlto_src_file",
MDNode::get(DestModule.getContext(),
{MDString::get(DestModule.getContext(),
SrcModule->getSourceFileName())}));
}
GlobalsToImport.insert(&F);
}
}
}
{
llvm::TimeTraceScope globalsScope("Globals");
for (GlobalVariable &GV : SrcModule->globals()) {
if (!GV.hasName())
continue;
auto GUID = GV.getGUID();
auto MaybeImportType = ImportList.getImportType(ModName, GUID);
bool ImportDefinition =
MaybeImportType == GlobalValueSummary::Definition;
LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
<< " importing global"
<< (ImportDefinition
? " definition "
: (MaybeImportType ? " declaration " : " "))
<< GUID << " " << GV.getName() << " from "
<< SrcModule->getSourceFileName() << "\n");
if (ImportDefinition) {
if (Error Err = GV.materialize())
return std::move(Err);
ImportedGVCount += GlobalsToImport.insert(&GV);
}
}
}
{
llvm::TimeTraceScope aliasesScope("Aliases");
for (GlobalAlias &GA : SrcModule->aliases()) {
if (!GA.hasName() || isa<GlobalIFunc>(GA.getAliaseeObject()))
continue;
auto GUID = GA.getGUID();
auto MaybeImportType = ImportList.getImportType(ModName, GUID);
bool ImportDefinition =
MaybeImportType == GlobalValueSummary::Definition;
LLVM_DEBUG(dbgs() << (MaybeImportType ? "Is" : "Not")
<< " importing alias"
<< (ImportDefinition
? " definition "
: (MaybeImportType ? " declaration " : " "))
<< GUID << " " << GA.getName() << " from "
<< SrcModule->getSourceFileName() << "\n");
if (ImportDefinition) {
if (Error Err = GA.materialize())
return std::move(Err);
// Import alias as a copy of its aliasee.
GlobalObject *GO = GA.getAliaseeObject();
if (Error Err = GO->materialize())
return std::move(Err);
auto *Fn = replaceAliasWithAliasee(SrcModule.get(), &GA);
LLVM_DEBUG(dbgs() << "Is importing aliasee fn " << GO->getGUID()
<< " " << GO->getName() << " from "
<< SrcModule->getSourceFileName() << "\n");
if (EnableImportMetadata || EnableMemProfContextDisambiguation) {
// Add 'thinlto_src_module' and 'thinlto_src_file' metadata for
// statistics and debugging.
Fn->setMetadata(
"thinlto_src_module",
MDNode::get(DestModule.getContext(),
{MDString::get(DestModule.getContext(),
SrcModule->getModuleIdentifier())}));
Fn->setMetadata(
"thinlto_src_file",
MDNode::get(DestModule.getContext(),
{MDString::get(DestModule.getContext(),
SrcModule->getSourceFileName())}));
}
GlobalsToImport.insert(Fn);
}
GlobalsToImport.insert(Fn);
}
}

View File

@ -90,6 +90,7 @@
#include "llvm/Support/Error.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/GlobPattern.h"
#include "llvm/Support/TimeProfiler.h"
#include "llvm/TargetParser/Triple.h"
#include "llvm/Transforms/IPO.h"
#include "llvm/Transforms/IPO/FunctionAttrs.h"
@ -869,6 +870,7 @@ void llvm::updateVCallVisibilityInModule(
void llvm::updatePublicTypeTestCalls(Module &M,
bool WholeProgramVisibilityEnabledInLTO) {
llvm::TimeTraceScope timeScope("Update public type test calls");
Function *PublicTypeTestFunc =
Intrinsic::getDeclarationIfExists(&M, Intrinsic::public_type_test);
if (!PublicTypeTestFunc)

View File

@ -13,6 +13,8 @@
#include "llvm/Transforms/Utils/FunctionImportUtils.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/TimeProfiler.h"
using namespace llvm;
/// Uses the "source_filename" instead of a Module hash ID for the suffix of
@ -370,6 +372,7 @@ void FunctionImportGlobalProcessing::run() { processGlobalsForThinLTO(); }
void llvm::renameModuleForThinLTO(Module &M, const ModuleSummaryIndex &Index,
bool ClearDSOLocalOnDeclarations,
SetVector<GlobalValue *> *GlobalsToImport) {
llvm::TimeTraceScope timeScope("Rename module for ThinLTO");
FunctionImportGlobalProcessing ThinLTOProcessing(M, Index, GlobalsToImport,
ClearDSOLocalOnDeclarations);
ThinLTOProcessing.run();