diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2019-08-20 20:50:12 +0000 |
commit | e6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch) | |
tree | 599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/LTO | |
parent | 1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff) |
Notes
Diffstat (limited to 'lib/LTO')
-rw-r--r-- | lib/LTO/Caching.cpp | 31 | ||||
-rw-r--r-- | lib/LTO/LTO.cpp | 193 | ||||
-rw-r--r-- | lib/LTO/LTOBackend.cpp | 41 | ||||
-rw-r--r-- | lib/LTO/LTOCodeGenerator.cpp | 60 | ||||
-rw-r--r-- | lib/LTO/LTOModule.cpp | 38 | ||||
-rw-r--r-- | lib/LTO/SummaryBasedOptimizations.cpp | 7 | ||||
-rw-r--r-- | lib/LTO/ThinLTOCodeGenerator.cpp | 207 | ||||
-rw-r--r-- | lib/LTO/UpdateCompilerUsed.cpp | 7 |
8 files changed, 394 insertions, 190 deletions
diff --git a/lib/LTO/Caching.cpp b/lib/LTO/Caching.cpp index 089e77e742eb..000ab91dba7c 100644 --- a/lib/LTO/Caching.cpp +++ b/lib/LTO/Caching.cpp @@ -1,9 +1,8 @@ //===-Caching.cpp - LLVM Link Time Optimizer Cache Handling ---------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -39,21 +38,23 @@ Expected<NativeObjectCache> lto::localCache(StringRef CacheDirectoryPath, SmallString<64> EntryPath; sys::path::append(EntryPath, CacheDirectoryPath, "llvmcache-" + Key); // First, see if we have a cache hit. - int FD; SmallString<64> ResultPath; - std::error_code EC = sys::fs::openFileForRead( - Twine(EntryPath), FD, sys::fs::OF_UpdateAtime, &ResultPath); - if (!EC) { + Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead( + Twine(EntryPath), sys::fs::OF_UpdateAtime, &ResultPath); + std::error_code EC; + if (FDOrErr) { ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = - MemoryBuffer::getOpenFile(FD, EntryPath, - /*FileSize*/ -1, - /*RequiresNullTerminator*/ false); - close(FD); + MemoryBuffer::getOpenFile(*FDOrErr, EntryPath, + /*FileSize=*/-1, + /*RequiresNullTerminator=*/false); + sys::fs::closeFile(*FDOrErr); if (MBOrErr) { AddBuffer(Task, std::move(*MBOrErr)); return AddStreamFn(); } EC = MBOrErr.getError(); + } else { + EC = errorToErrorCode(FDOrErr.takeError()); } // On Windows we can fail to open a cache file with a permission denied @@ -87,9 +88,9 @@ Expected<NativeObjectCache> lto::localCache(StringRef CacheDirectoryPath, // Open the file first to avoid racing with a cache pruner. ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = - MemoryBuffer::getOpenFile(TempFile.FD, TempFile.TmpName, - /*FileSize*/ -1, - /*RequiresNullTerminator*/ false); + MemoryBuffer::getOpenFile( + sys::fs::convertFDToNativeFile(TempFile.FD), TempFile.TmpName, + /*FileSize=*/-1, /*RequiresNullTerminator=*/false); if (!MBOrErr) report_fatal_error(Twine("Failed to open new cache file ") + TempFile.TmpName + ": " + diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp index 3a955060deaa..64506890956a 100644 --- a/lib/LTO/LTO.cpp +++ b/lib/LTO/LTO.cpp @@ -1,9 +1,8 @@ //===-LTO.cpp - LLVM Link Time Optimizer ----------------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -21,9 +20,11 @@ #include "llvm/Config/llvm-config.h" #include "llvm/IR/AutoUpgrade.h" #include "llvm/IR/DiagnosticPrinter.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/RemarkStreamer.h" #include "llvm/LTO/LTOBackend.h" #include "llvm/LTO/SummaryBasedOptimizations.h" #include "llvm/Linker/IRMover.h" @@ -186,12 +187,15 @@ void llvm::computeLTOCacheKey( auto AddUsedThings = [&](GlobalValueSummary *GS) { if (!GS) return; AddUnsigned(GS->isLive()); + AddUnsigned(GS->canAutoHide()); for (const ValueInfo &VI : GS->refs()) { AddUnsigned(VI.isDSOLocal()); AddUsedCfiGlobal(VI.getGUID()); } - if (auto *GVS = dyn_cast<GlobalVarSummary>(GS)) - AddUnsigned(GVS->isReadOnly()); + if (auto *GVS = dyn_cast<GlobalVarSummary>(GS)) { + AddUnsigned(GVS->maybeReadOnly()); + AddUnsigned(GVS->maybeWriteOnly()); + } if (auto *FS = dyn_cast<FunctionSummary>(GS)) { for (auto &TT : FS->type_tests()) UsedTypeIds.insert(TT); @@ -294,13 +298,13 @@ void llvm::computeLTOCacheKey( } static void thinLTOResolvePrevailingGUID( - GlobalValueSummaryList &GVSummaryList, GlobalValue::GUID GUID, - DenseSet<GlobalValueSummary *> &GlobalInvolvedWithAlias, + ValueInfo VI, DenseSet<GlobalValueSummary *> &GlobalInvolvedWithAlias, function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)> isPrevailing, function_ref<void(StringRef, GlobalValue::GUID, GlobalValue::LinkageTypes)> - recordNewLinkage) { - for (auto &S : GVSummaryList) { + recordNewLinkage, + const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) { + for (auto &S : VI.getSummaryList()) { GlobalValue::LinkageTypes OriginalLinkage = S->linkage(); // Ignore local and appending linkage values since the linker // doesn't resolve them. @@ -315,17 +319,29 @@ static void thinLTOResolvePrevailingGUID( // ensure a copy is kept to satisfy the exported reference. // FIXME: We may want to split the compile time and correctness // aspects into separate routines. - if (isPrevailing(GUID, S.get())) { - if (GlobalValue::isLinkOnceLinkage(OriginalLinkage)) + if (isPrevailing(VI.getGUID(), S.get())) { + if (GlobalValue::isLinkOnceLinkage(OriginalLinkage)) { S->setLinkage(GlobalValue::getWeakLinkage( GlobalValue::isLinkOnceODRLinkage(OriginalLinkage))); + // The kept copy is eligible for auto-hiding (hidden visibility) if all + // copies were (i.e. they were all linkonce_odr global unnamed addr). + // If any copy is not (e.g. it was originally weak_odr), then the symbol + // must remain externally available (e.g. a weak_odr from an explicitly + // instantiated template). Additionally, if it is in the + // GUIDPreservedSymbols set, that means that it is visibile outside + // the summary (e.g. in a native object or a bitcode file without + // summary), and in that case we cannot hide it as it isn't possible to + // check all copies. + S->setCanAutoHide(VI.canAutoHide() && + !GUIDPreservedSymbols.count(VI.getGUID())); + } } // Alias and aliasee can't be turned into available_externally. else if (!isa<AliasSummary>(S.get()) && !GlobalInvolvedWithAlias.count(S.get())) S->setLinkage(GlobalValue::AvailableExternallyLinkage); if (S->linkage() != OriginalLinkage) - recordNewLinkage(S->modulePath(), GUID, S->linkage()); + recordNewLinkage(S->modulePath(), VI.getGUID(), S->linkage()); } } @@ -340,7 +356,8 @@ void llvm::thinLTOResolvePrevailingInIndex( function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)> isPrevailing, function_ref<void(StringRef, GlobalValue::GUID, GlobalValue::LinkageTypes)> - recordNewLinkage) { + recordNewLinkage, + const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) { // We won't optimize the globals that are referenced by an alias for now // Ideally we should turn the alias into a global and duplicate the definition // when needed. @@ -351,9 +368,17 @@ void llvm::thinLTOResolvePrevailingInIndex( GlobalInvolvedWithAlias.insert(&AS->getAliasee()); for (auto &I : Index) - thinLTOResolvePrevailingGUID(I.second.SummaryList, I.first, - GlobalInvolvedWithAlias, isPrevailing, - recordNewLinkage); + thinLTOResolvePrevailingGUID(Index.getValueInfo(I), GlobalInvolvedWithAlias, + isPrevailing, recordNewLinkage, + GUIDPreservedSymbols); +} + +static bool isWeakObjectWithRWAccess(GlobalValueSummary *GVS) { + if (auto *VarSummary = dyn_cast<GlobalVarSummary>(GVS->getBaseObject())) + return !VarSummary->maybeReadOnly() && !VarSummary->maybeWriteOnly() && + (VarSummary->linkage() == GlobalValue::WeakODRLinkage || + VarSummary->linkage() == GlobalValue::LinkOnceODRLinkage); + return false; } static void thinLTOInternalizeAndPromoteGUID( @@ -370,7 +395,13 @@ static void thinLTOInternalizeAndPromoteGUID( S->linkage() != GlobalValue::AppendingLinkage && // We can't internalize available_externally globals because this // can break function pointer equality. - S->linkage() != GlobalValue::AvailableExternallyLinkage) + S->linkage() != GlobalValue::AvailableExternallyLinkage && + // Functions and read-only variables with linkonce_odr and + // weak_odr linkage can be internalized. We can't internalize + // linkonce_odr and weak_odr variables which are both modified + // and read somewhere in the program because reads and writes + // will become inconsistent. + !isWeakObjectWithRWAccess(S.get())) S->setLinkage(GlobalValue::InternalLinkage); } } @@ -397,6 +428,7 @@ Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) { File->TargetTriple = FOrErr->TheReader.getTargetTriple(); File->SourceFileName = FOrErr->TheReader.getSourceFileName(); File->COFFLinkerOpts = FOrErr->TheReader.getCOFFLinkerOpts(); + File->DependentLibraries = FOrErr->TheReader.getDependentLibraries(); File->ComdatTable = FOrErr->TheReader.getComdatTable(); for (unsigned I = 0; I != FOrErr->Mods.size(); ++I) { @@ -419,6 +451,11 @@ StringRef InputFile::getName() const { return Mods[0].getModuleIdentifier(); } +BitcodeModule &InputFile::getSingleBitcodeModule() { + assert(Mods.size() == 1 && "Expect only one bitcode module"); + return Mods[0]; +} + LTO::RegularLTOState::RegularLTOState(unsigned ParallelCodeGenParallelismLevel, Config &Conf) : ParallelCodeGenParallelismLevel(ParallelCodeGenParallelismLevel), @@ -809,6 +846,45 @@ unsigned LTO::getMaxTasks() const { return RegularLTO.ParallelCodeGenParallelismLevel + ThinLTO.ModuleMap.size(); } +// If only some of the modules were split, we cannot correctly handle +// code that contains type tests or type checked loads. +Error LTO::checkPartiallySplit() { + if (!ThinLTO.CombinedIndex.partiallySplitLTOUnits()) + return Error::success(); + + Function *TypeTestFunc = RegularLTO.CombinedModule->getFunction( + Intrinsic::getName(Intrinsic::type_test)); + Function *TypeCheckedLoadFunc = RegularLTO.CombinedModule->getFunction( + Intrinsic::getName(Intrinsic::type_checked_load)); + + // First check if there are type tests / type checked loads in the + // merged regular LTO module IR. + if ((TypeTestFunc && !TypeTestFunc->use_empty()) || + (TypeCheckedLoadFunc && !TypeCheckedLoadFunc->use_empty())) + return make_error<StringError>( + "inconsistent LTO Unit splitting (recompile with -fsplit-lto-unit)", + inconvertibleErrorCode()); + + // Otherwise check if there are any recorded in the combined summary from the + // ThinLTO modules. + for (auto &P : ThinLTO.CombinedIndex) { + for (auto &S : P.second.SummaryList) { + auto *FS = dyn_cast<FunctionSummary>(S.get()); + if (!FS) + continue; + if (!FS->type_test_assume_vcalls().empty() || + !FS->type_checked_load_vcalls().empty() || + !FS->type_test_assume_const_vcalls().empty() || + !FS->type_checked_load_const_vcalls().empty() || + !FS->type_tests().empty()) + return make_error<StringError>( + "inconsistent LTO Unit splitting (recompile with -fsplit-lto-unit)", + inconvertibleErrorCode()); + } + } + return Error::success(); +} + Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { // Compute "dead" symbols, we don't want to import/export these! DenseSet<GlobalValue::GUID> GUIDPreservedSymbols; @@ -840,20 +916,25 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { isPrevailing, Conf.OptLevel > 0); // 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(); - } + auto StatsFileOrErr = setupStatsFile(Conf.StatsFile); + if (!StatsFileOrErr) + return StatsFileOrErr.takeError(); + std::unique_ptr<ToolOutputFile> StatsFile = std::move(StatsFileOrErr.get()); + + // Finalize linking of regular LTO modules containing summaries now that + // we have computed liveness information. + for (auto &M : RegularLTO.ModsWithSummaries) + if (Error Err = linkRegularLTO(std::move(M), + /*LivenessFromIndex=*/true)) + return Err; + + // Ensure we don't have inconsistently split LTO units with type tests. + if (Error Err = checkPartiallySplit()) + return Err; Error Result = runRegularLTO(AddStream); if (!Result) - Result = runThinLTO(AddStream, Cache); + Result = runThinLTO(AddStream, Cache, GUIDPreservedSymbols); if (StatsFile) PrintStatisticsJSON(StatsFile->os()); @@ -862,11 +943,6 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) { } Error LTO::runRegularLTO(AddStreamFn AddStream) { - for (auto &M : RegularLTO.ModsWithSummaries) - if (Error Err = linkRegularLTO(std::move(M), - /*LivenessFromIndex=*/true)) - return Err; - // Make sure commons have the right size/alignment: we kept the largest from // all the prevailing when adding the inputs, and we apply it here. const DataLayout &DL = RegularLTO.CombinedModule->getDataLayout(); @@ -1161,7 +1237,8 @@ ThinBackend lto::createWriteIndexesThinBackend( }; } -Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache) { +Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache, + const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) { if (ThinLTO.ModuleMap.empty()) return Error::success(); @@ -1243,7 +1320,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache) { ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; }; thinLTOResolvePrevailingInIndex(ThinLTO.CombinedIndex, isPrevailing, - recordNewLinkage); + recordNewLinkage, GUIDPreservedSymbols); std::unique_ptr<ThinBackendProc> BackendProc = ThinLTO.Backend(Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, @@ -1264,25 +1341,37 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache) { } 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; - - std::string Filename = LTORemarksFilename; - if (Count != -1) +lto::setupOptimizationRemarks(LLVMContext &Context, StringRef RemarksFilename, + StringRef RemarksPasses, StringRef RemarksFormat, + bool RemarksWithHotness, int Count) { + std::string Filename = RemarksFilename; + if (!Filename.empty() && Count != -1) Filename += ".thin." + llvm::utostr(Count) + ".yaml"; + auto ResultOrErr = llvm::setupOptimizationRemarks( + Context, Filename, RemarksPasses, RemarksFormat, RemarksWithHotness); + if (Error E = ResultOrErr.takeError()) + return std::move(E); + + if (*ResultOrErr) + (*ResultOrErr)->keep(); + + return ResultOrErr; +} + +Expected<std::unique_ptr<ToolOutputFile>> +lto::setupStatsFile(StringRef StatsFilename) { + // Setup output file to emit statistics. + if (StatsFilename.empty()) + return nullptr; + + llvm::EnableStatistics(false); std::error_code EC; - auto DiagnosticFile = - llvm::make_unique<ToolOutputFile>(Filename, EC, sys::fs::F_None); + auto StatsFile = + llvm::make_unique<ToolOutputFile>(StatsFilename, EC, sys::fs::F_None); if (EC) return errorCodeToError(EC); - Context.setDiagnosticsOutputFile( - llvm::make_unique<yaml::Output>(DiagnosticFile->os())); - DiagnosticFile->keep(); - return std::move(DiagnosticFile); + + StatsFile->keep(); + return std::move(StatsFile); } diff --git a/lib/LTO/LTOBackend.cpp b/lib/LTO/LTOBackend.cpp index 926c419e34a8..7456e7175163 100644 --- a/lib/LTO/LTOBackend.cpp +++ b/lib/LTO/LTOBackend.cpp @@ -1,9 +1,8 @@ //===-LTOBackend.cpp - LLVM Link Time Optimizer Backend -------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -23,6 +22,7 @@ #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/PassManager.h" +#include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/Verifier.h" #include "llvm/LTO/LTO.h" #include "llvm/MC/SubtargetFeature.h" @@ -33,9 +33,9 @@ #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/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/Transforms/IPO.h" #include "llvm/Transforms/IPO/PassManagerBuilder.h" @@ -155,10 +155,17 @@ static void runNewPMPasses(Config &Conf, Module &Mod, TargetMachine *TM, const ModuleSummaryIndex *ImportSummary) { Optional<PGOOptions> PGOOpt; if (!Conf.SampleProfile.empty()) - PGOOpt = PGOOptions("", "", Conf.SampleProfile, Conf.ProfileRemapping, - false, true); + PGOOpt = PGOOptions(Conf.SampleProfile, "", Conf.ProfileRemapping, + PGOOptions::SampleUse, PGOOptions::NoCSAction, true); + else if (Conf.RunCSIRInstr) { + PGOOpt = PGOOptions("", Conf.CSIRProfile, Conf.ProfileRemapping, + PGOOptions::IRUse, PGOOptions::CSIRInstr); + } else if (!Conf.CSIRProfile.empty()) { + PGOOpt = PGOOptions(Conf.CSIRProfile, "", Conf.ProfileRemapping, + PGOOptions::IRUse, PGOOptions::CSIRUse); + } - PassBuilder PB(TM, PGOOpt); + PassBuilder PB(TM, PipelineTuningOptions(), PGOOpt); AAManager AA; // Parse a custom AA pipeline if asked to. @@ -274,6 +281,11 @@ static void runOldPMPasses(Config &Conf, Module &Mod, TargetMachine *TM, PMB.SLPVectorize = true; PMB.OptLevel = Conf.OptLevel; PMB.PGOSampleUse = Conf.SampleProfile; + PMB.EnablePGOCSInstrGen = Conf.RunCSIRInstr; + if (!Conf.RunCSIRInstr && !Conf.CSIRProfile.empty()) { + PMB.EnablePGOCSInstrUse = true; + PMB.PGOInstrUse = Conf.CSIRProfile; + } if (IsThinLTO) PMB.populateThinLTOPassManager(passes); else @@ -302,7 +314,7 @@ void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream, return; std::unique_ptr<ToolOutputFile> DwoOut; - SmallString<1024> DwoFile(Conf.DwoPath); + SmallString<1024> DwoFile(Conf.SplitDwarfOutput); if (!Conf.DwoDir.empty()) { std::error_code EC; if (auto EC = llvm::sys::fs::create_directories(Conf.DwoDir)) @@ -311,11 +323,12 @@ void codegen(Config &Conf, TargetMachine *TM, AddStreamFn AddStream, DwoFile = Conf.DwoDir; sys::path::append(DwoFile, std::to_string(Task) + ".dwo"); - } + TM->Options.MCOptions.SplitDwarfFile = DwoFile.str().str(); + } else + TM->Options.MCOptions.SplitDwarfFile = Conf.SplitDwarfFile; 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()); @@ -419,7 +432,8 @@ Error lto::backend(Config &C, AddStreamFn AddStream, // Setup optimization remarks. auto DiagFileOrErr = lto::setupOptimizationRemarks( - Mod->getContext(), C.RemarksFilename, C.RemarksWithHotness); + Mod->getContext(), C.RemarksFilename, C.RemarksPasses, C.RemarksFormat, + C.RemarksWithHotness); if (!DiagFileOrErr) return DiagFileOrErr.takeError(); auto DiagnosticOutputFile = std::move(*DiagFileOrErr); @@ -473,7 +487,8 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream, // Setup optimization remarks. auto DiagFileOrErr = lto::setupOptimizationRemarks( - Mod.getContext(), Conf.RemarksFilename, Conf.RemarksWithHotness, Task); + Mod.getContext(), Conf.RemarksFilename, Conf.RemarksPasses, + Conf.RemarksFormat, Conf.RemarksWithHotness, Task); if (!DiagFileOrErr) return DiagFileOrErr.takeError(); auto DiagnosticOutputFile = std::move(*DiagFileOrErr); diff --git a/lib/LTO/LTOCodeGenerator.cpp b/lib/LTO/LTOCodeGenerator.cpp index 3b63bbc7e256..6bb3bfaefc9c 100644 --- a/lib/LTO/LTOCodeGenerator.cpp +++ b/lib/LTO/LTOCodeGenerator.cpp @@ -1,9 +1,8 @@ //===-LTOCodeGenerator.cpp - LLVM Link Time Optimizer ---------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -34,6 +33,7 @@ #include "llvm/IR/Mangler.h" #include "llvm/IR/Module.h" #include "llvm/IR/PassTimingInfo.h" +#include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/Verifier.h" #include "llvm/InitializePasses.h" #include "llvm/LTO/LTO.h" @@ -81,15 +81,31 @@ cl::opt<bool> LTODiscardValueNames( #endif cl::Hidden); -cl::opt<std::string> - LTORemarksFilename("lto-pass-remarks-output", - cl::desc("Output filename for pass remarks"), - cl::value_desc("filename")); - -cl::opt<bool> LTOPassRemarksWithHotness( +cl::opt<bool> RemarksWithHotness( "lto-pass-remarks-with-hotness", cl::desc("With PGO, include profile count in optimization remarks"), cl::Hidden); + +cl::opt<std::string> + RemarksFilename("lto-pass-remarks-output", + cl::desc("Output filename for pass remarks"), + cl::value_desc("filename")); + +cl::opt<std::string> + RemarksPasses("lto-pass-remarks-filter", + cl::desc("Only record optimization remarks from passes whose " + "names match the given regular expression"), + cl::value_desc("regex")); + +cl::opt<std::string> RemarksFormat( + "lto-pass-remarks-format", + cl::desc("The format used for serializing remarks (default: YAML)"), + cl::value_desc("format"), cl::init("yaml")); + +cl::opt<std::string> LTOStatsFile( + "lto-stats-file", + cl::desc("Save statistics to the specified file"), + cl::Hidden); } LTOCodeGenerator::LTOCodeGenerator(LLVMContext &Context) @@ -120,6 +136,7 @@ void LTOCodeGenerator::initializeLTOPasses() { initializeArgPromotionPass(R); initializeJumpThreadingPass(R); initializeSROALegacyPassPass(R); + initializeAttributorLegacyPassPass(R); initializePostOrderFunctionAttrsLegacyPassPass(R); initializeReversePostOrderFunctionAttrsLegacyPassPass(R); initializeGlobalsAAWrapperPassPass(R); @@ -505,14 +522,23 @@ bool LTOCodeGenerator::optimize(bool DisableVerify, bool DisableInline, if (!this->determineTarget()) return false; - auto DiagFileOrErr = lto::setupOptimizationRemarks( - Context, LTORemarksFilename, LTOPassRemarksWithHotness); + auto DiagFileOrErr = + lto::setupOptimizationRemarks(Context, RemarksFilename, RemarksPasses, + RemarksFormat, RemarksWithHotness); if (!DiagFileOrErr) { errs() << "Error: " << toString(DiagFileOrErr.takeError()) << "\n"; report_fatal_error("Can't get an output file for the remarks"); } DiagnosticOutputFile = std::move(*DiagFileOrErr); + // Setup output file to emit statistics. + auto StatsFileOrErr = lto::setupStatsFile(LTOStatsFile); + if (!StatsFileOrErr) { + errs() << "Error: " << toString(StatsFileOrErr.takeError()) << "\n"; + report_fatal_error("Can't get an output file for the statistics"); + } + StatsFile = std::move(StatsFileOrErr.get()); + // We always run the verifier once on the merged module, the `DisableVerify` // parameter only applies to subsequent verify. verifyMergedModuleOnce(); @@ -579,9 +605,13 @@ bool LTOCodeGenerator::compileOptimized(ArrayRef<raw_pwrite_stream *> Out) { [&]() { return createTargetMachine(); }, FileType, ShouldRestoreGlobalsLinkage); - // If statistics were requested, print them out after codegen. - if (llvm::AreStatisticsEnabled()) - llvm::PrintStatistics(); + // If statistics were requested, save them to the specified file or + // print them out after codegen. + if (StatsFile) + PrintStatisticsJSON(StatsFile->os()); + else if (AreStatisticsEnabled()) + PrintStatistics(); + reportAndResetTimings(); finishOptimizationRemarks(); diff --git a/lib/LTO/LTOModule.cpp b/lib/LTO/LTOModule.cpp index 0d40d49dbe39..7ffe7bf84ba8 100644 --- a/lib/LTO/LTOModule.cpp +++ b/lib/LTO/LTOModule.cpp @@ -1,9 +1,8 @@ //===-- LTOModule.cpp - LLVM Link Time Optimizer --------------------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -131,7 +130,8 @@ LTOModule::createFromOpenFileSlice(LLVMContext &Context, int fd, StringRef path, size_t map_size, off_t offset, const TargetOptions &options) { ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = - MemoryBuffer::getOpenFileSlice(fd, path, map_size, offset); + MemoryBuffer::getOpenFileSlice(sys::fs::convertFDToNativeFile(fd), path, + map_size, offset); if (std::error_code EC = BufferOrErr.getError()) { Context.emitError(EC.message()); return EC; @@ -646,6 +646,32 @@ void LTOModule::parseMetadata() { continue; emitLinkerFlagsForGlobalCOFF(OS, Sym.symbol, TT, M); } +} + +lto::InputFile *LTOModule::createInputFile(const void *buffer, + size_t buffer_size, const char *path, + std::string &outErr) { + StringRef Data((const char *)buffer, buffer_size); + MemoryBufferRef BufferRef(Data, path); + + Expected<std::unique_ptr<lto::InputFile>> ObjOrErr = + lto::InputFile::create(BufferRef); + + if (ObjOrErr) + return ObjOrErr->release(); + + outErr = std::string(path) + + ": Could not read LTO input file: " + toString(ObjOrErr.takeError()); + return nullptr; +} + +size_t LTOModule::getDependentLibraryCount(lto::InputFile *input) { + return input->getDependentLibraries().size(); +} - // Add other interesting metadata here. +const char *LTOModule::getDependentLibrary(lto::InputFile *input, size_t index, + size_t *size) { + StringRef S = input->getDependentLibraries()[index]; + *size = S.size(); + return S.data(); } diff --git a/lib/LTO/SummaryBasedOptimizations.cpp b/lib/LTO/SummaryBasedOptimizations.cpp index bcdd984daa58..e919fd530fb0 100644 --- a/lib/LTO/SummaryBasedOptimizations.cpp +++ b/lib/LTO/SummaryBasedOptimizations.cpp @@ -1,9 +1,8 @@ //==-SummaryBasedOptimizations.cpp - Optimizations based on ThinLTO summary-==// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // diff --git a/lib/LTO/ThinLTOCodeGenerator.cpp b/lib/LTO/ThinLTOCodeGenerator.cpp index d9ec68fe3eb5..1c52218836ca 100644 --- a/lib/LTO/ThinLTOCodeGenerator.cpp +++ b/lib/LTO/ThinLTOCodeGenerator.cpp @@ -1,9 +1,8 @@ //===-ThinLTOCodeGenerator.cpp - LLVM Link Time Optimizer -----------------===// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // @@ -30,6 +29,7 @@ #include "llvm/IR/LegacyPassManager.h" #include "llvm/IR/Mangler.h" #include "llvm/IR/PassTimingInfo.h" +#include "llvm/IR/RemarkStreamer.h" #include "llvm/IR/Verifier.h" #include "llvm/IRReader/IRReader.h" #include "llvm/LTO/LTO.h" @@ -70,8 +70,10 @@ using namespace llvm; namespace llvm { // Flags -discard-value-names, defined in LTOCodeGenerator.cpp extern cl::opt<bool> LTODiscardValueNames; -extern cl::opt<std::string> LTORemarksFilename; -extern cl::opt<bool> LTOPassRemarksWithHotness; +extern cl::opt<std::string> RemarksFilename; +extern cl::opt<std::string> RemarksPasses; +extern cl::opt<bool> RemarksWithHotness; +extern cl::opt<std::string> RemarksFormat; } namespace { @@ -135,14 +137,13 @@ static void computePrevailingCopies( } } -static StringMap<MemoryBufferRef> -generateModuleMap(const std::vector<ThinLTOBuffer> &Modules) { - StringMap<MemoryBufferRef> ModuleMap; - for (auto &ModuleBuffer : Modules) { - assert(ModuleMap.find(ModuleBuffer.getBufferIdentifier()) == - ModuleMap.end() && +static StringMap<lto::InputFile *> +generateModuleMap(std::vector<std::unique_ptr<lto::InputFile>> &Modules) { + StringMap<lto::InputFile *> ModuleMap; + for (auto &M : Modules) { + assert(ModuleMap.find(M->getName()) == ModuleMap.end() && "Expect unique Buffer Identifier"); - ModuleMap[ModuleBuffer.getBufferIdentifier()] = ModuleBuffer.getMemBuffer(); + ModuleMap[M->getName()] = M.get(); } return ModuleMap; } @@ -175,18 +176,19 @@ static void verifyLoadedModule(Module &TheModule) { } } -static std::unique_ptr<Module> -loadModuleFromBuffer(const MemoryBufferRef &Buffer, LLVMContext &Context, - bool Lazy, bool IsImporting) { +static std::unique_ptr<Module> loadModuleFromInput(lto::InputFile *Input, + LLVMContext &Context, + bool Lazy, + bool IsImporting) { + auto &Mod = Input->getSingleBitcodeModule(); SMDiagnostic Err; Expected<std::unique_ptr<Module>> ModuleOrErr = - Lazy - ? getLazyBitcodeModule(Buffer, Context, - /* ShouldLazyLoadMetadata */ true, IsImporting) - : parseBitcodeFile(Buffer, Context); + Lazy ? Mod.getLazyModule(Context, + /* ShouldLazyLoadMetadata */ true, IsImporting) + : Mod.parseModule(Context); if (!ModuleOrErr) { handleAllErrors(ModuleOrErr.takeError(), [&](ErrorInfoBase &EIB) { - SMDiagnostic Err = SMDiagnostic(Buffer.getBufferIdentifier(), + SMDiagnostic Err = SMDiagnostic(Mod.getModuleIdentifier(), SourceMgr::DK_Error, EIB.message()); Err.print("ThinLTO", errs()); }); @@ -194,16 +196,17 @@ loadModuleFromBuffer(const MemoryBufferRef &Buffer, LLVMContext &Context, } if (!Lazy) verifyLoadedModule(*ModuleOrErr.get()); - return std::move(ModuleOrErr.get()); + return std::move(*ModuleOrErr); } static void crossImportIntoModule(Module &TheModule, const ModuleSummaryIndex &Index, - StringMap<MemoryBufferRef> &ModuleMap, + StringMap<lto::InputFile*> &ModuleMap, const FunctionImporter::ImportMapTy &ImportList) { auto Loader = [&](StringRef Identifier) { - return loadModuleFromBuffer(ModuleMap[Identifier], TheModule.getContext(), - /*Lazy=*/true, /*IsImporting*/ true); + auto &Input = ModuleMap[Identifier]; + return loadModuleFromInput(Input, TheModule.getContext(), + /*Lazy=*/true, /*IsImporting*/ true); }; FunctionImporter Importer(Index, Loader); @@ -248,6 +251,15 @@ static void optimizeModule(Module &TheModule, TargetMachine &TM, PM.run(TheModule); } +static void +addUsedSymbolToPreservedGUID(const lto::InputFile &File, + DenseSet<GlobalValue::GUID> &PreservedGUID) { + for (const auto &Sym : File.symbols()) { + if (Sym.isUsed()) + PreservedGUID.insert(GlobalValue::getGUID(Sym.getIRName())); + } +} + // Convert the PreservedSymbols map from "Name" based to "GUID" based. static DenseSet<GlobalValue::GUID> computeGUIDPreservedSymbols(const StringSet<> &PreservedSymbols, @@ -337,17 +349,14 @@ public: ErrorOr<std::unique_ptr<MemoryBuffer>> tryLoadingBuffer() { if (EntryPath.empty()) return std::error_code(); - 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); + Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead( + Twine(EntryPath), sys::fs::OF_UpdateAtime, &ResultPath); + if (!FDOrErr) + return errorToErrorCode(FDOrErr.takeError()); + ErrorOr<std::unique_ptr<MemoryBuffer>> MBOrErr = MemoryBuffer::getOpenFile( + *FDOrErr, EntryPath, /*FileSize=*/-1, /*RequiresNullTerminator=*/false); + sys::fs::closeFile(*FDOrErr); return MBOrErr; } @@ -381,7 +390,7 @@ public: static std::unique_ptr<MemoryBuffer> ProcessThinLTOModule(Module &TheModule, ModuleSummaryIndex &Index, - StringMap<MemoryBufferRef> &ModuleMap, TargetMachine &TM, + StringMap<lto::InputFile *> &ModuleMap, TargetMachine &TM, const FunctionImporter::ImportMapTy &ImportList, const FunctionImporter::ExportSetTy &ExportList, const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols, @@ -447,7 +456,8 @@ ProcessThinLTOModule(Module &TheModule, ModuleSummaryIndex &Index, static void resolvePrevailingInIndex( ModuleSummaryIndex &Index, StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> - &ResolvedODR) { + &ResolvedODR, + const DenseSet<GlobalValue::GUID> &GUIDPreservedSymbols) { DenseMap<GlobalValue::GUID, const GlobalValueSummary *> PrevailingCopy; computePrevailingCopies(Index, PrevailingCopy); @@ -466,7 +476,8 @@ static void resolvePrevailingInIndex( ResolvedODR[ModuleIdentifier][GUID] = NewLinkage; }; - thinLTOResolvePrevailingInIndex(Index, isPrevailing, recordNewLinkage); + thinLTOResolvePrevailingInIndex(Index, isPrevailing, recordNewLinkage, + GUIDPreservedSymbols); } // Initialize the TargetMachine builder for a given Triple @@ -488,15 +499,14 @@ static void initTMBuilder(TargetMachineBuilder &TMBuilder, } // end anonymous namespace void ThinLTOCodeGenerator::addModule(StringRef Identifier, StringRef Data) { - ThinLTOBuffer Buffer(Data, Identifier); - LLVMContext Context; - StringRef TripleStr; - ErrorOr<std::string> TripleOrErr = expectedToErrorOrAndEmitErrors( - Context, getBitcodeTargetTriple(Buffer.getMemBuffer())); + MemoryBufferRef Buffer(Data, Identifier); - if (TripleOrErr) - TripleStr = *TripleOrErr; + auto InputOrError = lto::InputFile::create(Buffer); + if (!InputOrError) + report_fatal_error("ThinLTO cannot create input file: " + + toString(InputOrError.takeError())); + auto TripleStr = (*InputOrError)->getTargetTriple(); Triple TheTriple(TripleStr); if (Modules.empty()) @@ -508,7 +518,7 @@ void ThinLTOCodeGenerator::addModule(StringRef Identifier, StringRef Data) { initTMBuilder(TMBuilder, Triple(TMBuilder.TheTriple.merge(TheTriple))); } - Modules.push_back(Buffer); + Modules.emplace_back(std::move(*InputOrError)); } void ThinLTOCodeGenerator::preserveSymbol(StringRef Name) { @@ -549,9 +559,10 @@ std::unique_ptr<ModuleSummaryIndex> ThinLTOCodeGenerator::linkCombinedIndex() { std::unique_ptr<ModuleSummaryIndex> CombinedIndex = llvm::make_unique<ModuleSummaryIndex>(/*HaveGVs=*/false); uint64_t NextModuleId = 0; - for (auto &ModuleBuffer : Modules) { - if (Error Err = readModuleSummaryIndex(ModuleBuffer.getMemBuffer(), - *CombinedIndex, NextModuleId++)) { + for (auto &Mod : Modules) { + auto &M = Mod->getSingleBitcodeModule(); + if (Error Err = + M.readSummary(*CombinedIndex, Mod->getName(), NextModuleId++)) { // FIXME diagnose logAllUnhandledErrors( std::move(Err), errs(), @@ -593,8 +604,8 @@ static void computeDeadSymbolsInIndex( * Perform promotion and renaming of exported internal functions. * Index is updated to reflect linkage changes from weak resolution. */ -void ThinLTOCodeGenerator::promote(Module &TheModule, - ModuleSummaryIndex &Index) { +void ThinLTOCodeGenerator::promote(Module &TheModule, ModuleSummaryIndex &Index, + const lto::InputFile &File) { auto ModuleCount = Index.modulePaths().size(); auto ModuleIdentifier = TheModule.getModuleIdentifier(); @@ -606,6 +617,9 @@ void ThinLTOCodeGenerator::promote(Module &TheModule, auto GUIDPreservedSymbols = computeGUIDPreservedSymbols( PreservedSymbols, Triple(TheModule.getTargetTriple())); + // Add used symbol to the preserved symbols. + addUsedSymbolToPreservedGUID(File, GUIDPreservedSymbols); + // Compute "dead" symbols, we don't want to import/export these! computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols); @@ -617,7 +631,7 @@ void ThinLTOCodeGenerator::promote(Module &TheModule, // Resolve prevailing symbols StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; - resolvePrevailingInIndex(Index, ResolvedODR); + resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols); thinLTOResolvePrevailingInModule( TheModule, ModuleToDefinedGVSummaries[ModuleIdentifier]); @@ -633,7 +647,8 @@ void ThinLTOCodeGenerator::promote(Module &TheModule, * Perform cross-module importing for the module identified by ModuleIdentifier. */ void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule, - ModuleSummaryIndex &Index) { + ModuleSummaryIndex &Index, + const lto::InputFile &File) { auto ModuleMap = generateModuleMap(Modules); auto ModuleCount = Index.modulePaths().size(); @@ -645,6 +660,8 @@ void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule, auto GUIDPreservedSymbols = computeGUIDPreservedSymbols( PreservedSymbols, Triple(TheModule.getTargetTriple())); + addUsedSymbolToPreservedGUID(File, GUIDPreservedSymbols); + // Compute "dead" symbols, we don't want to import/export these! computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols); @@ -663,7 +680,8 @@ void ThinLTOCodeGenerator::crossModuleImport(Module &TheModule, */ void ThinLTOCodeGenerator::gatherImportedSummariesForModule( Module &TheModule, ModuleSummaryIndex &Index, - std::map<std::string, GVSummaryMapTy> &ModuleToSummariesForIndex) { + std::map<std::string, GVSummaryMapTy> &ModuleToSummariesForIndex, + const lto::InputFile &File) { auto ModuleCount = Index.modulePaths().size(); auto ModuleIdentifier = TheModule.getModuleIdentifier(); @@ -675,6 +693,8 @@ void ThinLTOCodeGenerator::gatherImportedSummariesForModule( auto GUIDPreservedSymbols = computeGUIDPreservedSymbols( PreservedSymbols, Triple(TheModule.getTargetTriple())); + addUsedSymbolToPreservedGUID(File, GUIDPreservedSymbols); + // Compute "dead" symbols, we don't want to import/export these! computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols); @@ -693,7 +713,8 @@ void ThinLTOCodeGenerator::gatherImportedSummariesForModule( * Emit the list of files needed for importing into module. */ void ThinLTOCodeGenerator::emitImports(Module &TheModule, StringRef OutputName, - ModuleSummaryIndex &Index) { + ModuleSummaryIndex &Index, + const lto::InputFile &File) { auto ModuleCount = Index.modulePaths().size(); auto ModuleIdentifier = TheModule.getModuleIdentifier(); @@ -705,6 +726,8 @@ void ThinLTOCodeGenerator::emitImports(Module &TheModule, StringRef OutputName, auto GUIDPreservedSymbols = computeGUIDPreservedSymbols( PreservedSymbols, Triple(TheModule.getTargetTriple())); + addUsedSymbolToPreservedGUID(File, GUIDPreservedSymbols); + // Compute "dead" symbols, we don't want to import/export these! computeDeadSymbolsInIndex(Index, GUIDPreservedSymbols); @@ -727,10 +750,12 @@ void ThinLTOCodeGenerator::emitImports(Module &TheModule, StringRef OutputName, } /** - * Perform internalization. Index is updated to reflect linkage changes. + * Perform internalization. Runs promote and internalization together. + * Index is updated to reflect linkage changes. */ void ThinLTOCodeGenerator::internalize(Module &TheModule, - ModuleSummaryIndex &Index) { + ModuleSummaryIndex &Index, + const lto::InputFile &File) { initTMBuilder(TMBuilder, Triple(TheModule.getTargetTriple())); auto ModuleCount = Index.modulePaths().size(); auto ModuleIdentifier = TheModule.getModuleIdentifier(); @@ -739,6 +764,8 @@ void ThinLTOCodeGenerator::internalize(Module &TheModule, auto GUIDPreservedSymbols = computeGUIDPreservedSymbols(PreservedSymbols, TMBuilder.TheTriple); + addUsedSymbolToPreservedGUID(File, GUIDPreservedSymbols); + // Collect for each module the list of function it defines (GUID -> Summary). StringMap<GVSummaryMapTy> ModuleToDefinedGVSummaries(ModuleCount); Index.collectDefinedGVSummariesPerModule(ModuleToDefinedGVSummaries); @@ -758,8 +785,20 @@ void ThinLTOCodeGenerator::internalize(Module &TheModule, if (ExportList.empty() && GUIDPreservedSymbols.empty()) return; - // Internalization + // Resolve prevailing symbols + StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR; + resolvePrevailingInIndex(Index, ResolvedODR, GUIDPreservedSymbols); + + // Promote the exported values in the index, so that they are promoted + // in the module. internalizeAndPromoteInIndex(ExportLists, GUIDPreservedSymbols, Index); + + promoteModule(TheModule, Index); + + // Internalization + thinLTOResolvePrevailingInModule( + TheModule, ModuleToDefinedGVSummaries[ModuleIdentifier]); + thinLTOInternalizeModule(TheModule, ModuleToDefinedGVSummaries[ModuleIdentifier]); } @@ -777,11 +816,13 @@ void ThinLTOCodeGenerator::optimize(Module &TheModule) { /// Write out the generated object file, either from CacheEntryPath or from /// OutputBuffer, preferring hard-link when possible. /// Returns the path to the generated file in SavedObjectsDirectoryPath. -static std::string writeGeneratedObject(int count, StringRef CacheEntryPath, - StringRef SavedObjectsDirectoryPath, - const MemoryBuffer &OutputBuffer) { +std::string +ThinLTOCodeGenerator::writeGeneratedObject(int count, StringRef CacheEntryPath, + const MemoryBuffer &OutputBuffer) { + auto ArchName = TMBuilder.TheTriple.getArchName(); SmallString<128> OutputPath(SavedObjectsDirectoryPath); - llvm::sys::path::append(OutputPath, Twine(count) + ".thinlto.o"); + llvm::sys::path::append(OutputPath, + Twine(count) + "." + ArchName + ".thinlto.o"); OutputPath.c_str(); // Ensure the string is null terminated. if (sys::fs::exists(OutputPath)) sys::fs::remove(OutputPath); @@ -830,23 +871,22 @@ void ThinLTOCodeGenerator::run() { // Perform only parallel codegen and return. ThreadPool Pool; int count = 0; - for (auto &ModuleBuffer : Modules) { + for (auto &Mod : Modules) { Pool.async([&](int count) { LLVMContext Context; Context.setDiscardValueNames(LTODiscardValueNames); // Parse module now - auto TheModule = - loadModuleFromBuffer(ModuleBuffer.getMemBuffer(), Context, false, - /*IsImporting*/ false); + auto TheModule = loadModuleFromInput(Mod.get(), Context, false, + /*IsImporting*/ false); // CodeGen auto OutputBuffer = codegenModule(*TheModule, *TMBuilder.create()); if (SavedObjectsDirectoryPath.empty()) ProducedBinaries[count] = std::move(OutputBuffer); else - ProducedBinaryFiles[count] = writeGeneratedObject( - count, "", SavedObjectsDirectoryPath, *OutputBuffer); + ProducedBinaryFiles[count] = + writeGeneratedObject(count, "", *OutputBuffer); }, count++); } @@ -881,6 +921,10 @@ void ThinLTOCodeGenerator::run() { auto GUIDPreservedSymbols = computeGUIDPreservedSymbols(PreservedSymbols, TMBuilder.TheTriple); + // Add used symbol from inputs to the preserved symbols. + for (const auto &M : Modules) + addUsedSymbolToPreservedGUID(*M, GUIDPreservedSymbols); + // Compute "dead" symbols, we don't want to import/export these! computeDeadSymbolsInIndex(*Index, GUIDPreservedSymbols); @@ -902,7 +946,7 @@ void ThinLTOCodeGenerator::run() { // Resolve prevailing symbols, this has to be computed early because it // impacts the caching. - resolvePrevailingInIndex(*Index, ResolvedODR); + resolvePrevailingInIndex(*Index, ResolvedODR, GUIDPreservedSymbols); // Use global summary-based analysis to identify symbols that can be // internalized (because they aren't exported or preserved as per callback). @@ -913,7 +957,7 @@ void ThinLTOCodeGenerator::run() { // GVSummary and ResolvedODR maps to enable threaded access to these maps // below. for (auto &Module : Modules) { - auto ModuleIdentifier = Module.getBufferIdentifier(); + auto ModuleIdentifier = Module->getName(); ExportLists[ModuleIdentifier]; ImportLists[ModuleIdentifier]; ResolvedODR[ModuleIdentifier]; @@ -927,8 +971,10 @@ void ThinLTOCodeGenerator::run() { ModulesOrdering.resize(Modules.size()); std::iota(ModulesOrdering.begin(), ModulesOrdering.end(), 0); llvm::sort(ModulesOrdering, [&](int LeftIndex, int RightIndex) { - auto LSize = Modules[LeftIndex].getBuffer().size(); - auto RSize = Modules[RightIndex].getBuffer().size(); + auto LSize = + Modules[LeftIndex]->getSingleBitcodeModule().getBuffer().size(); + auto RSize = + Modules[RightIndex]->getSingleBitcodeModule().getBuffer().size(); return LSize > RSize; }); @@ -936,9 +982,9 @@ void ThinLTOCodeGenerator::run() { { ThreadPool Pool(ThreadCount); for (auto IndexCount : ModulesOrdering) { - auto &ModuleBuffer = Modules[IndexCount]; + auto &Mod = Modules[IndexCount]; Pool.async([&](int count) { - auto ModuleIdentifier = ModuleBuffer.getBufferIdentifier(); + auto ModuleIdentifier = Mod->getName(); auto &ExportList = ExportLists[ModuleIdentifier]; auto &DefinedGVSummaries = ModuleToDefinedGVSummaries[ModuleIdentifier]; @@ -963,8 +1009,7 @@ void ThinLTOCodeGenerator::run() { ProducedBinaries[count] = std::move(ErrOrBuffer.get()); else ProducedBinaryFiles[count] = writeGeneratedObject( - count, CacheEntryPath, SavedObjectsDirectoryPath, - *ErrOrBuffer.get()); + count, CacheEntryPath, *ErrOrBuffer.get()); return; } } @@ -973,7 +1018,8 @@ void ThinLTOCodeGenerator::run() { Context.setDiscardValueNames(LTODiscardValueNames); Context.enableDebugTypeODRUniquing(); auto DiagFileOrErr = lto::setupOptimizationRemarks( - Context, LTORemarksFilename, LTOPassRemarksWithHotness, count); + Context, RemarksFilename, RemarksPasses, RemarksFormat, + RemarksWithHotness, count); if (!DiagFileOrErr) { errs() << "Error: " << toString(DiagFileOrErr.takeError()) << "\n"; report_fatal_error("ThinLTO: Can't get an output file for the " @@ -981,9 +1027,8 @@ void ThinLTOCodeGenerator::run() { } // Parse module now - auto TheModule = - loadModuleFromBuffer(ModuleBuffer.getMemBuffer(), Context, false, - /*IsImporting*/ false); + auto TheModule = loadModuleFromInput(Mod.get(), Context, false, + /*IsImporting*/ false); // Save temps: original file. saveTempBitcode(*TheModule, SaveTempsDir, count, ".0.original.bc"); @@ -1021,7 +1066,7 @@ void ThinLTOCodeGenerator::run() { return; } ProducedBinaryFiles[count] = writeGeneratedObject( - count, CacheEntryPath, SavedObjectsDirectoryPath, *OutputBuffer); + count, CacheEntryPath, *OutputBuffer); }, IndexCount); } } diff --git a/lib/LTO/UpdateCompilerUsed.cpp b/lib/LTO/UpdateCompilerUsed.cpp index 00482dee6e10..6434f902088d 100644 --- a/lib/LTO/UpdateCompilerUsed.cpp +++ b/lib/LTO/UpdateCompilerUsed.cpp @@ -1,9 +1,8 @@ //==-LTOInternalize.cpp - LLVM Link Time Optimizer Internalization Utility -==// // -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // |