diff --git a/llvm/include/llvm/Bitcode/ReaderWriter.h b/llvm/include/llvm/Bitcode/ReaderWriter.h index 48bdabc88391..254949d1a33a 100644 --- a/llvm/include/llvm/Bitcode/ReaderWriter.h +++ b/llvm/include/llvm/Bitcode/ReaderWriter.h @@ -29,12 +29,14 @@ namespace llvm { class raw_ostream; /// Read the header of the specified bitcode buffer and prepare for lazy - /// deserialization of function bodies. If successful, this moves Buffer. On + /// deserialization of function bodies. If ShouldLazyLoadMetadata is true, + /// lazily load metadata as well. If successful, this moves Buffer. On /// error, this *does not* move Buffer. ErrorOr getLazyBitcodeModule(std::unique_ptr &&Buffer, LLVMContext &Context, - DiagnosticHandlerFunction DiagnosticHandler = nullptr); + DiagnosticHandlerFunction DiagnosticHandler = nullptr, + bool ShouldLazyLoadMetadata = false); /// Read the header of the specified stream and prepare for lazy /// deserialization and streaming of function bodies. diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp index e7e8b030ccb7..c4e070cd17bb 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp @@ -82,7 +82,7 @@ BitcodeReader::BitcodeReader(MemoryBuffer *buffer, LLVMContext &C, TheModule(nullptr), Buffer(buffer), LazyStreamer(nullptr), NextUnreadBit(0), SeenValueSymbolTable(false), ValueList(C), MDValueList(C), SeenFirstFunctionBody(false), UseRelativeIDs(false), - WillMaterializeAllForwardRefs(false) {} + WillMaterializeAllForwardRefs(false), IsMetadataMaterialized(false) {} BitcodeReader::BitcodeReader(DataStreamer *streamer, LLVMContext &C, DiagnosticHandlerFunction DiagnosticHandler) @@ -90,7 +90,7 @@ BitcodeReader::BitcodeReader(DataStreamer *streamer, LLVMContext &C, TheModule(nullptr), Buffer(nullptr), LazyStreamer(streamer), NextUnreadBit(0), SeenValueSymbolTable(false), ValueList(C), MDValueList(C), SeenFirstFunctionBody(false), UseRelativeIDs(false), - WillMaterializeAllForwardRefs(false) {} + WillMaterializeAllForwardRefs(false), IsMetadataMaterialized(false) {} std::error_code BitcodeReader::materializeForwardReferencedFunctions() { if (WillMaterializeAllForwardRefs) @@ -136,6 +136,7 @@ void BitcodeReader::FreeState() { std::vector().swap(FunctionBBs); std::vector().swap(FunctionsWithBodies); DeferredFunctionInfo.clear(); + DeferredMetadataInfo.clear(); MDKindMap.clear(); assert(BasicBlockFwdRefs.empty() && "Unresolved blockaddress fwd references"); @@ -1199,6 +1200,7 @@ std::error_code BitcodeReader::ParseValueSymbolTable() { static int64_t unrotateSign(uint64_t U) { return U & 1 ? ~(U >> 1) : U >> 1; } std::error_code BitcodeReader::ParseMetadata() { + IsMetadataMaterialized = true; unsigned NextMDValueNo = MDValueList.size(); if (Stream.EnterSubBlock(bitc::METADATA_BLOCK_ID)) @@ -2235,6 +2237,30 @@ std::error_code BitcodeReader::ParseUseLists() { } } +/// When we see the block for metadata, remember where it is and then skip it. +/// This lets us lazily deserialize the metadata. +std::error_code BitcodeReader::rememberAndSkipMetadata() { + // Save the current stream state. + uint64_t CurBit = Stream.GetCurrentBitNo(); + DeferredMetadataInfo.push_back(CurBit); + + // Skip over the block for now. + if (Stream.SkipBlock()) + return Error("Invalid record"); + return std::error_code(); +} + +std::error_code BitcodeReader::materializeMetadata() { + for (uint64_t BitPos : DeferredMetadataInfo) { + // Move the bit stream to the saved position. + Stream.JumpToBit(BitPos); + if (std::error_code EC = ParseMetadata()) + return EC; + } + DeferredMetadataInfo.clear(); + return std::error_code(); +} + /// RememberAndSkipFunctionBody - When we see the block for a function body, /// remember where it is and then skip it. This lets us lazily deserialize the /// functions. @@ -2285,7 +2311,8 @@ std::error_code BitcodeReader::GlobalCleanup() { return std::error_code(); } -std::error_code BitcodeReader::ParseModule(bool Resume) { +std::error_code BitcodeReader::ParseModule(bool Resume, + bool ShouldLazyLoadMetadata) { if (Resume) Stream.JumpToBit(NextUnreadBit); else if (Stream.EnterSubBlock(bitc::MODULE_BLOCK_ID)) @@ -2339,6 +2366,12 @@ std::error_code BitcodeReader::ParseModule(bool Resume) { return EC; break; case bitc::METADATA_BLOCK_ID: + if (ShouldLazyLoadMetadata && !IsMetadataMaterialized) { + if (std::error_code EC = rememberAndSkipMetadata()) + return EC; + break; + } + assert(DeferredMetadataInfo.empty() && "Unexpected deferred metadata"); if (std::error_code EC = ParseMetadata()) return EC; break; @@ -2653,7 +2686,8 @@ std::error_code BitcodeReader::ParseModule(bool Resume) { } } -std::error_code BitcodeReader::ParseBitcodeInto(Module *M) { +std::error_code BitcodeReader::ParseBitcodeInto(Module *M, + bool ShouldLazyLoadMetadata) { TheModule = nullptr; if (std::error_code EC = InitStream()) @@ -2694,7 +2728,7 @@ std::error_code BitcodeReader::ParseBitcodeInto(Module *M) { if (TheModule) return Error("Invalid multiple blocks"); TheModule = M; - if (std::error_code EC = ParseModule(false)) + if (std::error_code EC = ParseModule(false, ShouldLazyLoadMetadata)) return EC; if (LazyStreamer) return std::error_code(); @@ -3894,6 +3928,9 @@ std::error_code BitcodeReader::FindFunctionInStream( void BitcodeReader::releaseBuffer() { Buffer.release(); } std::error_code BitcodeReader::materialize(GlobalValue *GV) { + if (std::error_code EC = materializeMetadata()) + return EC; + Function *F = dyn_cast(GV); // If it's not a function or is already material, ignore the request. if (!F || !F->isMaterializable()) @@ -3961,6 +3998,9 @@ std::error_code BitcodeReader::MaterializeModule(Module *M) { assert(M == TheModule && "Can only Materialize the Module this BitcodeReader is attached to."); + if (std::error_code EC = materializeMetadata()) + return EC; + // Promise to materialize all forward references. WillMaterializeAllForwardRefs = true; @@ -4101,7 +4141,8 @@ const std::error_category &llvm::BitcodeErrorCategory() { static ErrorOr getLazyBitcodeModuleImpl(std::unique_ptr &&Buffer, LLVMContext &Context, bool WillMaterializeAll, - DiagnosticHandlerFunction DiagnosticHandler) { + DiagnosticHandlerFunction DiagnosticHandler, + bool ShouldLazyLoadMetadata = false) { Module *M = new Module(Buffer->getBufferIdentifier(), Context); BitcodeReader *R = new BitcodeReader(Buffer.get(), Context, DiagnosticHandler); @@ -4113,7 +4154,8 @@ getLazyBitcodeModuleImpl(std::unique_ptr &&Buffer, return EC; }; - if (std::error_code EC = R->ParseBitcodeInto(M)) + // Delay parsing Metadata if ShouldLazyLoadMetadata is true. + if (std::error_code EC = R->ParseBitcodeInto(M, ShouldLazyLoadMetadata)) return cleanupOnError(EC); if (!WillMaterializeAll) @@ -4128,9 +4170,10 @@ getLazyBitcodeModuleImpl(std::unique_ptr &&Buffer, ErrorOr llvm::getLazyBitcodeModule(std::unique_ptr &&Buffer, LLVMContext &Context, - DiagnosticHandlerFunction DiagnosticHandler) { + DiagnosticHandlerFunction DiagnosticHandler, + bool ShouldLazyLoadMetadata) { return getLazyBitcodeModuleImpl(std::move(Buffer), Context, false, - DiagnosticHandler); + DiagnosticHandler, ShouldLazyLoadMetadata); } ErrorOr> diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.h b/llvm/lib/Bitcode/Reader/BitcodeReader.h index 9803e78b929a..0a69148d84da 100644 --- a/llvm/lib/Bitcode/Reader/BitcodeReader.h +++ b/llvm/lib/Bitcode/Reader/BitcodeReader.h @@ -190,6 +190,11 @@ class BitcodeReader : public GVMaterializer { /// stream. DenseMap DeferredFunctionInfo; + /// When Metadata block is initially scanned when parsing the module, we may + /// choose to defer parsing of the metadata. This vector contains info about + /// which Metadata blocks are deferred. + std::vector DeferredMetadataInfo; + /// These are basic blocks forward-referenced by block addresses. They are /// inserted lazily into functions when they're loaded. The basic block ID is /// its index into the vector. @@ -212,6 +217,9 @@ class BitcodeReader : public GVMaterializer { /// Functions that have block addresses taken. This is usually empty. SmallPtrSet BlockAddressesTaken; + /// True if any Metadata block has been materialized. + bool IsMetadataMaterialized; + public: std::error_code Error(BitcodeError E, const Twine &Message); std::error_code Error(BitcodeError E); @@ -237,7 +245,8 @@ public: /// @brief Main interface to parsing a bitcode buffer. /// @returns true if an error occurred. - std::error_code ParseBitcodeInto(Module *M); + std::error_code ParseBitcodeInto(Module *M, + bool ShouldLazyLoadMetadata = false); /// @brief Cheap mechanism to just extract module triple /// @returns true if an error occurred. @@ -245,6 +254,9 @@ public: static uint64_t decodeSignRotatedValue(uint64_t V); + /// Materialize any deferred Metadata block. + std::error_code materializeMetadata(); + private: std::vector IdentifiedStructTypes; StructType *createIdentifiedStructType(LLVMContext &Context, StringRef Name); @@ -340,7 +352,7 @@ private: /// a corresponding error code. std::error_code parseAlignmentValue(uint64_t Exponent, unsigned &Alignment); std::error_code ParseAttrKind(uint64_t Code, Attribute::AttrKind *Kind); - std::error_code ParseModule(bool Resume); + std::error_code ParseModule(bool Resume, bool ShouldLazyLoadMetadata = false); std::error_code ParseAttributeBlock(); std::error_code ParseAttributeGroupBlock(); std::error_code ParseTypeTable(); @@ -349,6 +361,8 @@ private: std::error_code ParseValueSymbolTable(); std::error_code ParseConstants(); std::error_code RememberAndSkipFunctionBody(); + /// Save the positions of the Metadata blocks and skip parsing the blocks. + std::error_code rememberAndSkipMetadata(); std::error_code ParseFunctionBody(Function *F); std::error_code GlobalCleanup(); std::error_code ResolveGlobalAndAliasInits(); diff --git a/llvm/lib/LTO/LTOModule.cpp b/llvm/lib/LTO/LTOModule.cpp index 087c735cd774..49aa97d532ec 100644 --- a/llvm/lib/LTO/LTOModule.cpp +++ b/llvm/lib/LTO/LTOModule.cpp @@ -179,7 +179,8 @@ static Module *parseBitcodeFileImpl(MemoryBufferRef Buffer, std::unique_ptr LightweightBuf = MemoryBuffer::getMemBuffer(*MBOrErr, false); ErrorOr M = getLazyBitcodeModule(std::move(LightweightBuf), Context, - DiagnosticHandler); + DiagnosticHandler, + true/*ShouldLazyLoadMetadata*/); if (!M) return nullptr; return *M;