summaryrefslogtreecommitdiffstats
path: root/llvm/lib/LTO/LTO.cpp
diff options
context:
space:
mode:
authorTeresa Johnson <tejohnson@google.com>2016-08-11 12:56:40 +0000
committerTeresa Johnson <tejohnson@google.com>2016-08-11 12:56:40 +0000
commitf99573b3ee6009494d431348ec92dcab7b6a218b (patch)
tree57c77754b9215a0e3429c659d9c5eb56b15f351d /llvm/lib/LTO/LTO.cpp
parent5c91764af5d5dc27c4e52073c0361d7a452c5a8c (diff)
downloadbcm5719-llvm-f99573b3ee6009494d431348ec92dcab7b6a218b.tar.gz
bcm5719-llvm-f99573b3ee6009494d431348ec92dcab7b6a218b.zip
Resolution-based LTO API.
Summary: This introduces a resolution-based LTO API. The main advantage of this API over existing APIs is that it allows the linker to supply a resolution for each symbol in each object, rather than the combined object as a whole. This will become increasingly important for use cases such as ThinLTO which require us to process symbol resolutions in a more complicated way than just adjusting linkage. Patch by Peter Collingbourne. Reviewers: rafael, tejohnson, mehdi_amini Subscribers: lhames, tejohnson, mehdi_amini, llvm-commits Differential Revision: https://reviews.llvm.org/D20268 Address review comments llvm-svn: 278330
Diffstat (limited to 'llvm/lib/LTO/LTO.cpp')
-rw-r--r--llvm/lib/LTO/LTO.cpp536
1 files changed, 531 insertions, 5 deletions
diff --git a/llvm/lib/LTO/LTO.cpp b/llvm/lib/LTO/LTO.cpp
index 10226c4a3ff..f4be9b4205b 100644
--- a/llvm/lib/LTO/LTO.cpp
+++ b/llvm/lib/LTO/LTO.cpp
@@ -12,16 +12,39 @@
//===----------------------------------------------------------------------===//
#include "llvm/LTO/LTO.h"
+#include "llvm/Analysis/TargetLibraryInfo.h"
+#include "llvm/Analysis/TargetTransformInfo.h"
#include "llvm/Bitcode/ReaderWriter.h"
+#include "llvm/CodeGen/Analysis.h"
+#include "llvm/IR/AutoUpgrade.h"
+#include "llvm/IR/DiagnosticPrinter.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/LTO/LTOBackend.h"
+#include "llvm/Linker/IRMover.h"
+#include "llvm/Object/ModuleSummaryIndexObjectFile.h"
+#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
#include "llvm/Support/SourceMgr.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/ThreadPool.h"
#include "llvm/Support/raw_ostream.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetOptions.h"
+#include "llvm/Transforms/IPO.h"
+#include "llvm/Transforms/IPO/PassManagerBuilder.h"
+#include "llvm/Transforms/Utils/SplitModule.h"
-namespace llvm {
+#include <set>
+
+using namespace llvm;
+using namespace lto;
+using namespace object;
// Simple helper to load a module from bitcode
-std::unique_ptr<Module> loadModuleFromBuffer(const MemoryBufferRef &Buffer,
- LLVMContext &Context, bool Lazy) {
+std::unique_ptr<Module>
+llvm::loadModuleFromBuffer(const MemoryBufferRef &Buffer, LLVMContext &Context,
+ bool Lazy) {
SMDiagnostic Err;
ErrorOr<std::unique_ptr<Module>> ModuleOrErr(nullptr);
if (Lazy) {
@@ -76,7 +99,7 @@ static void thinLTOResolveWeakForLinkerGUID(
// current module. However there is a chance that another module is still
// referencing them because of the import. We make sure we always emit at least
// one copy.
-void thinLTOResolveWeakForLinkerInIndex(
+void llvm::thinLTOResolveWeakForLinkerInIndex(
ModuleSummaryIndex &Index,
function_ref<bool(GlobalValue::GUID, const GlobalValueSummary *)>
isPrevailing,
@@ -110,10 +133,513 @@ static void thinLTOInternalizeAndPromoteGUID(
// Update the linkages in the given \p Index to mark exported values
// as external and non-exported values as internal.
-void thinLTOInternalizeAndPromoteInIndex(
+void llvm::thinLTOInternalizeAndPromoteInIndex(
ModuleSummaryIndex &Index,
function_ref<bool(StringRef, GlobalValue::GUID)> isExported) {
for (auto &I : Index)
thinLTOInternalizeAndPromoteGUID(I.second, I.first, isExported);
}
+
+Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) {
+ std::unique_ptr<InputFile> File(new InputFile);
+ std::string Msg;
+ auto DiagHandler = [](const DiagnosticInfo &DI, void *MsgP) {
+ auto *Msg = reinterpret_cast<std::string *>(MsgP);
+ raw_string_ostream OS(*Msg);
+ DiagnosticPrinterRawOStream DP(OS);
+ DI.print(DP);
+ };
+ File->Ctx.setDiagnosticHandler(DiagHandler, static_cast<void *>(&Msg));
+
+ ErrorOr<std::unique_ptr<object::IRObjectFile>> IRObj =
+ IRObjectFile::create(Object, File->Ctx);
+ if (!Msg.empty())
+ return make_error<StringError>(Msg, inconvertibleErrorCode());
+ if (!IRObj)
+ return errorCodeToError(IRObj.getError());
+ File->Obj = std::move(*IRObj);
+
+ File->Ctx.setDiagnosticHandler(nullptr, nullptr);
+
+ return std::move(File);
+}
+
+LTO::RegularLTOState::RegularLTOState(unsigned ParallelCodeGenParallelismLevel,
+ Config &Conf)
+ : ParallelCodeGenParallelismLevel(ParallelCodeGenParallelismLevel),
+ Ctx(Conf), CombinedModule(make_unique<Module>("ld-temp.o", Ctx)),
+ Mover(*CombinedModule) {}
+
+LTO::ThinLTOState::ThinLTOState(ThinBackend Backend) : Backend(Backend) {
+ if (!Backend)
+ this->Backend = createInProcessThinBackend(thread::hardware_concurrency());
+}
+
+LTO::LTO(Config Conf, ThinBackend Backend,
+ unsigned ParallelCodeGenParallelismLevel)
+ : Conf(std::move(Conf)),
+ RegularLTO(ParallelCodeGenParallelismLevel, this->Conf),
+ ThinLTO(Backend) {}
+
+// Add the given symbol to the GlobalResolutions map, and resolve its partition.
+void LTO::addSymbolToGlobalRes(IRObjectFile *Obj,
+ SmallPtrSet<GlobalValue *, 8> &Used,
+ const InputFile::Symbol &Sym,
+ SymbolResolution Res, size_t Partition) {
+ GlobalValue *GV = Obj->getSymbolGV(Sym.I->getRawDataRefImpl());
+
+ auto &GlobalRes = GlobalResolutions[Sym.getName()];
+ if (GV) {
+ GlobalRes.UnnamedAddr &= GV->hasGlobalUnnamedAddr();
+ if (Res.Prevailing)
+ GlobalRes.IRName = GV->getName();
+ }
+ if (Res.VisibleToRegularObj || (GV && Used.count(GV)) ||
+ (GlobalRes.Partition != GlobalResolution::Unknown &&
+ GlobalRes.Partition != Partition))
+ GlobalRes.Partition = GlobalResolution::External;
+ else
+ GlobalRes.Partition = Partition;
+}
+
+void LTO::writeToResolutionFile(InputFile *Input,
+ ArrayRef<SymbolResolution> Res) {
+ StringRef Path = Input->Obj->getMemoryBufferRef().getBufferIdentifier();
+ *Conf.ResolutionFile << Path << '\n';
+ auto ResI = Res.begin();
+ for (const InputFile::Symbol &Sym : Input->symbols()) {
+ assert(ResI != Res.end());
+ SymbolResolution Res = *ResI++;
+
+ *Conf.ResolutionFile << "-r=" << Path << ',' << Sym.getName() << ',';
+ if (Res.Prevailing)
+ *Conf.ResolutionFile << 'p';
+ if (Res.FinalDefinitionInLinkageUnit)
+ *Conf.ResolutionFile << 'l';
+ if (Res.VisibleToRegularObj)
+ *Conf.ResolutionFile << 'x';
+ *Conf.ResolutionFile << '\n';
+ }
+ assert(ResI == Res.end());
+}
+
+Error LTO::add(std::unique_ptr<InputFile> Input,
+ ArrayRef<SymbolResolution> Res) {
+ assert(!CalledGetMaxTasks);
+
+ if (Conf.ResolutionFile)
+ writeToResolutionFile(Input.get(), Res);
+
+ Module &M = Input->Obj->getModule();
+ SmallPtrSet<GlobalValue *, 8> Used;
+ collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
+
+ if (!Conf.OverrideTriple.empty())
+ M.setTargetTriple(Conf.OverrideTriple);
+ else if (M.getTargetTriple().empty())
+ M.setTargetTriple(Conf.DefaultTriple);
+
+ MemoryBufferRef MBRef = Input->Obj->getMemoryBufferRef();
+ bool HasThinLTOSummary = hasGlobalValueSummary(MBRef, Conf.DiagHandler);
+
+ if (HasThinLTOSummary)
+ return addThinLTO(std::move(Input), Res);
+ else
+ return addRegularLTO(std::move(Input), Res);
+}
+
+// Add a regular LTO object to the link.
+Error LTO::addRegularLTO(std::unique_ptr<InputFile> Input,
+ ArrayRef<SymbolResolution> Res) {
+ RegularLTO.HasModule = true;
+
+ ErrorOr<std::unique_ptr<object::IRObjectFile>> ObjOrErr =
+ IRObjectFile::create(Input->Obj->getMemoryBufferRef(), RegularLTO.Ctx);
+ if (!ObjOrErr)
+ return errorCodeToError(ObjOrErr.getError());
+ std::unique_ptr<object::IRObjectFile> Obj = std::move(*ObjOrErr);
+
+ Module &M = Obj->getModule();
+ M.materializeMetadata();
+ UpgradeDebugInfo(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);
+
+ auto ResI = Res.begin();
+ for (const InputFile::Symbol &Sym :
+ make_range(InputFile::symbol_iterator(Obj->symbol_begin()),
+ InputFile::symbol_iterator(Obj->symbol_end()))) {
+ assert(ResI != Res.end());
+ SymbolResolution Res = *ResI++;
+ addSymbolToGlobalRes(Obj.get(), Used, Sym, Res, 0);
+
+ GlobalValue *GV = Obj->getSymbolGV(Sym.I->getRawDataRefImpl());
+ if (Res.Prevailing && GV) {
+ 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;
+ }
+ }
+
+ // FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit.
+ }
+ assert(ResI == Res.end());
+
+ return RegularLTO.Mover.move(Obj->takeModule(), Keep,
+ [](GlobalValue &, IRMover::ValueAdder) {});
+}
+
+// Add a ThinLTO object to the link.
+Error LTO::addThinLTO(std::unique_ptr<InputFile> Input,
+ ArrayRef<SymbolResolution> Res) {
+ Module &M = Input->Obj->getModule();
+ SmallPtrSet<GlobalValue *, 8> Used;
+ collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
+
+ // We need to initialize the target info for the combined regular LTO module
+ // in case we have no regular LTO objects. In that case we still need to build
+ // it as usual because the client may want to add symbol definitions to it.
+ if (RegularLTO.CombinedModule->getTargetTriple().empty()) {
+ RegularLTO.CombinedModule->setTargetTriple(M.getTargetTriple());
+ RegularLTO.CombinedModule->setDataLayout(M.getDataLayout());
+ }
+
+ MemoryBufferRef MBRef = Input->Obj->getMemoryBufferRef();
+ ErrorOr<std::unique_ptr<object::ModuleSummaryIndexObjectFile>>
+ SummaryObjOrErr =
+ object::ModuleSummaryIndexObjectFile::create(MBRef, Conf.DiagHandler);
+ if (!SummaryObjOrErr)
+ return errorCodeToError(SummaryObjOrErr.getError());
+ ThinLTO.CombinedIndex.mergeFrom((*SummaryObjOrErr)->takeIndex(),
+ ThinLTO.ModuleMap.size());
+
+ auto ResI = Res.begin();
+ for (const InputFile::Symbol &Sym : Input->symbols()) {
+ assert(ResI != Res.end());
+ SymbolResolution Res = *ResI++;
+ addSymbolToGlobalRes(Input->Obj.get(), Used, Sym, Res,
+ ThinLTO.ModuleMap.size() + 1);
+
+ GlobalValue *GV = Input->Obj->getSymbolGV(Sym.I->getRawDataRefImpl());
+ if (Res.Prevailing && GV)
+ ThinLTO.PrevailingModuleForGUID[GV->getGUID()] =
+ MBRef.getBufferIdentifier();
+ }
+ assert(ResI == Res.end());
+
+ ThinLTO.ModuleMap[MBRef.getBufferIdentifier()] = MBRef;
+ return Error();
+}
+
+size_t LTO::getMaxTasks() const {
+ CalledGetMaxTasks = true;
+ return RegularLTO.ParallelCodeGenParallelismLevel + ThinLTO.ModuleMap.size();
+}
+
+Error LTO::run(AddStreamFn AddStream) {
+ // Invoke regular LTO if there was a regular LTO module to start with,
+ // or if there are any hooks that the linker may have used to add
+ // its own resolved symbols to the combined module.
+ if (RegularLTO.HasModule || Conf.PreOptModuleHook ||
+ Conf.PostInternalizeModuleHook || Conf.PostOptModuleHook ||
+ Conf.PreCodeGenModuleHook)
+ if (auto E = runRegularLTO(AddStream))
+ return E;
+ return runThinLTO(AddStream);
+}
+
+Error LTO::runRegularLTO(AddStreamFn AddStream) {
+ if (Conf.PreOptModuleHook &&
+ !Conf.PreOptModuleHook(0, *RegularLTO.CombinedModule))
+ return Error();
+
+ for (const auto &R : GlobalResolutions) {
+ if (R.second.IRName.empty())
+ continue;
+ if (R.second.Partition != 0 &&
+ R.second.Partition != GlobalResolution::External)
+ continue;
+
+ GlobalValue *GV = RegularLTO.CombinedModule->getNamedValue(R.second.IRName);
+ // Ignore symbols defined in other partitions.
+ if (!GV || GV->hasLocalLinkage())
+ continue;
+ GV->setUnnamedAddr(R.second.UnnamedAddr ? GlobalValue::UnnamedAddr::Global
+ : GlobalValue::UnnamedAddr::None);
+ if (R.second.Partition == 0)
+ GV->setLinkage(GlobalValue::InternalLinkage);
+ }
+
+ if (Conf.PostInternalizeModuleHook &&
+ !Conf.PostInternalizeModuleHook(0, *RegularLTO.CombinedModule))
+ return Error();
+
+ return backend(Conf, AddStream, RegularLTO.ParallelCodeGenParallelismLevel,
+ std::move(RegularLTO.CombinedModule));
+}
+
+/// This class defines the interface to the ThinLTO backend.
+class lto::ThinBackendProc {
+protected:
+ Config &Conf;
+ ModuleSummaryIndex &CombinedIndex;
+ AddStreamFn AddStream;
+ StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries;
+
+public:
+ ThinBackendProc(Config &Conf, ModuleSummaryIndex &CombinedIndex,
+ AddStreamFn AddStream,
+ StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries)
+ : Conf(Conf), CombinedIndex(CombinedIndex), AddStream(AddStream),
+ ModuleToDefinedGVSummaries(ModuleToDefinedGVSummaries) {}
+
+ virtual ~ThinBackendProc() {}
+ virtual Error start(size_t Task, MemoryBufferRef MBRef,
+ StringMap<FunctionImporter::ImportMapTy> &ImportLists,
+ MapVector<StringRef, MemoryBufferRef> &ModuleMap) = 0;
+ virtual Error wait() = 0;
+};
+
+class InProcessThinBackend : public ThinBackendProc {
+ ThreadPool BackendThreadPool;
+
+ Optional<Error> Err;
+ std::mutex ErrMu;
+
+public:
+ InProcessThinBackend(Config &Conf, ModuleSummaryIndex &CombinedIndex,
+ unsigned ThinLTOParallelismLevel,
+ StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
+ AddStreamFn AddStream)
+ : ThinBackendProc(Conf, CombinedIndex, AddStream,
+ ModuleToDefinedGVSummaries),
+ BackendThreadPool(ThinLTOParallelismLevel) {}
+
+ Error
+ runThinLTOBackendThread(AddStreamFn AddStream, size_t Task,
+ MemoryBufferRef MBRef,
+ ModuleSummaryIndex &CombinedIndex,
+ const FunctionImporter::ImportMapTy &ImportList,
+ const GVSummaryMapTy &DefinedGlobals,
+ MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
+ LLVMContext BackendContext;
+
+ ErrorOr<std::unique_ptr<Module>> MOrErr =
+ parseBitcodeFile(MBRef, BackendContext);
+ assert(MOrErr && "Unable to load module in thread?");
+
+ return thinBackend(Conf, Task, AddStream, **MOrErr, CombinedIndex,
+ ImportList, DefinedGlobals, ModuleMap);
+ }
+
+ Error start(size_t Task, MemoryBufferRef MBRef,
+ StringMap<FunctionImporter::ImportMapTy> &ImportLists,
+ MapVector<StringRef, MemoryBufferRef> &ModuleMap) override {
+ StringRef ModulePath = MBRef.getBufferIdentifier();
+ BackendThreadPool.async(
+ [=](MemoryBufferRef MBRef, ModuleSummaryIndex &CombinedIndex,
+ const FunctionImporter::ImportMapTy &ImportList,
+ GVSummaryMapTy &DefinedGlobals,
+ MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
+ Error E =
+ runThinLTOBackendThread(AddStream, Task, MBRef, CombinedIndex,
+ ImportList, DefinedGlobals, ModuleMap);
+ if (E) {
+ std::unique_lock<std::mutex> L(ErrMu);
+ if (Err)
+ Err = joinErrors(std::move(*Err), std::move(E));
+ else
+ Err = std::move(E);
+ }
+ },
+ MBRef, std::ref(CombinedIndex), std::ref(ImportLists[ModulePath]),
+ std::ref(ModuleToDefinedGVSummaries[ModulePath]), std::ref(ModuleMap));
+ return Error();
+ }
+
+ Error wait() override {
+ BackendThreadPool.wait();
+ if (Err)
+ return std::move(*Err);
+ else
+ return Error();
+ }
+};
+
+ThinBackend lto::createInProcessThinBackend(unsigned ParallelismLevel) {
+ return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex,
+ StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
+ AddStreamFn AddStream) {
+ return make_unique<InProcessThinBackend>(
+ Conf, CombinedIndex, ParallelismLevel, ModuleToDefinedGVSummaries,
+ AddStream);
+ };
+}
+
+class WriteIndexesThinBackend : public ThinBackendProc {
+ std::string OldPrefix, NewPrefix;
+ bool ShouldEmitImportsFiles;
+
+ std::string LinkedObjectsFileName;
+ std::unique_ptr<llvm::raw_fd_ostream> LinkedObjectsFile;
+
+public:
+ WriteIndexesThinBackend(Config &Conf, ModuleSummaryIndex &CombinedIndex,
+ StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
+ AddStreamFn AddStream, std::string OldPrefix,
+ std::string NewPrefix, bool ShouldEmitImportsFiles,
+ std::string LinkedObjectsFileName)
+ : ThinBackendProc(Conf, CombinedIndex, AddStream,
+ ModuleToDefinedGVSummaries),
+ OldPrefix(OldPrefix), NewPrefix(NewPrefix),
+ ShouldEmitImportsFiles(ShouldEmitImportsFiles),
+ LinkedObjectsFileName(LinkedObjectsFileName) {}
+
+ /// Given the original \p Path to an output file, replace any path
+ /// prefix matching \p OldPrefix with \p NewPrefix. Also, create the
+ /// resulting directory if it does not yet exist.
+ std::string getThinLTOOutputFile(const std::string &Path,
+ const std::string &OldPrefix,
+ const std::string &NewPrefix) {
+ if (OldPrefix.empty() && NewPrefix.empty())
+ return Path;
+ SmallString<128> NewPath(Path);
+ llvm::sys::path::replace_path_prefix(NewPath, OldPrefix, NewPrefix);
+ StringRef ParentPath = llvm::sys::path::parent_path(NewPath.str());
+ if (!ParentPath.empty()) {
+ // Make sure the new directory exists, creating it if necessary.
+ if (std::error_code EC = llvm::sys::fs::create_directories(ParentPath))
+ llvm::errs() << "warning: could not create directory '" << ParentPath
+ << "': " << EC.message() << '\n';
+ }
+ return NewPath.str();
+ }
+
+ Error start(size_t Task, MemoryBufferRef MBRef,
+ StringMap<FunctionImporter::ImportMapTy> &ImportLists,
+ MapVector<StringRef, MemoryBufferRef> &ModuleMap) override {
+ StringRef ModulePath = MBRef.getBufferIdentifier();
+ std::string NewModulePath =
+ getThinLTOOutputFile(ModulePath, OldPrefix, NewPrefix);
+
+ std::error_code EC;
+ if (!LinkedObjectsFileName.empty()) {
+ if (!LinkedObjectsFile) {
+ LinkedObjectsFile = make_unique<raw_fd_ostream>(
+ LinkedObjectsFileName, EC, sys::fs::OpenFlags::F_None);
+ if (EC)
+ return errorCodeToError(EC);
+ }
+ *LinkedObjectsFile << NewModulePath << '\n';
+ }
+
+ std::map<std::string, GVSummaryMapTy> ModuleToSummariesForIndex;
+ gatherImportedSummariesForModule(ModulePath, ModuleToDefinedGVSummaries,
+ ImportLists, ModuleToSummariesForIndex);
+
+ raw_fd_ostream OS(NewModulePath + ".thinlto.bc", EC,
+ sys::fs::OpenFlags::F_None);
+ if (EC)
+ return errorCodeToError(EC);
+ WriteIndexToFile(CombinedIndex, OS, &ModuleToSummariesForIndex);
+
+ if (ShouldEmitImportsFiles)
+ return errorCodeToError(EmitImportsFiles(
+ ModulePath, NewModulePath + ".imports", ImportLists));
+ return Error();
+ }
+
+ Error wait() override { return Error(); }
+};
+
+ThinBackend lto::createWriteIndexesThinBackend(std::string OldPrefix,
+ std::string NewPrefix,
+ bool ShouldEmitImportsFiles,
+ std::string LinkedObjectsFile) {
+ return [=](Config &Conf, ModuleSummaryIndex &CombinedIndex,
+ StringMap<GVSummaryMapTy> &ModuleToDefinedGVSummaries,
+ AddStreamFn AddStream) {
+ return make_unique<WriteIndexesThinBackend>(
+ Conf, CombinedIndex, ModuleToDefinedGVSummaries, AddStream, OldPrefix,
+ NewPrefix, ShouldEmitImportsFiles, LinkedObjectsFile);
+ };
+}
+
+Error LTO::runThinLTO(AddStreamFn AddStream) {
+ if (ThinLTO.ModuleMap.empty())
+ return Error();
+
+ if (Conf.CombinedIndexHook && !Conf.CombinedIndexHook(ThinLTO.CombinedIndex))
+ return Error();
+
+ // Collect for each module the list of function it defines (GUID ->
+ // Summary).
+ StringMap<std::map<GlobalValue::GUID, GlobalValueSummary *>>
+ ModuleToDefinedGVSummaries(ThinLTO.ModuleMap.size());
+ ThinLTO.CombinedIndex.collectDefinedGVSummariesPerModule(
+ ModuleToDefinedGVSummaries);
+
+ StringMap<FunctionImporter::ImportMapTy> ImportLists(
+ ThinLTO.ModuleMap.size());
+ StringMap<FunctionImporter::ExportSetTy> ExportLists(
+ ThinLTO.ModuleMap.size());
+ ComputeCrossModuleImport(ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries,
+ ImportLists, ExportLists);
+
+ std::set<GlobalValue::GUID> ExportedGUIDs;
+ for (auto &Res : GlobalResolutions) {
+ if (!Res.second.IRName.empty() &&
+ Res.second.Partition == GlobalResolution::External)
+ ExportedGUIDs.insert(GlobalValue::getGUID(Res.second.IRName));
+ }
+
+ auto isPrevailing = [&](GlobalValue::GUID GUID, const GlobalValueSummary *S) {
+ return ThinLTO.PrevailingModuleForGUID[GUID] == S->modulePath();
+ };
+ auto isExported = [&](StringRef ModuleIdentifier, GlobalValue::GUID GUID) {
+ const auto &ExportList = ExportLists.find(ModuleIdentifier);
+ return (ExportList != ExportLists.end() &&
+ ExportList->second.count(GUID)) ||
+ ExportedGUIDs.count(GUID);
+ };
+ thinLTOInternalizeAndPromoteInIndex(ThinLTO.CombinedIndex, isExported);
+ thinLTOResolveWeakForLinkerInIndex(
+ ThinLTO.CombinedIndex, isPrevailing,
+ [](StringRef, GlobalValue::GUID, GlobalValue::LinkageTypes) {});
+
+ std::unique_ptr<ThinBackendProc> BackendProc = ThinLTO.Backend(
+ Conf, ThinLTO.CombinedIndex, ModuleToDefinedGVSummaries, AddStream);
+
+ // Partition numbers for ThinLTO jobs start at 1 (see comments for
+ // GlobalResolution in LTO.h). Task numbers, however, start at
+ // ParallelCodeGenParallelismLevel, as tasks 0 through
+ // ParallelCodeGenParallelismLevel-1 are reserved for parallel code generation
+ // partitions.
+ size_t Task = RegularLTO.ParallelCodeGenParallelismLevel;
+ size_t Partition = 1;
+
+ for (auto &Mod : ThinLTO.ModuleMap) {
+ if (Error E = BackendProc->start(Task, Mod.second, ImportLists,
+ ThinLTO.ModuleMap))
+ return E;
+
+ ++Task;
+ ++Partition;
+ }
+
+ return BackendProc->wait();
}
OpenPOWER on IntegriCloud