aboutsummaryrefslogtreecommitdiff
path: root/lib/LTO/LTO.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/LTO/LTO.cpp')
-rw-r--r--lib/LTO/LTO.cpp424
1 files changed, 276 insertions, 148 deletions
diff --git a/lib/LTO/LTO.cpp b/lib/LTO/LTO.cpp
index e3e2f9f806c8..9782c898bf50 100644
--- a/lib/LTO/LTO.cpp
+++ b/lib/LTO/LTO.cpp
@@ -20,9 +20,13 @@
#include "llvm/IR/AutoUpgrade.h"
#include "llvm/IR/DiagnosticPrinter.h"
#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/IR/Metadata.h"
#include "llvm/LTO/LTOBackend.h"
#include "llvm/Linker/IRMover.h"
+#include "llvm/Object/IRObjectFile.h"
#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
+#include "llvm/Support/Error.h"
#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
@@ -31,6 +35,7 @@
#include "llvm/Support/TargetRegistry.h"
#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/Threading.h"
+#include "llvm/Support/VCSRevision.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
@@ -46,6 +51,12 @@ using namespace object;
#define DEBUG_TYPE "lto"
+// The values are (type identifier, summary) pairs.
+typedef DenseMap<
+ GlobalValue::GUID,
+ TinyPtrVector<const std::pair<const std::string, TypeIdSummary> *>>
+ TypeIdSummariesByGuidTy;
+
// Returns a unique hash for the Module considering the current list of
// export/import and other global analysis results.
// The hash is produced in \p Key.
@@ -54,7 +65,8 @@ static void computeCacheKey(
StringRef ModuleID, const FunctionImporter::ImportMapTy &ImportList,
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
- const GVSummaryMapTy &DefinedGlobals) {
+ const GVSummaryMapTy &DefinedGlobals,
+ const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) {
// Compute the unique hash for this entry.
// This is based on the current compiler version, the module itself, the
// export list, the hash for every single module in the import list, the
@@ -63,7 +75,7 @@ static void computeCacheKey(
// Start with the compiler revision
Hasher.update(LLVM_VERSION_STRING);
-#ifdef HAVE_LLVM_REVISION
+#ifdef LLVM_REVISION
Hasher.update(LLVM_REVISION);
#endif
@@ -80,6 +92,18 @@ static void computeCacheKey(
Data[3] = I >> 24;
Hasher.update(ArrayRef<uint8_t>{Data, 4});
};
+ auto AddUint64 = [&](uint64_t I) {
+ uint8_t Data[8];
+ Data[0] = I;
+ Data[1] = I >> 8;
+ Data[2] = I >> 16;
+ Data[3] = I >> 24;
+ Data[4] = I >> 32;
+ Data[5] = I >> 40;
+ Data[6] = I >> 48;
+ Data[7] = I >> 56;
+ Hasher.update(ArrayRef<uint8_t>{Data, 8});
+ };
AddString(Conf.CPU);
// FIXME: Hash more of Options. For now all clients initialize Options from
// command-line flags (which is unsupported in production), but may set
@@ -94,6 +118,7 @@ static void computeCacheKey(
AddUnsigned(Conf.RelocModel);
AddUnsigned(Conf.CodeModel);
AddUnsigned(Conf.CGOptLevel);
+ AddUnsigned(Conf.CGFileType);
AddUnsigned(Conf.OptLevel);
AddString(Conf.OptPipeline);
AddString(Conf.AAPipeline);
@@ -107,10 +132,16 @@ static void computeCacheKey(
// The export list can impact the internalization, be conservative here
Hasher.update(ArrayRef<uint8_t>((uint8_t *)&F, sizeof(F)));
- // Include the hash for every module we import functions from
+ // Include the hash for every module we import functions from. The set of
+ // imported symbols for each module may affect code generation and is
+ // sensitive to link order, so include that as well.
for (auto &Entry : ImportList) {
auto ModHash = Index.getModuleHash(Entry.first());
Hasher.update(ArrayRef<uint8_t>((uint8_t *)&ModHash[0], sizeof(ModHash)));
+
+ AddUint64(Entry.second.size());
+ for (auto &Fn : Entry.second)
+ AddUint64(Fn.first);
}
// Include the hash for the resolved ODR.
@@ -121,12 +152,68 @@ static void computeCacheKey(
sizeof(GlobalValue::LinkageTypes)));
}
+ std::set<GlobalValue::GUID> UsedTypeIds;
+
+ auto AddUsedTypeIds = [&](GlobalValueSummary *GS) {
+ auto *FS = dyn_cast_or_null<FunctionSummary>(GS);
+ if (!FS)
+ return;
+ for (auto &TT : FS->type_tests())
+ UsedTypeIds.insert(TT);
+ for (auto &TT : FS->type_test_assume_vcalls())
+ UsedTypeIds.insert(TT.GUID);
+ for (auto &TT : FS->type_checked_load_vcalls())
+ UsedTypeIds.insert(TT.GUID);
+ for (auto &TT : FS->type_test_assume_const_vcalls())
+ UsedTypeIds.insert(TT.VFunc.GUID);
+ for (auto &TT : FS->type_checked_load_const_vcalls())
+ UsedTypeIds.insert(TT.VFunc.GUID);
+ };
+
// Include the hash for the linkage type to reflect internalization and weak
- // resolution.
+ // resolution, and collect any used type identifier resolutions.
for (auto &GS : DefinedGlobals) {
GlobalValue::LinkageTypes Linkage = GS.second->linkage();
Hasher.update(
ArrayRef<uint8_t>((const uint8_t *)&Linkage, sizeof(Linkage)));
+ AddUsedTypeIds(GS.second);
+ }
+
+ // Imported functions may introduce new uses of type identifier resolutions,
+ // so we need to collect their used resolutions as well.
+ for (auto &ImpM : ImportList)
+ for (auto &ImpF : ImpM.second)
+ AddUsedTypeIds(Index.findSummaryInModule(ImpF.first, ImpM.first()));
+
+ auto AddTypeIdSummary = [&](StringRef TId, const TypeIdSummary &S) {
+ AddString(TId);
+
+ AddUnsigned(S.TTRes.TheKind);
+ AddUnsigned(S.TTRes.SizeM1BitWidth);
+
+ AddUint64(S.WPDRes.size());
+ for (auto &WPD : S.WPDRes) {
+ AddUnsigned(WPD.first);
+ AddUnsigned(WPD.second.TheKind);
+ AddString(WPD.second.SingleImplName);
+
+ AddUint64(WPD.second.ResByArg.size());
+ for (auto &ByArg : WPD.second.ResByArg) {
+ AddUint64(ByArg.first.size());
+ for (uint64_t Arg : ByArg.first)
+ AddUint64(Arg);
+ AddUnsigned(ByArg.second.TheKind);
+ AddUint64(ByArg.second.Info);
+ }
+ }
+ };
+
+ // Include the hash for all type identifiers used by this module.
+ for (GlobalValue::GUID TId : UsedTypeIds) {
+ auto SummariesI = TypeIdSummariesByGuid.find(TId);
+ if (SummariesI != TypeIdSummariesByGuid.end())
+ for (auto *Summary : SummariesI->second)
+ AddTypeIdSummary(Summary->first, Summary->second);
}
if (!Conf.SampleProfile.empty()) {
@@ -164,9 +251,7 @@ static void thinLTOResolveWeakForLinkerGUID(
}
// Alias and aliasee can't be turned into available_externally.
else if (!isa<AliasSummary>(S.get()) &&
- !GlobalInvolvedWithAlias.count(S.get()) &&
- (GlobalValue::isLinkOnceODRLinkage(OriginalLinkage) ||
- GlobalValue::isWeakODRLinkage(OriginalLinkage)))
+ !GlobalInvolvedWithAlias.count(S.get()))
S->setLinkage(GlobalValue::AvailableExternallyLinkage);
if (S->linkage() != OriginalLinkage)
recordNewLinkage(S->modulePath(), GUID, S->linkage());
@@ -220,14 +305,6 @@ void llvm::thinLTOInternalizeAndPromoteInIndex(
thinLTOInternalizeAndPromoteGUID(I.second, I.first, isExported);
}
-struct InputFile::InputModule {
- BitcodeModule BM;
- std::unique_ptr<Module> Mod;
-
- // The range of ModuleSymbolTable entries for this input module.
- size_t SymBegin, SymEnd;
-};
-
// Requires a destructor for std::vector<InputModule>.
InputFile::~InputFile() = default;
@@ -248,61 +325,52 @@ Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) {
return make_error<StringError>("Bitcode file does not contain any modules",
inconvertibleErrorCode());
- // Create an InputModule for each module in the InputFile, and add it to the
- // ModuleSymbolTable.
+ File->Mods = *BMsOrErr;
+
+ LLVMContext Ctx;
+ std::vector<Module *> Mods;
+ std::vector<std::unique_ptr<Module>> OwnedMods;
for (auto BM : *BMsOrErr) {
Expected<std::unique_ptr<Module>> MOrErr =
- BM.getLazyModule(File->Ctx, /*ShouldLazyLoadMetadata*/ true,
+ BM.getLazyModule(Ctx, /*ShouldLazyLoadMetadata*/ true,
/*IsImporting*/ false);
if (!MOrErr)
return MOrErr.takeError();
- size_t SymBegin = File->SymTab.symbols().size();
- File->SymTab.addModule(MOrErr->get());
- size_t SymEnd = File->SymTab.symbols().size();
+ if ((*MOrErr)->getDataLayoutStr().empty())
+ return make_error<StringError>("input module has no datalayout",
+ inconvertibleErrorCode());
- for (const auto &C : (*MOrErr)->getComdatSymbolTable()) {
- auto P = File->ComdatMap.insert(
- std::make_pair(&C.second, File->Comdats.size()));
- assert(P.second);
- (void)P;
- File->Comdats.push_back(C.first());
- }
+ Mods.push_back(MOrErr->get());
+ OwnedMods.push_back(std::move(*MOrErr));
+ }
- File->Mods.push_back({BM, std::move(*MOrErr), SymBegin, SymEnd});
+ SmallVector<char, 0> Symtab;
+ if (Error E = irsymtab::build(Mods, Symtab, File->Strtab))
+ return std::move(E);
+
+ irsymtab::Reader R({Symtab.data(), Symtab.size()},
+ {File->Strtab.data(), File->Strtab.size()});
+ File->TargetTriple = R.getTargetTriple();
+ File->SourceFileName = R.getSourceFileName();
+ File->COFFLinkerOpts = R.getCOFFLinkerOpts();
+ File->ComdatTable = R.getComdatTable();
+
+ for (unsigned I = 0; I != Mods.size(); ++I) {
+ size_t Begin = File->Symbols.size();
+ for (const irsymtab::Reader::SymbolRef &Sym : R.module_symbols(I))
+ // Skip symbols that are irrelevant to LTO. Note that this condition needs
+ // to match the one in Skip() in LTO::addRegularLTO().
+ if (Sym.isGlobal() && !Sym.isFormatSpecific())
+ File->Symbols.push_back(Sym);
+ File->ModuleSymIndices.push_back({Begin, File->Symbols.size()});
}
return std::move(File);
}
-Expected<int> InputFile::Symbol::getComdatIndex() const {
- if (!isGV())
- return -1;
- const GlobalObject *GO = getGV()->getBaseObject();
- if (!GO)
- return make_error<StringError>("Unable to determine comdat of alias!",
- inconvertibleErrorCode());
- if (const Comdat *C = GO->getComdat()) {
- auto I = File->ComdatMap.find(C);
- assert(I != File->ComdatMap.end());
- return I->second;
- }
- return -1;
-}
-
StringRef InputFile::getName() const {
- return Mods[0].BM.getModuleIdentifier();
-}
-
-StringRef InputFile::getSourceFileName() const {
- return Mods[0].Mod->getSourceFileName();
-}
-
-iterator_range<InputFile::symbol_iterator>
-InputFile::module_symbols(InputModule &IM) {
- return llvm::make_range(
- symbol_iterator(SymTab.symbols().data() + IM.SymBegin, SymTab, this),
- symbol_iterator(SymTab.symbols().data() + IM.SymEnd, SymTab, this));
+ return Mods[0].getModuleIdentifier();
}
LTO::RegularLTOState::RegularLTOState(unsigned ParallelCodeGenParallelismLevel,
@@ -326,21 +394,17 @@ LTO::LTO(Config Conf, ThinBackend Backend,
LTO::~LTO() = default;
// Add the given symbol to the GlobalResolutions map, and resolve its partition.
-void LTO::addSymbolToGlobalRes(SmallPtrSet<GlobalValue *, 8> &Used,
- const InputFile::Symbol &Sym,
+void LTO::addSymbolToGlobalRes(const InputFile::Symbol &Sym,
SymbolResolution Res, unsigned Partition) {
- GlobalValue *GV = Sym.isGV() ? Sym.getGV() : nullptr;
-
auto &GlobalRes = GlobalResolutions[Sym.getName()];
- if (GV) {
- GlobalRes.UnnamedAddr &= GV->hasGlobalUnnamedAddr();
- if (Res.Prevailing)
- GlobalRes.IRName = GV->getName();
- }
+ GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr();
+ if (Res.Prevailing)
+ GlobalRes.IRName = Sym.getIRName();
+
// Set the partition to external if we know it is used elsewhere, e.g.
// it is visible to a regular object, is referenced from llvm.compiler_used,
// or was already recorded as being referenced from a different partition.
- if (Res.VisibleToRegularObj || (GV && Used.count(GV)) ||
+ if (Res.VisibleToRegularObj || Sym.isUsed() ||
(GlobalRes.Partition != GlobalResolution::Unknown &&
GlobalRes.Partition != Partition)) {
GlobalRes.Partition = GlobalResolution::External;
@@ -372,6 +436,7 @@ static void writeToResolutionFile(raw_ostream &OS, InputFile *Input,
OS << 'x';
OS << '\n';
}
+ OS.flush();
assert(ResI == Res.end());
}
@@ -383,41 +448,32 @@ Error LTO::add(std::unique_ptr<InputFile> Input,
writeToResolutionFile(*Conf.ResolutionFile, Input.get(), Res);
const SymbolResolution *ResI = Res.begin();
- for (InputFile::InputModule &IM : Input->Mods)
- if (Error Err = addModule(*Input, IM, ResI, Res.end()))
+ for (unsigned I = 0; I != Input->Mods.size(); ++I)
+ if (Error Err = addModule(*Input, I, ResI, Res.end()))
return Err;
assert(ResI == Res.end());
return Error::success();
}
-Error LTO::addModule(InputFile &Input, InputFile::InputModule &IM,
+Error LTO::addModule(InputFile &Input, unsigned ModI,
const SymbolResolution *&ResI,
const SymbolResolution *ResE) {
- // FIXME: move to backend
- Module &M = *IM.Mod;
-
- if (M.getDataLayoutStr().empty())
- return make_error<StringError>("input module has no datalayout",
- inconvertibleErrorCode());
-
- if (!Conf.OverrideTriple.empty())
- M.setTargetTriple(Conf.OverrideTriple);
- else if (M.getTargetTriple().empty())
- M.setTargetTriple(Conf.DefaultTriple);
-
- Expected<bool> HasThinLTOSummary = IM.BM.hasSummary();
+ Expected<bool> HasThinLTOSummary = Input.Mods[ModI].hasSummary();
if (!HasThinLTOSummary)
return HasThinLTOSummary.takeError();
+ auto ModSyms = Input.module_symbols(ModI);
if (*HasThinLTOSummary)
- return addThinLTO(IM.BM, M, Input.module_symbols(IM), ResI, ResE);
+ return addThinLTO(Input.Mods[ModI], ModSyms, ResI, ResE);
else
- return addRegularLTO(IM.BM, ResI, ResE);
+ return addRegularLTO(Input.Mods[ModI], ModSyms, ResI, ResE);
}
// Add a regular LTO object to the link.
-Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI,
+Error LTO::addRegularLTO(BitcodeModule BM,
+ ArrayRef<InputFile::Symbol> Syms,
+ const SymbolResolution *&ResI,
const SymbolResolution *ResE) {
if (!RegularLTO.CombinedModule) {
RegularLTO.CombinedModule =
@@ -438,47 +494,84 @@ Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI,
ModuleSymbolTable SymTab;
SymTab.addModule(&M);
- SmallPtrSet<GlobalValue *, 8> Used;
- collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
-
std::vector<GlobalValue *> Keep;
for (GlobalVariable &GV : M.globals())
if (GV.hasAppendingLinkage())
Keep.push_back(&GV);
- for (const InputFile::Symbol &Sym :
- make_range(InputFile::symbol_iterator(SymTab.symbols().begin(), SymTab,
- nullptr),
- InputFile::symbol_iterator(SymTab.symbols().end(), SymTab,
- nullptr))) {
+ DenseSet<GlobalObject *> AliasedGlobals;
+ for (auto &GA : M.aliases())
+ if (GlobalObject *GO = GA.getBaseObject())
+ AliasedGlobals.insert(GO);
+
+ // In this function we need IR GlobalValues matching the symbols in Syms
+ // (which is not backed by a module), so we need to enumerate them in the same
+ // order. The symbol enumeration order of a ModuleSymbolTable intentionally
+ // matches the order of an irsymtab, but when we read the irsymtab in
+ // InputFile::create we omit some symbols that are irrelevant to LTO. The
+ // Skip() function skips the same symbols from the module as InputFile does
+ // from the symbol table.
+ auto MsymI = SymTab.symbols().begin(), MsymE = SymTab.symbols().end();
+ auto Skip = [&]() {
+ while (MsymI != MsymE) {
+ auto Flags = SymTab.getSymbolFlags(*MsymI);
+ if ((Flags & object::BasicSymbolRef::SF_Global) &&
+ !(Flags & object::BasicSymbolRef::SF_FormatSpecific))
+ return;
+ ++MsymI;
+ }
+ };
+ Skip();
+
+ for (const InputFile::Symbol &Sym : Syms) {
assert(ResI != ResE);
SymbolResolution Res = *ResI++;
- addSymbolToGlobalRes(Used, Sym, Res, 0);
-
- if (Sym.getFlags() & object::BasicSymbolRef::SF_Undefined)
- continue;
- if (Res.Prevailing && Sym.isGV()) {
- GlobalValue *GV = Sym.getGV();
- Keep.push_back(GV);
- switch (GV->getLinkage()) {
- default:
- break;
- case GlobalValue::LinkOnceAnyLinkage:
- GV->setLinkage(GlobalValue::WeakAnyLinkage);
- break;
- case GlobalValue::LinkOnceODRLinkage:
- GV->setLinkage(GlobalValue::WeakODRLinkage);
- break;
+ addSymbolToGlobalRes(Sym, Res, 0);
+
+ assert(MsymI != MsymE);
+ ModuleSymbolTable::Symbol Msym = *MsymI++;
+ Skip();
+
+ if (GlobalValue *GV = Msym.dyn_cast<GlobalValue *>()) {
+ if (Res.Prevailing) {
+ if (Sym.isUndefined())
+ continue;
+ Keep.push_back(GV);
+ switch (GV->getLinkage()) {
+ default:
+ break;
+ case GlobalValue::LinkOnceAnyLinkage:
+ GV->setLinkage(GlobalValue::WeakAnyLinkage);
+ break;
+ case GlobalValue::LinkOnceODRLinkage:
+ GV->setLinkage(GlobalValue::WeakODRLinkage);
+ break;
+ }
+ } else if (isa<GlobalObject>(GV) &&
+ (GV->hasLinkOnceODRLinkage() || GV->hasWeakODRLinkage() ||
+ GV->hasAvailableExternallyLinkage()) &&
+ !AliasedGlobals.count(cast<GlobalObject>(GV))) {
+ // Either of the above three types of linkage indicates that the
+ // chosen prevailing symbol will have the same semantics as this copy of
+ // the symbol, so we can link it with available_externally linkage. We
+ // only need to do this if the symbol is undefined.
+ GlobalValue *CombinedGV =
+ RegularLTO.CombinedModule->getNamedValue(GV->getName());
+ if (!CombinedGV || CombinedGV->isDeclaration()) {
+ Keep.push_back(GV);
+ GV->setLinkage(GlobalValue::AvailableExternallyLinkage);
+ cast<GlobalObject>(GV)->setComdat(nullptr);
+ }
}
}
// Common resolution: collect the maximum size/alignment over all commons.
// We also record if we see an instance of a common as prevailing, so that
// if none is prevailing we can ignore it later.
- if (Sym.getFlags() & object::BasicSymbolRef::SF_Common) {
+ if (Sym.isCommon()) {
// FIXME: We should figure out what to do about commons defined by asm.
// For now they aren't reported correctly by ModuleSymbolTable.
- auto &CommonRes = RegularLTO.Commons[Sym.getGV()->getName()];
+ auto &CommonRes = RegularLTO.Commons[Sym.getIRName()];
CommonRes.Size = std::max(CommonRes.Size, Sym.getCommonSize());
CommonRes.Align = std::max(CommonRes.Align, Sym.getCommonAlignment());
CommonRes.Prevailing |= Res.Prevailing;
@@ -486,23 +579,18 @@ Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI,
// FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit.
}
+ assert(MsymI == MsymE);
return RegularLTO.Mover->move(std::move(*MOrErr), Keep,
[](GlobalValue &, IRMover::ValueAdder) {},
- /* LinkModuleInlineAsm */ true,
/* IsPerformingImport */ false);
}
// Add a ThinLTO object to the link.
-// FIXME: This function should not need to take as many parameters once we have
-// a bitcode symbol table.
-Error LTO::addThinLTO(BitcodeModule BM, Module &M,
- iterator_range<InputFile::symbol_iterator> Syms,
+Error LTO::addThinLTO(BitcodeModule BM,
+ ArrayRef<InputFile::Symbol> Syms,
const SymbolResolution *&ResI,
const SymbolResolution *ResE) {
- SmallPtrSet<GlobalValue *, 8> Used;
- collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
-
Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr = BM.getSummary();
if (!SummaryOrErr)
return SummaryOrErr.takeError();
@@ -512,11 +600,15 @@ Error LTO::addThinLTO(BitcodeModule BM, Module &M,
for (const InputFile::Symbol &Sym : Syms) {
assert(ResI != ResE);
SymbolResolution Res = *ResI++;
- addSymbolToGlobalRes(Used, Sym, Res, ThinLTO.ModuleMap.size() + 1);
+ addSymbolToGlobalRes(Sym, Res, ThinLTO.ModuleMap.size() + 1);
- if (Res.Prevailing && Sym.isGV())
- ThinLTO.PrevailingModuleForGUID[Sym.getGV()->getGUID()] =
- BM.getModuleIdentifier();
+ if (Res.Prevailing) {
+ if (!Sym.getIRName().empty()) {
+ auto GUID = GlobalValue::getGUID(GlobalValue::getGlobalIdentifier(
+ Sym.getIRName(), GlobalValue::ExternalLinkage, ""));
+ ThinLTO.PrevailingModuleForGUID[GUID] = BM.getModuleIdentifier();
+ }
+ }
}
if (!ThinLTO.ModuleMap.insert({BM.getModuleIdentifier(), BM}).second)
@@ -602,7 +694,7 @@ Error LTO::runRegularLTO(AddStreamFn AddStream) {
return Error::success();
}
return backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
- std::move(RegularLTO.CombinedModule));
+ std::move(RegularLTO.CombinedModule), ThinLTO.CombinedIndex);
}
/// This class defines the interface to the ThinLTO backend.
@@ -633,6 +725,7 @@ class InProcessThinBackend : public ThinBackendProc {
ThreadPool BackendThreadPool;
AddStreamFn AddStream;
NativeObjectCache Cache;
+ TypeIdSummariesByGuidTy TypeIdSummariesByGuid;
Optional<Error> Err;
std::mutex ErrMu;
@@ -645,7 +738,14 @@ public:
AddStreamFn AddStream, NativeObjectCache Cache)
: ThinBackendProc(Conf, CombinedIndex, ModuleToDefinedGVSummaries),
BackendThreadPool(ThinLTOParallelismLevel),
- AddStream(std::move(AddStream)), Cache(std::move(Cache)) {}
+ AddStream(std::move(AddStream)), Cache(std::move(Cache)) {
+ // Create a mapping from type identifier GUIDs to type identifier summaries.
+ // This allows backends to use the type identifier GUIDs stored in the
+ // function summaries to determine which type identifier summaries affect
+ // each function without needing to compute GUIDs in each backend.
+ for (auto &TId : CombinedIndex.typeIds())
+ TypeIdSummariesByGuid[GlobalValue::getGUID(TId.first)].push_back(&TId);
+ }
Error runThinLTOBackendThread(
AddStreamFn AddStream, NativeObjectCache Cache, unsigned Task,
@@ -654,7 +754,8 @@ public:
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
const GVSummaryMapTy &DefinedGlobals,
- MapVector<StringRef, BitcodeModule> &ModuleMap) {
+ MapVector<StringRef, BitcodeModule> &ModuleMap,
+ const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) {
auto RunThinBackend = [&](AddStreamFn AddStream) {
LTOLLVMContext BackendContext(Conf);
Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(BackendContext);
@@ -677,7 +778,7 @@ public:
SmallString<40> Key;
// The module may be cached, this helps handling it.
computeCacheKey(Key, Conf, CombinedIndex, ModuleID, ImportList, ExportList,
- ResolvedODR, DefinedGlobals);
+ ResolvedODR, DefinedGlobals, TypeIdSummariesByGuid);
if (AddStreamFn CacheAddStream = Cache(Task, Key))
return RunThinBackend(CacheAddStream);
@@ -701,10 +802,11 @@ public:
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>
&ResolvedODR,
const GVSummaryMapTy &DefinedGlobals,
- MapVector<StringRef, BitcodeModule> &ModuleMap) {
+ MapVector<StringRef, BitcodeModule> &ModuleMap,
+ const TypeIdSummariesByGuidTy &TypeIdSummariesByGuid) {
Error E = runThinLTOBackendThread(
- AddStream, Cache, Task, BM, CombinedIndex, ImportList,
- ExportList, ResolvedODR, DefinedGlobals, ModuleMap);
+ AddStream, Cache, Task, BM, CombinedIndex, ImportList, ExportList,
+ ResolvedODR, DefinedGlobals, ModuleMap, TypeIdSummariesByGuid);
if (E) {
std::unique_lock<std::mutex> L(ErrMu);
if (Err)
@@ -713,9 +815,9 @@ public:
Err = std::move(E);
}
},
- BM, std::ref(CombinedIndex), std::ref(ImportList),
- std::ref(ExportList), std::ref(ResolvedODR), std::ref(DefinedGlobals),
- std::ref(ModuleMap));
+ BM, std::ref(CombinedIndex), std::ref(ImportList), std::ref(ExportList),
+ std::ref(ResolvedODR), std::ref(DefinedGlobals), std::ref(ModuleMap),
+ std::ref(TypeIdSummariesByGuid));
return Error::success();
}
@@ -857,19 +959,6 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
if (!ModuleToDefinedGVSummaries.count(Mod.first))
ModuleToDefinedGVSummaries.try_emplace(Mod.first);
- // Compute "dead" symbols, we don't want to import/export these!
- DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
- for (auto &Res : GlobalResolutions) {
- if (Res.second.VisibleOutsideThinLTO &&
- // IRName will be defined if we have seen the prevailing copy of
- // this value. If not, no need to preserve any ThinLTO copies.
- !Res.second.IRName.empty())
- GUIDPreservedSymbols.insert(GlobalValue::getGUID(Res.second.IRName));
- }
-
- auto DeadSymbols =
- computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols);
-
StringMap<FunctionImporter::ImportMapTy> ImportLists(
ThinLTO.ModuleMap.size());
StringMap<FunctionImporter::ExportSetTy> ExportLists(
@@ -877,6 +966,20 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
StringMap<std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>> ResolvedODR;
if (Conf.OptLevel > 0) {
+ // Compute "dead" symbols, we don't want to import/export these!
+ DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
+ for (auto &Res : GlobalResolutions) {
+ if (Res.second.VisibleOutsideThinLTO &&
+ // IRName will be defined if we have seen the prevailing copy of
+ // this value. If not, no need to preserve any ThinLTO copies.
+ !Res.second.IRName.empty())
+ GUIDPreservedSymbols.insert(GlobalValue::getGUID(
+ GlobalValue::getRealLinkageName(Res.second.IRName)));
+ }
+
+ auto DeadSymbols =
+ computeDeadSymbols(ThinLTO.CombinedIndex, GUIDPreservedSymbols);
+
ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
ImportLists, ExportLists, &DeadSymbols);
@@ -890,10 +993,11 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
// partition (and we can't get the GUID).
if (Res.second.IRName.empty())
continue;
- auto GUID = GlobalValue::getGUID(Res.second.IRName);
+ auto GUID = GlobalValue::getGUID(
+ GlobalValue::getRealLinkageName(Res.second.IRName));
// Mark exported unless index-based analysis determined it to be dead.
if (!DeadSymbols.count(GUID))
- ExportedGUIDs.insert(GlobalValue::getGUID(Res.second.IRName));
+ ExportedGUIDs.insert(GUID);
}
auto isPrevailing = [&](GlobalValue::GUID GUID,
@@ -937,3 +1041,27 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
return BackendProc->wait();
}
+
+Expected<std::unique_ptr<tool_output_file>>
+lto::setupOptimizationRemarks(LLVMContext &Context,
+ StringRef LTORemarksFilename,
+ bool LTOPassRemarksWithHotness, int Count) {
+ if (LTORemarksFilename.empty())
+ return nullptr;
+
+ std::string Filename = LTORemarksFilename;
+ if (Count != -1)
+ Filename += ".thin." + llvm::utostr(Count) + ".yaml";
+
+ std::error_code EC;
+ auto DiagnosticFile =
+ llvm::make_unique<tool_output_file>(Filename, EC, sys::fs::F_None);
+ if (EC)
+ return errorCodeToError(EC);
+ Context.setDiagnosticsOutputFile(
+ llvm::make_unique<yaml::Output>(DiagnosticFile->os()));
+ if (LTOPassRemarksWithHotness)
+ Context.setDiagnosticHotnessRequested(true);
+ DiagnosticFile->keep();
+ return std::move(DiagnosticFile);
+}