Index: llvm/include/llvm/LTO/LTOBackend.h =================================================================== --- llvm/include/llvm/LTO/LTOBackend.h +++ llvm/include/llvm/LTO/LTOBackend.h @@ -42,7 +42,7 @@ /// Runs a ThinLTO backend. Error thinBackend(Config &C, unsigned Task, AddStreamFn AddStream, Module &M, - ModuleSummaryIndex &CombinedIndex, + const ModuleSummaryIndex &CombinedIndex, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, MapVector &ModuleMap); Index: llvm/include/llvm/Transforms/IPO.h =================================================================== --- llvm/include/llvm/Transforms/IPO.h +++ llvm/include/llvm/Transforms/IPO.h @@ -224,19 +224,33 @@ /// \brief This pass lowers type metadata and the llvm.type.test intrinsic to /// bitsets. -/// \param Action What to do with the summary passed as Index. -/// \param Index The summary to use for importing or exporting, this can be null -/// when Action is None. -ModulePass *createLowerTypeTestsPass(PassSummaryAction Action, - ModuleSummaryIndex *Index); +/// +/// The behavior depends on the summary arguments: +/// - If ExportSummary is non-null, this pass will export type identifiers to +/// the given summary. +/// - Otherwise, if ImportSummary is non-null, this pass will import type +/// identifiers from the given summary. +/// - Otherwise it does neither. +/// It is invalid for both ExportSummary and ImportSummary to be non-null. +ModulePass *createLowerTypeTestsPass(ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary); /// \brief This pass export CFI checks for use by external modules. ModulePass *createCrossDSOCFIPass(); /// \brief This pass implements whole-program devirtualization using type /// metadata. -ModulePass *createWholeProgramDevirtPass(PassSummaryAction Action, - ModuleSummaryIndex *Index); +/// +/// The behavior depends on the summary arguments: +/// - If ExportSummary is non-null, this pass will export type identifiers to +/// the given summary. +/// - Otherwise, if ImportSummary is non-null, this pass will import type +/// identifiers from the given summary. +/// - Otherwise it does neither. +/// It is invalid for both ExportSummary and ImportSummary to be non-null. +ModulePass * +createWholeProgramDevirtPass(ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary); /// This pass splits globals into pieces for the benefit of whole-program /// devirtualization and control-flow integrity. Index: llvm/include/llvm/Transforms/IPO/PassManagerBuilder.h =================================================================== --- llvm/include/llvm/Transforms/IPO/PassManagerBuilder.h +++ llvm/include/llvm/Transforms/IPO/PassManagerBuilder.h @@ -132,10 +132,15 @@ /// added to the per-module passes. Pass *Inliner; - /// The module summary index to use for passing information between the - /// regular LTO phase and the thin LTO backends, for example the CFI and - /// devirtualization type tests. - ModuleSummaryIndex *Summary = nullptr; + /// The module summary index to use for exporting information from the + /// regular LTO phase, for example for the CFI and devirtualization type + /// tests. + ModuleSummaryIndex *ExportSummary = nullptr; + + /// The module summary index to use for importing information to the + /// thin LTO backends, for example for the CFI and devirtualization type + /// tests. + const ModuleSummaryIndex *ImportSummary = nullptr; bool DisableTailCalls; bool DisableUnitAtATime; Index: llvm/lib/LTO/LTOBackend.cpp =================================================================== --- llvm/lib/LTO/LTOBackend.cpp +++ llvm/lib/LTO/LTOBackend.cpp @@ -223,14 +223,16 @@ } static void runOldPMPasses(Config &Conf, Module &Mod, TargetMachine *TM, - bool IsThinLTO, ModuleSummaryIndex &CombinedIndex) { + bool IsThinLTO, ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary) { legacy::PassManager passes; passes.add(createTargetTransformInfoWrapperPass(TM->getTargetIRAnalysis())); PassManagerBuilder PMB; PMB.LibraryInfo = new TargetLibraryInfoImpl(Triple(TM->getTargetTriple())); PMB.Inliner = createFunctionInliningPass(); - PMB.Summary = &CombinedIndex; + PMB.ExportSummary = ExportSummary; + PMB.ImportSummary = ImportSummary; // Unconditionally verify input since it is not verified before this // point and has unknown origin. PMB.VerifyInput = true; @@ -247,7 +249,8 @@ } bool opt(Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, - bool IsThinLTO, ModuleSummaryIndex &CombinedIndex) { + bool IsThinLTO, ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary) { // There's still no ThinLTO pipeline hooked up in the new pass manager, // once there is one, we can just remove this. if (LTOUseNewPM && IsThinLTO) @@ -260,7 +263,7 @@ else if (LTOUseNewPM) runNewPMPasses(Mod, TM, Conf.OptLevel); else - runOldPMPasses(Conf, Mod, TM, IsThinLTO, CombinedIndex); + runOldPMPasses(Conf, Mod, TM, IsThinLTO, ExportSummary, ImportSummary); return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod); } @@ -383,7 +386,8 @@ auto DiagnosticOutputFile = std::move(*DiagFileOrErr); if (!C.CodeGenOnly) { - if (!opt(C, TM.get(), 0, *Mod, /*IsThinLTO=*/false, CombinedIndex)) { + if (!opt(C, TM.get(), 0, *Mod, /*IsThinLTO=*/false, + /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr)) { finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); return Error::success(); } @@ -400,7 +404,7 @@ } Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, - Module &Mod, ModuleSummaryIndex &CombinedIndex, + Module &Mod, const ModuleSummaryIndex &CombinedIndex, const FunctionImporter::ImportMapTy &ImportList, const GVSummaryMapTy &DefinedGlobals, MapVector &ModuleMap) { @@ -452,7 +456,8 @@ if (Conf.PostImportModuleHook && !Conf.PostImportModuleHook(Task, Mod)) return Error::success(); - if (!opt(Conf, TM.get(), Task, Mod, /*IsThinLTO=*/true, CombinedIndex)) + if (!opt(Conf, TM.get(), Task, Mod, /*IsThinLTO=*/true, + /*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex)) return Error::success(); codegen(Conf, TM.get(), AddStream, Task, Mod); Index: llvm/lib/Transforms/IPO/LowerTypeTests.cpp =================================================================== --- llvm/lib/Transforms/IPO/LowerTypeTests.cpp +++ llvm/lib/Transforms/IPO/LowerTypeTests.cpp @@ -232,8 +232,8 @@ class LowerTypeTestsModule { Module &M; - PassSummaryAction Action; - ModuleSummaryIndex *Summary; + ModuleSummaryIndex *ExportSummary; + const ModuleSummaryIndex *ImportSummary; bool LinkerSubsectionsViaSymbols; Triple::ArchType Arch; @@ -332,8 +332,8 @@ void createJumpTable(Function *F, ArrayRef Functions); public: - LowerTypeTestsModule(Module &M, PassSummaryAction Action, - ModuleSummaryIndex *Summary); + LowerTypeTestsModule(Module &M, ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary); bool lower(); // Lower the module using the action and summary passed as command line @@ -346,15 +346,17 @@ bool UseCommandLine = false; - PassSummaryAction Action; - ModuleSummaryIndex *Summary; + ModuleSummaryIndex *ExportSummary; + const ModuleSummaryIndex *ImportSummary; LowerTypeTests() : ModulePass(ID), UseCommandLine(true) { initializeLowerTypeTestsPass(*PassRegistry::getPassRegistry()); } - LowerTypeTests(PassSummaryAction Action, ModuleSummaryIndex *Summary) - : ModulePass(ID), Action(Action), Summary(Summary) { + LowerTypeTests(ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary) + : ModulePass(ID), ExportSummary(ExportSummary), + ImportSummary(ImportSummary) { initializeLowerTypeTestsPass(*PassRegistry::getPassRegistry()); } @@ -363,7 +365,7 @@ return false; if (UseCommandLine) return LowerTypeTestsModule::runForTesting(M); - return LowerTypeTestsModule(M, Action, Summary).lower(); + return LowerTypeTestsModule(M, ExportSummary, ImportSummary).lower(); } }; @@ -373,9 +375,10 @@ false) char LowerTypeTests::ID = 0; -ModulePass *llvm::createLowerTypeTestsPass(PassSummaryAction Action, - ModuleSummaryIndex *Summary) { - return new LowerTypeTests(Action, Summary); +ModulePass * +llvm::createLowerTypeTestsPass(ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary) { + return new LowerTypeTests(ExportSummary, ImportSummary); } /// Build a bit set for TypeId using the object layouts in @@ -499,8 +502,7 @@ return createMaskedBitTest(B, TIL.InlineBits, BitOffset); } else { Constant *ByteArray = TIL.TheByteArray; - if (!LinkerSubsectionsViaSymbols && AvoidReuse && - Action != PassSummaryAction::Import) { + if (!LinkerSubsectionsViaSymbols && AvoidReuse && !ImportSummary) { // Each use of the byte array uses a different alias. This makes the // backend less likely to reuse previously computed byte array addresses, // improving the security of the CFI mechanism based on this pass. @@ -700,7 +702,8 @@ /// information about the type identifier. void LowerTypeTestsModule::exportTypeId(StringRef TypeId, const TypeIdLowering &TIL) { - TypeTestResolution &TTRes = Summary->getOrInsertTypeIdSummary(TypeId).TTRes; + TypeTestResolution &TTRes = + ExportSummary->getOrInsertTypeIdSummary(TypeId).TTRes; TTRes.TheKind = TIL.TheKind; auto ExportGlobal = [&](StringRef Name, Constant *C) { @@ -738,7 +741,7 @@ LowerTypeTestsModule::TypeIdLowering LowerTypeTestsModule::importTypeId(StringRef TypeId) { - const TypeIdSummary *TidSummary = Summary->getTypeIdSummary(TypeId); + const TypeIdSummary *TidSummary = ImportSummary->getTypeIdSummary(TypeId); if (!TidSummary) return {}; // Unsat: no globals match this type id. const TypeTestResolution &TTRes = TidSummary->TTRes; @@ -1293,9 +1296,11 @@ } /// Lower all type tests in this module. -LowerTypeTestsModule::LowerTypeTestsModule(Module &M, PassSummaryAction Action, - ModuleSummaryIndex *Summary) - : M(M), Action(Action), Summary(Summary) { +LowerTypeTestsModule::LowerTypeTestsModule( + Module &M, ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary) + : M(M), ExportSummary(ExportSummary), ImportSummary(ImportSummary) { + assert(!(ExportSummary && ImportSummary)); Triple TargetTriple(M.getTargetTriple()); LinkerSubsectionsViaSymbols = TargetTriple.isMacOSX(); Arch = TargetTriple.getArch(); @@ -1319,7 +1324,11 @@ ExitOnErr(errorCodeToError(In.error())); } - bool Changed = LowerTypeTestsModule(M, ClSummaryAction, &Summary).lower(); + bool Changed = + LowerTypeTestsModule( + M, ClSummaryAction == PassSummaryAction::Export ? &Summary : nullptr, + ClSummaryAction == PassSummaryAction::Import ? &Summary : nullptr) + .lower(); if (!ClWriteSummary.empty()) { ExitOnError ExitOnErr("-lowertypetests-write-summary: " + ClWriteSummary + @@ -1338,11 +1347,10 @@ bool LowerTypeTestsModule::lower() { Function *TypeTestFunc = M.getFunction(Intrinsic::getName(Intrinsic::type_test)); - if ((!TypeTestFunc || TypeTestFunc->use_empty()) && - Action != PassSummaryAction::Export) + if ((!TypeTestFunc || TypeTestFunc->use_empty()) && !ExportSummary) return false; - if (Action == PassSummaryAction::Import) { + if (ImportSummary) { for (auto UI = TypeTestFunc->use_begin(), UE = TypeTestFunc->use_end(); UI != UE;) { auto *CI = cast((*UI++).getUser()); @@ -1423,7 +1431,7 @@ } } - if (Action == PassSummaryAction::Export) { + if (ExportSummary) { DenseMap> MetadataByGUID; for (auto &P : TypeIdInfo) { if (auto *TypeId = dyn_cast(P.first)) @@ -1431,7 +1439,7 @@ TypeId); } - for (auto &P : *Summary) { + for (auto &P : *ExportSummary) { for (auto &S : P.second) { auto *FS = dyn_cast(S.get()); if (!FS) @@ -1502,9 +1510,9 @@ PreservedAnalyses LowerTypeTestsPass::run(Module &M, ModuleAnalysisManager &AM) { - bool Changed = - LowerTypeTestsModule(M, PassSummaryAction::None, /*Summary=*/nullptr) - .lower(); + bool Changed = LowerTypeTestsModule(M, /*ExportSummary=*/nullptr, + /*ImportSummary=*/nullptr) + .lower(); if (!Changed) return PreservedAnalyses::all(); return PreservedAnalyses::none(); Index: llvm/lib/Transforms/IPO/PassManagerBuilder.cpp =================================================================== --- llvm/lib/Transforms/IPO/PassManagerBuilder.cpp +++ llvm/lib/Transforms/IPO/PassManagerBuilder.cpp @@ -704,8 +704,7 @@ PM.add(createGlobalSplitPass()); // Apply whole-program devirtualization and virtual constant propagation. - PM.add(createWholeProgramDevirtPass( - Summary ? PassSummaryAction::Export : PassSummaryAction::None, Summary)); + PM.add(createWholeProgramDevirtPass(ExportSummary, nullptr)); // That's all we need at opt level 1. if (OptLevel == 1) @@ -834,7 +833,7 @@ if (VerifyInput) PM.add(createVerifierPass()); - if (Summary) { + if (ImportSummary) { // These passes import type identifier resolutions for whole-program // devirtualization and CFI. They must run early because other passes may // disturb the specific instruction patterns that these passes look for, @@ -847,8 +846,8 @@ // // Also, WPD has access to more precise information than ICP and can // devirtualize more effectively, so it should operate on the IR first. - PM.add(createWholeProgramDevirtPass(PassSummaryAction::Import, Summary)); - PM.add(createLowerTypeTestsPass(PassSummaryAction::Import, Summary)); + PM.add(createWholeProgramDevirtPass(nullptr, ImportSummary)); + PM.add(createLowerTypeTestsPass(nullptr, ImportSummary)); } populateModulePassManager(PM); @@ -875,8 +874,7 @@ // Lower type metadata and the type.test intrinsic. This pass supports Clang's // control flow integrity mechanisms (-fsanitize=cfi*) and needs to run at // link time if CFI is enabled. The pass does nothing if CFI is disabled. - PM.add(createLowerTypeTestsPass( - Summary ? PassSummaryAction::Export : PassSummaryAction::None, Summary)); + PM.add(createLowerTypeTestsPass(ExportSummary, nullptr)); if (OptLevel != 0) addLateLTOOptimizationPasses(PM); Index: llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp =================================================================== --- llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ llvm/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -373,8 +373,8 @@ Module &M; function_ref AARGetter; - PassSummaryAction Action; - ModuleSummaryIndex *Summary; + ModuleSummaryIndex *ExportSummary; + const ModuleSummaryIndex *ImportSummary; IntegerType *Int8Ty; PointerType *Int8PtrTy; @@ -397,14 +397,17 @@ std::map NumUnsafeUsesForTypeTest; DevirtModule(Module &M, function_ref AARGetter, - PassSummaryAction Action, ModuleSummaryIndex *Summary) - : M(M), AARGetter(AARGetter), Action(Action), Summary(Summary), - Int8Ty(Type::getInt8Ty(M.getContext())), + ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary) + : M(M), AARGetter(AARGetter), ExportSummary(ExportSummary), + ImportSummary(ImportSummary), Int8Ty(Type::getInt8Ty(M.getContext())), Int8PtrTy(Type::getInt8PtrTy(M.getContext())), Int32Ty(Type::getInt32Ty(M.getContext())), Int64Ty(Type::getInt64Ty(M.getContext())), IntPtrTy(M.getDataLayout().getIntPtrType(M.getContext(), 0)), - RemarksEnabled(areRemarksEnabled()) {} + RemarksEnabled(areRemarksEnabled()) { + assert(!(ExportSummary && ImportSummary)); + } bool areRemarksEnabled(); @@ -488,15 +491,17 @@ bool UseCommandLine = false; - PassSummaryAction Action; - ModuleSummaryIndex *Summary; + ModuleSummaryIndex *ExportSummary; + const ModuleSummaryIndex *ImportSummary; WholeProgramDevirt() : ModulePass(ID), UseCommandLine(true) { initializeWholeProgramDevirtPass(*PassRegistry::getPassRegistry()); } - WholeProgramDevirt(PassSummaryAction Action, ModuleSummaryIndex *Summary) - : ModulePass(ID), Action(Action), Summary(Summary) { + WholeProgramDevirt(ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary) + : ModulePass(ID), ExportSummary(ExportSummary), + ImportSummary(ImportSummary) { initializeWholeProgramDevirtPass(*PassRegistry::getPassRegistry()); } @@ -505,7 +510,8 @@ return false; if (UseCommandLine) return DevirtModule::runForTesting(M, LegacyAARGetter(*this)); - return DevirtModule(M, LegacyAARGetter(*this), Action, Summary).run(); + return DevirtModule(M, LegacyAARGetter(*this), ExportSummary, ImportSummary) + .run(); } void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -524,9 +530,10 @@ "Whole program devirtualization", false, false) char WholeProgramDevirt::ID = 0; -ModulePass *llvm::createWholeProgramDevirtPass(PassSummaryAction Action, - ModuleSummaryIndex *Summary) { - return new WholeProgramDevirt(Action, Summary); +ModulePass * +llvm::createWholeProgramDevirtPass(ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary) { + return new WholeProgramDevirt(ExportSummary, ImportSummary); } PreservedAnalyses WholeProgramDevirtPass::run(Module &M, @@ -535,7 +542,7 @@ auto AARGetter = [&](Function &F) -> AAResults & { return FAM.getResult(F); }; - if (!DevirtModule(M, AARGetter, PassSummaryAction::None, nullptr).run()) + if (!DevirtModule(M, AARGetter, nullptr, nullptr).run()) return PreservedAnalyses::all(); return PreservedAnalyses::none(); } @@ -557,7 +564,12 @@ ExitOnErr(errorCodeToError(In.error())); } - bool Changed = DevirtModule(M, AARGetter, ClSummaryAction, &Summary).run(); + bool Changed = + DevirtModule( + M, AARGetter, + ClSummaryAction == PassSummaryAction::Export ? &Summary : nullptr, + ClSummaryAction == PassSummaryAction::Import ? &Summary : nullptr) + .run(); if (!ClWriteSummary.empty()) { ExitOnError ExitOnErr( @@ -1197,7 +1209,7 @@ void DevirtModule::importResolution(VTableSlot Slot, VTableSlotInfo &SlotInfo) { const TypeIdSummary *TidSummary = - Summary->getTypeIdSummary(cast(Slot.TypeID)->getString()); + ImportSummary->getTypeIdSummary(cast(Slot.TypeID)->getString()); if (!TidSummary) return; auto ResI = TidSummary->WPDRes.find(Slot.ByteOffset); @@ -1270,7 +1282,7 @@ // Normally if there are no users of the devirtualization intrinsics in the // module, this pass has nothing to do. But if we are exporting, we also need // to handle any users that appear only in the function summaries. - if (Action != PassSummaryAction::Export && + if (!ExportSummary && (!TypeTestFunc || TypeTestFunc->use_empty() || !AssumeFunc || AssumeFunc->use_empty()) && (!TypeCheckedLoadFunc || TypeCheckedLoadFunc->use_empty())) @@ -1282,7 +1294,7 @@ if (TypeCheckedLoadFunc) scanTypeCheckedLoadUsers(TypeCheckedLoadFunc); - if (Action == PassSummaryAction::Import) { + if (ImportSummary) { for (auto &S : CallSlots) importResolution(S.first, S.second); @@ -1301,7 +1313,7 @@ return true; // Collect information from summary about which calls to try to devirtualize. - if (Action == PassSummaryAction::Export) { + if (ExportSummary) { DenseMap> MetadataByGUID; for (auto &P : TypeIdMap) { if (auto *TypeId = dyn_cast(P.first)) @@ -1309,7 +1321,7 @@ TypeId); } - for (auto &P : *Summary) { + for (auto &P : *ExportSummary) { for (auto &S : P.second) { auto *FS = dyn_cast(S.get()); if (!FS) @@ -1358,8 +1370,8 @@ if (tryFindVirtualCallTargets(TargetsForSlot, TypeIdMap[S.first.TypeID], S.first.ByteOffset)) { WholeProgramDevirtResolution *Res = nullptr; - if (Action == PassSummaryAction::Export && isa(S.first.TypeID)) - Res = &Summary + if (ExportSummary && isa(S.first.TypeID)) + Res = &ExportSummary ->getOrInsertTypeIdSummary( cast(S.first.TypeID)->getString()) .WPDRes[S.first.ByteOffset]; @@ -1379,7 +1391,7 @@ // intrinsics were *not* devirtualized, we need to add the resulting // llvm.type.test intrinsics to the function summaries so that the // LowerTypeTests pass will export them. - if (Action == PassSummaryAction::Export && isa(S.first.TypeID)) { + if (ExportSummary && isa(S.first.TypeID)) { auto GUID = GlobalValue::getGUID(cast(S.first.TypeID)->getString()); for (auto FS : S.second.CSInfo.SummaryTypeCheckedLoadUsers)