forked from OSchip/llvm-project
Use lazy-loading of Metadata in MetadataLoader when importing is enabled (NFC)
Summary: This is a relatively simple scheme: we use the index emitted in the bitcode to avoid loading all the global metadata. Instead we load the index with their position in the bitcode so that we can load each of them individually. Materializing the global metadata block in this condition only triggers loading the named metadata, and the ones referenced from there (transitively). When materializing a function, metadata from the global block are loaded lazily as they are referenced. Two main current limitations are: 1) Global values other than functions are not materialized on demand, so we need to eagerly load METADATA_GLOBAL_DECL_ATTACHMENT records (and their transitive dependencies). 2) When we load a single metadata, we don't recurse on the operands, instead we use a placeholder or a temporary metadata. Unfortunately tepmorary nodes are very expensive. This is why we don't have it always enabled and only for importing. These two limitations can be lifted in a subsequent improvement if needed. With this change, the total link time of opt with ThinLTO and Debug Info enabled is going down from 282s to 224s (~20%). Reviewers: pcc, tejohnson, dexonsmith Subscribers: llvm-commits Differential Revision: https://reviews.llvm.org/D28113 llvm-svn: 291027
This commit is contained in:
parent
867aad1359
commit
19ef4fad91
|
@ -14,10 +14,12 @@
|
||||||
#include "llvm/ADT/APInt.h"
|
#include "llvm/ADT/APInt.h"
|
||||||
#include "llvm/ADT/ArrayRef.h"
|
#include "llvm/ADT/ArrayRef.h"
|
||||||
#include "llvm/ADT/DenseMap.h"
|
#include "llvm/ADT/DenseMap.h"
|
||||||
|
#include "llvm/ADT/DenseSet.h"
|
||||||
#include "llvm/ADT/None.h"
|
#include "llvm/ADT/None.h"
|
||||||
#include "llvm/ADT/STLExtras.h"
|
#include "llvm/ADT/STLExtras.h"
|
||||||
#include "llvm/ADT/SmallString.h"
|
#include "llvm/ADT/SmallString.h"
|
||||||
#include "llvm/ADT/SmallVector.h"
|
#include "llvm/ADT/SmallVector.h"
|
||||||
|
#include "llvm/ADT/Statistic.h"
|
||||||
#include "llvm/ADT/StringRef.h"
|
#include "llvm/ADT/StringRef.h"
|
||||||
#include "llvm/ADT/Triple.h"
|
#include "llvm/ADT/Triple.h"
|
||||||
#include "llvm/ADT/Twine.h"
|
#include "llvm/ADT/Twine.h"
|
||||||
|
@ -86,12 +88,23 @@
|
||||||
|
|
||||||
using namespace llvm;
|
using namespace llvm;
|
||||||
|
|
||||||
|
#define DEBUG_TYPE "bitcode-reader"
|
||||||
|
|
||||||
|
STATISTIC(NumMDStringLoaded, "Number of MDStrings loaded");
|
||||||
|
STATISTIC(NumMDNodeTemporary, "Number of MDNode::Temporary created");
|
||||||
|
STATISTIC(NumMDRecordLoaded, "Number of Metadata records loaded");
|
||||||
|
|
||||||
/// Flag whether we need to import full type definitions for ThinLTO.
|
/// Flag whether we need to import full type definitions for ThinLTO.
|
||||||
/// Currently needed for Darwin and LLDB.
|
/// Currently needed for Darwin and LLDB.
|
||||||
static cl::opt<bool> ImportFullTypeDefinitions(
|
static cl::opt<bool> ImportFullTypeDefinitions(
|
||||||
"import-full-type-definitions", cl::init(false), cl::Hidden,
|
"import-full-type-definitions", cl::init(false), cl::Hidden,
|
||||||
cl::desc("Import full type definitions for ThinLTO."));
|
cl::desc("Import full type definitions for ThinLTO."));
|
||||||
|
|
||||||
|
static cl::opt<bool> DisableLazyLoading(
|
||||||
|
"disable-ondemand-mds-loading", cl::init(false), cl::Hidden,
|
||||||
|
cl::desc("Force disable the lazy-loading on-demand of metadata when "
|
||||||
|
"loading bitcode for importing."));
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
static int64_t unrotateSign(uint64_t U) { return U & 1 ? ~(U >> 1) : U >> 1; }
|
static int64_t unrotateSign(uint64_t U) { return U & 1 ? ~(U >> 1) : U >> 1; }
|
||||||
|
@ -165,6 +178,10 @@ public:
|
||||||
void assignValue(Metadata *MD, unsigned Idx);
|
void assignValue(Metadata *MD, unsigned Idx);
|
||||||
void tryToResolveCycles();
|
void tryToResolveCycles();
|
||||||
bool hasFwdRefs() const { return !ForwardReference.empty(); }
|
bool hasFwdRefs() const { return !ForwardReference.empty(); }
|
||||||
|
int getNextFwdRef() {
|
||||||
|
assert(hasFwdRefs());
|
||||||
|
return *ForwardReference.begin();
|
||||||
|
}
|
||||||
|
|
||||||
/// Upgrade a type that had an MDString reference.
|
/// Upgrade a type that had an MDString reference.
|
||||||
void addTypeRef(MDString &UUID, DICompositeType &CT);
|
void addTypeRef(MDString &UUID, DICompositeType &CT);
|
||||||
|
@ -215,6 +232,7 @@ Metadata *BitcodeReaderMetadataList::getMetadataFwdRef(unsigned Idx) {
|
||||||
ForwardReference.insert(Idx);
|
ForwardReference.insert(Idx);
|
||||||
|
|
||||||
// Create and return a placeholder, which will later be RAUW'd.
|
// Create and return a placeholder, which will later be RAUW'd.
|
||||||
|
++NumMDNodeTemporary;
|
||||||
Metadata *MD = MDNode::getTemporary(Context, None).release();
|
Metadata *MD = MDNode::getTemporary(Context, None).release();
|
||||||
MetadataPtrs[Idx].reset(MD);
|
MetadataPtrs[Idx].reset(MD);
|
||||||
return MD;
|
return MD;
|
||||||
|
@ -340,8 +358,26 @@ class PlaceholderQueue {
|
||||||
std::deque<DistinctMDOperandPlaceholder> PHs;
|
std::deque<DistinctMDOperandPlaceholder> PHs;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
bool empty() { return PHs.empty(); }
|
||||||
DistinctMDOperandPlaceholder &getPlaceholderOp(unsigned ID);
|
DistinctMDOperandPlaceholder &getPlaceholderOp(unsigned ID);
|
||||||
void flush(BitcodeReaderMetadataList &MetadataList);
|
void flush(BitcodeReaderMetadataList &MetadataList);
|
||||||
|
|
||||||
|
/// Return the list of temporaries nodes in the queue, these need to be
|
||||||
|
/// loaded before we can flush the queue.
|
||||||
|
void getTemporaries(BitcodeReaderMetadataList &MetadataList,
|
||||||
|
DenseSet<unsigned> &Temporaries) {
|
||||||
|
for (auto &PH : PHs) {
|
||||||
|
auto ID = PH.getID();
|
||||||
|
auto *MD = MetadataList.lookup(ID);
|
||||||
|
if (!MD) {
|
||||||
|
Temporaries.insert(ID);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
auto *N = dyn_cast_or_null<MDNode>(MD);
|
||||||
|
if (N && N->isTemporary())
|
||||||
|
Temporaries.insert(ID);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // end anonymous namespace
|
} // end anonymous namespace
|
||||||
|
@ -375,6 +411,30 @@ class MetadataLoader::MetadataLoaderImpl {
|
||||||
Module &TheModule;
|
Module &TheModule;
|
||||||
std::function<Type *(unsigned)> getTypeByID;
|
std::function<Type *(unsigned)> getTypeByID;
|
||||||
|
|
||||||
|
/// Cursor associated with the lazy-loading of Metadata. This is the easy way
|
||||||
|
/// to keep around the right "context" (Abbrev list) to be able to jump in
|
||||||
|
/// the middle of the metadata block and load any record.
|
||||||
|
BitstreamCursor IndexCursor;
|
||||||
|
|
||||||
|
/// Index that keeps track of MDString values.
|
||||||
|
std::vector<StringRef> MDStringRef;
|
||||||
|
|
||||||
|
/// On-demand loading of a single MDString. Requires the index above to be
|
||||||
|
/// populated.
|
||||||
|
MDString *lazyLoadOneMDString(unsigned Idx);
|
||||||
|
|
||||||
|
/// Index that keeps track of where to find a metadata record in the stream.
|
||||||
|
std::vector<uint64_t> GlobalMetadataBitPosIndex;
|
||||||
|
|
||||||
|
/// Populate the index above to enable lazily loading of metadata, and load
|
||||||
|
/// the named metadata as well as the transitively referenced global
|
||||||
|
/// Metadata.
|
||||||
|
Expected<bool> lazyLoadModuleMetadataBlock(PlaceholderQueue &Placeholders);
|
||||||
|
|
||||||
|
/// On-demand loading of a single metadata. Requires the index above to be
|
||||||
|
/// populated.
|
||||||
|
void lazyLoadOneMetadata(unsigned Idx, PlaceholderQueue &Placeholders);
|
||||||
|
|
||||||
// Keep mapping of seens pair of old-style CU <-> SP, and update pointers to
|
// Keep mapping of seens pair of old-style CU <-> SP, and update pointers to
|
||||||
// point from SP to CU after a block is completly parsed.
|
// point from SP to CU after a block is completly parsed.
|
||||||
std::vector<std::pair<DICompileUnit *, Metadata *>> CUSubprograms;
|
std::vector<std::pair<DICompileUnit *, Metadata *>> CUSubprograms;
|
||||||
|
@ -394,13 +454,25 @@ class MetadataLoader::MetadataLoaderImpl {
|
||||||
|
|
||||||
Error parseOneMetadata(SmallVectorImpl<uint64_t> &Record, unsigned Code,
|
Error parseOneMetadata(SmallVectorImpl<uint64_t> &Record, unsigned Code,
|
||||||
PlaceholderQueue &Placeholders, StringRef Blob,
|
PlaceholderQueue &Placeholders, StringRef Blob,
|
||||||
bool ModuleLevel, unsigned &NextMetadataNo);
|
unsigned &NextMetadataNo);
|
||||||
Error parseMetadataStrings(ArrayRef<uint64_t> Record, StringRef Blob,
|
Error parseMetadataStrings(ArrayRef<uint64_t> Record, StringRef Blob,
|
||||||
unsigned &NextMetadataNo);
|
std::function<void(StringRef)> CallBack);
|
||||||
Error parseGlobalObjectAttachment(GlobalObject &GO,
|
Error parseGlobalObjectAttachment(GlobalObject &GO,
|
||||||
ArrayRef<uint64_t> Record);
|
ArrayRef<uint64_t> Record);
|
||||||
Error parseMetadataKindRecord(SmallVectorImpl<uint64_t> &Record);
|
Error parseMetadataKindRecord(SmallVectorImpl<uint64_t> &Record);
|
||||||
|
|
||||||
|
void resolveForwardRefsAndPlaceholders(PlaceholderQueue &Placeholders);
|
||||||
|
|
||||||
|
/// Upgrade old-style CU <-> SP pointers to point from SP to CU.
|
||||||
|
void upgradeCUSubprograms() {
|
||||||
|
for (auto CU_SP : CUSubprograms)
|
||||||
|
if (auto *SPs = dyn_cast_or_null<MDTuple>(CU_SP.second))
|
||||||
|
for (auto &Op : SPs->operands())
|
||||||
|
if (auto *SP = dyn_cast_or_null<MDNode>(Op))
|
||||||
|
SP->replaceOperandWith(7, CU_SP.first);
|
||||||
|
CUSubprograms.clear();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
MetadataLoaderImpl(BitstreamCursor &Stream, Module &TheModule,
|
MetadataLoaderImpl(BitstreamCursor &Stream, Module &TheModule,
|
||||||
BitcodeReaderValueList &ValueList,
|
BitcodeReaderValueList &ValueList,
|
||||||
|
@ -444,20 +516,217 @@ Error error(const Twine &Message) {
|
||||||
Message, make_error_code(BitcodeError::CorruptedBitcode));
|
Message, make_error_code(BitcodeError::CorruptedBitcode));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Expected<bool> MetadataLoader::MetadataLoaderImpl::lazyLoadModuleMetadataBlock(
|
||||||
|
PlaceholderQueue &Placeholders) {
|
||||||
|
IndexCursor = Stream;
|
||||||
|
SmallVector<uint64_t, 64> Record;
|
||||||
|
// Get the abbrevs, and preload record positions to make them lazy-loadable.
|
||||||
|
while (true) {
|
||||||
|
BitstreamEntry Entry = IndexCursor.advanceSkippingSubblocks(
|
||||||
|
BitstreamCursor::AF_DontPopBlockAtEnd);
|
||||||
|
switch (Entry.Kind) {
|
||||||
|
case BitstreamEntry::SubBlock: // Handled for us already.
|
||||||
|
case BitstreamEntry::Error:
|
||||||
|
return error("Malformed block");
|
||||||
|
case BitstreamEntry::EndBlock: {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case BitstreamEntry::Record: {
|
||||||
|
// The interesting case.
|
||||||
|
++NumMDRecordLoaded;
|
||||||
|
uint64_t CurrentPos = IndexCursor.GetCurrentBitNo();
|
||||||
|
auto Code = IndexCursor.skipRecord(Entry.ID);
|
||||||
|
switch (Code) {
|
||||||
|
case bitc::METADATA_STRINGS: {
|
||||||
|
// Rewind and parse the strings.
|
||||||
|
IndexCursor.JumpToBit(CurrentPos);
|
||||||
|
StringRef Blob;
|
||||||
|
Record.clear();
|
||||||
|
IndexCursor.readRecord(Entry.ID, Record, &Blob);
|
||||||
|
unsigned NumStrings = Record[0];
|
||||||
|
MDStringRef.reserve(NumStrings);
|
||||||
|
auto IndexNextMDString = [&](StringRef Str) {
|
||||||
|
MDStringRef.push_back(Str);
|
||||||
|
};
|
||||||
|
if (auto Err = parseMetadataStrings(Record, Blob, IndexNextMDString))
|
||||||
|
return std::move(Err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case bitc::METADATA_INDEX_OFFSET: {
|
||||||
|
// This is the offset to the index, when we see this we skip all the
|
||||||
|
// records and load only an index to these.
|
||||||
|
IndexCursor.JumpToBit(CurrentPos);
|
||||||
|
Record.clear();
|
||||||
|
IndexCursor.readRecord(Entry.ID, Record);
|
||||||
|
if (Record.size() != 2)
|
||||||
|
return error("Invalid record");
|
||||||
|
auto Offset = Record[0] + (Record[1] << 32);
|
||||||
|
auto BeginPos = IndexCursor.GetCurrentBitNo();
|
||||||
|
IndexCursor.JumpToBit(BeginPos + Offset);
|
||||||
|
Entry = IndexCursor.advanceSkippingSubblocks(
|
||||||
|
BitstreamCursor::AF_DontPopBlockAtEnd);
|
||||||
|
assert(Entry.Kind == BitstreamEntry::Record &&
|
||||||
|
"Corrupted bitcode: Expected `Record` when trying to find the "
|
||||||
|
"Metadata index");
|
||||||
|
Record.clear();
|
||||||
|
auto Code = IndexCursor.readRecord(Entry.ID, Record);
|
||||||
|
(void)Code;
|
||||||
|
assert(Code == bitc::METADATA_INDEX && "Corrupted bitcode: Expected "
|
||||||
|
"`METADATA_INDEX` when trying "
|
||||||
|
"to find the Metadata index");
|
||||||
|
|
||||||
|
// Delta unpack
|
||||||
|
auto CurrentValue = BeginPos;
|
||||||
|
GlobalMetadataBitPosIndex.reserve(Record.size());
|
||||||
|
for (auto &Elt : Record) {
|
||||||
|
CurrentValue += Elt;
|
||||||
|
GlobalMetadataBitPosIndex.push_back(CurrentValue);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case bitc::METADATA_INDEX:
|
||||||
|
// We don't expect to get there, the Index is loaded when we encounter
|
||||||
|
// the offset.
|
||||||
|
return error("Corrupted Metadata block");
|
||||||
|
case bitc::METADATA_NAME: {
|
||||||
|
// Named metadata need to be materialized now and aren't deferred.
|
||||||
|
IndexCursor.JumpToBit(CurrentPos);
|
||||||
|
Record.clear();
|
||||||
|
unsigned Code = IndexCursor.readRecord(Entry.ID, Record);
|
||||||
|
assert(Code == bitc::METADATA_NAME);
|
||||||
|
|
||||||
|
// Read name of the named metadata.
|
||||||
|
SmallString<8> Name(Record.begin(), Record.end());
|
||||||
|
Code = IndexCursor.ReadCode();
|
||||||
|
|
||||||
|
// Named Metadata comes in two parts, we expect the name to be followed
|
||||||
|
// by the node
|
||||||
|
Record.clear();
|
||||||
|
unsigned NextBitCode = IndexCursor.readRecord(Code, Record);
|
||||||
|
assert(NextBitCode == bitc::METADATA_NAMED_NODE);
|
||||||
|
(void)NextBitCode;
|
||||||
|
|
||||||
|
// Read named metadata elements.
|
||||||
|
unsigned Size = Record.size();
|
||||||
|
NamedMDNode *NMD = TheModule.getOrInsertNamedMetadata(Name);
|
||||||
|
for (unsigned i = 0; i != Size; ++i) {
|
||||||
|
// FIXME: We could use a placeholder here, however NamedMDNode are
|
||||||
|
// taking MDNode as operand and not using the Metadata infrastructure.
|
||||||
|
// It is acknowledged by 'TODO: Inherit from Metadata' in the
|
||||||
|
// NamedMDNode class definition.
|
||||||
|
MDNode *MD = MetadataList.getMDNodeFwdRefOrNull(Record[i]);
|
||||||
|
assert(MD && "Invalid record");
|
||||||
|
NMD->addOperand(MD);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case bitc::METADATA_GLOBAL_DECL_ATTACHMENT: {
|
||||||
|
// FIXME: we need to do this early because we don't materialize global
|
||||||
|
// value explicitly.
|
||||||
|
IndexCursor.JumpToBit(CurrentPos);
|
||||||
|
Record.clear();
|
||||||
|
IndexCursor.readRecord(Entry.ID, Record);
|
||||||
|
if (Record.size() % 2 == 0)
|
||||||
|
return error("Invalid record");
|
||||||
|
unsigned ValueID = Record[0];
|
||||||
|
if (ValueID >= ValueList.size())
|
||||||
|
return error("Invalid record");
|
||||||
|
if (auto *GO = dyn_cast<GlobalObject>(ValueList[ValueID]))
|
||||||
|
if (Error Err = parseGlobalObjectAttachment(
|
||||||
|
*GO, ArrayRef<uint64_t>(Record).slice(1)))
|
||||||
|
return std::move(Err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case bitc::METADATA_KIND:
|
||||||
|
case bitc::METADATA_STRING_OLD:
|
||||||
|
case bitc::METADATA_OLD_FN_NODE:
|
||||||
|
case bitc::METADATA_OLD_NODE:
|
||||||
|
case bitc::METADATA_VALUE:
|
||||||
|
case bitc::METADATA_DISTINCT_NODE:
|
||||||
|
case bitc::METADATA_NODE:
|
||||||
|
case bitc::METADATA_LOCATION:
|
||||||
|
case bitc::METADATA_GENERIC_DEBUG:
|
||||||
|
case bitc::METADATA_SUBRANGE:
|
||||||
|
case bitc::METADATA_ENUMERATOR:
|
||||||
|
case bitc::METADATA_BASIC_TYPE:
|
||||||
|
case bitc::METADATA_DERIVED_TYPE:
|
||||||
|
case bitc::METADATA_COMPOSITE_TYPE:
|
||||||
|
case bitc::METADATA_SUBROUTINE_TYPE:
|
||||||
|
case bitc::METADATA_MODULE:
|
||||||
|
case bitc::METADATA_FILE:
|
||||||
|
case bitc::METADATA_COMPILE_UNIT:
|
||||||
|
case bitc::METADATA_SUBPROGRAM:
|
||||||
|
case bitc::METADATA_LEXICAL_BLOCK:
|
||||||
|
case bitc::METADATA_LEXICAL_BLOCK_FILE:
|
||||||
|
case bitc::METADATA_NAMESPACE:
|
||||||
|
case bitc::METADATA_MACRO:
|
||||||
|
case bitc::METADATA_MACRO_FILE:
|
||||||
|
case bitc::METADATA_TEMPLATE_TYPE:
|
||||||
|
case bitc::METADATA_TEMPLATE_VALUE:
|
||||||
|
case bitc::METADATA_GLOBAL_VAR:
|
||||||
|
case bitc::METADATA_LOCAL_VAR:
|
||||||
|
case bitc::METADATA_EXPRESSION:
|
||||||
|
case bitc::METADATA_OBJC_PROPERTY:
|
||||||
|
case bitc::METADATA_IMPORTED_ENTITY:
|
||||||
|
case bitc::METADATA_GLOBAL_VAR_EXPR:
|
||||||
|
// We don't expect to see any of these, if we see one, give up on
|
||||||
|
// lazy-loading and fallback.
|
||||||
|
MDStringRef.clear();
|
||||||
|
GlobalMetadataBitPosIndex.clear();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Parse a METADATA_BLOCK. If ModuleLevel is true then we are parsing
|
/// Parse a METADATA_BLOCK. If ModuleLevel is true then we are parsing
|
||||||
/// module level metadata.
|
/// module level metadata.
|
||||||
Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
|
Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
|
||||||
if (!ModuleLevel && MetadataList.hasFwdRefs())
|
if (!ModuleLevel && MetadataList.hasFwdRefs())
|
||||||
return error("Invalid metadata: fwd refs into function blocks");
|
return error("Invalid metadata: fwd refs into function blocks");
|
||||||
|
|
||||||
|
// Record the entry position so that we can jump back here and efficiently
|
||||||
|
// skip the whole block in case we lazy-load.
|
||||||
|
auto EntryPos = Stream.GetCurrentBitNo();
|
||||||
|
|
||||||
if (Stream.EnterSubBlock(bitc::METADATA_BLOCK_ID))
|
if (Stream.EnterSubBlock(bitc::METADATA_BLOCK_ID))
|
||||||
return error("Invalid record");
|
return error("Invalid record");
|
||||||
|
|
||||||
unsigned NextMetadataNo = MetadataList.size();
|
|
||||||
SmallVector<uint64_t, 64> Record;
|
SmallVector<uint64_t, 64> Record;
|
||||||
|
|
||||||
PlaceholderQueue Placeholders;
|
PlaceholderQueue Placeholders;
|
||||||
|
|
||||||
|
// We lazy-load module-level metadata: we build an index for each record, and
|
||||||
|
// then load individual record as needed, starting with the named metadata.
|
||||||
|
if (ModuleLevel && IsImporting && MetadataList.empty() &&
|
||||||
|
!DisableLazyLoading) {
|
||||||
|
auto SuccessOrErr = lazyLoadModuleMetadataBlock(Placeholders);
|
||||||
|
if (!SuccessOrErr)
|
||||||
|
return SuccessOrErr.takeError();
|
||||||
|
if (SuccessOrErr.get()) {
|
||||||
|
// An index was successfully created and we will be able to load metadata
|
||||||
|
// on-demand.
|
||||||
|
MetadataList.resize(MDStringRef.size() +
|
||||||
|
GlobalMetadataBitPosIndex.size());
|
||||||
|
|
||||||
|
// Reading the named metadata created forward references and/or
|
||||||
|
// placeholders, that we flush here.
|
||||||
|
resolveForwardRefsAndPlaceholders(Placeholders);
|
||||||
|
upgradeCUSubprograms();
|
||||||
|
// Return at the beginning of the block, since it is easy to skip it
|
||||||
|
// entirely from there.
|
||||||
|
Stream.ReadBlockEnd(); // Pop the abbrev block context.
|
||||||
|
Stream.JumpToBit(EntryPos);
|
||||||
|
if (Stream.SkipBlock())
|
||||||
|
return error("Invalid record");
|
||||||
|
return Error::success();
|
||||||
|
}
|
||||||
|
// Couldn't load an index, fallback to loading all the block "old-style".
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned NextMetadataNo = MetadataList.size();
|
||||||
|
|
||||||
// Read all the records.
|
// Read all the records.
|
||||||
while (true) {
|
while (true) {
|
||||||
BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
|
BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
|
||||||
|
@ -467,16 +736,8 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
|
||||||
case BitstreamEntry::Error:
|
case BitstreamEntry::Error:
|
||||||
return error("Malformed block");
|
return error("Malformed block");
|
||||||
case BitstreamEntry::EndBlock:
|
case BitstreamEntry::EndBlock:
|
||||||
// Upgrade old-style CU <-> SP pointers to point from SP to CU.
|
resolveForwardRefsAndPlaceholders(Placeholders);
|
||||||
for (auto CU_SP : CUSubprograms)
|
upgradeCUSubprograms();
|
||||||
if (auto *SPs = dyn_cast_or_null<MDTuple>(CU_SP.second))
|
|
||||||
for (auto &Op : SPs->operands())
|
|
||||||
if (auto *SP = dyn_cast_or_null<MDNode>(Op))
|
|
||||||
SP->replaceOperandWith(7, CU_SP.first);
|
|
||||||
CUSubprograms.clear();
|
|
||||||
|
|
||||||
MetadataList.tryToResolveCycles();
|
|
||||||
Placeholders.flush(MetadataList);
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
case BitstreamEntry::Record:
|
case BitstreamEntry::Record:
|
||||||
// The interesting case.
|
// The interesting case.
|
||||||
|
@ -486,20 +747,86 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadata(bool ModuleLevel) {
|
||||||
// Read a record.
|
// Read a record.
|
||||||
Record.clear();
|
Record.clear();
|
||||||
StringRef Blob;
|
StringRef Blob;
|
||||||
|
++NumMDRecordLoaded;
|
||||||
unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob);
|
unsigned Code = Stream.readRecord(Entry.ID, Record, &Blob);
|
||||||
if (Error Err = parseOneMetadata(Record, Code, Placeholders, Blob,
|
if (Error Err =
|
||||||
ModuleLevel, NextMetadataNo))
|
parseOneMetadata(Record, Code, Placeholders, Blob, NextMetadataNo))
|
||||||
return Err;
|
return Err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MDString *MetadataLoader::MetadataLoaderImpl::lazyLoadOneMDString(unsigned ID) {
|
||||||
|
++NumMDStringLoaded;
|
||||||
|
if (Metadata *MD = MetadataList.lookup(ID))
|
||||||
|
return cast<MDString>(MD);
|
||||||
|
auto MDS = MDString::get(Context, MDStringRef[ID]);
|
||||||
|
MetadataList.assignValue(MDS, ID);
|
||||||
|
return MDS;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MetadataLoader::MetadataLoaderImpl::lazyLoadOneMetadata(
|
||||||
|
unsigned ID, PlaceholderQueue &Placeholders) {
|
||||||
|
assert(ID < (MDStringRef.size()) + GlobalMetadataBitPosIndex.size());
|
||||||
|
assert(ID >= MDStringRef.size() && "Unexpected lazy-loading of MDString");
|
||||||
|
#ifndef NDEBUG
|
||||||
|
// Lookup first if the metadata hasn't already been loaded.
|
||||||
|
if (auto *MD = MetadataList.lookup(ID)) {
|
||||||
|
auto *N = dyn_cast_or_null<MDNode>(MD);
|
||||||
|
assert(N && N->isTemporary() && "Lazy loading an already loaded metadata");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
SmallVector<uint64_t, 64> Record;
|
||||||
|
StringRef Blob;
|
||||||
|
IndexCursor.JumpToBit(GlobalMetadataBitPosIndex[ID - MDStringRef.size()]);
|
||||||
|
auto Entry = IndexCursor.advanceSkippingSubblocks();
|
||||||
|
++NumMDRecordLoaded;
|
||||||
|
unsigned Code = IndexCursor.readRecord(Entry.ID, Record, &Blob);
|
||||||
|
if (Error Err = parseOneMetadata(Record, Code, Placeholders, Blob, ID))
|
||||||
|
report_fatal_error("Can't lazyload MD");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Ensure that all forward-references and placeholders are resolved.
|
||||||
|
/// Iteratively lazy-loading metadata on-demand if needed.
|
||||||
|
void MetadataLoader::MetadataLoaderImpl::resolveForwardRefsAndPlaceholders(
|
||||||
|
PlaceholderQueue &Placeholders) {
|
||||||
|
DenseSet<unsigned> Temporaries;
|
||||||
|
while (1) {
|
||||||
|
// Populate Temporaries with the placeholders that haven't been loaded yet.
|
||||||
|
Placeholders.getTemporaries(MetadataList, Temporaries);
|
||||||
|
|
||||||
|
// If we don't have any temporary, or FwdReference, we're done!
|
||||||
|
if (Temporaries.empty() && !MetadataList.hasFwdRefs())
|
||||||
|
break;
|
||||||
|
|
||||||
|
// First, load all the temporaries. This can add new placeholders or
|
||||||
|
// forward references.
|
||||||
|
for (auto ID : Temporaries)
|
||||||
|
lazyLoadOneMetadata(ID, Placeholders);
|
||||||
|
Temporaries.clear();
|
||||||
|
|
||||||
|
// Second, load the forward-references. This can also add new placeholders
|
||||||
|
// or forward references.
|
||||||
|
while (MetadataList.hasFwdRefs())
|
||||||
|
lazyLoadOneMetadata(MetadataList.getNextFwdRef(), Placeholders);
|
||||||
|
}
|
||||||
|
// At this point we don't have any forward reference remaining, or temporary
|
||||||
|
// that haven't been loaded. We can safely drop RAUW support and mark cycles
|
||||||
|
// as resolved.
|
||||||
|
MetadataList.tryToResolveCycles();
|
||||||
|
|
||||||
|
// Finally, everything is in place, we can replace the placeholders operands
|
||||||
|
// with the final node they refer to.
|
||||||
|
Placeholders.flush(MetadataList);
|
||||||
|
}
|
||||||
|
|
||||||
Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
|
Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
|
||||||
SmallVectorImpl<uint64_t> &Record, unsigned Code,
|
SmallVectorImpl<uint64_t> &Record, unsigned Code,
|
||||||
PlaceholderQueue &Placeholders, StringRef Blob, bool ModuleLevel,
|
PlaceholderQueue &Placeholders, StringRef Blob, unsigned &NextMetadataNo) {
|
||||||
unsigned &NextMetadataNo) {
|
|
||||||
|
|
||||||
bool IsDistinct = false;
|
bool IsDistinct = false;
|
||||||
auto getMD = [&](unsigned ID) -> Metadata * {
|
auto getMD = [&](unsigned ID) -> Metadata * {
|
||||||
|
if (ID < MDStringRef.size())
|
||||||
|
return lazyLoadOneMDString(ID);
|
||||||
if (!IsDistinct)
|
if (!IsDistinct)
|
||||||
return MetadataList.getMetadataFwdRef(ID);
|
return MetadataList.getMetadataFwdRef(ID);
|
||||||
if (auto *MD = MetadataList.getMetadataIfResolved(ID))
|
if (auto *MD = MetadataList.getMetadataIfResolved(ID))
|
||||||
|
@ -519,7 +846,8 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
|
||||||
auto getMDString = [&](unsigned ID) -> MDString * {
|
auto getMDString = [&](unsigned ID) -> MDString * {
|
||||||
// This requires that the ID is not really a forward reference. In
|
// This requires that the ID is not really a forward reference. In
|
||||||
// particular, the MDString must already have been resolved.
|
// particular, the MDString must already have been resolved.
|
||||||
return cast_or_null<MDString>(getMDOrNull(ID));
|
auto MDS = getMDOrNull(ID);
|
||||||
|
return cast_or_null<MDString>(MDS);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Support for old type refs.
|
// Support for old type refs.
|
||||||
|
@ -539,6 +867,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
|
||||||
Record.clear();
|
Record.clear();
|
||||||
Code = Stream.ReadCode();
|
Code = Stream.ReadCode();
|
||||||
|
|
||||||
|
++NumMDRecordLoaded;
|
||||||
unsigned NextBitCode = Stream.readRecord(Code, Record);
|
unsigned NextBitCode = Stream.readRecord(Code, Record);
|
||||||
if (NextBitCode != bitc::METADATA_NAMED_NODE)
|
if (NextBitCode != bitc::METADATA_NAMED_NODE)
|
||||||
return error("METADATA_NAME not followed by METADATA_NAMED_NODE");
|
return error("METADATA_NAME not followed by METADATA_NAMED_NODE");
|
||||||
|
@ -1137,15 +1466,20 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
|
||||||
|
|
||||||
// Test for upgrading !llvm.loop.
|
// Test for upgrading !llvm.loop.
|
||||||
HasSeenOldLoopTags |= mayBeOldLoopAttachmentTag(String);
|
HasSeenOldLoopTags |= mayBeOldLoopAttachmentTag(String);
|
||||||
|
++NumMDStringLoaded;
|
||||||
Metadata *MD = MDString::get(Context, String);
|
Metadata *MD = MDString::get(Context, String);
|
||||||
MetadataList.assignValue(MD, NextMetadataNo++);
|
MetadataList.assignValue(MD, NextMetadataNo++);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case bitc::METADATA_STRINGS:
|
case bitc::METADATA_STRINGS: {
|
||||||
if (Error Err = parseMetadataStrings(Record, Blob, NextMetadataNo))
|
auto CreateNextMDString = [&](StringRef Str) {
|
||||||
|
++NumMDStringLoaded;
|
||||||
|
MetadataList.assignValue(MDString::get(Context, Str), NextMetadataNo++);
|
||||||
|
};
|
||||||
|
if (Error Err = parseMetadataStrings(Record, Blob, CreateNextMDString))
|
||||||
return Err;
|
return Err;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case bitc::METADATA_GLOBAL_DECL_ATTACHMENT: {
|
case bitc::METADATA_GLOBAL_DECL_ATTACHMENT: {
|
||||||
if (Record.size() % 2 == 0)
|
if (Record.size() % 2 == 0)
|
||||||
return error("Invalid record");
|
return error("Invalid record");
|
||||||
|
@ -1166,12 +1500,13 @@ Error MetadataLoader::MetadataLoaderImpl::parseOneMetadata(
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#undef GET_OR_DISTINCT
|
|
||||||
return Error::success();
|
return Error::success();
|
||||||
|
#undef GET_OR_DISTINCT
|
||||||
}
|
}
|
||||||
|
|
||||||
Error MetadataLoader::MetadataLoaderImpl::parseMetadataStrings(
|
Error MetadataLoader::MetadataLoaderImpl::parseMetadataStrings(
|
||||||
ArrayRef<uint64_t> Record, StringRef Blob, unsigned &NextMetadataNo) {
|
ArrayRef<uint64_t> Record, StringRef Blob,
|
||||||
|
std::function<void(StringRef)> CallBack) {
|
||||||
// All the MDStrings in the block are emitted together in a single
|
// All the MDStrings in the block are emitted together in a single
|
||||||
// record. The strings are concatenated and stored in a blob along with
|
// record. The strings are concatenated and stored in a blob along with
|
||||||
// their sizes.
|
// their sizes.
|
||||||
|
@ -1197,8 +1532,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataStrings(
|
||||||
if (Strings.size() < Size)
|
if (Strings.size() < Size)
|
||||||
return error("Invalid record: metadata strings truncated chars");
|
return error("Invalid record: metadata strings truncated chars");
|
||||||
|
|
||||||
MetadataList.assignValue(MDString::get(Context, Strings.slice(0, Size)),
|
CallBack(Strings.slice(0, Size));
|
||||||
NextMetadataNo++);
|
|
||||||
Strings = Strings.drop_front(Size);
|
Strings = Strings.drop_front(Size);
|
||||||
} while (--NumStrings);
|
} while (--NumStrings);
|
||||||
|
|
||||||
|
@ -1228,6 +1562,8 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataAttachment(
|
||||||
|
|
||||||
SmallVector<uint64_t, 64> Record;
|
SmallVector<uint64_t, 64> Record;
|
||||||
|
|
||||||
|
PlaceholderQueue Placeholders;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
|
BitstreamEntry Entry = Stream.advanceSkippingSubblocks();
|
||||||
|
|
||||||
|
@ -1236,6 +1572,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataAttachment(
|
||||||
case BitstreamEntry::Error:
|
case BitstreamEntry::Error:
|
||||||
return error("Malformed block");
|
return error("Malformed block");
|
||||||
case BitstreamEntry::EndBlock:
|
case BitstreamEntry::EndBlock:
|
||||||
|
resolveForwardRefsAndPlaceholders(Placeholders);
|
||||||
return Error::success();
|
return Error::success();
|
||||||
case BitstreamEntry::Record:
|
case BitstreamEntry::Record:
|
||||||
// The interesting case.
|
// The interesting case.
|
||||||
|
@ -1244,6 +1581,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataAttachment(
|
||||||
|
|
||||||
// Read a metadata attachment record.
|
// Read a metadata attachment record.
|
||||||
Record.clear();
|
Record.clear();
|
||||||
|
++NumMDRecordLoaded;
|
||||||
switch (Stream.readRecord(Entry.ID, Record)) {
|
switch (Stream.readRecord(Entry.ID, Record)) {
|
||||||
default: // Default behavior: ignore.
|
default: // Default behavior: ignore.
|
||||||
break;
|
break;
|
||||||
|
@ -1268,7 +1606,14 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataAttachment(
|
||||||
if (I->second == LLVMContext::MD_tbaa && StripTBAA)
|
if (I->second == LLVMContext::MD_tbaa && StripTBAA)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Metadata *Node = MetadataList.getMetadataFwdRef(Record[i + 1]);
|
auto Idx = Record[i + 1];
|
||||||
|
if (Idx < (MDStringRef.size() + GlobalMetadataBitPosIndex.size()) &&
|
||||||
|
!MetadataList.lookup(Idx))
|
||||||
|
// Load the attachment if it is in the lazy-loadable range and hasn't
|
||||||
|
// been loaded yet.
|
||||||
|
lazyLoadOneMetadata(Idx, Placeholders);
|
||||||
|
|
||||||
|
Metadata *Node = MetadataList.getMetadataFwdRef(Idx);
|
||||||
if (isa<LocalAsMetadata>(Node))
|
if (isa<LocalAsMetadata>(Node))
|
||||||
// Drop the attachment. This used to be legal, but there's no
|
// Drop the attachment. This used to be legal, but there's no
|
||||||
// upgrade path.
|
// upgrade path.
|
||||||
|
@ -1331,6 +1676,7 @@ Error MetadataLoader::MetadataLoaderImpl::parseMetadataKinds() {
|
||||||
|
|
||||||
// Read a record.
|
// Read a record.
|
||||||
Record.clear();
|
Record.clear();
|
||||||
|
++NumMDRecordLoaded;
|
||||||
unsigned Code = Stream.readRecord(Entry.ID, Record);
|
unsigned Code = Stream.readRecord(Entry.ID, Record);
|
||||||
switch (Code) {
|
switch (Code) {
|
||||||
default: // Default behavior: ignore.
|
default: // Default behavior: ignore.
|
||||||
|
|
|
@ -625,7 +625,6 @@ Expected<bool> FunctionImporter::importFunctions(
|
||||||
// now, before linking it (otherwise this will be a noop).
|
// now, before linking it (otherwise this will be a noop).
|
||||||
if (Error Err = SrcModule->materializeMetadata())
|
if (Error Err = SrcModule->materializeMetadata())
|
||||||
return std::move(Err);
|
return std::move(Err);
|
||||||
UpgradeDebugInfo(*SrcModule);
|
|
||||||
|
|
||||||
auto &ImportGUIDs = FunctionsToImportPerModule->second;
|
auto &ImportGUIDs = FunctionsToImportPerModule->second;
|
||||||
// Find the globals to import
|
// Find the globals to import
|
||||||
|
@ -698,6 +697,10 @@ Expected<bool> FunctionImporter::importFunctions(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Upgrade debug info after we're done materializing all the globals and we
|
||||||
|
// have loaded all the required metadata!
|
||||||
|
UpgradeDebugInfo(*SrcModule);
|
||||||
|
|
||||||
// Link in the specified functions.
|
// Link in the specified functions.
|
||||||
if (renameModuleForThinLTO(*SrcModule, Index, &GlobalsToImport))
|
if (renameModuleForThinLTO(*SrcModule, Index, &GlobalsToImport))
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
||||||
|
target triple = "x86_64-apple-macosx10.11.0"
|
||||||
|
|
||||||
|
declare void @globalfunc1()
|
||||||
|
|
||||||
|
|
||||||
|
define i32 @main() {
|
||||||
|
call void @globalfunc1()
|
||||||
|
ret i32 0
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,54 @@
|
||||||
|
; Do setup work for all below tests: generate bitcode and combined index
|
||||||
|
; RUN: opt -module-summary %s -o %t.bc -bitcode-mdindex-threshold=0
|
||||||
|
; RUN: opt -module-summary %p/Inputs/lazyload_metadata.ll -o %t2.bc -bitcode-mdindex-threshold=0
|
||||||
|
; RUN: llvm-lto -thinlto-action=thinlink -o %t3.bc %t.bc %t2.bc
|
||||||
|
|
||||||
|
|
||||||
|
; Check that importing @globalfunc1 does not trigger loading all the global
|
||||||
|
; metadata for @globalfunc2 and @globalfunc3
|
||||||
|
|
||||||
|
; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc \
|
||||||
|
; RUN: -o /dev/null -stats \
|
||||||
|
; RUN: 2>&1 | FileCheck %s -check-prefix=LAZY
|
||||||
|
; LAZY: 49 bitcode-reader - Number of Metadata records loaded
|
||||||
|
; LAZY: 1 bitcode-reader - Number of MDStrings loaded
|
||||||
|
|
||||||
|
; RUN: llvm-lto -thinlto-action=import %t2.bc -thinlto-index=%t3.bc \
|
||||||
|
; RUN: -o /dev/null -disable-ondemand-mds-loading -stats \
|
||||||
|
; RUN: 2>&1 | FileCheck %s -check-prefix=NOTLAZY
|
||||||
|
; NOTLAZY: 58 bitcode-reader - Number of Metadata records loaded
|
||||||
|
; NOTLAZY: 8 bitcode-reader - Number of MDStrings loaded
|
||||||
|
|
||||||
|
|
||||||
|
target datalayout = "e-m:o-i64:64-f80:128-n8:16:32:64-S128"
|
||||||
|
target triple = "x86_64-apple-macosx10.11.0"
|
||||||
|
|
||||||
|
define void @globalfunc1(i32 %arg) {
|
||||||
|
%tmp = add i32 %arg, 0, !metadata !2
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
; We need two functions here that will both reference the same metadata.
|
||||||
|
; This is to force the metadata to be emitted in the global metadata block and
|
||||||
|
; not in the function specific metadata.
|
||||||
|
; These function are not imported and so we don't want to load their metadata.
|
||||||
|
|
||||||
|
define void @globalfunc2(i32 %arg) {
|
||||||
|
%tmp = add i32 %arg, 0, !metadata !1
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
define void @globalfunc3(i32 %arg) {
|
||||||
|
%tmp = add i32 %arg, 0, !metadata !1
|
||||||
|
ret void
|
||||||
|
}
|
||||||
|
|
||||||
|
!1 = !{!2, !3, !4, !5, !6, !7, !8, !9}
|
||||||
|
!2 = !{!"Hello World"}
|
||||||
|
!3 = !{!"3"}
|
||||||
|
!4 = !{!"4"}
|
||||||
|
!5 = !{!"5"}
|
||||||
|
!6 = !{!"6"}
|
||||||
|
!7 = !{!"7"}
|
||||||
|
!8 = !{!"8"}
|
||||||
|
!9 = !{!"9"}
|
Loading…
Reference in New Issue