Index: llvm/include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- llvm/include/llvm/IR/ModuleSummaryIndex.h +++ llvm/include/llvm/IR/ModuleSummaryIndex.h @@ -655,6 +655,10 @@ return ModulePathStringTable.count(M.getModuleIdentifier()); } + const std::map &typeIds() const { + return TypeIdMap; + } + TypeIdSummary &getTypeIdSummary(StringRef TypeId) { return TypeIdMap[TypeId]; } Index: llvm/lib/LTO/LTO.cpp =================================================================== --- llvm/lib/LTO/LTO.cpp +++ llvm/lib/LTO/LTO.cpp @@ -50,6 +50,11 @@ #define DEBUG_TYPE "lto" +typedef DenseMap< + GlobalValue::GUID, + TinyPtrVector *>> + TypeIdSummariesByGuidTy; + // Returns a unique hash for the Module considering the current list of // export/import and other global analysis results. // The hash is produced in \p Key. @@ -58,7 +63,8 @@ StringRef ModuleID, const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const std::map &ResolvedODR, - const GVSummaryMapTy &DefinedGlobals) { + const GVSummaryMapTy &DefinedGlobals, + const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) { // Compute the unique hash for this entry. // This is based on the current compiler version, the module itself, the // export list, the hash for every single module in the import list, the @@ -126,12 +132,52 @@ sizeof(GlobalValue::LinkageTypes))); } + std::set UsedTypeIds; + + auto AddUsedTypeIds = [&](GlobalValueSummary *GS) { + auto *FS = dyn_cast_or_null(GS); + if (!FS) + return; + for (auto &TT : FS->type_tests()) + UsedTypeIds.insert(TT); + for (auto &TT : FS->type_test_assume_vcalls()) + UsedTypeIds.insert(TT.GUID); + for (auto &TT : FS->type_checked_load_vcalls()) + UsedTypeIds.insert(TT.GUID); + for (auto &TT : FS->type_test_assume_const_vcalls()) + UsedTypeIds.insert(TT.VFunc.GUID); + for (auto &TT : FS->type_checked_load_const_vcalls()) + UsedTypeIds.insert(TT.VFunc.GUID); + }; + // Include the hash for the linkage type to reflect internalization and weak - // resolution. + // resolution, and collect any used type identifier resolutions. for (auto &GS : DefinedGlobals) { GlobalValue::LinkageTypes Linkage = GS.second->linkage(); Hasher.update( ArrayRef((const uint8_t *)&Linkage, sizeof(Linkage))); + AddUsedTypeIds(GS.second); + } + + // Imported functions may introduce new uses of type identifier resolutions, + // so we need to collect their used resolutions as well. + for (auto &ImpM : ImportList) + for (auto &ImpF : ImpM.second) + AddUsedTypeIds(Index.findSummaryInModule(ImpF.first, ImpM.first())); + + auto AddTypeIdSummary = [&](StringRef TId, const TypeIdSummary &S) { + AddString(TId); + + AddUnsigned(S.TTRes.TheKind); + AddUnsigned(S.TTRes.SizeM1BitWidth); + }; + + // Include the hash for all type identifiers used by this module. + for (GlobalValue::GUID TId : UsedTypeIds) { + auto SummariesI = TypeIdSummariesByGuid.find(TId); + if (SummariesI != TypeIdSummariesByGuid.end()) + for (auto *Summary : SummariesI->second) + AddTypeIdSummary(Summary->first, Summary->second); } if (!Conf.SampleProfile.empty()) { @@ -684,6 +730,7 @@ ThreadPool BackendThreadPool; AddStreamFn AddStream; NativeObjectCache Cache; + TypeIdSummariesByGuidTy TypeIdSummariesByGuid; Optional Err; std::mutex ErrMu; @@ -696,7 +743,14 @@ AddStreamFn AddStream, NativeObjectCache Cache) : ThinBackendProc(Conf, CombinedIndex, ModuleToDefinedGVSummaries), BackendThreadPool(ThinLTOParallelismLevel), - AddStream(std::move(AddStream)), Cache(std::move(Cache)) {} + AddStream(std::move(AddStream)), Cache(std::move(Cache)) { + // Create a mapping from type identifier GUIDs to type identifier summaries. + // This allows backends to use the type identifier GUIDs stored in the + // function summaries to determine which type identifier summaries affect + // each function without needing to compute GUIDs in each backend. + for (auto &TId : CombinedIndex.typeIds()) + TypeIdSummariesByGuid[GlobalValue::getGUID(TId.first)].push_back(&TId); + } Error runThinLTOBackendThread( AddStreamFn AddStream, NativeObjectCache Cache, unsigned Task, @@ -705,7 +759,8 @@ const FunctionImporter::ExportSetTy &ExportList, const std::map &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - MapVector &ModuleMap) { + MapVector &ModuleMap, + const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) { auto RunThinBackend = [&](AddStreamFn AddStream) { LTOLLVMContext BackendContext(Conf); Expected> MOrErr = BM.parseModule(BackendContext); @@ -728,7 +783,7 @@ SmallString<40> Key; // The module may be cached, this helps handling it. computeCacheKey(Key, Conf, CombinedIndex, ModuleID, ImportList, ExportList, - ResolvedODR, DefinedGlobals); + ResolvedODR, DefinedGlobals, TypeIdSummariesByGuid); if (AddStreamFn CacheAddStream = Cache(Task, Key)) return RunThinBackend(CacheAddStream); @@ -752,10 +807,11 @@ const std::map &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - MapVector &ModuleMap) { + MapVector &ModuleMap, + const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) { Error E = runThinLTOBackendThread( - AddStream, Cache, Task, BM, CombinedIndex, ImportList, - ExportList, ResolvedODR, DefinedGlobals, ModuleMap); + AddStream, Cache, Task, BM, CombinedIndex, ImportList, ExportList, + ResolvedODR, DefinedGlobals, ModuleMap, TypeIdSummariesByGuid); if (E) { std::unique_lock L(ErrMu); if (Err) @@ -764,9 +820,9 @@ Err = std::move(E); } }, - BM, std::ref(CombinedIndex), std::ref(ImportList), - std::ref(ExportList), std::ref(ResolvedODR), std::ref(DefinedGlobals), - std::ref(ModuleMap)); + BM, std::ref(CombinedIndex), std::ref(ImportList), std::ref(ExportList), + std::ref(ResolvedODR), std::ref(DefinedGlobals), std::ref(ModuleMap), + std::ref(TypeIdSummariesByGuid)); return Error::success(); } Index: llvm/test/ThinLTO/X86/Inputs/cache-typeid-resolutions-import.ll =================================================================== --- /dev/null +++ llvm/test/ThinLTO/X86/Inputs/cache-typeid-resolutions-import.ll @@ -0,0 +1,9 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i1 @importf1(i8* %p) { + %x = call i1 @f1(i8* %p) + ret i1 %x +} + +declare i1 @f1(i8* %p) Index: llvm/test/ThinLTO/X86/Inputs/cache-typeid-resolutions1.ll =================================================================== --- /dev/null +++ llvm/test/ThinLTO/X86/Inputs/cache-typeid-resolutions1.ll @@ -0,0 +1,6 @@ +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +@vt1 = constant i32 0, !type !0 + +!0 = !{i32 0, !"typeid1"} Index: llvm/test/ThinLTO/X86/cache-typeid-resolutions.ll =================================================================== --- /dev/null +++ llvm/test/ThinLTO/X86/cache-typeid-resolutions.ll @@ -0,0 +1,22 @@ +; RUN: opt -module-hash -module-summary %s -o %t.bc +; RUN: opt -module-hash -module-summary %S/Inputs/cache-typeid-resolutions-import.ll -o %t-import.bc + +; RUN: llvm-as -o %t1.bc %S/Inputs/cache-typeid-resolutions1.ll + +; Two resolutions for typeid1: Unsat, Single +; where both t and t-import are sensitive to typeid1's resolution +; so 4 distinct objects in total. +; RUN: rm -rf %t.cache +; RUN: llvm-lto2 -o %t.o %t.bc %t-import.bc -cache-dir %t.cache -r=%t.bc,f1,plx -r=%t-import.bc,importf1,plx -r=%t-import.bc,f1,lx +; RUN: llvm-lto2 -o %t.o %t.bc %t-import.bc %t1.bc -cache-dir %t.cache -r=%t.bc,f1,plx -r=%t-import.bc,importf1,plx -r=%t-import.bc,f1,lx -r=%t1.bc,vt1,plx +; RUN: ls %t.cache | count 4 + +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +define i1 @f1(i8* %p) { + %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1") + ret i1 %x +} + +declare i1 @llvm.type.test(i8*, metadata)