Use llvm::computeLTOCacheKey to determine post-ThinLTO CGU reuse
During incremental ThinLTO compilation, we attempt to re-use the optimized (post-ThinLTO) bitcode file for a module if it is 'safe' to do so. Up until now, 'safe' has meant that the set of modules that our current modules imports from/exports to is unchanged from the previous compilation session. See PR #67020 and PR #71131 for more details. However, this turns out be insufficient to guarantee that it's safe to reuse the post-LTO module (i.e. that optimizing the pre-LTO module would produce the same result). When LLVM optimizes a module during ThinLTO, it may look at other information from the 'module index', such as whether a (non-imported!) global variable is used. If this information changes between compilation runs, we may end up re-using an optimized module that (for example) had dead-code elimination run on a function that is now used by another module. Fortunately, LLVM implements its own ThinLTO module cache, which is used when ThinLTO is performed by a linker plugin (e.g. when clang is used to compile a C proect). Using this cache directly would require extensive refactoring of our code - but fortunately for us, LLVM provides a function that does exactly what we need. The function `llvm::computeLTOCacheKey` is used to compute a SHA-1 hash from all data that might influence the result of ThinLTO on a module. In addition to the module imports/exports that we manually track, it also hashes information about global variables (e.g. their liveness) which might be used during optimization. By using this function, we shouldn't have to worry about new LLVM passes breaking our module re-use behavior. In LLVM, the output of this function forms part of the filename used to store the post-ThinLTO module. To keep our current filename structure intact, this PR just writes out the mapping 'CGU name -> Hash' to a file. To determine if a post-LTO module should be reused, we compare hashes from the previous session. This should unblock PR #75199 - by sheer chance, it seems to have hit this issue due to the particular CGU partitioning and optimization decisions that end up getting made.
This commit is contained in:
parent
7bdb5dee7b
commit
cfe07cd42a
6 changed files with 164 additions and 197 deletions
|
@ -1212,6 +1212,7 @@ struct LLVMRustThinLTOData {
|
|||
StringMap<FunctionImporter::ImportMapTy> ImportLists;
|
||||
StringMap<FunctionImporter::ExportSetTy> ExportLists;
|
||||
StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries;
|
||||
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
|
||||
|
||||
LLVMRustThinLTOData() : Index(/* HaveGVs = */ false) {}
|
||||
};
|
||||
|
@ -1308,7 +1309,6 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
|
|||
//
|
||||
// This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp` with some of this
|
||||
// being lifted from `lib/LTO/LTO.cpp` as well
|
||||
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
|
||||
DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy;
|
||||
for (auto &I : Ret->Index) {
|
||||
if (I.second.SummaryList.size() > 1)
|
||||
|
@ -1323,7 +1323,7 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
|
|||
auto recordNewLinkage = [&](StringRef ModuleIdentifier,
|
||||
GlobalValue::GUID GUID,
|
||||
GlobalValue::LinkageTypes NewLinkage) {
|
||||
ResolvedODR[ModuleIdentifier][GUID] = NewLinkage;
|
||||
Ret->ResolvedODR[ModuleIdentifier][GUID] = NewLinkage;
|
||||
};
|
||||
#if LLVM_VERSION_GE(9, 0)
|
||||
thinLTOResolvePrevailingInIndex(Ret->Index, isPrevailing, recordNewLinkage,
|
||||
|
@ -1491,7 +1491,7 @@ extern "C" typedef void (*LLVMRustModuleNameCallback)(void*, // payload
|
|||
// Calls `module_name_callback` for each module import done by ThinLTO.
|
||||
// The callback is provided with regular null-terminated C strings.
|
||||
extern "C" void
|
||||
LLVMRustGetThinLTOModuleImports(const LLVMRustThinLTOData *data,
|
||||
LLVMRustGetThinLTOModules(const LLVMRustThinLTOData *data,
|
||||
LLVMRustModuleNameCallback module_name_callback,
|
||||
void* callback_payload) {
|
||||
for (const auto& importing_module : data->ImportLists) {
|
||||
|
@ -1653,3 +1653,36 @@ LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) {
|
|||
MD->clearOperands();
|
||||
MD->addOperand(Unit);
|
||||
}
|
||||
|
||||
// Computes the LTO cache key for the provided 'ModId' in the given 'Data',
|
||||
// storing the result in 'KeyOut'.
|
||||
// Currently, this cache key is a SHA-1 hash of anything that could affect
|
||||
// the result of optimizing this module (e.g. module imports, exports, liveness
|
||||
// of access globals, etc).
|
||||
// The precise details are determined by LLVM in `computeLTOCacheKey`, which is
|
||||
// used during the normal linker-plugin incremental thin-LTO process.
|
||||
extern "C" void
|
||||
LLVMRustComputeLTOCacheKey(RustStringRef KeyOut, const char *ModId, LLVMRustThinLTOData *Data) {
|
||||
SmallString<40> Key;
|
||||
llvm::lto::Config conf;
|
||||
const auto &ImportList = Data->ImportLists.lookup(ModId);
|
||||
const auto &ExportList = Data->ExportLists.lookup(ModId);
|
||||
const auto &ResolvedODR = Data->ResolvedODR.lookup(ModId);
|
||||
const auto &DefinedGlobals = Data->ModuleToDefinedGVSummaries.lookup(ModId);
|
||||
std::set<GlobalValue::GUID> CfiFunctionDefs;
|
||||
std::set<GlobalValue::GUID> CfiFunctionDecls;
|
||||
|
||||
// Based on the 'InProcessThinBackend' constructor in LLVM
|
||||
for (auto &Name : Data->Index.cfiFunctionDefs())
|
||||
CfiFunctionDefs.insert(
|
||||
GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
|
||||
for (auto &Name : Data->Index.cfiFunctionDecls())
|
||||
CfiFunctionDecls.insert(
|
||||
GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name)));
|
||||
|
||||
llvm::computeLTOCacheKey(Key, conf, Data->Index, ModId,
|
||||
ImportList, ExportList, ResolvedODR, DefinedGlobals, CfiFunctionDefs, CfiFunctionDecls
|
||||
);
|
||||
|
||||
LLVMRustStringWriteImpl(KeyOut, Key.c_str(), Key.size());
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue