//===-- BitstreamRemarkParser.h - Parser for Bitstream remarks --*- C++/-*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file provides the impementation of the Bitstream remark parser. // //===----------------------------------------------------------------------===// #ifndef LLVM_LIB_REMARKS_BITSTREAM_REMARK_PARSER_H #define LLVM_LIB_REMARKS_BITSTREAM_REMARK_PARSER_H #include "llvm/ADT/StringRef.h" #include "llvm/Bitstream/BitstreamReader.h" #include "llvm/Remarks/BitstreamRemarkContainer.h" #include "llvm/Remarks/Remark.h" #include "llvm/Remarks/RemarkFormat.h" #include "llvm/Remarks/RemarkParser.h" #include "llvm/Remarks/RemarkStringTable.h" #include "llvm/Support/Error.h" #include "llvm/Support/FormatVariadic.h" #include #include #include namespace llvm { namespace remarks { class BitstreamBlockParserHelperBase { protected: BitstreamCursor &Stream; StringRef BlockName; unsigned BlockID; public: BitstreamBlockParserHelperBase(BitstreamCursor &Stream, unsigned BlockID, StringRef BlockName) : Stream(Stream), BlockName(BlockName), BlockID(BlockID) {} template Error error(char const *Fmt, const Ts &...Vals) { std::string Buffer; raw_string_ostream OS(Buffer); OS << "Error while parsing " << BlockName << " block: "; OS << formatv(Fmt, Vals...); return make_error( std::move(Buffer), std::make_error_code(std::errc::illegal_byte_sequence)); } Error expectBlock(); protected: Error enterBlock(); Error unknownRecord(unsigned AbbrevID); Error unexpectedRecord(StringRef RecordName); Error malformedRecord(StringRef RecordName); Error unexpectedBlock(unsigned Code); }; template class BitstreamBlockParserHelper : public BitstreamBlockParserHelperBase { protected: using BitstreamBlockParserHelperBase::BitstreamBlockParserHelperBase; Derived &derived() { return *static_cast(this); } /// Parse a record and fill in the fields in the parser. /// The subclass must statically override this method. Error parseRecord(unsigned Code) = delete; /// Parse a subblock and fill in the fields in the parser. /// The subclass can statically override this method. Error parseSubBlock(unsigned Code) { return unexpectedBlock(Code); } public: /// Enter, parse, and leave this bitstream block. This expects the /// BitstreamCursor to be right after the SubBlock entry (i.e. after calling /// expectBlock). Error parseBlock() { if (Error E = enterBlock()) return E; // Stop when there is nothing to read anymore or when we encounter an // END_BLOCK. while (true) { Expected Next = Stream.advance(); if (!Next) return Next.takeError(); switch (Next->Kind) { case BitstreamEntry::SubBlock: if (Error E = derived().parseSubBlock(Next->ID)) return E; continue; case BitstreamEntry::EndBlock: return Error::success(); case BitstreamEntry::Record: if (Error E = derived().parseRecord(Next->ID)) return E; continue; case BitstreamEntry::Error: return error("Unexpected end of bitstream."); } llvm_unreachable("Unexpected BitstreamEntry"); } } }; /// Helper to parse a META_BLOCK for a bitstream remark container. class BitstreamMetaParserHelper : public BitstreamBlockParserHelper { friend class BitstreamBlockParserHelper; public: struct ContainerInfo { uint64_t Version; uint64_t Type; }; /// The parsed content: depending on the container type, some fields might /// be empty. std::optional Container; std::optional RemarkVersion; std::optional ExternalFilePath; std::optional StrTabBuf; BitstreamMetaParserHelper(BitstreamCursor &Stream) : BitstreamBlockParserHelper(Stream, META_BLOCK_ID, MetaBlockName) {} protected: Error parseRecord(unsigned Code); }; /// Helper to parse a REMARK_BLOCK for a bitstream remark container. class BitstreamRemarkParserHelper : public BitstreamBlockParserHelper { friend class BitstreamBlockParserHelper; protected: SmallVector Record; StringRef RecordBlob; unsigned RecordID; public: struct RemarkLoc { uint64_t SourceFileNameIdx; uint64_t SourceLine; uint64_t SourceColumn; }; struct Argument { std::optional KeyIdx; std::optional ValueIdx; std::optional Loc; Argument(std::optional KeyIdx, std::optional ValueIdx) : KeyIdx(KeyIdx), ValueIdx(ValueIdx) {} }; /// The parsed content: depending on the remark, some fields might be empty. std::optional Type; std::optional RemarkNameIdx; std::optional PassNameIdx; std::optional FunctionNameIdx; std::optional Hotness; std::optional Loc; SmallVector Args; BitstreamRemarkParserHelper(BitstreamCursor &Stream) : BitstreamBlockParserHelper(Stream, REMARK_BLOCK_ID, RemarkBlockName) {} /// Clear helper state and parse next remark block. Error parseNext(); protected: Error parseRecord(unsigned Code); Error handleRecord(); }; /// Helper to parse any bitstream remark container. struct BitstreamParserHelper { /// The Bitstream reader. BitstreamCursor Stream; /// The block info block. BitstreamBlockInfo BlockInfo; /// Helper to parse the metadata blocks in this bitstream. BitstreamMetaParserHelper MetaHelper; /// Helper to parse the remark blocks in this bitstream. Only needed /// for ContainerType RemarksFile. std::optional RemarksHelper; /// The position of the first remark block we encounter after /// the initial metadata block. std::optional RemarkStartBitPos; /// Start parsing at \p Buffer. BitstreamParserHelper(StringRef Buffer) : Stream(Buffer), MetaHelper(Stream), RemarksHelper(Stream) {} /// Parse and validate the magic number. Error expectMagic(); /// Parse the block info block containing all the abbrevs. /// This needs to be called before calling any other parsing function. Error parseBlockInfoBlock(); /// Parse all metadata blocks in the file. This populates the meta helper. Error parseMeta(); /// Parse the next remark. This populates the remark helper data. Error parseRemark(); }; /// Parses and holds the state of the latest parsed remark. struct BitstreamRemarkParser : public RemarkParser { /// The buffer to parse. std::optional ParserHelper; /// The string table used for parsing strings. std::optional StrTab; /// Temporary remark buffer used when the remarks are stored separately. std::unique_ptr TmpRemarkBuffer; /// Whether the metadata has already been parsed, so we can continue parsing /// remarks. bool IsMetaReady = false; /// The common metadata used to decide how to parse the buffer. /// This is filled when parsing the metadata block. uint64_t ContainerVersion = 0; uint64_t RemarkVersion = 0; BitstreamRemarkContainerType ContainerType = BitstreamRemarkContainerType::RemarksFile; /// Create a parser that expects to find a string table embedded in the /// stream. explicit BitstreamRemarkParser(StringRef Buf); Expected> next() override; static bool classof(const RemarkParser *P) { return P->ParserFormat == Format::Bitstream; } /// Parse and process the metadata of the buffer. Error parseMeta(); private: Error processCommonMeta(); Error processFileContainerMeta(); Error processExternalFilePath(); Expected> processRemark(); Error processStrTab(); Error processRemarkVersion(); }; Expected> createBitstreamParserFromMeta( StringRef Buf, std::optional ExternalFilePrependPath = std::nullopt); } // end namespace remarks } // end namespace llvm #endif /* LLVM_LIB_REMARKS_BITSTREAM_REMARK_PARSER_H */