LTO: Add support for multi-module bitcode files.

Differential Revision: https://reviews.llvm.org/D27313

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@289621 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Peter Collingbourne 2016-12-14 01:17:59 +00:00
parent d5f6cc37da
commit 08850161ec
8 changed files with 162 additions and 71 deletions

View File

@ -70,6 +70,8 @@ namespace llvm {
return StringRef((const char *)Buffer.begin(), Buffer.size());
}
StringRef getModuleIdentifier() const { return ModuleIdentifier; }
/// Read the bitcode module and prepare for lazy deserialization of function
/// bodies. If ShouldLazyLoadMetadata is true, lazily load metadata as well.
Expected<std::unique_ptr<Module>>

View File

@ -31,6 +31,7 @@
namespace llvm {
class BitcodeModule;
class Error;
class LLVMContext;
class MemoryBufferRef;
@ -80,14 +81,16 @@ class InputFile {
// FIXME: Remove the LLVMContext once we have bitcode symbol tables.
LLVMContext Ctx;
struct InputModule;
std::vector<InputModule> Mods;
ModuleSymbolTable SymTab;
std::unique_ptr<Module> Mod;
MemoryBufferRef MBRef;
std::vector<StringRef> Comdats;
DenseMap<const Comdat *, unsigned> ComdatMap;
public:
~InputFile();
/// Create an InputFile.
static Expected<std::unique_ptr<InputFile>> create(MemoryBufferRef Object);
@ -217,11 +220,17 @@ public:
symbol_iterator(SymTab.symbols().end(), SymTab, this));
}
StringRef getSourceFileName() const { return Mod->getSourceFileName(); }
MemoryBufferRef getMemoryBufferRef() const { return MBRef; }
/// Returns the path to the InputFile.
StringRef getName() const;
/// Returns the source file path specified at compile time.
StringRef getSourceFileName() const;
// Returns a table with all the comdats used by this file.
ArrayRef<StringRef> getComdatTable() const { return Comdats; }
private:
iterator_range<symbol_iterator> module_symbols(InputModule &IM);
};
/// This class wraps an output stream for a native object. Most clients should
@ -311,6 +320,7 @@ public:
/// Until that is fixed, a Config argument is required.
LTO(Config Conf, ThinBackend Backend = nullptr,
unsigned ParallelCodeGenParallelismLevel = 1);
~LTO();
/// Add an input file to the LTO link, using the provided symbol resolutions.
/// The symbol resolutions must appear in the enumeration order given by
@ -357,7 +367,7 @@ private:
ThinBackend Backend;
ModuleSummaryIndex CombinedIndex;
MapVector<StringRef, MemoryBufferRef> ModuleMap;
MapVector<StringRef, BitcodeModule> ModuleMap;
DenseMap<GlobalValue::GUID, StringRef> PrevailingModuleForGUID;
} ThinLTO;
@ -405,10 +415,17 @@ private:
const InputFile::Symbol &Sym, SymbolResolution Res,
unsigned Partition);
Error addRegularLTO(std::unique_ptr<InputFile> Input,
ArrayRef<SymbolResolution> Res);
Error addThinLTO(std::unique_ptr<InputFile> Input,
ArrayRef<SymbolResolution> Res);
// These functions take a range of symbol resolutions [ResI, ResE) and consume
// the resolutions used by a single input module by incrementing ResI. After
// these functions return, [ResI, ResE) will refer to the resolution range for
// the remaining modules in the InputFile.
Error addModule(InputFile &Input, InputFile::InputModule &IM,
const SymbolResolution *&ResI, const SymbolResolution *ResE);
Error addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI,
const SymbolResolution *ResE);
Error addThinLTO(BitcodeModule BM, Module &M,
iterator_range<InputFile::symbol_iterator> Syms,
const SymbolResolution *&ResI, const SymbolResolution *ResE);
Error runRegularLTO(AddStreamFn AddStream);
Error runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,

