diff options
author | Teresa Johnson <tejohnson@google.com> | 2016-03-11 18:52:24 +0000 |
---|---|---|
committer | Teresa Johnson <tejohnson@google.com> | 2016-03-11 18:52:24 +0000 |
commit | 76a1c1d0ba05993f3e57f935698ec0fd09b66c8c (patch) | |
tree | e89825099cc401c2546bbfa7e0ac83c2e1d98644 /llvm/lib/Bitcode/Reader/BitcodeReader.cpp | |
parent | c134810cfb91716554177992c4bbbf2543545a1a (diff) | |
download | bcm5719-llvm-76a1c1d0ba05993f3e57f935698ec0fd09b66c8c.tar.gz bcm5719-llvm-76a1c1d0ba05993f3e57f935698ec0fd09b66c8c.zip |
[ThinLTO] Support for reference graph in per-module and combined summary.
Summary:
This patch adds support for including a full reference graph including
call graph edges and other GV references in the summary.
The reference graph edges can be used to make importing decisions
without materializing any source modules, can be used in the plugin
to make file staging decisions for distributed build systems, and is
expected to have other uses.
The call graph edges are recorded in each function summary in the
bitcode via a list of <CalleeValueIds, StaticCount> tuples when no PGO
data exists, or <CalleeValueId, StaticCount, ProfileCount> pairs when
there is PGO, where the ValueId can be mapped to the function GUID via
the ValueSymbolTable. In the function index in memory, the call graph
edges reference the target via the CalleeGUID instead of the
CalleeValueId.
The reference graph edges are recorded in each summary record with a
list of referenced value IDs, which can be mapped to value GUID via the
ValueSymbolTable.
Addtionally, a new summary record type is added to record references
from global variable initializers. A number of bitcode records and data
structures have been renamed to reflect the newly expanded scope of the
summary beyond functions. More cleanup will follow.
Reviewers: joker.eph, davidxl
Subscribers: joker.eph, llvm-commits
Differential Revision: http://reviews.llvm.org/D17212
llvm-svn: 263275
Diffstat (limited to 'llvm/lib/Bitcode/Reader/BitcodeReader.cpp')
-rw-r--r-- | llvm/lib/Bitcode/Reader/BitcodeReader.cpp | 461 |
1 files changed, 341 insertions, 120 deletions
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index 06a120a5ff1..4b1ccf85231 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -416,7 +416,7 @@ private: class FunctionIndexBitcodeReader { DiagnosticHandlerFunction DiagnosticHandler; - /// Eventually points to the function index built during parsing. + /// Eventually points to the module index built during parsing. FunctionInfoIndex *TheIndex = nullptr; std::unique_ptr<MemoryBuffer> Buffer; @@ -432,29 +432,37 @@ class FunctionIndexBitcodeReader { bool IsLazy = false; /// Used to indicate whether caller only wants to check for the presence - /// of the function summary bitcode section. All blocks are skipped, - /// but the SeenFuncSummary boolean is set. - bool CheckFuncSummaryPresenceOnly = false; + /// of the global value summary bitcode section. All blocks are skipped, + /// but the SeenGlobalValSummary boolean is set. + bool CheckGlobalValSummaryPresenceOnly = false; - /// Indicates whether we have encountered a function summary section - /// yet during parsing, used when checking if file contains function + /// Indicates whether we have encountered a global value summary section + /// yet during parsing, used when checking if file contains global value /// summary section. - bool SeenFuncSummary = false; + bool SeenGlobalValSummary = false; - /// \brief Map populated during function summary section parsing, and - /// consumed during ValueSymbolTable parsing. - /// - /// Used to correlate summary records with VST entries. For the per-module - /// index this maps the ValueID to the parsed function summary, and - /// for the combined index this maps the summary record's bitcode - /// offset to the function summary (since in the combined index the - /// VST records do not hold value IDs but rather hold the function - /// summary record offset). - DenseMap<uint64_t, std::unique_ptr<FunctionSummary>> SummaryMap; + /// Indicates whether we have already parsed the VST, used for error checking. + bool SeenValueSymbolTable = false; + + /// Set to the offset of the VST recorded in the MODULE_CODE_VSTOFFSET record. + /// Used to enable on-demand parsing of the VST. + uint64_t VSTOffset = 0; + + // Map to save ValueId to GUID association that was recorded in the + // ValueSymbolTable. It is used after the VST is parsed to convert + // call graph edges read from the function summary from referencing + // callees by their ValueId to using the GUID instead, which is how + // they are recorded in the function index being built. + DenseMap<unsigned, uint64_t> ValueIdToCallGraphGUIDMap; + + /// Map to save the association between summary offset in the VST to the + /// GlobalValueInfo object created when parsing it. Used to access the + /// info object when parsing the summary section. + DenseMap<uint64_t, GlobalValueInfo *> SummaryOffsetToInfoMap; /// Map populated during module path string table parsing, from the /// module ID to a string reference owned by the index's module - /// path string table, used to correlate with combined index function + /// path string table, used to correlate with combined index /// summary records. DenseMap<uint64_t, StringRef> ModuleIdMap; @@ -469,37 +477,41 @@ public: FunctionIndexBitcodeReader(MemoryBuffer *Buffer, DiagnosticHandlerFunction DiagnosticHandler, bool IsLazy = false, - bool CheckFuncSummaryPresenceOnly = false); + bool CheckGlobalValSummaryPresenceOnly = false); FunctionIndexBitcodeReader(DiagnosticHandlerFunction DiagnosticHandler, bool IsLazy = false, - bool CheckFuncSummaryPresenceOnly = false); + bool CheckGlobalValSummaryPresenceOnly = false); ~FunctionIndexBitcodeReader() { freeState(); } void freeState(); void releaseBuffer(); - /// Check if the parser has encountered a function summary section. - bool foundFuncSummary() { return SeenFuncSummary; } + /// Check if the parser has encountered a summary section. + bool foundGlobalValSummary() { return SeenGlobalValSummary; } /// \brief Main interface to parsing a bitcode buffer. /// \returns true if an error occurred. std::error_code parseSummaryIndexInto(std::unique_ptr<DataStreamer> Streamer, FunctionInfoIndex *I); - /// \brief Interface for parsing a function summary lazily. + /// \brief Interface for parsing a summary lazily. std::error_code parseFunctionSummary(std::unique_ptr<DataStreamer> Streamer, FunctionInfoIndex *I, size_t FunctionSummaryOffset); private: std::error_code parseModule(); - std::error_code parseValueSymbolTable(); + std::error_code parseValueSymbolTable( + uint64_t Offset, + DenseMap<unsigned, GlobalValue::LinkageTypes> &ValueIdToLinkageMap); std::error_code parseEntireSummary(); std::error_code parseModuleStringTable(); std::error_code initStream(std::unique_ptr<DataStreamer> Streamer); std::error_code initStreamFromBuffer(); std::error_code initLazyStream(std::unique_ptr<DataStreamer> Streamer); + uint64_t getGUIDFromValueId(unsigned ValueId); + GlobalValueInfo *getInfoFromSummaryOffset(uint64_t Offset); }; } // end anonymous namespace @@ -1727,6 +1739,27 @@ ErrorOr<Value *> BitcodeReader::recordValue(SmallVectorImpl<uint64_t> &Record, return V; } +/// Helper to note and return the current location, and jump to the given +/// offset. +static uint64_t jumpToValueSymbolTable(uint64_t Offset, + BitstreamCursor &Stream) { + // Save the current parsing location so we can jump back at the end + // of the VST read. + uint64_t CurrentBit = Stream.GetCurrentBitNo(); + Stream.JumpToBit(Offset * 32); +#ifndef NDEBUG + // Do some checking if we are in debug mode. + BitstreamEntry Entry = Stream.advance(); + assert(Entry.Kind == BitstreamEntry::SubBlock); + assert(Entry.ID == bitc::VALUE_SYMTAB_BLOCK_ID); +#else + // In NDEBUG mode ignore the output so we don't get an unused variable + // warning. + Stream.advance(); +#endif + return CurrentBit; +} + /// Parse the value symbol table at either the current parsing location or /// at the given bit offset if provided. std::error_code BitcodeReader::parseValueSymbolTable(uint64_t Offset) { @@ -1734,22 +1767,8 @@ std::error_code BitcodeReader::parseValueSymbolTable(uint64_t Offset) { // Pass in the Offset to distinguish between calling for the module-level // VST (where we want to jump to the VST offset) and the function-level // VST (where we don't). - if (Offset > 0) { - // Save the current parsing location so we can jump back at the end - // of the VST read. - CurrentBit = Stream.GetCurrentBitNo(); - Stream.JumpToBit(Offset * 32); -#ifndef NDEBUG - // Do some checking if we are in debug mode. - BitstreamEntry Entry = Stream.advance(); - assert(Entry.Kind == BitstreamEntry::SubBlock); - assert(Entry.ID == bitc::VALUE_SYMTAB_BLOCK_ID); -#else - // In NDEBUG mode ignore the output so we don't get an unused variable - // warning. - Stream.advance(); -#endif - } + if (Offset > 0) + CurrentBit = jumpToValueSymbolTable(Offset, Stream); // Compute the delta between the bitcode indices in the VST (the word offset // to the word-aligned ENTER_SUBBLOCK for the function block, and that @@ -5411,27 +5430,45 @@ std::error_code FunctionIndexBitcodeReader::error(BitcodeError E) { FunctionIndexBitcodeReader::FunctionIndexBitcodeReader( MemoryBuffer *Buffer, DiagnosticHandlerFunction DiagnosticHandler, - bool IsLazy, bool CheckFuncSummaryPresenceOnly) + bool IsLazy, bool CheckGlobalValSummaryPresenceOnly) : DiagnosticHandler(DiagnosticHandler), Buffer(Buffer), IsLazy(IsLazy), - CheckFuncSummaryPresenceOnly(CheckFuncSummaryPresenceOnly) {} + CheckGlobalValSummaryPresenceOnly(CheckGlobalValSummaryPresenceOnly) {} FunctionIndexBitcodeReader::FunctionIndexBitcodeReader( DiagnosticHandlerFunction DiagnosticHandler, bool IsLazy, - bool CheckFuncSummaryPresenceOnly) + bool CheckGlobalValSummaryPresenceOnly) : DiagnosticHandler(DiagnosticHandler), Buffer(nullptr), IsLazy(IsLazy), - CheckFuncSummaryPresenceOnly(CheckFuncSummaryPresenceOnly) {} + CheckGlobalValSummaryPresenceOnly(CheckGlobalValSummaryPresenceOnly) {} void FunctionIndexBitcodeReader::freeState() { Buffer = nullptr; } void FunctionIndexBitcodeReader::releaseBuffer() { Buffer.release(); } -// Specialized value symbol table parser used when reading function index +uint64_t FunctionIndexBitcodeReader::getGUIDFromValueId(unsigned ValueId) { + auto VGI = ValueIdToCallGraphGUIDMap.find(ValueId); + assert(VGI != ValueIdToCallGraphGUIDMap.end()); + return VGI->second; +} + +GlobalValueInfo * +FunctionIndexBitcodeReader::getInfoFromSummaryOffset(uint64_t Offset) { + auto I = SummaryOffsetToInfoMap.find(Offset); + assert(I != SummaryOffsetToInfoMap.end()); + return I->second; +} + +// Specialized value symbol table parser used when reading module index // blocks where we don't actually create global values. -// At the end of this routine the function index is populated with a map -// from function name to FunctionInfo. The function info contains -// the function block's bitcode offset as well as the offset into the -// function summary section. -std::error_code FunctionIndexBitcodeReader::parseValueSymbolTable() { +// At the end of this routine the module index is populated with a map +// from global value name to GlobalValueInfo. The global value info contains +// the function block's bitcode offset (if applicable), or the offset into the +// summary section for the combined index. +std::error_code FunctionIndexBitcodeReader::parseValueSymbolTable( + uint64_t Offset, + DenseMap<unsigned, GlobalValue::LinkageTypes> &ValueIdToLinkageMap) { + assert(Offset > 0 && "Expected non-zero VST offset"); + uint64_t CurrentBit = jumpToValueSymbolTable(Offset, Stream); + if (Stream.EnterSubBlock(bitc::VALUE_SYMTAB_BLOCK_ID)) return error("Invalid record"); @@ -5447,6 +5484,8 @@ std::error_code FunctionIndexBitcodeReader::parseValueSymbolTable() { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: + // Done parsing VST, jump back to wherever we came from. + Stream.JumpToBit(CurrentBit); return std::error_code(); case BitstreamEntry::Record: // The interesting case. @@ -5458,6 +5497,23 @@ std::error_code FunctionIndexBitcodeReader::parseValueSymbolTable() { switch (Stream.readRecord(Entry.ID, Record)) { default: // Default behavior: ignore (e.g. VST_CODE_BBENTRY records). break; + case bitc::VST_CODE_ENTRY: { // VST_CODE_ENTRY: [valueid, namechar x N] + if (convertToString(Record, 1, ValueName)) + return error("Invalid record"); + unsigned ValueID = Record[0]; + std::unique_ptr<GlobalValueInfo> GlobalValInfo = + llvm::make_unique<GlobalValueInfo>(); + assert(!SourceFileName.empty()); + auto VLI = ValueIdToLinkageMap.find(ValueID); + assert(VLI != ValueIdToLinkageMap.end() && + "No linkage found for VST entry?"); + std::string GlobalId = + Function::getGlobalIdentifier(ValueName, VLI->second, SourceFileName); + TheIndex->addGlobalValueInfo(GlobalId, std::move(GlobalValInfo)); + ValueIdToCallGraphGUIDMap[ValueID] = Function::getGUID(GlobalId); + ValueName.clear(); + break; + } case bitc::VST_CODE_FNENTRY: { // VST_CODE_FNENTRY: [valueid, offset, namechar x N] if (convertToString(Record, 2, ValueName)) @@ -5465,59 +5521,58 @@ std::error_code FunctionIndexBitcodeReader::parseValueSymbolTable() { unsigned ValueID = Record[0]; uint64_t FuncOffset = Record[1]; assert(!IsLazy && "Lazy summary read only supported for combined index"); - // Gracefully handle bitcode without a function summary section, - // which will simply not populate the index. - if (foundFuncSummary()) { - DenseMap<uint64_t, std::unique_ptr<FunctionSummary>>::iterator SMI = - SummaryMap.find(ValueID); - assert(SMI != SummaryMap.end() && "Summary info not found"); - std::unique_ptr<FunctionInfo> FuncInfo = - llvm::make_unique<FunctionInfo>(FuncOffset); - FuncInfo->setFunctionSummary(std::move(SMI->second)); - assert(!SourceFileName.empty()); - std::string FunctionGlobalId = Function::getGlobalIdentifier( - ValueName, FuncInfo->functionSummary()->getFunctionLinkage(), - SourceFileName); - TheIndex->addFunctionInfo(FunctionGlobalId, std::move(FuncInfo)); - } + std::unique_ptr<GlobalValueInfo> FuncInfo = + llvm::make_unique<GlobalValueInfo>(FuncOffset); + assert(!SourceFileName.empty()); + auto VLI = ValueIdToLinkageMap.find(ValueID); + assert(VLI != ValueIdToLinkageMap.end() && + "No linkage found for VST entry?"); + std::string FunctionGlobalId = + Function::getGlobalIdentifier(ValueName, VLI->second, SourceFileName); + TheIndex->addGlobalValueInfo(FunctionGlobalId, std::move(FuncInfo)); + ValueIdToCallGraphGUIDMap[ValueID] = Function::getGUID(FunctionGlobalId); ValueName.clear(); break; } - case bitc::VST_CODE_COMBINED_FNENTRY: { - // VST_CODE_COMBINED_FNENTRY: [offset, funcguid] - uint64_t FuncSummaryOffset = Record[0]; - uint64_t FuncGUID = Record[1]; - std::unique_ptr<FunctionInfo> FuncInfo = - llvm::make_unique<FunctionInfo>(FuncSummaryOffset); - if (foundFuncSummary() && !IsLazy) { - DenseMap<uint64_t, std::unique_ptr<FunctionSummary>>::iterator SMI = - SummaryMap.find(FuncSummaryOffset); - assert(SMI != SummaryMap.end() && "Summary info not found"); - FuncInfo->setFunctionSummary(std::move(SMI->second)); - } - TheIndex->addFunctionInfo(FuncGUID, std::move(FuncInfo)); - - ValueName.clear(); + case bitc::VST_CODE_COMBINED_GVDEFENTRY: { + // VST_CODE_COMBINED_GVDEFENTRY: [valueid, offset, guid] + unsigned ValueID = Record[0]; + uint64_t GlobalValSummaryOffset = Record[1]; + uint64_t GlobalValGUID = Record[2]; + std::unique_ptr<GlobalValueInfo> GlobalValInfo = + llvm::make_unique<GlobalValueInfo>(GlobalValSummaryOffset); + SummaryOffsetToInfoMap[GlobalValSummaryOffset] = GlobalValInfo.get(); + TheIndex->addGlobalValueInfo(GlobalValGUID, std::move(GlobalValInfo)); + ValueIdToCallGraphGUIDMap[ValueID] = GlobalValGUID; + break; + } + case bitc::VST_CODE_COMBINED_ENTRY: { + // VST_CODE_COMBINED_ENTRY: [valueid, refguid] + unsigned ValueID = Record[0]; + uint64_t RefGUID = Record[1]; + ValueIdToCallGraphGUIDMap[ValueID] = RefGUID; break; } } } } -// Parse just the blocks needed for function index building out of the module. -// At the end of this routine the function Index is populated with a map -// from function name to FunctionInfo. The function info contains -// either the parsed function summary information (when parsing summaries -// eagerly), or just to the function summary record's offset +// Parse just the blocks needed for building the index out of the module. +// At the end of this routine the module Index is populated with a map +// from global value name to GlobalValueInfo. The global value info contains +// either the parsed summary information (when parsing summaries +// eagerly), or just to the summary record's offset // if parsing lazily (IsLazy). std::error_code FunctionIndexBitcodeReader::parseModule() { if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) return error("Invalid record"); SmallVector<uint64_t, 64> Record; + DenseMap<unsigned, GlobalValue::LinkageTypes> ValueIdToLinkageMap; + unsigned ValueId = 0; - // Read the function index for this module. + // Read the index for this module. while (1) { BitstreamEntry Entry = Stream.advance(); @@ -5528,9 +5583,9 @@ std::error_code FunctionIndexBitcodeReader::parseModule() { return std::error_code(); case BitstreamEntry::SubBlock: - if (CheckFuncSummaryPresenceOnly) { - if (Entry.ID == bitc::FUNCTION_SUMMARY_BLOCK_ID) { - SeenFuncSummary = true; + if (CheckGlobalValSummaryPresenceOnly) { + if (Entry.ID == bitc::GLOBALVAL_SUMMARY_BLOCK_ID) { + SeenGlobalValSummary = true; // No need to parse the rest since we found the summary. return std::error_code(); } @@ -5549,11 +5604,23 @@ std::error_code FunctionIndexBitcodeReader::parseModule() { return error("Malformed block"); break; case bitc::VALUE_SYMTAB_BLOCK_ID: - if (std::error_code EC = parseValueSymbolTable()) - return EC; + // Should have been parsed earlier via VSTOffset, unless there + // is no summary section. + assert(((SeenValueSymbolTable && VSTOffset > 0) || + !SeenGlobalValSummary) && + "Expected early VST parse via VSTOffset record"); + if (Stream.SkipBlock()) + return error("Invalid record"); break; - case bitc::FUNCTION_SUMMARY_BLOCK_ID: - SeenFuncSummary = true; + case bitc::GLOBALVAL_SUMMARY_BLOCK_ID: + assert(VSTOffset > 0 && "Expected non-zero VST offset"); + assert(!SeenValueSymbolTable && + "Already read VST when parsing summary block?"); + if (std::error_code EC = + parseValueSymbolTable(VSTOffset, ValueIdToLinkageMap)) + return EC; + SeenValueSymbolTable = true; + SeenGlobalValSummary = true; if (IsLazy) { // Lazy parsing of summary info, skip it. if (Stream.SkipBlock()) @@ -5569,8 +5636,8 @@ std::error_code FunctionIndexBitcodeReader::parseModule() { continue; case BitstreamEntry::Record: - // Once we find the single record of interest, skip the rest. - if (!SourceFileName.empty()) + // Once we find the last record of interest, skip the rest. + if (VSTOffset > 0) Stream.skipRecord(Entry.ID); else { Record.clear(); @@ -5579,28 +5646,68 @@ std::error_code FunctionIndexBitcodeReader::parseModule() { default: break; // Default behavior, ignore unknown content. /// MODULE_CODE_SOURCE_FILENAME: [namechar x N] - case bitc::MODULE_CODE_SOURCE_FILENAME: + case bitc::MODULE_CODE_SOURCE_FILENAME: { SmallString<128> ValueName; if (convertToString(Record, 0, ValueName)) return error("Invalid record"); SourceFileName = ValueName.c_str(); break; } + /// MODULE_CODE_VSTOFFSET: [offset] + case bitc::MODULE_CODE_VSTOFFSET: + if (Record.size() < 1) + return error("Invalid record"); + VSTOffset = Record[0]; + break; + // GLOBALVAR: [pointer type, isconst, initid, + // linkage, alignment, section, visibility, threadlocal, + // unnamed_addr, externally_initialized, dllstorageclass, + // comdat] + case bitc::MODULE_CODE_GLOBALVAR: { + if (Record.size() < 6) + return error("Invalid record"); + uint64_t RawLinkage = Record[3]; + GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); + ValueIdToLinkageMap[ValueId++] = Linkage; + break; + } + // FUNCTION: [type, callingconv, isproto, linkage, paramattr, + // alignment, section, visibility, gc, unnamed_addr, + // prologuedata, dllstorageclass, comdat, prefixdata] + case bitc::MODULE_CODE_FUNCTION: { + if (Record.size() < 8) + return error("Invalid record"); + uint64_t RawLinkage = Record[3]; + GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); + ValueIdToLinkageMap[ValueId++] = Linkage; + break; + } + // ALIAS: [alias type, addrspace, aliasee val#, linkage, visibility, + // dllstorageclass] + case bitc::MODULE_CODE_ALIAS: { + if (Record.size() < 6) + return error("Invalid record"); + uint64_t RawLinkage = Record[3]; + GlobalValue::LinkageTypes Linkage = getDecodedLinkage(RawLinkage); + ValueIdToLinkageMap[ValueId++] = Linkage; + break; + } + } } continue; } } } -// Eagerly parse the entire function summary block (i.e. for all functions -// in the index). This populates the FunctionSummary objects in -// the index. +// Eagerly parse the entire summary block. This populates the GlobalValueSummary +// objects in the index. std::error_code FunctionIndexBitcodeReader::parseEntireSummary() { - if (Stream.EnterSubBlock(bitc::FUNCTION_SUMMARY_BLOCK_ID)) + if (Stream.EnterSubBlock(bitc::GLOBALVAL_SUMMARY_BLOCK_ID)) return error("Invalid record"); SmallVector<uint64_t, 64> Record; + bool Combined = false; while (1) { BitstreamEntry Entry = Stream.advanceSkippingSubblocks(); @@ -5609,6 +5716,16 @@ std::error_code FunctionIndexBitcodeReader::parseEntireSummary() { case BitstreamEntry::Error: return error("Malformed block"); case BitstreamEntry::EndBlock: + // For a per-module index, remove any entries that still have empty + // summaries. The VST parsing creates entries eagerly for all symbols, + // but not all have associated summaries (e.g. it doesn't know how to + // distinguish between VST_CODE_ENTRY for function declarations vs global + // variables with initializers that end up with a summary). Remove those + // entries now so that we don't need to rely on the combined index merger + // to clean them up (especially since that may not run for the first + // module's index if we merge into that). + if (!Combined) + TheIndex->removeEmptySummaryEntries(); return std::error_code(); case BitstreamEntry::Record: // The interesting case. @@ -5624,17 +5741,23 @@ std::error_code FunctionIndexBitcodeReader::parseEntireSummary() { // information used for ThinLTO renaming and importing. Record.clear(); uint64_t CurRecordBit = Stream.GetCurrentBitNo(); - switch (Stream.readRecord(Entry.ID, Record)) { + auto BitCode = Stream.readRecord(Entry.ID, Record); + switch (BitCode) { default: // Default behavior: ignore. break; - // FS_PERMODULE_ENTRY: [valueid, linkage, instcount] - case bitc::FS_CODE_PERMODULE_ENTRY: { + // FS_PERMODULE: [valueid, linkage, instcount, numrefs, numrefs x valueid, + // n x (valueid, callsitecount)] + // FS_PERMODULE_PROFILE: [valueid, linkage, instcount, numrefs, + // numrefs x valueid, + // n x (valueid, callsitecount, profilecount)] + case bitc::FS_PERMODULE: + case bitc::FS_PERMODULE_PROFILE: { unsigned ValueID = Record[0]; uint64_t RawLinkage = Record[1]; unsigned InstCount = Record[2]; - std::unique_ptr<FunctionSummary> FS = - llvm::make_unique<FunctionSummary>(InstCount); - FS->setFunctionLinkage(getDecodedLinkage(RawLinkage)); + unsigned NumRefs = Record[3]; + std::unique_ptr<FunctionSummary> FS = llvm::make_unique<FunctionSummary>( + getDecodedLinkage(RawLinkage), InstCount); // The module path string ref set in the summary must be owned by the // index's module string table. Since we don't have a module path // string table section in the per-module index, we create a single @@ -5642,19 +5765,115 @@ std::error_code FunctionIndexBitcodeReader::parseEntireSummary() { // ownership. FS->setModulePath( TheIndex->addModulePath(Buffer->getBufferIdentifier(), 0)); - SummaryMap[ValueID] = std::move(FS); + static int RefListStartIndex = 4; + int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; + assert(Record.size() >= RefListStartIndex + NumRefs && + "Record size inconsistent with number of references"); + for (unsigned I = 4, E = CallGraphEdgeStartIndex; I != E; ++I) { + unsigned RefValueId = Record[I]; + uint64_t RefGUID = getGUIDFromValueId(RefValueId); + FS->addRefEdge(RefGUID); + } + bool HasProfile = (BitCode == bitc::FS_PERMODULE_PROFILE); + for (unsigned I = CallGraphEdgeStartIndex, E = Record.size(); I != E; + ++I) { + unsigned CalleeValueId = Record[I]; + unsigned CallsiteCount = Record[++I]; + uint64_t ProfileCount = HasProfile ? Record[++I] : 0; + uint64_t CalleeGUID = getGUIDFromValueId(CalleeValueId); + FS->addCallGraphEdge(CalleeGUID, + CalleeInfo(CallsiteCount, ProfileCount)); + } + uint64_t GUID = getGUIDFromValueId(ValueID); + auto InfoList = TheIndex->findGlobalValueInfoList(GUID); + assert(InfoList != TheIndex->end() && + "Expected VST parse to create GlobalValueInfo entry"); + assert(InfoList->second.size() == 1 && + "Expected a single GlobalValueInfo per GUID in module"); + auto &Info = InfoList->second[0]; + assert(!Info->summary() && "Expected a single summary per VST entry"); + Info->setSummary(std::move(FS)); + break; + } + // FS_PERMODULE_GLOBALVAR_INIT_REFS: [valueid, linkage, n x valueid] + case bitc::FS_PERMODULE_GLOBALVAR_INIT_REFS: { + unsigned ValueID = Record[0]; + uint64_t RawLinkage = Record[1]; + std::unique_ptr<GlobalVarSummary> FS = + llvm::make_unique<GlobalVarSummary>(getDecodedLinkage(RawLinkage)); + FS->setModulePath( + TheIndex->addModulePath(Buffer->getBufferIdentifier(), 0)); + for (unsigned I = 2, E = Record.size(); I != E; ++I) { + unsigned RefValueId = Record[I]; + uint64_t RefGUID = getGUIDFromValueId(RefValueId); + FS->addRefEdge(RefGUID); + } + uint64_t GUID = getGUIDFromValueId(ValueID); + auto InfoList = TheIndex->findGlobalValueInfoList(GUID); + assert(InfoList != TheIndex->end() && + "Expected VST parse to create GlobalValueInfo entry"); + assert(InfoList->second.size() == 1 && + "Expected a single GlobalValueInfo per GUID in module"); + auto &Info = InfoList->second[0]; + assert(!Info->summary() && "Expected a single summary per VST entry"); + Info->setSummary(std::move(FS)); + break; + } + // FS_COMBINED: [modid, linkage, instcount, numrefs, numrefs x valueid, + // n x (valueid, callsitecount)] + // FS_COMBINED_PROFILE: [modid, linkage, instcount, numrefs, + // numrefs x valueid, + // n x (valueid, callsitecount, profilecount)] + case bitc::FS_COMBINED: + case bitc::FS_COMBINED_PROFILE: { + uint64_t ModuleId = Record[0]; + uint64_t RawLinkage = Record[1]; + unsigned InstCount = Record[2]; + unsigned NumRefs = Record[3]; + std::unique_ptr<FunctionSummary> FS = llvm::make_unique<FunctionSummary>( + getDecodedLinkage(RawLinkage), InstCount); + FS->setModulePath(ModuleIdMap[ModuleId]); + static int RefListStartIndex = 4; + int CallGraphEdgeStartIndex = RefListStartIndex + NumRefs; + assert(Record.size() >= RefListStartIndex + NumRefs && + "Record size inconsistent with number of references"); + for (unsigned I = 4, E = CallGraphEdgeStartIndex; I != E; ++I) { + unsigned RefValueId = Record[I]; + uint64_t RefGUID = getGUIDFromValueId(RefValueId); + FS->addRefEdge(RefGUID); + } + bool HasProfile = (BitCode == bitc::FS_COMBINED_PROFILE); + for (unsigned I = CallGraphEdgeStartIndex, E = Record.size(); I != E; + ++I) { + unsigned CalleeValueId = Record[I]; + unsigned CallsiteCount = Record[++I]; + uint64_t ProfileCount = HasProfile ? Record[++I] : 0; + uint64_t CalleeGUID = getGUIDFromValueId(CalleeValueId); + FS->addCallGraphEdge(CalleeGUID, + CalleeInfo(CallsiteCount, ProfileCount)); + } + auto *Info = getInfoFromSummaryOffset(CurRecordBit); + assert(!Info->summary() && "Expected a single summary per VST entry"); + Info->setSummary(std::move(FS)); + Combined = true; break; } - // FS_COMBINED_ENTRY: [modid, linkage, instcount] - case bitc::FS_CODE_COMBINED_ENTRY: { + // FS_COMBINED_GLOBALVAR_INIT_REFS: [modid, linkage, n x valueid] + case bitc::FS_COMBINED_GLOBALVAR_INIT_REFS: { uint64_t ModuleId = Record[0]; uint64_t RawLinkage = Record[1]; - unsigned InstCount = Record[2]; - std::unique_ptr<FunctionSummary> FS = - llvm::make_unique<FunctionSummary>(InstCount); - FS->setFunctionLinkage(getDecodedLinkage(RawLinkage)); + std::unique_ptr<GlobalVarSummary> FS = + llvm::make_unique<GlobalVarSummary>(getDecodedLinkage(RawLinkage)); FS->setModulePath(ModuleIdMap[ModuleId]); - SummaryMap[CurRecordBit] = std::move(FS); + for (unsigned I = 2, E = Record.size(); I != E; ++I) { + unsigned RefValueId = Record[I]; + uint64_t RefGUID = getGUIDFromValueId(RefValueId); + FS->addRefEdge(RefGUID); + } + auto *Info = getInfoFromSummaryOffset(CurRecordBit); + assert(!Info->summary() && "Expected a single summary per VST entry"); + Info->setSummary(std::move(FS)); + Combined = true; break; } } @@ -5773,7 +5992,9 @@ std::error_code FunctionIndexBitcodeReader::parseFunctionSummary( // importing is added so that it can be tested. SmallVector<uint64_t, 64> Record; switch (Stream.readRecord(Entry.ID, Record)) { - case bitc::FS_CODE_COMBINED_ENTRY: + case bitc::FS_COMBINED: + case bitc::FS_COMBINED_PROFILE: + case bitc::FS_COMBINED_GLOBALVAR_INIT_REFS: default: return error("Invalid record"); } @@ -5987,9 +6208,9 @@ llvm::getFunctionInfoIndex(MemoryBufferRef Buffer, return std::move(Index); } -// Check if the given bitcode buffer contains a function summary block. -bool llvm::hasFunctionSummary(MemoryBufferRef Buffer, - DiagnosticHandlerFunction DiagnosticHandler) { +// Check if the given bitcode buffer contains a global value summary block. +bool llvm::hasGlobalValueSummary(MemoryBufferRef Buffer, + DiagnosticHandlerFunction DiagnosticHandler) { std::unique_ptr<MemoryBuffer> Buf = MemoryBuffer::getMemBuffer(Buffer, false); FunctionIndexBitcodeReader R(Buf.get(), DiagnosticHandler, false, true); @@ -6002,7 +6223,7 @@ bool llvm::hasFunctionSummary(MemoryBufferRef Buffer, return cleanupOnError(EC); Buf.release(); // The FunctionIndexBitcodeReader owns it now. - return R.foundFuncSummary(); + return R.foundGlobalValSummary(); } // This method supports lazy reading of function summary data from the combined @@ -6026,7 +6247,7 @@ std::error_code llvm::readFunctionSummary( // contain a list of function infos in the case of a COMDAT. Walk through // and parse each function summary info at the function summary offset // recorded when parsing the value symbol table. - for (const auto &FI : Index->getFunctionInfoList(FunctionName)) { + for (const auto &FI : Index->getGlobalValueInfoList(FunctionName)) { size_t FunctionSummaryOffset = FI->bitcodeIndex(); if (std::error_code EC = R.parseFunctionSummary(nullptr, Index.get(), FunctionSummaryOffset)) |