diff options
Diffstat (limited to 'lib/LTO/LTO.cpp')
| -rw-r--r-- | lib/LTO/LTO.cpp | 210 |
1 files changed, 134 insertions, 76 deletions
diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp index 19973946ac5a..64e5186255bd 100644 --- a/lib/LTO/LTO.cpp +++ b/lib/LTO/LTO.cpp @@ -65,7 +65,9 @@ static void computeCacheKey( const FunctionImporter::ExportSetTy &ExportList, const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR, const GVSummaryMapTy &DefinedGlobals, - const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) { + const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid, + const std::set<GlobalValue::GUID> &CfiFunctionDefs, + const std::set<GlobalValue::GUID> &CfiFunctionDecls) { // 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 @@ -118,7 +120,10 @@ static void computeCacheKey( AddUnsigned(*Conf.RelocModel); else AddUnsigned(-1); - AddUnsigned(Conf.CodeModel); + if (Conf.CodeModel) + AddUnsigned(*Conf.CodeModel); + else + AddUnsigned(-1); AddUnsigned(Conf.CGOptLevel); AddUnsigned(Conf.CGFileType); AddUnsigned(Conf.OptLevel); @@ -155,22 +160,39 @@ static void computeCacheKey( sizeof(GlobalValue::LinkageTypes))); } + // Members of CfiFunctionDefs and CfiFunctionDecls that are referenced or + // defined in this module. + std::set<GlobalValue::GUID> UsedCfiDefs; + std::set<GlobalValue::GUID> UsedCfiDecls; + + // Typeids used in this module. std::set<GlobalValue::GUID> UsedTypeIds; - auto AddUsedTypeIds = [&](GlobalValueSummary *GS) { - auto *FS = dyn_cast_or_null<FunctionSummary>(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); + auto AddUsedCfiGlobal = [&](GlobalValue::GUID ValueGUID) { + if (CfiFunctionDefs.count(ValueGUID)) + UsedCfiDefs.insert(ValueGUID); + if (CfiFunctionDecls.count(ValueGUID)) + UsedCfiDecls.insert(ValueGUID); + }; + + auto AddUsedThings = [&](GlobalValueSummary *GS) { + if (!GS) return; + for (const ValueInfo &VI : GS->refs()) + AddUsedCfiGlobal(VI.getGUID()); + if (auto *FS = dyn_cast<FunctionSummary>(GS)) { + 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); + for (auto &ET : FS->calls()) + AddUsedCfiGlobal(ET.first.getGUID()); + } }; // Include the hash for the linkage type to reflect internalization and weak @@ -179,14 +201,15 @@ static void computeCacheKey( GlobalValue::LinkageTypes Linkage = GS.second->linkage(); Hasher.update( ArrayRef<uint8_t>((const uint8_t *)&Linkage, sizeof(Linkage))); - AddUsedTypeIds(GS.second); + AddUsedCfiGlobal(GS.first); + AddUsedThings(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())); + AddUsedThings(Index.findSummaryInModule(ImpF.first, ImpM.first())); auto AddTypeIdSummary = [&](StringRef TId, const TypeIdSummary &S) { AddString(TId); @@ -194,6 +217,11 @@ static void computeCacheKey( AddUnsigned(S.TTRes.TheKind); AddUnsigned(S.TTRes.SizeM1BitWidth); + AddUint64(S.TTRes.AlignLog2); + AddUint64(S.TTRes.SizeM1); + AddUint64(S.TTRes.BitMask); + AddUint64(S.TTRes.InlineBits); + AddUint64(S.WPDRes.size()); for (auto &WPD : S.WPDRes) { AddUnsigned(WPD.first); @@ -207,6 +235,8 @@ static void computeCacheKey( AddUint64(Arg); AddUnsigned(ByArg.second.TheKind); AddUint64(ByArg.second.Info); + AddUnsigned(ByArg.second.Byte); + AddUnsigned(ByArg.second.Bit); } } }; @@ -219,6 +249,14 @@ static void computeCacheKey( AddTypeIdSummary(Summary->first, Summary->second); } + AddUnsigned(UsedCfiDefs.size()); + for (auto &V : UsedCfiDefs) + AddUint64(V); + + AddUnsigned(UsedCfiDecls.size()); + for (auto &V : UsedCfiDecls) + AddUint64(V); + if (!Conf.SampleProfile.empty()) { auto FileOrErr = MemoryBuffer::getFile(Conf.SampleProfile); if (FileOrErr) @@ -347,7 +385,8 @@ StringRef InputFile::getName() const { LTO::RegularLTOState::RegularLTOState(unsigned ParallelCodeGenParallelismLevel, Config &Conf) : ParallelCodeGenParallelismLevel(ParallelCodeGenParallelismLevel), - Ctx(Conf) {} + Ctx(Conf), CombinedModule(llvm::make_unique<Module>("ld-temp.o", Ctx)), + Mover(llvm::make_unique<IRMover>(*CombinedModule)) {} LTO::ThinLTOState::ThinLTOState(ThinBackend Backend) : Backend(Backend) { if (!Backend) @@ -378,8 +417,11 @@ void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms, auto &GlobalRes = GlobalResolutions[Sym.getName()]; GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr(); - if (Res.Prevailing) + if (Res.Prevailing) { + assert(GlobalRes.IRName.empty() && + "Multiple prevailing defs are not allowed"); GlobalRes.IRName = Sym.getIRName(); + } // Set the partition to external if we know it is re-defined by the linker // with -defsym or -wrap options, used elsewhere, e.g. it is visible to a @@ -431,6 +473,9 @@ Error LTO::add(std::unique_ptr<InputFile> Input, if (Conf.ResolutionFile) writeToResolutionFile(*Conf.ResolutionFile, Input.get(), Res); + if (RegularLTO.CombinedModule->getTargetTriple().empty()) + RegularLTO.CombinedModule->setTargetTriple(Input->getTargetTriple()); + const SymbolResolution *ResI = Res.begin(); for (unsigned I = 0; I != Input->Mods.size(); ++I) if (Error Err = addModule(*Input, I, ResI, Res.end())) @@ -592,6 +637,9 @@ LTO::addRegularLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms, NonPrevailingComdats.insert(GV->getComdat()); cast<GlobalObject>(GV)->setComdat(nullptr); } + + // Set the 'local' flag based on the linker resolution for this symbol. + GV->setDSOLocal(Res.FinalDefinitionInLinkageUnit); } // Common resolution: collect the maximum size/alignment over all commons. // We also record if we see an instance of a common as prevailing, so that @@ -605,7 +653,6 @@ LTO::addRegularLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms, CommonRes.Prevailing |= Res.Prevailing; } - // FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit. } if (!M.getComdatSymbolTable().empty()) for (GlobalValue &GV : M.global_values()) @@ -616,12 +663,6 @@ LTO::addRegularLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms, Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod, bool LivenessFromIndex) { - if (!RegularLTO.CombinedModule) { - RegularLTO.CombinedModule = - llvm::make_unique<Module>("ld-temp.o", RegularLTO.Ctx); - RegularLTO.Mover = llvm::make_unique<IRMover>(*RegularLTO.CombinedModule); - } - std::vector<GlobalValue *> Keep; for (GlobalValue *GV : Mod.Keep) { if (LivenessFromIndex && !ThinLTO.CombinedIndex.isGUIDLive(GV->getGUID())) @@ -660,10 +701,10 @@ Error LTO::addThinLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms, assert(ResI != ResE); SymbolResolution Res = *ResI++; - if (Res.Prevailing) { - if (!Sym.getIRName().empty()) { - auto GUID = GlobalValue::getGUID(GlobalValue::getGlobalIdentifier( - Sym.getIRName(), GlobalValue::ExternalLinkage, "")); + if (!Sym.getIRName().empty()) { + auto GUID = GlobalValue::getGUID(GlobalValue::getGlobalIdentifier( + Sym.getIRName(), GlobalValue::ExternalLinkage, "")); + if (Res.Prevailing) { ThinLTO.PrevailingModuleForGUID[GUID] = BM.getModuleIdentifier(); // For linker redefined symbols (via --wrap or --defsym) we want to @@ -675,6 +716,15 @@ Error LTO::addThinLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms, GUID, BM.getModuleIdentifier())) S->setLinkage(GlobalValue::WeakAnyLinkage); } + + // If the linker resolved the symbol to a local definition then mark it + // as local in the summary for the module we are adding. + if (Res.FinalDefinitionInLinkageUnit) { + if (auto S = ThinLTO.CombinedIndex.findSummaryInModule( + GUID, BM.getModuleIdentifier())) { + S->setDSOLocal(true); + } + } } } @@ -705,16 +755,9 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols); - // Save the status of having a regularLTO combined module, as - // this is needed for generating the ThinLTO Task ID, and - // the CombinedModule will be moved at the end of runRegularLTO. - bool HasRegularLTO = RegularLTO.CombinedModule != nullptr || - !RegularLTO.ModsWithSummaries.empty(); - // Invoke regular LTO if there was a regular LTO module to start with. - if (HasRegularLTO) - if (auto E = runRegularLTO(AddStream)) - return E; - return runThinLTO(AddStream, Cache, HasRegularLTO); + if (auto E = runRegularLTO(AddStream)) + return E; + return runThinLTO(AddStream, Cache); } Error LTO::runRegularLTO(AddStreamFn AddStream) { @@ -812,6 +855,8 @@ class InProcessThinBackend : public ThinBackendProc { AddStreamFn AddStream; NativeObjectCache Cache; TypeIdSummariesByGuidTy TypeIdSummariesByGuid; + std::set<GlobalValue::GUID> CfiFunctionDefs; + std::set<GlobalValue::GUID> CfiFunctionDecls; Optional<Error> Err; std::mutex ErrMu; @@ -831,6 +876,12 @@ public: // each function without needing to compute GUIDs in each backend. for (auto &TId : CombinedIndex.typeIds()) TypeIdSummariesByGuid[GlobalValue::getGUID(TId.first)].push_back(&TId); + for (auto &Name : CombinedIndex.cfiFunctionDefs()) + CfiFunctionDefs.insert( + GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); + for (auto &Name : CombinedIndex.cfiFunctionDecls()) + CfiFunctionDecls.insert( + GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Name))); } Error runThinLTOBackendThread( @@ -864,7 +915,8 @@ public: SmallString<40> Key; // The module may be cached, this helps handling it. computeCacheKey(Key, Conf, CombinedIndex, ModuleID, ImportList, ExportList, - ResolvedODR, DefinedGlobals, TypeIdSummariesByGuid); + ResolvedODR, DefinedGlobals, TypeIdSummariesByGuid, + CfiFunctionDefs, CfiFunctionDecls); if (AddStreamFn CacheAddStream = Cache(Task, Key)) return RunThinBackend(CacheAddStream); @@ -1020,8 +1072,7 @@ ThinBackend lto::createWriteIndexesThinBackend(std::string OldPrefix, }; } -Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, - bool HasRegularLTO) { +Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache) { if (ThinLTO.ModuleMap.empty()) return Error::success(); @@ -1051,36 +1102,45 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, ThinLTO.ModuleMap.size()); StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; - if (Conf.OptLevel > 0) { + if (Conf.OptLevel > 0) ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, ImportLists, ExportLists); - std::set<GlobalValue::GUID> ExportedGUIDs; - for (auto &Res : GlobalResolutions) { - // First check if the symbol was flagged as having external references. - if (Res.second.Partition != GlobalResolution::External) - continue; - // IRName will be defined if we have seen the prevailing copy of - // this value. If not, no need to mark as exported from a ThinLTO - // partition (and we can't get the GUID). - if (Res.second.IRName.empty()) - continue; - auto GUID = GlobalValue::getGUID( - GlobalValue::dropLLVMManglingEscape(Res.second.IRName)); - // Mark exported unless index-based analysis determined it to be dead. - if (ThinLTO.CombinedIndex.isGUIDLive(GUID)) - ExportedGUIDs.insert(GUID); - } - - auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { - const auto &ExportList = ExportLists.find(ModuleIdentifier); - return (ExportList != ExportLists.end() && - ExportList->second.count(GUID)) || - ExportedGUIDs.count(GUID); - }; - thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported); + // Figure out which symbols need to be internalized. This also needs to happen + // at -O0 because summary-based DCE is implemented using internalization, and + // we must apply DCE consistently with the full LTO module in order to avoid + // undefined references during the final link. + std::set<GlobalValue::GUID> ExportedGUIDs; + for (auto &Res : GlobalResolutions) { + // First check if the symbol was flagged as having external references. + if (Res.second.Partition != GlobalResolution::External) + continue; + // IRName will be defined if we have seen the prevailing copy of + // this value. If not, no need to mark as exported from a ThinLTO + // partition (and we can't get the GUID). + if (Res.second.IRName.empty()) + continue; + auto GUID = GlobalValue::getGUID( + GlobalValue::dropLLVMManglingEscape(Res.second.IRName)); + // Mark exported unless index-based analysis determined it to be dead. + if (ThinLTO.CombinedIndex.isGUIDLive(GUID)) + ExportedGUIDs.insert(GUID); } + // Any functions referenced by the jump table in the regular LTO object must + // be exported. + for (auto &Def : ThinLTO.CombinedIndex.cfiFunctionDefs()) + ExportedGUIDs.insert( + GlobalValue::getGUID(GlobalValue::dropLLVMManglingEscape(Def))); + + auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { + const auto &ExportList = ExportLists.find(ModuleIdentifier); + return (ExportList != ExportLists.end() && + ExportList->second.count(GUID)) || + ExportedGUIDs.count(GUID); + }; + thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported); + auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) { return ThinLTO.PrevailingModuleForGUID[GUID] == S->modulePath(); @@ -1097,11 +1157,9 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, AddStream, Cache); - // Task numbers start at ParallelCodeGenParallelismLevel if an LTO - // module is present, as tasks 0 through ParallelCodeGenParallelismLevel-1 - // are reserved for parallel code generation partitions. - unsigned Task = - HasRegularLTO ? RegularLTO.ParallelCodeGenParallelismLevel : 0; + // Tasks 0 through ParallelCodeGenParallelismLevel-1 are reserved for combined + // module and parallel code generation partitions. + unsigned Task = RegularLTO.ParallelCodeGenParallelismLevel; for (auto &Mod : ThinLTO.ModuleMap) { if (Error E = BackendProc->start(Task, Mod.second, ImportLists[Mod.first], ExportLists[Mod.first], @@ -1113,7 +1171,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, return BackendProc->wait(); } -Expected<std::unique_ptr<tool_output_file>> +Expected<std::unique_ptr<ToolOutputFile>> lto::setupOptimizationRemarks(LLVMContext &Context, StringRef LTORemarksFilename, bool LTOPassRemarksWithHotness, int Count) { @@ -1126,7 +1184,7 @@ lto::setupOptimizationRemarks(LLVMContext &Context, std::error_code EC; auto DiagnosticFile = - llvm::make_unique<tool_output_file>(Filename, EC, sys::fs::F_None); + llvm::make_unique<ToolOutputFile>(Filename, EC, sys::fs::F_None); if (EC) return errorCodeToError(EC); Context.setDiagnosticsOutputFile( |
