266 lines · c
1//===-- BitstreamRemarkParser.h - Parser for Bitstream remarks --*- C++/-*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file provides the impementation of the Bitstream remark parser.10//11//===----------------------------------------------------------------------===//12 13#ifndef LLVM_LIB_REMARKS_BITSTREAM_REMARK_PARSER_H14#define LLVM_LIB_REMARKS_BITSTREAM_REMARK_PARSER_H15 16#include "llvm/ADT/StringRef.h"17#include "llvm/Bitstream/BitstreamReader.h"18#include "llvm/Remarks/BitstreamRemarkContainer.h"19#include "llvm/Remarks/Remark.h"20#include "llvm/Remarks/RemarkFormat.h"21#include "llvm/Remarks/RemarkParser.h"22#include "llvm/Remarks/RemarkStringTable.h"23#include "llvm/Support/Error.h"24#include "llvm/Support/FormatVariadic.h"25#include <cstdint>26#include <memory>27#include <optional>28 29namespace llvm {30namespace remarks {31 32class BitstreamBlockParserHelperBase {33protected:34 BitstreamCursor &Stream;35 36 StringRef BlockName;37 unsigned BlockID;38 39public:40 BitstreamBlockParserHelperBase(BitstreamCursor &Stream, unsigned BlockID,41 StringRef BlockName)42 : Stream(Stream), BlockName(BlockName), BlockID(BlockID) {}43 44 template <typename... Ts> Error error(char const *Fmt, const Ts &...Vals) {45 std::string Buffer;46 raw_string_ostream OS(Buffer);47 OS << "Error while parsing " << BlockName << " block: ";48 OS << formatv(Fmt, Vals...);49 return make_error<StringError>(50 std::move(Buffer),51 std::make_error_code(std::errc::illegal_byte_sequence));52 }53 54 Error expectBlock();55 56protected:57 Error enterBlock();58 59 Error unknownRecord(unsigned AbbrevID);60 Error unexpectedRecord(StringRef RecordName);61 Error malformedRecord(StringRef RecordName);62 Error unexpectedBlock(unsigned Code);63};64 65template <typename Derived>66class BitstreamBlockParserHelper : public BitstreamBlockParserHelperBase {67protected:68 using BitstreamBlockParserHelperBase::BitstreamBlockParserHelperBase;69 Derived &derived() { return *static_cast<Derived *>(this); }70 71 /// Parse a record and fill in the fields in the parser.72 /// The subclass must statically override this method.73 Error parseRecord(unsigned Code) = delete;74 75 /// Parse a subblock and fill in the fields in the parser.76 /// The subclass can statically override this method.77 Error parseSubBlock(unsigned Code) { return unexpectedBlock(Code); }78 79public:80 /// Enter, parse, and leave this bitstream block. This expects the81 /// BitstreamCursor to be right after the SubBlock entry (i.e. after calling82 /// expectBlock).83 Error parseBlock() {84 if (Error E = enterBlock())85 return E;86 87 // Stop when there is nothing to read anymore or when we encounter an88 // END_BLOCK.89 while (true) {90 Expected<BitstreamEntry> Next = Stream.advance();91 if (!Next)92 return Next.takeError();93 switch (Next->Kind) {94 case BitstreamEntry::SubBlock:95 if (Error E = derived().parseSubBlock(Next->ID))96 return E;97 continue;98 case BitstreamEntry::EndBlock:99 return Error::success();100 case BitstreamEntry::Record:101 if (Error E = derived().parseRecord(Next->ID))102 return E;103 continue;104 case BitstreamEntry::Error:105 return error("Unexpected end of bitstream.");106 }107 llvm_unreachable("Unexpected BitstreamEntry");108 }109 }110};111 112/// Helper to parse a META_BLOCK for a bitstream remark container.113class BitstreamMetaParserHelper114 : public BitstreamBlockParserHelper<BitstreamMetaParserHelper> {115 friend class BitstreamBlockParserHelper<BitstreamMetaParserHelper>;116 117public:118 struct ContainerInfo {119 uint64_t Version;120 uint64_t Type;121 };122 123 /// The parsed content: depending on the container type, some fields might124 /// be empty.125 std::optional<ContainerInfo> Container;126 std::optional<uint64_t> RemarkVersion;127 std::optional<StringRef> ExternalFilePath;128 std::optional<StringRef> StrTabBuf;129 130 BitstreamMetaParserHelper(BitstreamCursor &Stream)131 : BitstreamBlockParserHelper(Stream, META_BLOCK_ID, MetaBlockName) {}132 133protected:134 Error parseRecord(unsigned Code);135};136 137/// Helper to parse a REMARK_BLOCK for a bitstream remark container.138class BitstreamRemarkParserHelper139 : public BitstreamBlockParserHelper<BitstreamRemarkParserHelper> {140 friend class BitstreamBlockParserHelper<BitstreamRemarkParserHelper>;141 142protected:143 SmallVector<uint64_t, 5> Record;144 StringRef RecordBlob;145 unsigned RecordID;146 147public:148 struct RemarkLoc {149 uint64_t SourceFileNameIdx;150 uint64_t SourceLine;151 uint64_t SourceColumn;152 };153 154 struct Argument {155 std::optional<uint64_t> KeyIdx;156 std::optional<uint64_t> ValueIdx;157 std::optional<RemarkLoc> Loc;158 159 Argument(std::optional<uint64_t> KeyIdx, std::optional<uint64_t> ValueIdx)160 : KeyIdx(KeyIdx), ValueIdx(ValueIdx) {}161 };162 163 /// The parsed content: depending on the remark, some fields might be empty.164 std::optional<uint8_t> Type;165 std::optional<uint64_t> RemarkNameIdx;166 std::optional<uint64_t> PassNameIdx;167 std::optional<uint64_t> FunctionNameIdx;168 std::optional<uint64_t> Hotness;169 std::optional<RemarkLoc> Loc;170 171 SmallVector<Argument, 8> Args;172 173 BitstreamRemarkParserHelper(BitstreamCursor &Stream)174 : BitstreamBlockParserHelper(Stream, REMARK_BLOCK_ID, RemarkBlockName) {}175 176 /// Clear helper state and parse next remark block.177 Error parseNext();178 179protected:180 Error parseRecord(unsigned Code);181 Error handleRecord();182};183 184/// Helper to parse any bitstream remark container.185struct BitstreamParserHelper {186 /// The Bitstream reader.187 BitstreamCursor Stream;188 /// The block info block.189 BitstreamBlockInfo BlockInfo;190 191 /// Helper to parse the metadata blocks in this bitstream.192 BitstreamMetaParserHelper MetaHelper;193 /// Helper to parse the remark blocks in this bitstream. Only needed194 /// for ContainerType RemarksFile.195 std::optional<BitstreamRemarkParserHelper> RemarksHelper;196 /// The position of the first remark block we encounter after197 /// the initial metadata block.198 std::optional<uint64_t> RemarkStartBitPos;199 200 /// Start parsing at \p Buffer.201 BitstreamParserHelper(StringRef Buffer)202 : Stream(Buffer), MetaHelper(Stream), RemarksHelper(Stream) {}203 204 /// Parse and validate the magic number.205 Error expectMagic();206 /// Parse the block info block containing all the abbrevs.207 /// This needs to be called before calling any other parsing function.208 Error parseBlockInfoBlock();209 210 /// Parse all metadata blocks in the file. This populates the meta helper.211 Error parseMeta();212 /// Parse the next remark. This populates the remark helper data.213 Error parseRemark();214};215 216/// Parses and holds the state of the latest parsed remark.217struct BitstreamRemarkParser : public RemarkParser {218 /// The buffer to parse.219 std::optional<BitstreamParserHelper> ParserHelper;220 /// The string table used for parsing strings.221 std::optional<ParsedStringTable> StrTab;222 /// Temporary remark buffer used when the remarks are stored separately.223 std::unique_ptr<MemoryBuffer> TmpRemarkBuffer;224 /// Whether the metadata has already been parsed, so we can continue parsing225 /// remarks.226 bool IsMetaReady = false;227 /// The common metadata used to decide how to parse the buffer.228 /// This is filled when parsing the metadata block.229 uint64_t ContainerVersion = 0;230 uint64_t RemarkVersion = 0;231 BitstreamRemarkContainerType ContainerType =232 BitstreamRemarkContainerType::RemarksFile;233 234 /// Create a parser that expects to find a string table embedded in the235 /// stream.236 explicit BitstreamRemarkParser(StringRef Buf);237 238 Expected<std::unique_ptr<Remark>> next() override;239 240 static bool classof(const RemarkParser *P) {241 return P->ParserFormat == Format::Bitstream;242 }243 244 /// Parse and process the metadata of the buffer.245 Error parseMeta();246 247private:248 Error processCommonMeta();249 Error processFileContainerMeta();250 Error processExternalFilePath();251 252 Expected<std::unique_ptr<Remark>> processRemark();253 254 Error processStrTab();255 Error processRemarkVersion();256};257 258Expected<std::unique_ptr<BitstreamRemarkParser>> createBitstreamParserFromMeta(259 StringRef Buf,260 std::optional<StringRef> ExternalFilePrependPath = std::nullopt);261 262} // end namespace remarks263} // end namespace llvm264 265#endif /* LLVM_LIB_REMARKS_BITSTREAM_REMARK_PARSER_H */266