mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 18:54:02 +01:00
Apply summary-based dead stripping to regular LTO modules with summaries.
If a regular LTO module has a summary index, then instead of linking it into the combined regular LTO module right away, add it to the combined summary index and associate it with a special module that represents the combined regular LTO module. Any such modules are linked during LTO::run(), at which time we use the results of summary-based dead stripping to control whether to link prevailing symbols. Differential Revision: https://reviews.llvm.org/D33922 llvm-svn: 305482
This commit is contained in:
parent
d74b25c229
commit
910e0ef4ff
@ -42,6 +42,12 @@ namespace llvm {
|
||||
|
||||
struct BitcodeFileContents;
|
||||
|
||||
/// Basic information extracted from a bitcode module to be used for LTO.
|
||||
struct BitcodeLTOInfo {
|
||||
bool IsThinLTO;
|
||||
bool HasSummary;
|
||||
};
|
||||
|
||||
/// Represents a module in a bitcode file.
|
||||
class BitcodeModule {
|
||||
// This covers the identification (if present) and module blocks.
|
||||
@ -90,15 +96,17 @@ namespace llvm {
|
||||
/// Read the entire bitcode module and return it.
|
||||
Expected<std::unique_ptr<Module>> parseModule(LLVMContext &Context);
|
||||
|
||||
/// Check if the given bitcode buffer contains a summary block.
|
||||
Expected<bool> hasSummary();
|
||||
/// Returns information about the module to be used for LTO: whether to
|
||||
/// compile with ThinLTO, and whether it has a summary.
|
||||
Expected<BitcodeLTOInfo> getLTOInfo();
|
||||
|
||||
/// Parse the specified bitcode buffer, returning the module summary index.
|
||||
Expected<std::unique_ptr<ModuleSummaryIndex>> getSummary();
|
||||
|
||||
/// Parse the specified bitcode buffer and merge its module summary index
|
||||
/// into CombinedIndex.
|
||||
Error readSummary(ModuleSummaryIndex &CombinedIndex, unsigned ModuleId);
|
||||
Error readSummary(ModuleSummaryIndex &CombinedIndex, StringRef ModulePath,
|
||||
uint64_t ModuleId);
|
||||
};
|
||||
|
||||
struct BitcodeFileContents {
|
||||
@ -147,8 +155,8 @@ namespace llvm {
|
||||
Expected<std::unique_ptr<Module>> parseBitcodeFile(MemoryBufferRef Buffer,
|
||||
LLVMContext &Context);
|
||||
|
||||
/// Check if the given bitcode buffer contains a summary block.
|
||||
Expected<bool> hasGlobalValueSummary(MemoryBufferRef Buffer);
|
||||
/// Returns LTO information for the specified bitcode file.
|
||||
Expected<BitcodeLTOInfo> getBitcodeLTOInfo(MemoryBufferRef Buffer);
|
||||
|
||||
/// Parse the specified bitcode buffer, returning the module summary index.
|
||||
Expected<std::unique_ptr<ModuleSummaryIndex>>
|
||||
@ -157,7 +165,7 @@ namespace llvm {
|
||||
/// Parse the specified bitcode buffer and merge the index into CombinedIndex.
|
||||
Error readModuleSummaryIndex(MemoryBufferRef Buffer,
|
||||
ModuleSummaryIndex &CombinedIndex,
|
||||
unsigned ModuleId);
|
||||
uint64_t ModuleId);
|
||||
|
||||
/// Parse the module summary index out of an IR file and return the module
|
||||
/// summary index object if found, or an empty summary if not. If Path refers
|
||||
|
@ -567,6 +567,7 @@ public:
|
||||
bool isGlobalValueLive(const GlobalValueSummary *GVS) const {
|
||||
return !WithGlobalValueDeadStripping || GVS->isLive();
|
||||
}
|
||||
bool isGUIDLive(GlobalValue::GUID GUID) const;
|
||||
|
||||
/// Return a ValueInfo for GUID if it exists, otherwise return ValueInfo().
|
||||
ValueInfo getValueInfo(GlobalValue::GUID GUID) const {
|
||||
|
@ -281,6 +281,16 @@ private:
|
||||
bool HasModule = false;
|
||||
std::unique_ptr<Module> CombinedModule;
|
||||
std::unique_ptr<IRMover> Mover;
|
||||
|
||||
// This stores the information about a regular LTO module that we have added
|
||||
// to the link. It will either be linked immediately (for modules without
|
||||
// summaries) or after summary-based dead stripping (for modules with
|
||||
// summaries).
|
||||
struct AddedModule {
|
||||
std::unique_ptr<Module> M;
|
||||
std::vector<GlobalValue *> Keep;
|
||||
};
|
||||
std::vector<AddedModule> ModsWithSummaries;
|
||||
} RegularLTO;
|
||||
|
||||
struct ThinLTOState {
|
||||
@ -303,9 +313,10 @@ private:
|
||||
/// The unmangled name of the global.
|
||||
std::string IRName;
|
||||
|
||||
/// Keep track if the symbol is visible outside of ThinLTO (i.e. in
|
||||
/// either a regular object or the regular LTO partition).
|
||||
bool VisibleOutsideThinLTO = false;
|
||||
/// Keep track if the symbol is visible outside of a module with a summary
|
||||
/// (i.e. in either a regular object or a regular LTO module without a
|
||||
/// summary).
|
||||
bool VisibleOutsideSummary = false;
|
||||
|
||||
bool UnnamedAddr = true;
|
||||
|
||||
@ -339,8 +350,9 @@ private:
|
||||
// Global mapping from mangled symbol names to resolutions.
|
||||
StringMap<GlobalResolution> GlobalResolutions;
|
||||
|
||||
void addSymbolToGlobalRes(const InputFile::Symbol &Sym, SymbolResolution Res,
|
||||
unsigned Partition);
|
||||
void addModuleToGlobalRes(ArrayRef<InputFile::Symbol> Syms,
|
||||
ArrayRef<SymbolResolution> Res, unsigned Partition,
|
||||
bool InSummary);
|
||||
|
||||
// These functions take a range of symbol resolutions [ResI, ResE) and consume
|
||||
// the resolutions used by a single input module by incrementing ResI. After
|
||||
@ -348,10 +360,13 @@ private:
|
||||
// the remaining modules in the InputFile.
|
||||
Error addModule(InputFile &Input, unsigned ModI,
|
||||
const SymbolResolution *&ResI, const SymbolResolution *ResE);
|
||||
Error addRegularLTO(BitcodeModule BM,
|
||||
ArrayRef<InputFile::Symbol> Syms,
|
||||
const SymbolResolution *&ResI,
|
||||
const SymbolResolution *ResE);
|
||||
|
||||
Expected<RegularLTOState::AddedModule>
|
||||
addRegularLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
|
||||
const SymbolResolution *&ResI, const SymbolResolution *ResE);
|
||||
Error linkRegularLTO(RegularLTOState::AddedModule Mod,
|
||||
bool LivenessFromIndex);
|
||||
|
||||
Error addThinLTO(BitcodeModule BM, ArrayRef<InputFile::Symbol> Syms,
|
||||
const SymbolResolution *&ResI, const SymbolResolution *ResE);
|
||||
|
||||
|
@ -733,7 +733,7 @@ private:
|
||||
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>
|
||||
@ -4854,6 +4854,7 @@ Error ModuleSummaryIndexBitcodeReader::parseModule() {
|
||||
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
|
||||
@ -4866,7 +4867,7 @@ Error ModuleSummaryIndexBitcodeReader::parseModule() {
|
||||
SeenValueSymbolTable = true;
|
||||
}
|
||||
SeenGlobalValSummary = true;
|
||||
if (Error Err = parseEntireSummary())
|
||||
if (Error Err = parseEntireSummary(Entry.ID))
|
||||
return Err;
|
||||
break;
|
||||
case bitc::MODULE_STRTAB_BLOCK_ID:
|
||||
@ -4974,8 +4975,8 @@ std::vector<FunctionSummary::EdgeTy> ModuleSummaryIndexBitcodeReader::makeCallLi
|
||||
|
||||
// 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;
|
||||
|
||||
@ -5517,13 +5518,16 @@ BitcodeModule::getLazyModule(LLVMContext &Context, bool ShouldLazyLoadMetadata,
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
@ -5543,7 +5547,7 @@ Expected<std::unique_ptr<ModuleSummaryIndex>> BitcodeModule::getSummary() {
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
@ -5557,11 +5561,14 @@ Expected<bool> BitcodeModule::hasSummary() {
|
||||
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())
|
||||
@ -5648,12 +5655,12 @@ Expected<std::string> llvm::getBitcodeProducerString(MemoryBufferRef Buffer) {
|
||||
|
||||
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>>
|
||||
@ -5665,12 +5672,12 @@ llvm::getModuleSummaryIndex(MemoryBufferRef Buffer) {
|
||||
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>>
|
||||
|
@ -56,3 +56,13 @@ ModuleSummaryIndex::getGlobalValueSummary(uint64_t ValueGUID,
|
||||
auto &Summary = VI.getSummaryList()[0];
|
||||
return Summary.get();
|
||||
}
|
||||
|
||||
bool ModuleSummaryIndex::isGUIDLive(GlobalValue::GUID GUID) const {
|
||||
auto VI = getValueInfo(GUID);
|
||||
if (!VI)
|
||||
return false;
|
||||
for (auto &I : VI.getSummaryList())
|
||||
if (isGlobalValueLive(I.get()))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
195
lib/LTO/LTO.cpp
195
lib/LTO/LTO.cpp
@ -364,31 +364,39 @@ LTO::LTO(Config Conf, ThinBackend 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(const InputFile::Symbol &Sym,
|
||||
SymbolResolution Res, unsigned Partition) {
|
||||
auto &GlobalRes = GlobalResolutions[Sym.getName()];
|
||||
GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr();
|
||||
if (Res.Prevailing)
|
||||
GlobalRes.IRName = Sym.getIRName();
|
||||
// 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++;
|
||||
|
||||
// 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;
|
||||
auto &GlobalRes = GlobalResolutions[Sym.getName()];
|
||||
GlobalRes.UnnamedAddr &= Sym.isUnnamedAddr();
|
||||
if (Res.Prevailing)
|
||||
GlobalRes.IRName = Sym.getIRName();
|
||||
|
||||
// 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);
|
||||
// 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,
|
||||
@ -434,46 +442,61 @@ Error LTO::add(std::unique_ptr<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())
|
||||
@ -502,7 +525,6 @@ Error LTO::addRegularLTO(BitcodeModule BM,
|
||||
for (const InputFile::Symbol &Sym : Syms) {
|
||||
assert(ResI != ResE);
|
||||
SymbolResolution Res = *ResI++;
|
||||
addSymbolToGlobalRes(Sym, Res, 0);
|
||||
|
||||
assert(MsymI != MsymE);
|
||||
ModuleSymbolTable::Symbol Msym = *MsymI++;
|
||||
@ -512,7 +534,7 @@ Error LTO::addRegularLTO(BitcodeModule BM,
|
||||
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.
|
||||
@ -527,17 +549,14 @@ Error LTO::addRegularLTO(BitcodeModule BM,
|
||||
(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.
|
||||
@ -555,25 +574,54 @@ Error LTO::addRegularLTO(BitcodeModule BM,
|
||||
// FIXME: use proposed local attribute for FinalDefinitionInLinkageUnit.
|
||||
}
|
||||
assert(MsymI == MsymE);
|
||||
return std::move(Mod);
|
||||
}
|
||||
|
||||
return RegularLTO.Mover->move(std::move(*MOrErr), Keep,
|
||||
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;
|
||||
|
||||
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()) {
|
||||
@ -601,7 +649,7 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) {
|
||||
// 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())
|
||||
@ -614,7 +662,8 @@ Error LTO::run(AddStreamFn AddStream, NativeObjectCache Cache) {
|
||||
// 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))
|
||||
@ -623,6 +672,11 @@ 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();
|
||||
@ -920,17 +974,6 @@ ThinBackend lto::createWriteIndexesThinBackend(std::string OldPrefix,
|
||||
};
|
||||
}
|
||||
|
||||
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())
|
||||
@ -979,7 +1022,7 @@ Error LTO::runThinLTO(AddStreamFn AddStream, NativeObjectCache Cache,
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -77,14 +77,12 @@ bool LTOModule::isBitcodeFile(StringRef Path) {
|
||||
}
|
||||
|
||||
bool LTOModule::isThinLTO() {
|
||||
// Right now the detection is only based on the summary presence. We may want
|
||||
// to add a dedicated flag at some point.
|
||||
Expected<bool> Result = hasGlobalValueSummary(MBRef);
|
||||
Expected<BitcodeLTOInfo> Result = getBitcodeLTOInfo(MBRef);
|
||||
if (!Result) {
|
||||
logAllUnhandledErrors(Result.takeError(), errs(), "");
|
||||
return false;
|
||||
}
|
||||
return *Result;
|
||||
return Result->IsThinLTO;
|
||||
}
|
||||
|
||||
bool LTOModule::isBitcodeForTarget(MemoryBuffer *Buffer,
|
||||
|
16
test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll
Normal file
16
test/LTO/Resolution/X86/Inputs/dead-strip-fulllto.ll
Normal file
@ -0,0 +1,16 @@
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
define void @live1() {
|
||||
call void @live2()
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @live2()
|
||||
|
||||
define void @dead1() {
|
||||
call void @dead2()
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @dead2()
|
37
test/LTO/Resolution/X86/dead-strip-fulllto.ll
Normal file
37
test/LTO/Resolution/X86/dead-strip-fulllto.ll
Normal file
@ -0,0 +1,37 @@
|
||||
; RUN: opt -module-summary -o %t %s
|
||||
; RUN: opt -module-summary -o %t2 %S/Inputs/dead-strip-fulllto.ll
|
||||
; RUN: llvm-lto2 run %t -r %t,main,px -r %t,live1,p -r %t,live2,p -r %t,dead2,p \
|
||||
; RUN: %t2 -r %t2,live1,p -r %t2,live2, -r %t2,dead1,p -r %t2,dead2, \
|
||||
; RUN: -save-temps -o %t3
|
||||
; RUN: llvm-nm %t3.0 | FileCheck --check-prefix=FULL %s
|
||||
; RUN: llvm-nm %t3.1 | FileCheck --check-prefix=THIN %s
|
||||
|
||||
; FULL-NOT: dead
|
||||
; FULL: U live1
|
||||
; FULL: T live2
|
||||
; FULL: T main
|
||||
|
||||
; THIN-NOT: dead
|
||||
; THIN: T live1
|
||||
; THIN: U live2
|
||||
|
||||
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
|
||||
target triple = "x86_64-unknown-linux-gnu"
|
||||
|
||||
define void @main() {
|
||||
call void @live1()
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @live1()
|
||||
|
||||
define void @live2() {
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @dead2() {
|
||||
ret void
|
||||
}
|
||||
|
||||
!0 = !{i32 1, !"ThinLTO", i32 0}
|
||||
!llvm.module.flags = !{ !0 }
|
Loading…
Reference in New Issue
Block a user