The following errors are seen in our builds using MSVC 2022: BitstreamRemarkParser.h(115): error C2990: 'llvm::remarks::BitstreamBlockParserHelper': non-class template has already been declared as a class template BitstreamRemarkParser.h(66): note: see declaration of 'llvm::remarks::BitstreamBlockParserHelper' This change fixes the build issue by adding an explicit template argument to the `friend class` statements. This issue is not seen if using `-std:c++20`, but we still support building as C++17.
266 lines
8.4 KiB
C++
266 lines
8.4 KiB
C++
//===-- 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 <cstdint>
|
|
#include <memory>
|
|
#include <optional>
|
|
|
|
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 <typename... Ts> 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<StringError>(
|
|
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 <typename Derived>
|
|
class BitstreamBlockParserHelper : public BitstreamBlockParserHelperBase {
|
|
protected:
|
|
using BitstreamBlockParserHelperBase::BitstreamBlockParserHelperBase;
|
|
Derived &derived() { return *static_cast<Derived *>(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<BitstreamEntry> 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<BitstreamMetaParserHelper> {
|
|
friend class BitstreamBlockParserHelper<BitstreamMetaParserHelper>;
|
|
|
|
public:
|
|
struct ContainerInfo {
|
|
uint64_t Version;
|
|
uint64_t Type;
|
|
};
|
|
|
|
/// The parsed content: depending on the container type, some fields might
|
|
/// be empty.
|
|
std::optional<ContainerInfo> Container;
|
|
std::optional<uint64_t> RemarkVersion;
|
|
std::optional<StringRef> ExternalFilePath;
|
|
std::optional<StringRef> 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<BitstreamRemarkParserHelper> {
|
|
friend class BitstreamBlockParserHelper<BitstreamRemarkParserHelper>;
|
|
|
|
protected:
|
|
SmallVector<uint64_t, 5> Record;
|
|
StringRef RecordBlob;
|
|
unsigned RecordID;
|
|
|
|
public:
|
|
struct RemarkLoc {
|
|
uint64_t SourceFileNameIdx;
|
|
uint64_t SourceLine;
|
|
uint64_t SourceColumn;
|
|
};
|
|
|
|
struct Argument {
|
|
std::optional<uint64_t> KeyIdx;
|
|
std::optional<uint64_t> ValueIdx;
|
|
std::optional<RemarkLoc> Loc;
|
|
|
|
Argument(std::optional<uint64_t> KeyIdx, std::optional<uint64_t> ValueIdx)
|
|
: KeyIdx(KeyIdx), ValueIdx(ValueIdx) {}
|
|
};
|
|
|
|
/// The parsed content: depending on the remark, some fields might be empty.
|
|
std::optional<uint8_t> Type;
|
|
std::optional<uint64_t> RemarkNameIdx;
|
|
std::optional<uint64_t> PassNameIdx;
|
|
std::optional<uint64_t> FunctionNameIdx;
|
|
std::optional<uint64_t> Hotness;
|
|
std::optional<RemarkLoc> Loc;
|
|
|
|
SmallVector<Argument, 8> 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<BitstreamRemarkParserHelper> RemarksHelper;
|
|
/// The position of the first remark block we encounter after
|
|
/// the initial metadata block.
|
|
std::optional<uint64_t> 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<BitstreamParserHelper> ParserHelper;
|
|
/// The string table used for parsing strings.
|
|
std::optional<ParsedStringTable> StrTab;
|
|
/// Temporary remark buffer used when the remarks are stored separately.
|
|
std::unique_ptr<MemoryBuffer> 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<std::unique_ptr<Remark>> 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<std::unique_ptr<Remark>> processRemark();
|
|
|
|
Error processStrTab();
|
|
Error processRemarkVersion();
|
|
};
|
|
|
|
Expected<std::unique_ptr<BitstreamRemarkParser>> createBitstreamParserFromMeta(
|
|
StringRef Buf,
|
|
std::optional<StringRef> ExternalFilePrependPath = std::nullopt);
|
|
|
|
} // end namespace remarks
|
|
} // end namespace llvm
|
|
|
|
#endif /* LLVM_LIB_REMARKS_BITSTREAM_REMARK_PARSER_H */
|