diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2018-07-28 10:51:19 +0000 |
commit | eb11fae6d08f479c0799db45860a98af528fa6e7 (patch) | |
tree | 44d492a50c8c1a7eb8e2d17ea3360ec4d066f042 /lib/LTO/LTO.cpp | |
parent | b8a2042aa938069e862750553db0e4d82d25822c (diff) |
Notes
Diffstat (limited to 'lib/LTO/LTO.cpp')
-rw-r--r-- | lib/LTO/LTO.cpp | 158 |
1 files changed, 109 insertions, 49 deletions
diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp index 64e5186255bd..68d210cb7d73 100644 --- a/lib/LTO/LTO.cpp +++ b/lib/LTO/LTO.cpp @@ -12,11 +12,13 @@ //===----------------------------------------------------------------------===// #include "llvm/LTO/LTO.h" +#include "llvm/ADT/Statistic.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/CodeGen/Analysis.h" +#include "llvm/Config/llvm-config.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LegacyPassManager.h" @@ -50,6 +52,10 @@ using namespace object; #define DEBUG_TYPE "lto" +static cl::opt<bool> + DumpThinCGSCCs("dump-thin-cg-sccs", cl::init(false), cl::Hidden, + cl::desc("Dump the SCCs in the ThinLTO index's callgraph")); + // The values are (type identifier, summary) pairs. typedef DenseMap< GlobalValue::GUID, @@ -132,6 +138,7 @@ static void computeCacheKey( AddString(Conf.AAPipeline); AddString(Conf.OverrideTriple); AddString(Conf.DefaultTriple); + AddString(Conf.DwoDir); // Include the hash for the current module auto ModHash = Index.getModuleHash(ModuleID); @@ -149,7 +156,7 @@ static void computeCacheKey( AddUint64(Entry.second.size()); for (auto &Fn : Entry.second) - AddUint64(Fn.first); + AddUint64(Fn); } // Include the hash for the resolved ODR. @@ -177,8 +184,11 @@ static void computeCacheKey( auto AddUsedThings = [&](GlobalValueSummary *GS) { if (!GS) return; - for (const ValueInfo &VI : GS->refs()) + AddUnsigned(GS->isLive()); + for (const ValueInfo &VI : GS->refs()) { + AddUnsigned(VI.isDSOLocal()); AddUsedCfiGlobal(VI.getGUID()); + } if (auto *FS = dyn_cast<FunctionSummary>(GS)) { for (auto &TT : FS->type_tests()) UsedTypeIds.insert(TT); @@ -190,8 +200,10 @@ static void computeCacheKey( UsedTypeIds.insert(TT.VFunc.GUID); for (auto &TT : FS->type_checked_load_const_vcalls()) UsedTypeIds.insert(TT.VFunc.GUID); - for (auto &ET : FS->calls()) + for (auto &ET : FS->calls()) { + AddUnsigned(ET.first.isDSOLocal()); AddUsedCfiGlobal(ET.first.getGUID()); + } } }; @@ -209,7 +221,7 @@ static void computeCacheKey( // so we need to collect their used resolutions as well. for (auto &ImpM : ImportList) for (auto &ImpF : ImpM.second) - AddUsedThings(Index.findSummaryInModule(ImpF.first, ImpM.first())); + AddUsedThings(Index.findSummaryInModule(ImpF, ImpM.first())); auto AddTypeIdSummary = [&](StringRef TId, const TypeIdSummary &S) { AddString(TId); @@ -388,7 +400,8 @@ LTO::RegularLTOState::RegularLTOState(unsigned ParallelCodeGenParallelismLevel, Ctx(Conf), CombinedModule(llvm::make_unique<Module>("ld-temp.o", Ctx)), Mover(llvm::make_unique<IRMover>(*CombinedModule)) {} -LTO::ThinLTOState::ThinLTOState(ThinBackend Backend) : Backend(Backend) { +LTO::ThinLTOState::ThinLTOState(ThinBackend Backend) + : Backend(Backend), CombinedIndex(/*HaveGVs*/ false) { if (!Backend) this->Backend = createInProcessThinBackend(llvm::heavyweight_hardware_concurrency()); @@ -415,11 +428,27 @@ void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms, assert(ResI != ResE); SymbolResolution Res = *ResI++; - auto &GlobalRes = GlobalResolutions[Sym.getName()]; + StringRef Name = Sym.getName(); + Triple TT(RegularLTO.CombinedModule->getTargetTriple()); + // Strip the __imp_ prefix from COFF dllimport symbols (similar to the + // way they are handled by lld), otherwise we can end up with two + // global resolutions (one with and one for a copy of the symbol without). + if (TT.isOSBinFormatCOFF() && Name.startswith("__imp_")) + Name = Name.substr(strlen("__imp_")); + auto &GlobalRes = GlobalResolutions[Name]; GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr(); if (Res.Prevailing) { - assert(GlobalRes.IRName.empty() && + assert(!GlobalRes.Prevailing && "Multiple prevailing defs are not allowed"); + GlobalRes.Prevailing = true; + GlobalRes.IRName = Sym.getIRName(); + } else if (!GlobalRes.Prevailing && GlobalRes.IRName.empty()) { + // Sometimes it can be two copies of symbol in a module and prevailing + // symbol can have no IR name. That might happen if symbol is defined in + // module level inline asm block. In case we have multiple modules with + // the same symbol we want to use IR name of the prevailing symbol. + // Otherwise, if we haven't seen a prevailing symbol, set the name so that + // we can later use it to check if there is any prevailing copy in IR. GlobalRes.IRName = Sym.getIRName(); } @@ -639,7 +668,8 @@ LTO::addRegularLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms, } // Set the 'local' flag based on the linker resolution for this symbol. - GV->setDSOLocal(Res.FinalDefinitionInLinkageUnit); + if (Res.FinalDefinitionInLinkageUnit) + GV->setDSOLocal(true); } // 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 @@ -744,20 +774,52 @@ unsigned LTO::getMaxTasks() const { Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { // Compute "dead" symbols, we don't want to import/export these! DenseSet<GlobalValue::GUID> GUIDPreservedSymbols; + DenseMap<GlobalValue::GUID, PrevailingType> GUIDPrevailingResolutions; for (auto &Res : GlobalResolutions) { - if (Res.second.VisibleOutsideSummary && - // IRName will be defined if we have seen the prevailing copy of - // this value. If not, no need to preserve any ThinLTO copies. - !Res.second.IRName.empty()) + // Normally resolution have IR name of symbol. We can do nothing here + // otherwise. See comments in GlobalResolution struct for more details. + if (Res.second.IRName.empty()) + continue; + + GlobalValue::GUID GUID = GlobalValue::getGUID( + GlobalValue::dropLLVMManglingEscape(Res.second.IRName)); + + if (Res.second.VisibleOutsideSummary && Res.second.Prevailing) GUIDPreservedSymbols.insert(GlobalValue::getGUID( GlobalValue::dropLLVMManglingEscape(Res.second.IRName))); + + GUIDPrevailingResolutions[GUID] = + Res.second.Prevailing ? PrevailingType::Yes : PrevailingType::No; + } + + auto isPrevailing = [&](GlobalValue::GUID G) { + auto It = GUIDPrevailingResolutions.find(G); + if (It == GUIDPrevailingResolutions.end()) + return PrevailingType::Unknown; + return It->second; + }; + computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols, isPrevailing); + + // Setup output file to emit statistics. + std::unique_ptr<ToolOutputFile> StatsFile = nullptr; + if (!Conf.StatsFile.empty()) { + EnableStatistics(false); + std::error_code EC; + StatsFile = + llvm::make_unique<ToolOutputFile>(Conf.StatsFile, EC, sys::fs::F_None); + if (EC) + return errorCodeToError(EC); + StatsFile->keep(); } - computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols); + Error Result = runRegularLTO(AddStream); + if (!Result) + Result = runThinLTO(AddStream, Cache); + + if (StatsFile) + PrintStatisticsJSON(StatsFile->os()); - if (auto E = runRegularLTO(AddStream)) - return E; - return runThinLTO(AddStream, Cache); + return Result; } Error LTO::runRegularLTO(AddStreamFn AddStream) { @@ -801,7 +863,7 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) { if (!Conf.CodeGenOnly) { for (const auto &R : GlobalResolutions) { - if (R.second.IRName.empty()) + if (!R.second.isPrevailingIRSymbol()) continue; if (R.second.Partition != 0 && R.second.Partition != GlobalResolution::External) @@ -810,7 +872,8 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) { GlobalValue *GV = RegularLTO.CombinedModule->getNamedValue(R.second.IRName); // Ignore symbols defined in other partitions. - if (!GV || GV->hasLocalLinkage()) + // Also skip declarations, which are not allowed to have internal linkage. + if (!GV || GV->hasLocalLinkage() || GV->isDeclaration()) continue; GV->setUnnamedAddr(R.second.UnnamedAddr ? GlobalValue::UnnamedAddr::Global : GlobalValue::UnnamedAddr::None); @@ -1003,20 +1066,19 @@ namespace { class WriteIndexesThinBackend : public ThinBackendProc { std::string OldPrefix, NewPrefix; bool ShouldEmitImportsFiles; - - std::string LinkedObjectsFileName; - std::unique_ptr<llvm::raw_fd_ostream> LinkedObjectsFile; + raw_fd_ostream *LinkedObjectsFile; + lto::IndexWriteCallback OnWrite; public: WriteIndexesThinBackend( Config &Conf, ModuleSummaryIndex &CombinedIndex, const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries, std::string OldPrefix, std::string NewPrefix, bool ShouldEmitImportsFiles, - std::string LinkedObjectsFileName) + raw_fd_ostream *LinkedObjectsFile, lto::IndexWriteCallback OnWrite) : ThinBackendProc(Conf, CombinedIndex, ModuleToDefinedGVSummaries), OldPrefix(OldPrefix), NewPrefix(NewPrefix), ShouldEmitImportsFiles(ShouldEmitImportsFiles), - LinkedObjectsFileName(LinkedObjectsFileName) {} + LinkedObjectsFile(LinkedObjectsFile), OnWrite(OnWrite) {} Error start( unsigned Task, BitcodeModule BM, @@ -1028,30 +1090,29 @@ public: std::string NewModulePath = getThinLTOOutputFile(ModulePath, OldPrefix, NewPrefix); - std::error_code EC; - if (!LinkedObjectsFileName.empty()) { - if (!LinkedObjectsFile) { - LinkedObjectsFile = llvm::make_unique<raw_fd_ostream>( - LinkedObjectsFileName, EC, sys::fs::OpenFlags::F_None); - if (EC) - return errorCodeToError(EC); - } + if (LinkedObjectsFile) *LinkedObjectsFile << NewModulePath << '\n'; - } std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex; gatherImportedSummariesForModule(ModulePath, ModuleToDefinedGVSummaries, ImportList, ModuleToSummariesForIndex); + std::error_code EC; raw_fd_ostream OS(NewModulePath + ".thinlto.bc", EC, sys::fs::OpenFlags::F_None); if (EC) return errorCodeToError(EC); WriteIndexToFile(CombinedIndex, OS, &ModuleToSummariesForIndex); - if (ShouldEmitImportsFiles) - return errorCodeToError( - EmitImportsFiles(ModulePath, NewModulePath + ".imports", ImportList)); + if (ShouldEmitImportsFiles) { + EC = EmitImportsFiles(ModulePath, NewModulePath + ".imports", + ModuleToSummariesForIndex); + if (EC) + return errorCodeToError(EC); + } + + if (OnWrite) + OnWrite(ModulePath); return Error::success(); } @@ -1059,16 +1120,15 @@ public: }; } // end anonymous namespace -ThinBackend lto::createWriteIndexesThinBackend(std::string OldPrefix, - std::string NewPrefix, - bool ShouldEmitImportsFiles, - std::string LinkedObjectsFile) { +ThinBackend lto::createWriteIndexesThinBackend( + std::string OldPrefix, std::string NewPrefix, bool ShouldEmitImportsFiles, + raw_fd_ostream *LinkedObjectsFile, IndexWriteCallback OnWrite) { return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex, const StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries, AddStreamFn AddStream, NativeObjectCache Cache) { return llvm::make_unique<WriteIndexesThinBackend>( Conf, CombinedIndex, ModuleToDefinedGVSummaries, OldPrefix, NewPrefix, - ShouldEmitImportsFiles, LinkedObjectsFile); + ShouldEmitImportsFiles, LinkedObjectsFile, OnWrite); }; } @@ -1102,6 +1162,9 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache) { ThinLTO.ModuleMap.size()); StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; + if (DumpThinCGSCCs) + ThinLTO.CombinedIndex.dumpSCCs(outs()); + if (Conf.OptLevel > 0) ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, ImportLists, ExportLists); @@ -1112,13 +1175,10 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache) { // 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()) + // If the symbol does not have external references or it is not prevailing, + // then not need to mark it as exported from a ThinLTO partition. + if (Res.second.Partition != GlobalResolution::External || + !Res.second.isPrevailingIRSymbol()) continue; auto GUID = GlobalValue::getGUID( GlobalValue::dropLLVMManglingEscape(Res.second.IRName)); @@ -1175,6 +1235,8 @@ Expected<std::unique_ptr<ToolOutputFile>> lto::setupOptimizationRemarks(LLVMContext &Context, StringRef LTORemarksFilename, bool LTOPassRemarksWithHotness, int Count) { + if (LTOPassRemarksWithHotness) + Context.setDiagnosticsHotnessRequested(true); if (LTORemarksFilename.empty()) return nullptr; @@ -1189,8 +1251,6 @@ lto::setupOptimizationRemarks(LLVMContext &Context, return errorCodeToError(EC); Context.setDiagnosticsOutputFile( llvm::make_unique<yaml::Output>(DiagnosticFile->os())); - if (LTOPassRemarksWithHotness) - Context.setDiagnosticsHotnessRequested(true); DiagnosticFile->keep(); return std::move(DiagnosticFile); } |