View File

@ -27,6 +27,7 @@
namespace llvm {
class BitcodeModule;
class Error;
class Module;
class Target;
@ -43,7 +44,7 @@ Error thinBackend(Config &C, unsigned Task, AddStreamFn AddStream, Module &M,
ModuleSummaryIndex &CombinedIndex,
const FunctionImporter::ImportMapTy &ImportList,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, MemoryBufferRef> &ModuleMap);
MapVector<StringRef, BitcodeModule> &ModuleMap);
}
}

View File

@ -214,6 +214,17 @@ 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;
Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) {
std::unique_ptr<InputFile> File(new InputFile);
@ -221,23 +232,37 @@ Expected<std::unique_ptr<InputFile>> InputFile::create(MemoryBufferRef Object) {
IRObjectFile::findBitcodeInMemBuffer(Object);
if (!BCOrErr)
return errorCodeToError(BCOrErr.getError());
File->MBRef = *BCOrErr;
Expected<std::unique_ptr<Module>> MOrErr =
getLazyBitcodeModule(*BCOrErr, File->Ctx,
/*ShouldLazyLoadMetadata*/ true);
if (!MOrErr)
return MOrErr.takeError();
Expected<std::vector<BitcodeModule>> BMsOrErr =
getBitcodeModuleList(*BCOrErr);
if (!BMsOrErr)
return BMsOrErr.takeError();
File->Mod = std::move(*MOrErr);
File->SymTab.addModule(File->Mod.get());
if (BMsOrErr->empty())
return make_error<StringError>("Bitcode file does not contain any modules",
inconvertibleErrorCode());
for (const auto &C : File->Mod->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());
// Create an InputModule for each module in the InputFile, and add it to the
// ModuleSymbolTable.
for (auto BM : *BMsOrErr) {
Expected<std::unique_ptr<Module>> MOrErr =
BM.getLazyModule(File->Ctx, /*ShouldLazyLoadMetadata*/ true);
if (!MOrErr)
return MOrErr.takeError();
size_t SymBegin = File->SymTab.symbols().size();
File->SymTab.addModule(MOrErr->get());
size_t SymEnd = File->SymTab.symbols().size();
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());
}
File->Mods.push_back({BM, std::move(*MOrErr), SymBegin, SymEnd});
}
return std::move(File);
@ -258,6 +283,21 @@ Expected<int> InputFile::Symbol::getComdatIndex() const {
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));
}
LTO::RegularLTOState::RegularLTOState(unsigned ParallelCodeGenParallelismLevel,
Config &Conf)
: ParallelCodeGenParallelismLevel(ParallelCodeGenParallelismLevel),
@ -275,6 +315,9 @@ LTO::LTO(Config Conf, ThinBackend Backend,
RegularLTO(ParallelCodeGenParallelismLevel, this->Conf),
ThinLTO(std::move(Backend)) {}
// Requires a destructor for MapVector<BitcodeModule>.
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,
@ -297,7 +340,7 @@ void LTO::addSymbolToGlobalRes(SmallPtrSet<GlobalValue *, 8> &Used,
static void writeToResolutionFile(raw_ostream &OS, InputFile *Input,
ArrayRef<SymbolResolution> Res) {
StringRef Path = Input->getMemoryBufferRef().getBufferIdentifier();
StringRef Path = Input->getName();
OS << Path << '\n';
auto ResI = Res.begin();
for (const InputFile::Symbol &Sym : Input->symbols()) {
@ -323,34 +366,45 @@ Error LTO::add(std::unique_ptr<InputFile> Input,
if (Conf.ResolutionFile)
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()))
return Err;
assert(ResI == Res.end());
return Error::success();
}
Error LTO::addModule(InputFile &Input, InputFile::InputModule &IM,
const SymbolResolution *&ResI,
const SymbolResolution *ResE) {
// FIXME: move to backend
Module &M = *Input->Mod;
Module &M = *IM.Mod;
if (!Conf.OverrideTriple.empty())
M.setTargetTriple(Conf.OverrideTriple);
else if (M.getTargetTriple().empty())
M.setTargetTriple(Conf.DefaultTriple);
Expected<bool> HasThinLTOSummary = hasGlobalValueSummary(Input->MBRef);
Expected<bool> HasThinLTOSummary = IM.BM.hasSummary();
if (!HasThinLTOSummary)
return HasThinLTOSummary.takeError();
if (*HasThinLTOSummary)
return addThinLTO(std::move(Input), Res);
return addThinLTO(IM.BM, M, Input.module_symbols(IM), ResI, ResE);
else
return addRegularLTO(std::move(Input), Res);
return addRegularLTO(IM.BM, ResI, ResE);
}
// Add a regular LTO object to the link.
Error LTO::addRegularLTO(std::unique_ptr<InputFile> Input,
ArrayRef<SymbolResolution> Res) {
Error LTO::addRegularLTO(BitcodeModule BM, const SymbolResolution *&ResI,
const SymbolResolution *ResE) {
if (!RegularLTO.CombinedModule) {
RegularLTO.CombinedModule =
llvm::make_unique<Module>("ld-temp.o", RegularLTO.Ctx);
RegularLTO.Mover = llvm::make_unique<IRMover>(*RegularLTO.CombinedModule);
}
Expected<std::unique_ptr<Module>> MOrErr =
getLazyBitcodeModule(Input->MBRef, RegularLTO.Ctx,
/*ShouldLazyLoadMetadata*/ true);
BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true);
if (!MOrErr)
return MOrErr.takeError();
@ -371,13 +425,12 @@ Error LTO::addRegularLTO(std::unique_ptr<InputFile> Input,
if (GV.hasAppendingLinkage())
Keep.push_back(&GV);
auto ResI = Res.begin();
for (const InputFile::Symbol &Sym :
make_range(InputFile::symbol_iterator(SymTab.symbols().begin(), SymTab,
nullptr),
InputFile::symbol_iterator(SymTab.symbols().end(), SymTab,
nullptr))) {
assert(ResI != Res.end());
assert(ResI != ResE);
SymbolResolution Res = *ResI++;
addSymbolToGlobalRes(Used, Sym, Res, 0);
@ -411,7 +464,6 @@ Error LTO::addRegularLTO(std::unique_ptr<InputFile> Input,
// FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit.
}
assert(ResI == Res.end());
return RegularLTO.Mover->move(std::move(*MOrErr), Keep,
[](GlobalValue &, IRMover::ValueAdder) {},
@ -420,33 +472,36 @@ Error LTO::addRegularLTO(std::unique_ptr<InputFile> Input,
}
// Add a ThinLTO object to the link.
Error LTO::addThinLTO(std::unique_ptr<InputFile> Input,
ArrayRef<SymbolResolution> Res) {
Module &M = *Input->Mod;
// 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,
const SymbolResolution *&ResI,
const SymbolResolution *ResE) {
SmallPtrSet<GlobalValue *, 8> Used;
collectUsedGlobalVariables(M, Used, /*CompilerUsed*/ false);
MemoryBufferRef MBRef = Input->MBRef;
Expected<std::unique_ptr<object::ModuleSummaryIndexObjectFile>>
SummaryObjOrErr = object::ModuleSummaryIndexObjectFile::create(MBRef);
if (!SummaryObjOrErr)
return SummaryObjOrErr.takeError();
ThinLTO.CombinedIndex.mergeFrom((*SummaryObjOrErr)->takeIndex(),
Expected<std::unique_ptr<ModuleSummaryIndex>> SummaryOrErr = BM.getSummary();
if (!SummaryOrErr)
return SummaryOrErr.takeError();
ThinLTO.CombinedIndex.mergeFrom(std::move(*SummaryOrErr),
ThinLTO.ModuleMap.size());
auto ResI = Res.begin();
for (const InputFile::Symbol &Sym : Input->symbols()) {
assert(ResI != Res.end());
for (const InputFile::Symbol &Sym : Syms) {
assert(ResI != ResE);
SymbolResolution Res = *ResI++;
addSymbolToGlobalRes(Used, Sym, Res, ThinLTO.ModuleMap.size() + 1);
if (Res.Prevailing && Sym.isGV())
ThinLTO.PrevailingModuleForGUID[Sym.getGV()->getGUID()] =
MBRef.getBufferIdentifier();
BM.getModuleIdentifier();
}
assert(ResI == Res.end());
ThinLTO.ModuleMap[MBRef.getBufferIdentifier()] = MBRef;
if (!ThinLTO.ModuleMap.insert({BM.getModuleIdentifier(), BM}).second)
return make_error<StringError>(
"Expected at most one ThinLTO module per bitcode file",
inconvertibleErrorCode());
return Error::success();
}
@ -543,11 +598,11 @@ public:
virtual ~ThinBackendProc() {}
virtual Error start(
unsigned Task, MemoryBufferRef MBRef,
unsigned Task, BitcodeModule BM,
const FunctionImporter::ImportMapTy &ImportList,
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
MapVector<StringRef, MemoryBufferRef> &ModuleMap) = 0;
MapVector<StringRef, BitcodeModule> &ModuleMap) = 0;
virtual Error wait() = 0;
};
@ -572,16 +627,15 @@ public:
Error runThinLTOBackendThread(
AddStreamFn AddStream, NativeObjectCache Cache, unsigned Task,
MemoryBufferRef MBRef, ModuleSummaryIndex &CombinedIndex,
BitcodeModule BM, ModuleSummaryIndex &CombinedIndex,
const FunctionImporter::ImportMapTy &ImportList,
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
MapVector<StringRef, BitcodeModule> &ModuleMap) {
auto RunThinBackend = [&](AddStreamFn AddStream) {
LTOLLVMContext BackendContext(Conf);
Expected<std::unique_ptr<Module>> MOrErr =
parseBitcodeFile(MBRef, BackendContext);
Expected<std::unique_ptr<Module>> MOrErr = BM.parseModule(BackendContext);
if (!MOrErr)
return MOrErr.takeError();
@ -589,7 +643,7 @@ public:
ImportList, DefinedGlobals, ModuleMap);
};
auto ModuleID = MBRef.getBufferIdentifier();
auto ModuleID = BM.getModuleIdentifier();
if (!Cache || !CombinedIndex.modulePaths().count(ModuleID) ||
all_of(CombinedIndex.getModuleHash(ModuleID),
@ -609,25 +663,25 @@ public:
}
Error start(
unsigned Task, MemoryBufferRef MBRef,
unsigned Task, BitcodeModule BM,
const FunctionImporter::ImportMapTy &ImportList,
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
MapVector<StringRef, MemoryBufferRef> &ModuleMap) override {
StringRef ModulePath = MBRef.getBufferIdentifier();
MapVector<StringRef, BitcodeModule> &ModuleMap) override {
StringRef ModulePath = BM.getModuleIdentifier();
assert(ModuleToDefinedGVSummaries.count(ModulePath));
const GVSummaryMapTy &DefinedGlobals =
ModuleToDefinedGVSummaries.find(ModulePath)->second;
BackendThreadPool.async(
[=](MemoryBufferRef MBRef, ModuleSummaryIndex &CombinedIndex,
[=](BitcodeModule BM, ModuleSummaryIndex &CombinedIndex,
const FunctionImporter::ImportMapTy &ImportList,
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes>
&ResolvedODR,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
MapVector<StringRef, BitcodeModule> &ModuleMap) {
Error E = runThinLTOBackendThread(
AddStream, Cache, Task, MBRef, CombinedIndex, ImportList,
AddStream, Cache, Task, BM, CombinedIndex, ImportList,
ExportList, ResolvedODR, DefinedGlobals, ModuleMap);
if (E) {
std::unique_lock<std::mutex> L(ErrMu);
@ -637,7 +691,7 @@ public:
Err = std::move(E);
}
},
MBRef, std::ref(CombinedIndex), std::ref(ImportList),
BM, std::ref(CombinedIndex), std::ref(ImportList),
std::ref(ExportList), std::ref(ResolvedODR), std::ref(DefinedGlobals),
std::ref(ModuleMap));
return Error::success();
@ -703,12 +757,12 @@ public:
LinkedObjectsFileName(LinkedObjectsFileName) {}
Error start(
unsigned Task, MemoryBufferRef MBRef,
unsigned Task, BitcodeModule BM,
const FunctionImporter::ImportMapTy &ImportList,
const FunctionImporter::ExportSetTy &ExportList,
const std::map<GlobalValue::GUID, GlobalValue::LinkageTypes> &ResolvedODR,
MapVector<StringRef, MemoryBufferRef> &ModuleMap) override {
StringRef ModulePath = MBRef.getBufferIdentifier();
MapVector<StringRef, BitcodeModule> &ModuleMap) override {
StringRef ModulePath = BM.getModuleIdentifier();
std::string NewModulePath =
getThinLTOOutputFile(ModulePath, OldPrefix, NewPrefix);

View File

@ -318,7 +318,7 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream,
Module &Mod, ModuleSummaryIndex &CombinedIndex,
const FunctionImporter::ImportMapTy &ImportList,
const GVSummaryMapTy &DefinedGlobals,
MapVector<StringRef, MemoryBufferRef> &ModuleMap) {
MapVector<StringRef, BitcodeModule> &ModuleMap) {
Expected<const Target *> TOrErr = initAndLookupTarget(Conf, Mod);
if (!TOrErr)
return TOrErr.takeError();
@ -353,8 +353,10 @@ Error lto::thinBackend(Config &Conf, unsigned Task, AddStreamFn AddStream,
auto ModuleLoader = [&](StringRef Identifier) {
assert(Mod.getContext().isODRUniquingDebugTypes() &&
"ODR Type uniquing should be enabled on the context");
return getLazyBitcodeModule(ModuleMap[Identifier], Mod.getContext(),
/*ShouldLazyLoadMetadata=*/true);
auto I = ModuleMap.find(Identifier);
assert(I != ModuleMap.end());
return I->second.getLazyModule(Mod.getContext(),
/*ShouldLazyLoadMetadata=*/true);
};
FunctionImporter Importer(CombinedIndex, ModuleLoader);

View File

@ -0,0 +1,3 @@
RUN: llvm-cat -o %t.o
RUN: not llvm-lto2 -o %t2 %t.o 2>&1 | FileCheck %s
CHECK: Bitcode file does not contain any modules

View File

@ -13,6 +13,12 @@
; NM1-DAG: T main
; NM1-DAG: U g
; Do the same test again, but with the regular and thin LTO modules in the same file.
; RUN: llvm-cat -b -o %t4.o %t2.o %t1.o
; RUN: llvm-lto2 -o %t5.o %t4.o -r %t4.o,main,px -r %t4.o,g, -r %t4.o,g,px
; RUN: llvm-nm %t5.o.0 | FileCheck %s --check-prefix=NM0
; RUN: llvm-nm %t5.o.1 | FileCheck %s --check-prefix=NM1
target triple = "x86_64-unknown-linux-gnu"
define i32 @g() {
ret i32 0

View File

@ -0,0 +1,6 @@
; RUN: opt -module-summary %s -o %t.o
; RUN: llvm-cat -b -o %t2.o %t.o %t.o
; RUN: not llvm-lto2 -o %t3.o %t2.o 2>&1 | FileCheck %s
; CHECK: Expected at most one ThinLTO module per bitcode file
target triple = "x86_64-unknown-linux-gnu"