diff options
Diffstat (limited to 'contrib/llvm/lib/LTO')
-rw-r--r-- | contrib/llvm/lib/LTO/Caching.cpp | 38 | ||||
-rw-r--r-- | contrib/llvm/lib/LTO/LTO.cpp | 158 | ||||
-rw-r--r-- | contrib/llvm/lib/LTO/LTOBackend.cpp | 119 | ||||
-rw-r--r-- | contrib/llvm/lib/LTO/LTOCodeGenerator.cpp | 2 | ||||
-rw-r--r-- | contrib/llvm/lib/LTO/LTOModule.cpp | 27 | ||||
-rw-r--r-- | contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp | 150 |
6 files changed, 330 insertions, 164 deletions
diff --git a/contrib/llvm/lib/LTO/Caching.cpp b/contrib/llvm/lib/LTO/Caching.cpp index dd47eb584b7f..089e77e742eb 100644 --- a/contrib/llvm/lib/LTO/Caching.cpp +++ b/contrib/llvm/lib/LTO/Caching.cpp @@ -19,6 +19,12 @@ #include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <unistd.h> +#else +#include <io.h> +#endif + using namespace llvm; using namespace llvm::lto; @@ -33,16 +39,32 @@ Expected<NativeObjectCache> lto::localCache(StringRef CacheDirectoryPath, SmallString<64> EntryPath; sys::path::append(EntryPath, CacheDirectoryPath, "llvmcache-" + Key); // First, see if we have a cache hit. - ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = - MemoryBuffer::getFile(EntryPath); - if (MBOrErr) { - AddBuffer(Task, std::move(*MBOrErr), EntryPath); - return AddStreamFn(); + int FD; + SmallString<64> ResultPath; + std::error_code EC = sys::fs::openFileForRead( + Twine(EntryPath), FD, sys::fs::OF_UpdateAtime, &ResultPath); + if (!EC) { + ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = + MemoryBuffer::getOpenFile(FD, EntryPath, + /*FileSize*/ -1, + /*RequiresNullTerminator*/ false); + close(FD); + if (MBOrErr) { + AddBuffer(Task, std::move(*MBOrErr)); + return AddStreamFn(); + } + EC = MBOrErr.getError(); } - if (MBOrErr.getError() != errc::no_such_file_or_directory) + // On Windows we can fail to open a cache file with a permission denied + // error. This generally means that another process has requested to delete + // the file while it is still open, but it could also mean that another + // process has opened the file without the sharing permissions we need. + // Since the file is probably being deleted we handle it in the same way as + // if the file did not exist at all. + if (EC != errc::no_such_file_or_directory && EC != errc::permission_denied) report_fatal_error(Twine("Failed to open cache file ") + EntryPath + - ": " + MBOrErr.getError().message() + "\n"); + ": " + EC.message() + "\n"); // This native object stream is responsible for commiting the resulting // file to the cache and calling AddBuffer to add it to the link. @@ -103,7 +125,7 @@ Expected<NativeObjectCache> lto::localCache(StringRef CacheDirectoryPath, TempFile.TmpName + " to " + EntryPath + ": " + toString(std::move(E)) + "\n"); - AddBuffer(Task, std::move(*MBOrErr), EntryPath); + AddBuffer(Task, std::move(*MBOrErr)); } }; diff --git a/contrib/llvm/lib/LTO/LTO.cpp b/contrib/llvm/lib/LTO/LTO.cpp index 64e5186255bd..68d210cb7d73 100644 --- a/contrib/llvm/lib/LTO/LTO.cpp +++ b/contrib/llvm/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); } diff --git a/contrib/llvm/lib/LTO/LTOBackend.cpp b/contrib/llvm/lib/LTO/LTOBackend.cpp index 501d6284117b..eadbb410bd5a 100644 --- a/contrib/llvm/lib/LTO/LTOBackend.cpp +++ b/contrib/llvm/lib/LTO/LTOBackend.cpp @@ -30,6 +30,10 @@ #include "llvm/Passes/PassBuilder.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileSystem.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Target/TargetMachine.h" @@ -72,17 +76,19 @@ Error Config::addSaveTemps(std::string OutputFileName, // user hasn't requested using the input module's path, emit to a file // named from the provided OutputFileName with the Task ID appended. if (M.getModuleIdentifier() == "ld-temp.o" || !UseInputModulePath) { - PathPrefix = OutputFileName + utostr(Task); + PathPrefix = OutputFileName; + if (Task != (unsigned)-1) + PathPrefix += utostr(Task) + "."; } else - PathPrefix = M.getModuleIdentifier(); - std::string Path = PathPrefix + "." + PathSuffix + ".bc"; + PathPrefix = M.getModuleIdentifier() + "."; + std::string Path = PathPrefix + PathSuffix + ".bc"; std::error_code EC; raw_fd_ostream OS(Path, EC, sys::fs::OpenFlags::F_None); // Because -save-temps is a debugging feature, we report the error // directly and exit. if (EC) reportOpenError(Path, EC.message()); - WriteBitcodeToFile(&M, OS, /*ShouldPreserveUseListOrder=*/false); + WriteBitcodeToFile(M, OS, /*ShouldPreserveUseListOrder=*/false); return true; }; }; @@ -103,6 +109,12 @@ Error Config::addSaveTemps(std::string OutputFileName, if (EC) reportOpenError(Path, EC.message()); WriteIndexToFile(Index, OS); + + Path = OutputFileName + "index.dot"; + raw_fd_ostream OSDot(Path, EC, sys::fs::OpenFlags::F_None); + if (EC) + reportOpenError(Path, EC.message()); + Index.exportToDot(OSDot); return true; }; @@ -132,7 +144,9 @@ createTargetMachine(Config &Conf, const Target *TheTarget, Module &M) { } static void runNewPMPasses(Config &Conf, Module &Mod, TargetMachine *TM, - unsigned OptLevel, bool IsThinLTO) { + unsigned OptLevel, bool IsThinLTO, + ModuleSummaryIndex *ExportSummary, + const ModuleSummaryIndex *ImportSummary) { Optional<PGOOptions> PGOOpt; if (!Conf.SampleProfile.empty()) PGOOpt = PGOOptions("", "", Conf.SampleProfile, false, true); @@ -182,9 +196,10 @@ static void runNewPMPasses(Config &Conf, Module &Mod, TargetMachine *TM, } if (IsThinLTO) - MPM = PB.buildThinLTODefaultPipeline(OL, Conf.DebugPassManager); + MPM = PB.buildThinLTODefaultPipeline(OL, Conf.DebugPassManager, + ImportSummary); else - MPM = PB.buildLTODefaultPipeline(OL, Conf.DebugPassManager); + MPM = PB.buildLTODefaultPipeline(OL, Conf.DebugPassManager, ExportSummary); MPM.run(Mod, MAM); // FIXME (davide): verify the output. @@ -267,7 +282,8 @@ bool opt(Config &Conf, TargetMachine *TM, unsigned Task, Module &Mod, runNewPMCustomPasses(Mod, TM, Conf.OptPipeline, Conf.AAPipeline, Conf.DisableVerify); else if (Conf.UseNewPM) - runNewPMPasses(Conf, Mod, TM, Conf.OptLevel, IsThinLTO); + runNewPMPasses(Conf, Mod, TM, Conf.OptLevel, IsThinLTO, ExportSummary, + ImportSummary); else runOldPMPasses(Conf, Mod, TM, IsThinLTO, ExportSummary, ImportSummary); return !Conf.PostOptModuleHook || Conf.PostOptModuleHook(Task, Mod); @@ -278,11 +294,36 @@ void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream, if (Conf.PreCodeGenModuleHook && !Conf.PreCodeGenModuleHook(Task, Mod)) return; + std::unique_ptr<ToolOutputFile> DwoOut; + SmallString<1024> DwoFile(Conf.DwoPath); + if (!Conf.DwoDir.empty()) { + std::error_code EC; + if (auto EC = llvm::sys::fs::create_directories(Conf.DwoDir)) + report_fatal_error("Failed to create directory " + Conf.DwoDir + ": " + + EC.message()); + + DwoFile = Conf.DwoDir; + sys::path::append(DwoFile, std::to_string(Task) + ".dwo"); + } + + if (!DwoFile.empty()) { + std::error_code EC; + TM->Options.MCOptions.SplitDwarfFile = DwoFile.str().str(); + DwoOut = llvm::make_unique<ToolOutputFile>(DwoFile, EC, sys::fs::F_None); + if (EC) + report_fatal_error("Failed to open " + DwoFile + ": " + EC.message()); + } + auto Stream = AddStream(Task); legacy::PassManager CodeGenPasses; - if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS, Conf.CGFileType)) + if (TM->addPassesToEmitFile(CodeGenPasses, *Stream->OS, + DwoOut ? &DwoOut->os() : nullptr, + Conf.CGFileType)) report_fatal_error("Failed to setup codegen"); CodeGenPasses.run(Mod); + + if (DwoOut) + DwoOut->keep(); } void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream, @@ -303,7 +344,7 @@ void splitCodeGen(Config &C, TargetMachine *TM, AddStreamFn AddStream, // FIXME: Provide a more direct way to do this in LLVM. SmallString<0> BC; raw_svector_ostream BCOS(BC); - WriteBitcodeToFile(MPart.get(), BCOS); + WriteBitcodeToFile(*MPart, BCOS); // Enqueue the task CodegenThreadPool.async( @@ -348,14 +389,15 @@ Expected<const Target *> initAndLookupTarget(Config &C, Module &Mod) { } -static void +static Error finalizeOptimizationRemarks(std::unique_ptr<ToolOutputFile> DiagOutputFile) { // Make sure we flush the diagnostic remarks file in case the linker doesn't // call the global destructors before exiting. if (!DiagOutputFile) - return; + return Error::success(); DiagOutputFile->keep(); DiagOutputFile->os().flush(); + return Error::success(); } Error lto::backend(Config &C, AddStreamFn AddStream, @@ -377,10 +419,8 @@ Error lto::backend(Config &C, AddStreamFn AddStream, if (!C.CodeGenOnly) { if (!opt(C, TM.get(), 0, *Mod, /*IsThinLTO=*/false, - /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr)) { - finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); - return Error::success(); - } + /*ExportSummary=*/&CombinedIndex, /*ImportSummary=*/nullptr)) + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); } if (ParallelCodeGenParallelismLevel == 1) { @@ -389,8 +429,28 @@ Error lto::backend(Config &C, AddStreamFn AddStream, splitCodeGen(C, TM.get(), AddStream, ParallelCodeGenParallelismLevel, std::move(Mod)); } - finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); - return Error::success(); + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); +} + +static void dropDeadSymbols(Module &Mod, const GVSummaryMapTy &DefinedGlobals, + const ModuleSummaryIndex &Index) { + std::vector<GlobalValue*> DeadGVs; + for (auto &GV : Mod.global_values()) + if (GlobalValueSummary *GVS = DefinedGlobals.lookup(GV.getGUID())) + if (!Index.isGlobalValueLive(GVS)) { + DeadGVs.push_back(&GV); + convertToDeclaration(GV); + } + + // Now that all dead bodies have been dropped, delete the actual objects + // themselves when possible. + for (GlobalValue *GV : DeadGVs) { + GV->removeDeadConstantUsers(); + // Might reference something defined in native object (i.e. dropped a + // non-prevailing IR def, but we need to keep the declaration). + if (GV->use_empty()) + GV->eraseFromParent(); + } } Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, @@ -404,27 +464,36 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, std::unique_ptr<TargetMachine> TM = createTargetMachine(Conf, *TOrErr, Mod); + // Setup optimization remarks. + auto DiagFileOrErr = lto::setupOptimizationRemarks( + Mod.getContext(), Conf.RemarksFilename, Conf.RemarksWithHotness, Task); + if (!DiagFileOrErr) + return DiagFileOrErr.takeError(); + auto DiagnosticOutputFile = std::move(*DiagFileOrErr); + if (Conf.CodeGenOnly) { codegen(Conf, TM.get(), AddStream, Task, Mod); - return Error::success(); + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); } if (Conf.PreOptModuleHook && !Conf.PreOptModuleHook(Task, Mod)) - return Error::success(); + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); renameModuleForThinLTO(Mod, CombinedIndex); + dropDeadSymbols(Mod, DefinedGlobals, CombinedIndex); + thinLTOResolveWeakForLinkerModule(Mod, DefinedGlobals); if (Conf.PostPromoteModuleHook && !Conf.PostPromoteModuleHook(Task, Mod)) - return Error::success(); + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); if (!DefinedGlobals.empty()) thinLTOInternalizeModule(Mod, DefinedGlobals); if (Conf.PostInternalizeModuleHook && !Conf.PostInternalizeModuleHook(Task, Mod)) - return Error::success(); + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); auto ModuleLoader = [&](StringRef Identifier) { assert(Mod.getContext().isODRUniquingDebugTypes() && @@ -441,12 +510,12 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, return Err; if (Conf.PostImportModuleHook && !Conf.PostImportModuleHook(Task, Mod)) - return Error::success(); + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); if (!opt(Conf, TM.get(), Task, Mod, /*IsThinLTO=*/true, /*ExportSummary=*/nullptr, /*ImportSummary=*/&CombinedIndex)) - return Error::success(); + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); codegen(Conf, TM.get(), AddStream, Task, Mod); - return Error::success(); + return finalizeOptimizationRemarks(std::move(DiagnosticOutputFile)); } diff --git a/contrib/llvm/lib/LTO/LTOCodeGenerator.cpp b/contrib/llvm/lib/LTO/LTOCodeGenerator.cpp index c7306df95d3d..ffe9af74cdca 100644 --- a/contrib/llvm/lib/LTO/LTOCodeGenerator.cpp +++ b/contrib/llvm/lib/LTO/LTOCodeGenerator.cpp @@ -220,7 +220,7 @@ bool LTOCodeGenerator::writeMergedModules(StringRef Path) { } // write bitcode to it - WriteBitcodeToFile(MergedModule.get(), Out.os(), ShouldEmbedUselists); + WriteBitcodeToFile(*MergedModule, Out.os(), ShouldEmbedUselists); Out.os().close(); if (Out.os().has_error()) { diff --git a/contrib/llvm/lib/LTO/LTOModule.cpp b/contrib/llvm/lib/LTO/LTOModule.cpp index 626d2f5dc813..20fc0943539f 100644 --- a/contrib/llvm/lib/LTO/LTOModule.cpp +++ b/contrib/llvm/lib/LTO/LTOModule.cpp @@ -14,9 +14,7 @@ #include "llvm/LTO/legacy/LTOModule.h" #include "llvm/ADT/Triple.h" -#include "llvm/Analysis/ObjectUtils.h" #include "llvm/Bitcode/BitcodeReader.h" -#include "llvm/CodeGen/TargetLoweringObjectFile.h" #include "llvm/CodeGen/TargetSubtargetInfo.h" #include "llvm/IR/Constants.h" #include "llvm/IR/LLVMContext.h" @@ -39,6 +37,7 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/TargetSelect.h" +#include "llvm/Target/TargetLoweringObjectFile.h" #include "llvm/Transforms/Utils/GlobalStatus.h" #include <system_error> using namespace llvm; @@ -57,11 +56,7 @@ LTOModule::~LTOModule() {} bool LTOModule::isBitcodeFile(const void *Mem, size_t Length) { Expected<MemoryBufferRef> BCData = IRObjectFile::findBitcodeInMemBuffer( MemoryBufferRef(StringRef((const char *)Mem, Length), "<mem>")); - if (!BCData) { - consumeError(BCData.takeError()); - return false; - } - return true; + return !errorToBool(BCData.takeError()); } bool LTOModule::isBitcodeFile(StringRef Path) { @@ -72,11 +67,7 @@ bool LTOModule::isBitcodeFile(StringRef Path) { Expected<MemoryBufferRef> BCData = IRObjectFile::findBitcodeInMemBuffer( BufferOrErr.get()->getMemBufferRef()); - if (!BCData) { - consumeError(BCData.takeError()); - return false; - } - return true; + return !errorToBool(BCData.takeError()); } bool LTOModule::isThinLTO() { @@ -92,10 +83,8 @@ bool LTOModule::isBitcodeForTarget(MemoryBuffer *Buffer, StringRef TriplePrefix) { Expected<MemoryBufferRef> BCOrErr = IRObjectFile::findBitcodeInMemBuffer(Buffer->getMemBufferRef()); - if (!BCOrErr) { - consumeError(BCOrErr.takeError()); + if (errorToBool(BCOrErr.takeError())) return false; - } LLVMContext Context; ErrorOr<std::string> TripleOrErr = expectedToErrorOrAndEmitErrors(Context, getBitcodeTargetTriple(*BCOrErr)); @@ -107,10 +96,8 @@ bool LTOModule::isBitcodeForTarget(MemoryBuffer *Buffer, std::string LTOModule::getProducerString(MemoryBuffer *Buffer) { Expected<MemoryBufferRef> BCOrErr = IRObjectFile::findBitcodeInMemBuffer(Buffer->getMemBufferRef()); - if (!BCOrErr) { - consumeError(BCOrErr.takeError()); + if (errorToBool(BCOrErr.takeError())) return ""; - } LLVMContext Context; ErrorOr<std::string> ProducerOrErr = expectedToErrorOrAndEmitErrors( Context, getBitcodeProducerString(*BCOrErr)); @@ -220,7 +207,7 @@ LTOModule::makeLTOModule(MemoryBufferRef Buffer, const TargetOptions &options, std::string errMsg; const Target *march = TargetRegistry::lookupTarget(TripleStr, errMsg); if (!march) - return std::unique_ptr<LTOModule>(nullptr); + return make_error_code(object::object_error::arch_not_found); // construct LTOModule, hand over ownership of module and target SubtargetFeatures Features; @@ -456,7 +443,7 @@ void LTOModule::addDefinedSymbol(StringRef Name, const GlobalValue *def, attr |= LTO_SYMBOL_SCOPE_HIDDEN; else if (def->hasProtectedVisibility()) attr |= LTO_SYMBOL_SCOPE_PROTECTED; - else if (canBeOmittedFromSymbolTable(def)) + else if (def->canBeOmittedFromSymbolTable()) attr |= LTO_SYMBOL_SCOPE_DEFAULT_CAN_BE_HIDDEN; else attr |= LTO_SYMBOL_SCOPE_DEFAULT; diff --git a/contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp b/contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp index abcd8905ad35..90d0f9bdb885 100644 --- a/contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/contrib/llvm/lib/LTO/ThinLTOCodeGenerator.cpp @@ -23,7 +23,7 @@ #include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/Bitcode/BitcodeWriterPass.h" -#include "llvm/ExecutionEngine/ObjectMemoryBuffer.h" +#include "llvm/Config/llvm-config.h" #include "llvm/IR/DebugInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LLVMContext.h" @@ -39,6 +39,7 @@ #include "llvm/Support/Error.h" #include "llvm/Support/Path.h" #include "llvm/Support/SHA1.h" +#include "llvm/Support/SmallVectorMemoryBuffer.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/Threading.h" @@ -54,6 +55,12 @@ #include <numeric> +#if !defined(_MSC_VER) && !defined(__MINGW32__) +#include <unistd.h> +#else +#include <io.h> +#endif + using namespace llvm; #define DEBUG_TYPE "thinlto" @@ -82,7 +89,7 @@ static void saveTempBitcode(const Module &TheModule, StringRef TempDir, if (EC) report_fatal_error(Twine("Failed to open ") + SaveTempPath + " to save optimized bitcode\n"); - WriteBitcodeToFile(&TheModule, OS, /* ShouldPreserveUseListOrder */ true); + WriteBitcodeToFile(TheModule, OS, /* ShouldPreserveUseListOrder */ true); } static const GlobalValueSummary * @@ -267,14 +274,14 @@ std::unique_ptr<MemoryBuffer> codegenModule(Module &TheModule, PM.add(createObjCARCContractPass()); // Setup the codegen now. - if (TM.addPassesToEmitFile(PM, OS, TargetMachine::CGFT_ObjectFile, + if (TM.addPassesToEmitFile(PM, OS, nullptr, TargetMachine::CGFT_ObjectFile, /* DisableVerify */ true)) report_fatal_error("Failed to setup codegen"); // Run codegen now. resulting binary is in OutputBuffer. PM.run(TheModule); } - return make_unique<ObjectMemoryBuffer>(std::move(OutputBuffer)); + return make_unique<SmallVectorMemoryBuffer>(std::move(OutputBuffer)); } /// Manage caching for a single Module. @@ -390,7 +397,18 @@ public: ErrorOr<std::unique_ptr<MemoryBuffer>> tryLoadingBuffer() { if (EntryPath.empty()) return std::error_code(); - return MemoryBuffer::getFile(EntryPath); + int FD; + SmallString<64> ResultPath; + std::error_code EC = sys::fs::openFileForRead( + Twine(EntryPath), FD, sys::fs::OF_UpdateAtime, &ResultPath); + if (EC) + return EC; + ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = + MemoryBuffer::getOpenFile(FD, EntryPath, + /*FileSize*/ -1, + /*RequiresNullTerminator*/ false); + close(FD); + return MBOrErr; } // Cache the Produced object file @@ -400,9 +418,12 @@ public: // Write to a temporary to avoid race condition SmallString<128> TempFilename; + SmallString<128> CachePath(EntryPath); int TempFD; - std::error_code EC = - sys::fs::createTemporaryFile("Thin", "tmp.o", TempFD, TempFilename); + llvm::sys::path::remove_filename(CachePath); + sys::path::append(TempFilename, CachePath, "Thin-%%%%%%.tmp.o"); + std::error_code EC = + sys::fs::createUniqueFile(TempFilename, TempFD, TempFilename); if (EC) { errs() << "Error: " << EC.message() << "\n"; report_fatal_error("ThinLTO: Can't get a temporary file"); @@ -411,16 +432,10 @@ public: raw_fd_ostream OS(TempFD, /* ShouldClose */ true); OS << OutputBuffer.getBuffer(); } - // Rename to final destination (hopefully race condition won't matter here) + // Rename temp file to final destination; rename is atomic EC = sys::fs::rename(TempFilename, EntryPath); - if (EC) { + if (EC) sys::fs::remove(TempFilename); - raw_fd_ostream OS(EntryPath, EC, sys::fs::F_None); - if (EC) - report_fatal_error(Twine("Failed to open ") + EntryPath + - " to save cached entry\n"); - OS << OutputBuffer.getBuffer(); - } } }; @@ -476,9 +491,9 @@ ProcessThinLTOModule(Module &TheModule, ModuleSummaryIndex &Index, raw_svector_ostream OS(OutputBuffer); ProfileSummaryInfo PSI(TheModule); auto Index = buildModuleSummaryIndex(TheModule, nullptr, &PSI); - WriteBitcodeToFile(&TheModule, OS, true, &Index); + WriteBitcodeToFile(TheModule, OS, true, &Index); } - return make_unique<ObjectMemoryBuffer>(std::move(OutputBuffer)); + return make_unique<SmallVectorMemoryBuffer>(std::move(OutputBuffer)); } return codegenModule(TheModule, TM); @@ -592,7 +607,7 @@ std::unique_ptr<TargetMachine> TargetMachineBuilder::create() const { */ std::unique_ptr<ModuleSummaryIndex> ThinLTOCodeGenerator::linkCombinedIndex() { std::unique_ptr<ModuleSummaryIndex> CombinedIndex = - llvm::make_unique<ModuleSummaryIndex>(); + llvm::make_unique<ModuleSummaryIndex>(/*HaveGVs=*/false); uint64_t NextModuleId = 0; for (auto &ModuleBuffer : Modules) { if (Error Err = readModuleSummaryIndex(ModuleBuffer.getMemBuffer(), @@ -607,6 +622,32 @@ std::unique_ptr<ModuleSummaryIndex> ThinLTOCodeGenerator::linkCombinedIndex() { return CombinedIndex; } +static void internalizeAndPromoteInIndex( + const StringMap<FunctionImporter::ExportSetTy> &ExportLists, + const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols, + ModuleSummaryIndex &Index) { + auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { + const auto &ExportList = ExportLists.find(ModuleIdentifier); + return (ExportList != ExportLists.end() && + ExportList->second.count(GUID)) || + GUIDPreservedSymbols.count(GUID); + }; + + thinLTOInternalizeAndPromoteInIndex(Index, isExported); +} + +static void computeDeadSymbolsInIndex( + ModuleSummaryIndex &Index, + const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) { + // We have no symbols resolution available. And can't do any better now in the + // case where the prevailing symbol is in a native object. It can be refined + // with linker information in the future. + auto isPrevailing = [&](GlobalValue::GUID G) { + return PrevailingType::Unknown; + }; + computeDeadSymbols(Index, GUIDPreservedSymbols, isPrevailing); +} + /** * Perform promotion and renaming of exported internal functions. * Index is updated to reflect linkage changes from weak resolution. @@ -625,7 +666,7 @@ void ThinLTOCodeGenerator::promote(Module &TheModule, PreservedSymbols, Triple(TheModule.getTargetTriple())); // Compute "dead" symbols, we don't want to import/export these! - computeDeadSymbols(Index, GUIDPreservedSymbols); + computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols); // Generate import/export list StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount); @@ -642,13 +683,7 @@ void ThinLTOCodeGenerator::promote(Module &TheModule, // Promote the exported values in the index, so that they are promoted // in the module. - auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { - const auto &ExportList = ExportLists.find(ModuleIdentifier); - return (ExportList != ExportLists.end() && - ExportList->second.count(GUID)) || - GUIDPreservedSymbols.count(GUID); - }; - thinLTOInternalizeAndPromoteInIndex(Index, isExported); + internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, Index); promoteModule(TheModule, Index); } @@ -670,7 +705,7 @@ void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule, PreservedSymbols, Triple(TheModule.getTargetTriple())); // Compute "dead" symbols, we don't want to import/export these! - computeDeadSymbols(Index, GUIDPreservedSymbols); + computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols); // Generate import/export list StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount); @@ -723,8 +758,14 @@ void ThinLTOCodeGenerator::emitImports(StringRef ModulePath, ComputeCrossModuleImport(Index, ModuleToDefinedGVSummaries, ImportLists, ExportLists); + std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex; + llvm::gatherImportedSummariesForModule(ModulePath, ModuleToDefinedGVSummaries, + ImportLists[ModulePath], + ModuleToSummariesForIndex); + std::error_code EC; - if ((EC = EmitImportsFiles(ModulePath, OutputName, ImportLists[ModulePath]))) + if ((EC = + EmitImportsFiles(ModulePath, OutputName, ModuleToSummariesForIndex))) report_fatal_error(Twine("Failed to open ") + OutputName + " to save imports lists\n"); } @@ -747,7 +788,7 @@ void ThinLTOCodeGenerator::internalize(Module &TheModule, Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); // Compute "dead" symbols, we don't want to import/export these! - computeDeadSymbols(Index, GUIDPreservedSymbols); + computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols); // Generate import/export list StringMap<FunctionImporter::ImportMapTy> ImportLists(ModuleCount); @@ -762,13 +803,7 @@ void ThinLTOCodeGenerator::internalize(Module &TheModule, return; // Internalization - auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { - const auto &ExportList = ExportLists.find(ModuleIdentifier); - return (ExportList != ExportLists.end() && - ExportList->second.count(GUID)) || - GUIDPreservedSymbols.count(GUID); - }; - thinLTOInternalizeAndPromoteInIndex(Index, isExported); + internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, Index); thinLTOInternalizeModule(TheModule, ModuleToDefinedGVSummaries[ModuleIdentifier]); } @@ -899,7 +934,7 @@ void ThinLTOCodeGenerator::run() { computeGUIDPreservedSymbols(PreservedSymbols, TMBuilder.TheTriple); // Compute "dead" symbols, we don't want to import/export these! - computeDeadSymbols(*Index, GUIDPreservedSymbols); + computeDeadSymbolsInIndex(*Index, GUIDPreservedSymbols); // Collect the import/export lists for all modules from the call-graph in the // combined index. @@ -918,17 +953,10 @@ void ThinLTOCodeGenerator::run() { // impacts the caching. resolveWeakForLinkerInIndex(*Index, ResolvedODR); - auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) { - const auto &ExportList = ExportLists.find(ModuleIdentifier); - return (ExportList != ExportLists.end() && - ExportList->second.count(GUID)) || - GUIDPreservedSymbols.count(GUID); - }; - // Use global summary-based analysis to identify symbols that can be // internalized (because they aren't exported or preserved as per callback). // Changes are made in the index, consumed in the ThinLTO backends. - thinLTOInternalizeAndPromoteInIndex(*Index, isExported); + internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, *Index); // Make sure that every module has an entry in the ExportLists and // ResolvedODR maps to enable threaded access to these maps below. @@ -943,12 +971,12 @@ void ThinLTOCodeGenerator::run() { std::vector<int> ModulesOrdering; ModulesOrdering.resize(Modules.size()); std::iota(ModulesOrdering.begin(), ModulesOrdering.end(), 0); - std::sort(ModulesOrdering.begin(), ModulesOrdering.end(), - [&](int LeftIndex, int RightIndex) { - auto LSize = Modules[LeftIndex].getBuffer().size(); - auto RSize = Modules[RightIndex].getBuffer().size(); - return LSize > RSize; - }); + llvm::sort(ModulesOrdering.begin(), ModulesOrdering.end(), + [&](int LeftIndex, int RightIndex) { + auto LSize = Modules[LeftIndex].getBuffer().size(); + auto RSize = Modules[RightIndex].getBuffer().size(); + return LSize > RSize; + }); // Parallel optimizer + codegen { @@ -971,9 +999,9 @@ void ThinLTOCodeGenerator::run() { { auto ErrOrBuffer = CacheEntry.tryLoadingBuffer(); - DEBUG(dbgs() << "Cache " << (ErrOrBuffer ? "hit" : "miss") << " '" - << CacheEntryPath << "' for buffer " << count << " " - << ModuleIdentifier << "\n"); + LLVM_DEBUG(dbgs() << "Cache " << (ErrOrBuffer ? "hit" : "miss") + << " '" << CacheEntryPath << "' for buffer " + << count << " " << ModuleIdentifier << "\n"); if (ErrOrBuffer) { // Cache Hit! @@ -1020,15 +1048,15 @@ void ThinLTOCodeGenerator::run() { if (SavedObjectsDirectoryPath.empty()) { // We need to generated a memory buffer for the linker. if (!CacheEntryPath.empty()) { - // Cache is enabled, reload from the cache - // We do this to lower memory pressuree: the buffer is on the heap - // and releasing it frees memory that can be used for the next input - // file. The final binary link will read from the VFS cache - // (hopefully!) or from disk if the memory pressure wasn't too high. + // When cache is enabled, reload from the cache if possible. + // Releasing the buffer from the heap and reloading it from the + // cache file with mmap helps us to lower memory pressure. + // The freed memory can be used for the next input file. + // The final binary link will read from the VFS cache (hopefully!) + // or from disk (if the memory pressure was too high). auto ReloadedBufferOrErr = CacheEntry.tryLoadingBuffer(); if (auto EC = ReloadedBufferOrErr.getError()) { - // On error, keeping the preexisting buffer and printing a - // diagnostic is more friendly than just crashing. + // On error, keep the preexisting buffer and print a diagnostic. errs() << "error: can't reload cached file '" << CacheEntryPath << "': " << EC.message() << "\n"; } else { |