summaryrefslogtreecommitdiff
path: root/lib/LTO
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
committerDimitry Andric <dim@FreeBSD.org>2019-08-20 20:50:12 +0000
commite6d1592492a3a379186bfb02bd0f4eda0669c0d5 (patch)
tree599ab169a01f1c86eda9adc774edaedde2f2db5b /lib/LTO
parent1a56a5ead7a2e84bee8240f5f6b033b5f1707154 (diff)
Notes
Diffstat (limited to 'lib/LTO')
-rw-r--r--lib/LTO/Caching.cpp31
-rw-r--r--lib/LTO/LTO.cpp193
-rw-r--r--lib/LTO/LTOBackend.cpp41
-rw-r--r--lib/LTO/LTOCodeGenerator.cpp60
-rw-r--r--lib/LTO/LTOModule.cpp38
-rw-r--r--lib/LTO/SummaryBasedOptimizations.cpp7
-rw-r--r--lib/LTO/ThinLTOCodeGenerator.cpp207
-rw-r--r--lib/LTO/UpdateCompilerUsed.cpp7
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
//
//===----------------------------------------------------------------------===//
//