std::vector<FunctionSummary::EdgeTy> makeCallList(ArrayRef<uint64_t> Record,
bool IsOldProfileFormat,
bool HasProfile);
- Error parseEntireSummary();
+ Error parseEntireSummary(unsigned ID);
Error parseModuleStringTable();
std::pair<ValueInfo, GlobalValue::GUID>
return error("Invalid record");
break;
case bitc::GLOBALVAL_SUMMARY_BLOCK_ID:
+ case bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID:
assert(!SeenValueSymbolTable &&
"Already read VST when parsing summary block?");
// We might not have a VST if there were no values in the
SeenValueSymbolTable = true;
}
SeenGlobalValSummary = true;
- if (Error Err = parseEntireSummary())
+ if (Error Err = parseEntireSummary(Entry.ID))
return Err;
break;
case bitc::MODULE_STRTAB_BLOCK_ID:
// Eagerly parse the entire summary block. This populates the GlobalValueSummary
// objects in the index.
-Error ModuleSummaryIndexBitcodeReader::parseEntireSummary() {
- if (Stream.EnterSubBlock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID))
+Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
+ if (Stream.EnterSubBlock(ID))
return error("Invalid record");
SmallVector<uint64_t, 64> Record;
}
// Parse the specified bitcode buffer and merge the index into CombinedIndex.
+// We don't use ModuleIdentifier here because the client may need to control the
+// module path used in the combined summary (e.g. when reading summaries for
+// regular LTO modules).
Error BitcodeModule::readSummary(ModuleSummaryIndex &CombinedIndex,
- unsigned ModuleId) {
+ StringRef ModulePath, uint64_t ModuleId) {
BitstreamCursor Stream(Buffer);
Stream.JumpToBit(ModuleBit);
ModuleSummaryIndexBitcodeReader R(std::move(Stream), Strtab, CombinedIndex,
- ModuleIdentifier, ModuleId);
+ ModulePath, ModuleId);
return R.parseModule();
}
}
// Check if the given bitcode buffer contains a global value summary block.
-Expected<bool> BitcodeModule::hasSummary() {
+Expected<BitcodeLTOInfo> BitcodeModule::getLTOInfo() {
BitstreamCursor Stream(Buffer);
Stream.JumpToBit(ModuleBit);
case BitstreamEntry::Error:
return error("Malformed block");
case BitstreamEntry::EndBlock:
- return false;
+ return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/false};
case BitstreamEntry::SubBlock:
if (Entry.ID == bitc::GLOBALVAL_SUMMARY_BLOCK_ID)
- return true;
+ return BitcodeLTOInfo{/*IsThinLTO=*/true, /*HasSummary=*/true};
+
+ if (Entry.ID == bitc::FULL_LTO_GLOBALVAL_SUMMARY_BLOCK_ID)
+ return BitcodeLTOInfo{/*IsThinLTO=*/false, /*HasSummary=*/true};
// Ignore other sub-blocks.
if (Stream.SkipBlock())
Error llvm::readModuleSummaryIndex(MemoryBufferRef Buffer,
ModuleSummaryIndex &CombinedIndex,
- unsigned ModuleId) {
+ uint64_t ModuleId) {
Expected<BitcodeModule> BM = getSingleModule(Buffer);
if (!BM)
return BM.takeError();
- return BM->readSummary(CombinedIndex, ModuleId);
+ return BM->readSummary(CombinedIndex, BM->getModuleIdentifier(), ModuleId);
}
Expected<std::unique_ptr<ModuleSummaryIndex>>
return BM->getSummary();
}
-Expected<bool> llvm::hasGlobalValueSummary(MemoryBufferRef Buffer) {
+Expected<BitcodeLTOInfo> llvm::getBitcodeLTOInfo(MemoryBufferRef Buffer) {
Expected<BitcodeModule> BM = getSingleModule(Buffer);
if (!BM)
return BM.takeError();
- return BM->hasSummary();
+ return BM->getLTOInfo();
}
Expected<std::unique_ptr<ModuleSummaryIndex>>
// Requires a destructor for MapVector<BitcodeModule>.
LTO::~LTO() = default;
-// Add the given symbol to the GlobalResolutions map, and resolve its partition.
-void LTO::addSymbolToGlobalRes(const InputFile::Symbol &Sym,
- SymbolResolution Res, unsigned Partition) {
- auto &GlobalRes = GlobalResolutions[Sym.getName()];
- GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr();
- if (Res.Prevailing)
- GlobalRes.IRName = Sym.getIRName();
-
- // Set the partition to external if we know it is re-defined by the linker
- // with -defsym or -wrap options, 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.LinkerRedefined || Res.VisibleToRegularObj || Sym.isUsed() ||
- (GlobalRes.Partition != GlobalResolution::Unknown &&
- GlobalRes.Partition != Partition)) {
- GlobalRes.Partition = GlobalResolution::External;
- } else
- // First recorded reference, save the current partition.
- GlobalRes.Partition = Partition;
-
- // Flag as visible outside of ThinLTO if visible from a regular object or
- // if this is a reference in the regular LTO partition.
- GlobalRes.VisibleOutsideThinLTO |=
- (Res.VisibleToRegularObj || Sym.isUsed() ||
- Partition == GlobalResolution::RegularLTO);
+// Add the symbols in the given module to the GlobalResolutions map, and resolve
+// their partitions.
+void LTO::addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
+ ArrayRef<SymbolResolution> Res,
+ unsigned Partition, bool InSummary) {
+ auto *ResI = Res.begin();
+ auto *ResE = Res.end();
+ for (const InputFile::Symbol &Sym : Syms) {
+ assert(ResI != ResE);
+ SymbolResolution Res = *ResI++;
+
+ auto &GlobalRes = GlobalResolutions[Sym.getName()];
+ GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr();
+ if (Res.Prevailing)
+ GlobalRes.IRName = Sym.getIRName();
+
+ // Set the partition to external if we know it is re-defined by the linker
+ // with -defsym or -wrap options, 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.LinkerRedefined || Res.VisibleToRegularObj || Sym.isUsed() ||
+ (GlobalRes.Partition != GlobalResolution::Unknown &&
+ GlobalRes.Partition != Partition)) {
+ GlobalRes.Partition = GlobalResolution::External;
+ } else
+ // First recorded reference, save the current partition.
+ GlobalRes.Partition = Partition;
+
+ // Flag as visible outside of summary if visible from a regular object or
+ // from a module that does not have a summary.
+ GlobalRes.VisibleOutsideSummary |=
+ (Res.VisibleToRegularObj || Sym.isUsed() || !InSummary);
+ }
}
static void writeToResolutionFile(raw_ostream &OS, InputFile *Input,
Error LTO::addModule(InputFile &Input, unsigned ModI,
const SymbolResolution *&ResI,
const SymbolResolution *ResE) {
- Expected<bool> HasThinLTOSummary = Input.Mods[ModI].hasSummary();
- if (!HasThinLTOSummary)
- return HasThinLTOSummary.takeError();
+ Expected<BitcodeLTOInfo> LTOInfo = Input.Mods[ModI].getLTOInfo();
+ if (!LTOInfo)
+ return LTOInfo.takeError();
+ BitcodeModule BM = Input.Mods[ModI];
auto ModSyms = Input.module_symbols(ModI);
- if (*HasThinLTOSummary)
- return addThinLTO(Input.Mods[ModI], ModSyms, ResI, ResE);
- else
- return addRegularLTO(Input.Mods[ModI], ModSyms, ResI, ResE);
+ addModuleToGlobalRes(ModSyms, {ResI, ResE},
+ LTOInfo->IsThinLTO ? ThinLTO.ModuleMap.size() + 1 : 0,
+ LTOInfo->HasSummary);
+
+ if (LTOInfo->IsThinLTO)
+ return addThinLTO(BM, ModSyms, ResI, ResE);
+
+ Expected<RegularLTOState::AddedModule> ModOrErr =
+ addRegularLTO(BM, ModSyms, ResI, ResE);
+ if (!ModOrErr)
+ return ModOrErr.takeError();
+
+ if (!LTOInfo->HasSummary)
+ return linkRegularLTO(std::move(*ModOrErr), /*LivenessFromIndex=*/false);
+
+ // Regular LTO module summaries are added to a dummy module that represents
+ // the combined regular LTO module.
+ if (Error Err = BM.readSummary(ThinLTO.CombinedIndex, "", -1ull))
+ return Err;
+ RegularLTO.ModsWithSummaries.push_back(std::move(*ModOrErr));
+ return Error::success();
}
// Add a regular LTO object to the link.
-Error LTO::addRegularLTO(BitcodeModule BM,
- ArrayRef<InputFile::Symbol> Syms,
- 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);
- }
+// The resulting module needs to be linked into the combined LTO module with
+// linkRegularLTO.
+Expected<LTO::RegularLTOState::AddedModule>
+LTO::addRegularLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
+ const SymbolResolution *&ResI,
+ const SymbolResolution *ResE) {
+ RegularLTOState::AddedModule Mod;
Expected<std::unique_ptr<Module>> MOrErr =
BM.getLazyModule(RegularLTO.Ctx, /*ShouldLazyLoadMetadata*/ true,
/*IsImporting*/ false);
if (!MOrErr)
return MOrErr.takeError();
-
Module &M = **MOrErr;
+ Mod.M = std::move(*MOrErr);
+
if (Error Err = M.materializeMetadata())
- return Err;
+ return std::move(Err);
UpgradeDebugInfo(M);
ModuleSymbolTable SymTab;
SymTab.addModule(&M);
- std::vector<GlobalValue *> Keep;
-
for (GlobalVariable &GV : M.globals())
if (GV.hasAppendingLinkage())
- Keep.push_back(&GV);
+ Mod.Keep.push_back(&GV);
DenseSet<GlobalObject *> AliasedGlobals;
for (auto &GA : M.aliases())
for (const InputFile::Symbol &Sym : Syms) {
assert(ResI != ResE);
SymbolResolution Res = *ResI++;
- addSymbolToGlobalRes(Sym, Res, 0);
assert(MsymI != MsymE);
ModuleSymbolTable::Symbol Msym = *MsymI++;
if (Res.Prevailing) {
if (Sym.isUndefined())
continue;
- Keep.push_back(GV);
+ Mod.Keep.push_back(GV);
// For symbols re-defined with linker -wrap and -defsym options,
// set the linkage to weak to inhibit IPO. The linkage will be
// restored by the linker.
(GV->hasLinkOnceODRLinkage() || GV->hasWeakODRLinkage() ||
GV->hasAvailableExternallyLinkage()) &&
!AliasedGlobals.count(cast<GlobalObject>(GV))) {
- // Either of the above three types of linkage indicates that the
+ // Any 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);
- }
+ // the symbol, so we may be able to link it with available_externally
+ // linkage. We will decide later whether to do that when we link this
+ // module (in linkRegularLTO), based on whether it is undefined.
+ Mod.Keep.push_back(GV);
+ GV->setLinkage(GlobalValue::AvailableExternallyLinkage);
+ cast<GlobalObject>(GV)->setComdat(nullptr);
}
}
// Common resolution: collect the maximum size/alignment over all commons.
// FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit.
}
assert(MsymI == MsymE);
+ return std::move(Mod);
+}
+
+Error LTO::linkRegularLTO(RegularLTOState::AddedModule Mod,
+ bool LivenessFromIndex) {
+ if (!RegularLTO.CombinedModule) {
+ RegularLTO.CombinedModule =
+ llvm::make_unique<Module>("ld-temp.o", RegularLTO.Ctx);
+ RegularLTO.Mover = llvm::make_unique<IRMover>(*RegularLTO.CombinedModule);
+ }
+
+ std::vector<GlobalValue *> Keep;
+ for (GlobalValue *GV : Mod.Keep) {
+ if (LivenessFromIndex && !ThinLTO.CombinedIndex.isGUIDLive(GV->getGUID()))
+ continue;
- return RegularLTO.Mover->move(std::move(*MOrErr), Keep,
+ if (!GV->hasAvailableExternallyLinkage()) {
+ Keep.push_back(GV);
+ continue;
+ }
+
+ // Only link available_externally definitions if we don't already have a
+ // definition.
+ GlobalValue *CombinedGV =
+ RegularLTO.CombinedModule->getNamedValue(GV->getName());
+ if (CombinedGV && !CombinedGV->isDeclaration())
+ continue;
+
+ Keep.push_back(GV);
+ }
+
+ return RegularLTO.Mover->move(std::move(Mod.M), Keep,
[](GlobalValue &, IRMover::ValueAdder) {},
/* IsPerformingImport */ false);
}
-// Add a ThinLTO object to the link.
-Error LTO::addThinLTO(BitcodeModule BM,
- ArrayRef<InputFile::Symbol> Syms,
+// Add a ThinLTO module to the link.
+Error LTO::addThinLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
const SymbolResolution *&ResI,
const SymbolResolution *ResE) {
if (Error Err =
- BM.readSummary(ThinLTO.CombinedIndex, ThinLTO.ModuleMap.size()))
+ BM.readSummary(ThinLTO.CombinedIndex, BM.getModuleIdentifier(),
+ ThinLTO.ModuleMap.size()))
return Err;
for (const InputFile::Symbol &Sym : Syms) {
assert(ResI != ResE);
SymbolResolution Res = *ResI++;
- addSymbolToGlobalRes(Sym, Res, ThinLTO.ModuleMap.size() + 1);
if (Res.Prevailing) {
if (!Sym.getIRName().empty()) {
// Compute "dead" symbols, we don't want to import/export these!
DenseSet<GlobalValue::GUID> GUIDPreservedSymbols;
for (auto &Res : GlobalResolutions) {
- if (Res.second.VisibleOutsideThinLTO &&
+ if (Res.second.VisibleOutsideSummary &&
// 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())
// Save the status of having a regularLTO combined module, as
// this is needed for generating the ThinLTO Task ID, and
// the CombinedModule will be moved at the end of runRegularLTO.
- bool HasRegularLTO = RegularLTO.CombinedModule != nullptr;
+ bool HasRegularLTO = RegularLTO.CombinedModule != nullptr ||
+ !RegularLTO.ModsWithSummaries.empty();
// Invoke regular LTO if there was a regular LTO module to start with.
if (HasRegularLTO)
if (auto E = runRegularLTO(AddStream))
}
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();
};
}
-static bool IsLiveByGUID(const ModuleSummaryIndex &Index,
- GlobalValue::GUID GUID) {
- auto VI = Index.getValueInfo(GUID);
- if (!VI)
- return false;
- for (auto &I : VI.getSummaryList())
- if (Index.isGlobalValueLive(I.get()))
- return true;
- return false;
-}
-
Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
bool HasRegularLTO) {
if (ThinLTO.ModuleMap.empty())
auto GUID = GlobalValue::getGUID(
GlobalValue::dropLLVMManglingEscape(Res.second.IRName));
// Mark exported unless index-based analysis determined it to be dead.
- if (IsLiveByGUID(ThinLTO.CombinedIndex, GUID))
+ if (ThinLTO.CombinedIndex.isGUIDLive(GUID))
ExportedGUIDs.insert(GUID);
}