[llvm] Revert "[Remarks] BitstreamRemarkParser: Refactor error handling" (PR #158647)
Tobias Stadler via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 15 07:30:22 PDT 2025
https://github.com/tobias-stadler created https://github.com/llvm/llvm-project/pull/158647
Reverts llvm/llvm-project#156511. Build failure not caught by pre-commit CI.
>From d4cc49816151da4fb8825f5ee910a1bfa679460b Mon Sep 17 00:00:00 2001
From: Tobias Stadler <mail at stadler-tobias.de>
Date: Mon, 15 Sep 2025 15:29:10 +0100
Subject: [PATCH] Revert "[Remarks] BitstreamRemarkParser: Refactor error
handling (#156511)"
This reverts commit c723cc2a041d6e7e741b0ce6abc1f18d4ada9b4a.
---
llvm/lib/Remarks/BitstreamRemarkParser.cpp | 502 +++++++++++++--------
llvm/lib/Remarks/BitstreamRemarkParser.h | 207 +++------
2 files changed, 365 insertions(+), 344 deletions(-)
diff --git a/llvm/lib/Remarks/BitstreamRemarkParser.cpp b/llvm/lib/Remarks/BitstreamRemarkParser.cpp
index d40b40dfb2ba0..86a6c6dffb187 100644
--- a/llvm/lib/Remarks/BitstreamRemarkParser.cpp
+++ b/llvm/lib/Remarks/BitstreamRemarkParser.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "BitstreamRemarkParser.h"
+#include "llvm/Remarks/Remark.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Path.h"
#include <optional>
@@ -19,68 +20,27 @@
using namespace llvm;
using namespace llvm::remarks;
-namespace {
-
-template <typename... Ts> Error error(char const *Fmt, const Ts &...Vals) {
- std::string Buffer;
- raw_string_ostream OS(Buffer);
- OS << formatv(Fmt, Vals...);
- return make_error<StringError>(
- std::move(Buffer),
- std::make_error_code(std::errc::illegal_byte_sequence));
-}
-
-} // namespace
-
-Error BitstreamBlockParserHelperBase::unknownRecord(unsigned AbbrevID) {
- return error("Unknown record entry ({}).", AbbrevID);
-}
-
-Error BitstreamBlockParserHelperBase::unexpectedRecord(StringRef RecordName) {
- return error("Unexpected record entry ({}).", RecordName);
-}
-
-Error BitstreamBlockParserHelperBase::malformedRecord(StringRef RecordName) {
- return error("Malformed record entry ({}).", RecordName);
-}
-
-Error BitstreamBlockParserHelperBase::unexpectedBlock(unsigned Code) {
- return error("Unexpected subblock ({}).", Code);
+static Error unknownRecord(const char *BlockName, unsigned RecordID) {
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing %s: unknown record entry (%lu).", BlockName,
+ RecordID);
}
-static Expected<unsigned> expectSubBlock(BitstreamCursor &Stream) {
- Expected<BitstreamEntry> Next = Stream.advance();
- if (!Next)
- return Next.takeError();
- switch (Next->Kind) {
- case BitstreamEntry::SubBlock:
- return Next->ID;
- case BitstreamEntry::Record:
- case BitstreamEntry::EndBlock:
- return error("Expected subblock, but got unexpected record.");
- case BitstreamEntry::Error:
- return error("Expected subblock, but got unexpected end of bitstream.");
- }
- llvm_unreachable("Unexpected BitstreamEntry");
+static Error malformedRecord(const char *BlockName, const char *RecordName) {
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing %s: malformed record entry (%s).", BlockName,
+ RecordName);
}
-Error BitstreamBlockParserHelperBase::expectBlock() {
- auto MaybeBlockID = expectSubBlock(Stream);
- if (!MaybeBlockID)
- return MaybeBlockID.takeError();
- if (*MaybeBlockID != BlockID)
- return error("Expected {} block, but got unexpected block ({}).", BlockName,
- *MaybeBlockID);
- return Error::success();
-}
+BitstreamMetaParserHelper::BitstreamMetaParserHelper(
+ BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo)
+ : Stream(Stream), BlockInfo(BlockInfo) {}
-Error BitstreamBlockParserHelperBase::enterBlock() {
- if (Stream.EnterSubBlock(BlockID))
- return error("Error while entering {} block.", BlockName);
- return Error::success();
-}
-
-Error BitstreamMetaParserHelper::parseRecord(unsigned Code) {
+/// Parse a record and fill in the fields in the parser.
+static Error parseRecord(BitstreamMetaParserHelper &Parser, unsigned Code) {
+ BitstreamCursor &Stream = Parser.Stream;
// Note: 2 is used here because it's the max number of fields we have per
// record.
SmallVector<uint64_t, 2> Record;
@@ -92,132 +52,171 @@ Error BitstreamMetaParserHelper::parseRecord(unsigned Code) {
switch (*RecordID) {
case RECORD_META_CONTAINER_INFO: {
if (Record.size() != 2)
- return malformedRecord(MetaContainerInfoName);
- Container = {Record[0], Record[1]};
- // Error immediately if container version is outdated, so the user sees an
- // explanation instead of a parser error.
- if (Container->Version != CurrentContainerVersion) {
- return ::error(
- "Unsupported remark container version (expected: {}, read: {}). "
- "Please upgrade/downgrade your toolchain to read this container.",
- CurrentContainerVersion, Container->Version);
- }
+ return malformedRecord("BLOCK_META", "RECORD_META_CONTAINER_INFO");
+ Parser.ContainerVersion = Record[0];
+ Parser.ContainerType = Record[1];
break;
}
case RECORD_META_REMARK_VERSION: {
if (Record.size() != 1)
- return malformedRecord(MetaRemarkVersionName);
- RemarkVersion = Record[0];
- // Error immediately if remark version is outdated, so the user sees an
- // explanation instead of a parser error.
- if (*RemarkVersion != CurrentRemarkVersion) {
- return ::error(
- "Unsupported remark version in container (expected: {}, read: {}). "
- "Please upgrade/downgrade your toolchain to read this container.",
- CurrentRemarkVersion, *RemarkVersion);
- }
+ return malformedRecord("BLOCK_META", "RECORD_META_REMARK_VERSION");
+ Parser.RemarkVersion = Record[0];
break;
}
case RECORD_META_STRTAB: {
if (Record.size() != 0)
- return malformedRecord(MetaStrTabName);
- StrTabBuf = Blob;
+ return malformedRecord("BLOCK_META", "RECORD_META_STRTAB");
+ Parser.StrTabBuf = Blob;
break;
}
case RECORD_META_EXTERNAL_FILE: {
if (Record.size() != 0)
- return malformedRecord(MetaExternalFileName);
- ExternalFilePath = Blob;
+ return malformedRecord("BLOCK_META", "RECORD_META_EXTERNAL_FILE");
+ Parser.ExternalFilePath = Blob;
break;
}
default:
- return unknownRecord(*RecordID);
+ return unknownRecord("BLOCK_META", *RecordID);
}
return Error::success();
}
-Error BitstreamRemarkParserHelper::parseRecord(unsigned Code) {
- Record.clear();
- Expected<unsigned> MaybeRecordID =
- Stream.readRecord(Code, Record, &RecordBlob);
- if (!MaybeRecordID)
- return MaybeRecordID.takeError();
- RecordID = *MaybeRecordID;
- return handleRecord();
-}
+BitstreamRemarkParserHelper::BitstreamRemarkParserHelper(
+ BitstreamCursor &Stream)
+ : Stream(Stream) {}
-Error BitstreamRemarkParserHelper::handleRecord() {
- switch (RecordID) {
+/// Parse a record and fill in the fields in the parser.
+static Error parseRecord(BitstreamRemarkParserHelper &Parser, unsigned Code) {
+ BitstreamCursor &Stream = Parser.Stream;
+ // Note: 5 is used here because it's the max number of fields we have per
+ // record.
+ SmallVector<uint64_t, 5> Record;
+ StringRef Blob;
+ Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob);
+ if (!RecordID)
+ return RecordID.takeError();
+
+ switch (*RecordID) {
case RECORD_REMARK_HEADER: {
if (Record.size() != 4)
- return malformedRecord(RemarkHeaderName);
- Type = Record[0];
- RemarkNameIdx = Record[1];
- PassNameIdx = Record[2];
- FunctionNameIdx = Record[3];
+ return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HEADER");
+ Parser.Type = Record[0];
+ Parser.RemarkNameIdx = Record[1];
+ Parser.PassNameIdx = Record[2];
+ Parser.FunctionNameIdx = Record[3];
break;
}
case RECORD_REMARK_DEBUG_LOC: {
if (Record.size() != 3)
- return malformedRecord(RemarkDebugLocName);
- Loc = {Record[0], Record[1], Record[2]};
+ return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_DEBUG_LOC");
+ Parser.SourceFileNameIdx = Record[0];
+ Parser.SourceLine = Record[1];
+ Parser.SourceColumn = Record[2];
break;
}
case RECORD_REMARK_HOTNESS: {
if (Record.size() != 1)
- return malformedRecord(RemarkHotnessName);
- Hotness = Record[0];
+ return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HOTNESS");
+ Parser.Hotness = Record[0];
break;
}
case RECORD_REMARK_ARG_WITH_DEBUGLOC: {
if (Record.size() != 5)
- return malformedRecord(RemarkArgWithDebugLocName);
- auto &Arg = Args.emplace_back(Record[0], Record[1]);
- Arg.Loc = {Record[2], Record[3], Record[4]};
+ return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_ARG_WITH_DEBUGLOC");
+ // Create a temporary argument. Use that as a valid memory location for this
+ // argument entry.
+ Parser.TmpArgs.emplace_back();
+ Parser.TmpArgs.back().KeyIdx = Record[0];
+ Parser.TmpArgs.back().ValueIdx = Record[1];
+ Parser.TmpArgs.back().SourceFileNameIdx = Record[2];
+ Parser.TmpArgs.back().SourceLine = Record[3];
+ Parser.TmpArgs.back().SourceColumn = Record[4];
+ Parser.Args =
+ ArrayRef<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs);
break;
}
case RECORD_REMARK_ARG_WITHOUT_DEBUGLOC: {
if (Record.size() != 2)
- return malformedRecord(RemarkArgWithoutDebugLocName);
- Args.emplace_back(Record[0], Record[1]);
+ return malformedRecord("BLOCK_REMARK",
+ "RECORD_REMARK_ARG_WITHOUT_DEBUGLOC");
+ // Create a temporary argument. Use that as a valid memory location for this
+ // argument entry.
+ Parser.TmpArgs.emplace_back();
+ Parser.TmpArgs.back().KeyIdx = Record[0];
+ Parser.TmpArgs.back().ValueIdx = Record[1];
+ Parser.Args =
+ ArrayRef<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs);
break;
}
default:
- return unknownRecord(RecordID);
+ return unknownRecord("BLOCK_REMARK", *RecordID);
}
return Error::success();
}
-Error BitstreamRemarkParserHelper::parseNext() {
- Type.reset();
- RemarkNameIdx.reset();
- PassNameIdx.reset();
- FunctionNameIdx.reset();
- Hotness.reset();
- Loc.reset();
- Args.clear();
+template <typename T>
+static Error parseBlock(T &ParserHelper, unsigned BlockID,
+ const char *BlockName) {
+ BitstreamCursor &Stream = ParserHelper.Stream;
+ Expected<BitstreamEntry> Next = Stream.advance();
+ if (!Next)
+ return Next.takeError();
+ if (Next->Kind != BitstreamEntry::SubBlock || Next->ID != BlockID)
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing %s: expecting [ENTER_SUBBLOCK, %s, ...].",
+ BlockName, BlockName);
+ if (Stream.EnterSubBlock(BlockID))
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while entering %s.", BlockName);
+
+ // Stop when there is nothing to read anymore or when we encounter an
+ // END_BLOCK.
+ while (!Stream.AtEndOfStream()) {
+ Next = Stream.advance();
+ if (!Next)
+ return Next.takeError();
+ switch (Next->Kind) {
+ case BitstreamEntry::EndBlock:
+ return Error::success();
+ case BitstreamEntry::Error:
+ case BitstreamEntry::SubBlock:
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing %s: expecting records.", BlockName);
+ case BitstreamEntry::Record:
+ if (Error E = parseRecord(ParserHelper, Next->ID))
+ return E;
+ continue;
+ }
+ }
+ // If we're here, it means we didn't get an END_BLOCK yet, but we're at the
+ // end of the stream. In this case, error.
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing %s: unterminated block.", BlockName);
+}
+
+Error BitstreamMetaParserHelper::parse() {
+ return parseBlock(*this, META_BLOCK_ID, "META_BLOCK");
+}
- if (Error E = expectBlock())
- return E;
- return parseBlock();
+Error BitstreamRemarkParserHelper::parse() {
+ return parseBlock(*this, REMARK_BLOCK_ID, "REMARK_BLOCK");
}
BitstreamParserHelper::BitstreamParserHelper(StringRef Buffer)
: Stream(Buffer) {}
-Error BitstreamParserHelper::expectMagic() {
+Expected<std::array<char, 4>> BitstreamParserHelper::parseMagic() {
std::array<char, 4> Result;
- for (unsigned I = 0; I < 4; ++I)
+ for (unsigned i = 0; i < 4; ++i)
if (Expected<unsigned> R = Stream.Read(8))
- Result[I] = *R;
+ Result[i] = *R;
else
return R.takeError();
-
- StringRef MagicNumber{Result.data(), Result.size()};
- if (MagicNumber != remarks::ContainerMagic)
- return error("Unknown magic number: expecting {}, got {}.",
- remarks::ContainerMagic, MagicNumber);
- return Error::success();
+ return Result;
}
Error BitstreamParserHelper::parseBlockInfoBlock() {
@@ -226,7 +225,8 @@ Error BitstreamParserHelper::parseBlockInfoBlock() {
return Next.takeError();
if (Next->Kind != BitstreamEntry::SubBlock ||
Next->ID != llvm::bitc::BLOCKINFO_BLOCK_ID)
- return error(
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
"Error while parsing BLOCKINFO_BLOCK: expecting [ENTER_SUBBLOCK, "
"BLOCKINFO_BLOCK, ...].");
@@ -236,7 +236,9 @@ Error BitstreamParserHelper::parseBlockInfoBlock() {
return MaybeBlockInfo.takeError();
if (!*MaybeBlockInfo)
- return error("Missing BLOCKINFO_BLOCK.");
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCKINFO_BLOCK.");
BlockInfo = **MaybeBlockInfo;
@@ -244,17 +246,77 @@ Error BitstreamParserHelper::parseBlockInfoBlock() {
return Error::success();
}
-Error BitstreamParserHelper::advanceToMetaBlock() {
- if (Error E = expectMagic())
+static Expected<bool> isBlock(BitstreamCursor &Stream, unsigned BlockID) {
+ bool Result = false;
+ uint64_t PreviousBitNo = Stream.GetCurrentBitNo();
+ Expected<BitstreamEntry> Next = Stream.advance();
+ if (!Next)
+ return Next.takeError();
+ switch (Next->Kind) {
+ case BitstreamEntry::SubBlock:
+ // Check for the block id.
+ Result = Next->ID == BlockID;
+ break;
+ case BitstreamEntry::Error:
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Unexpected error while parsing bitstream.");
+ default:
+ Result = false;
+ break;
+ }
+ if (Error E = Stream.JumpToBit(PreviousBitNo))
+ return std::move(E);
+ return Result;
+}
+
+Expected<bool> BitstreamParserHelper::isMetaBlock() {
+ return isBlock(Stream, META_BLOCK_ID);
+}
+
+Expected<bool> BitstreamParserHelper::isRemarkBlock() {
+ return isBlock(Stream, META_BLOCK_ID);
+}
+
+static Error validateMagicNumber(StringRef MagicNumber) {
+ if (MagicNumber != remarks::ContainerMagic)
+ return createStringError(std::make_error_code(std::errc::invalid_argument),
+ "Unknown magic number: expecting %s, got %.4s.",
+ remarks::ContainerMagic.data(), MagicNumber.data());
+ return Error::success();
+}
+
+static Error advanceToMetaBlock(BitstreamParserHelper &Helper) {
+ Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic();
+ if (!MagicNumber)
+ return MagicNumber.takeError();
+ if (Error E = validateMagicNumber(
+ StringRef(MagicNumber->data(), MagicNumber->size())))
return E;
- if (Error E = parseBlockInfoBlock())
+ if (Error E = Helper.parseBlockInfoBlock())
return E;
+ Expected<bool> isMetaBlock = Helper.isMetaBlock();
+ if (!isMetaBlock)
+ return isMetaBlock.takeError();
+ if (!*isMetaBlock)
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Expecting META_BLOCK after the BLOCKINFO_BLOCK.");
return Error::success();
}
Expected<std::unique_ptr<BitstreamRemarkParser>>
remarks::createBitstreamParserFromMeta(
StringRef Buf, std::optional<StringRef> ExternalFilePrependPath) {
+ BitstreamParserHelper Helper(Buf);
+ Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic();
+ if (!MagicNumber)
+ return MagicNumber.takeError();
+
+ if (Error E = validateMagicNumber(
+ StringRef(MagicNumber->data(), MagicNumber->size())))
+ return std::move(E);
+
auto Parser = std::make_unique<BitstreamRemarkParser>(Buf);
if (ExternalFilePrependPath)
@@ -277,13 +339,13 @@ Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() {
}
Error BitstreamRemarkParser::parseMeta() {
- if (Error E = ParserHelper.advanceToMetaBlock())
+ // Advance and to the meta block.
+ if (Error E = advanceToMetaBlock(ParserHelper))
return E;
- BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream);
- if (Error E = MetaHelper.expectBlock())
- return E;
- if (Error E = MetaHelper.parseBlock())
+ BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream,
+ ParserHelper.BlockInfo);
+ if (Error E = MetaHelper.parse())
return E;
if (Error E = processCommonMeta(MetaHelper))
@@ -302,41 +364,59 @@ Error BitstreamRemarkParser::parseMeta() {
Error BitstreamRemarkParser::processCommonMeta(
BitstreamMetaParserHelper &Helper) {
- if (!Helper.Container)
- return Helper.error("Missing container info.");
- auto &Container = *Helper.Container;
- ContainerVersion = Container.Version;
- // Always >= BitstreamRemarkContainerType::First since it's unsigned.
- if (Container.Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last))
- return Helper.error("Invalid container type.");
- ContainerType = static_cast<BitstreamRemarkContainerType>(Container.Type);
+ if (std::optional<uint64_t> Version = Helper.ContainerVersion)
+ ContainerVersion = *Version;
+ else
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_META: missing container version.");
+
+ if (std::optional<uint8_t> Type = Helper.ContainerType) {
+ // Always >= BitstreamRemarkContainerType::First since it's unsigned.
+ if (*Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last))
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_META: invalid container type.");
+
+ ContainerType = static_cast<BitstreamRemarkContainerType>(*Type);
+ } else
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_META: missing container type.");
+
return Error::success();
}
-Error BitstreamRemarkParser::processStrTab(BitstreamMetaParserHelper &Helper) {
- if (!Helper.StrTabBuf)
- return Helper.error("Missing string table.");
+static Error processStrTab(BitstreamRemarkParser &P,
+ std::optional<StringRef> StrTabBuf) {
+ if (!StrTabBuf)
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_META: missing string table.");
// Parse and assign the string table.
- StrTab.emplace(*Helper.StrTabBuf);
+ P.StrTab.emplace(*StrTabBuf);
return Error::success();
}
-Error BitstreamRemarkParser::processRemarkVersion(
- BitstreamMetaParserHelper &Helper) {
- if (!Helper.RemarkVersion)
- return Helper.error("Missing remark version.");
- RemarkVersion = *Helper.RemarkVersion;
+static Error processRemarkVersion(BitstreamRemarkParser &P,
+ std::optional<uint64_t> RemarkVersion) {
+ if (!RemarkVersion)
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_META: missing remark version.");
+ P.RemarkVersion = *RemarkVersion;
return Error::success();
}
Error BitstreamRemarkParser::processExternalFilePath(
- BitstreamMetaParserHelper &Helper) {
- if (!Helper.ExternalFilePath)
- return Helper.error("Missing external file path.");
- StringRef ExternalFilePath = *Helper.ExternalFilePath;
+ std::optional<StringRef> ExternalFilePath) {
+ if (!ExternalFilePath)
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_META: missing external file path.");
SmallString<80> FullPath(ExternalFilePrependPath);
- sys::path::append(FullPath, ExternalFilePath);
+ sys::path::append(FullPath, *ExternalFilePath);
// External file: open the external file, parse it, check if its metadata
// matches the one from the separate metadata, then replace the current parser
@@ -355,22 +435,32 @@ Error BitstreamRemarkParser::processExternalFilePath(
// Create a separate parser used for parsing the separate file.
ParserHelper = BitstreamParserHelper(TmpRemarkBuffer->getBuffer());
// Advance and check until we can parse the meta block.
- if (Error E = ParserHelper.advanceToMetaBlock())
+ if (Error E = advanceToMetaBlock(ParserHelper))
return E;
// Parse the meta from the separate file.
// Note: here we overwrite the BlockInfo with the one from the file. This will
// be used to parse the rest of the file.
- BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream);
- if (Error E = SeparateMetaHelper.expectBlock())
- return E;
- if (Error E = SeparateMetaHelper.parseBlock())
+ BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream,
+ ParserHelper.BlockInfo);
+ if (Error E = SeparateMetaHelper.parse())
return E;
+ uint64_t PreviousContainerVersion = ContainerVersion;
if (Error E = processCommonMeta(SeparateMetaHelper))
return E;
if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile)
- return SeparateMetaHelper.error("Wrong container type in external file.");
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing external file's BLOCK_META: wrong container "
+ "type.");
+
+ if (PreviousContainerVersion != ContainerVersion)
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing external file's BLOCK_META: mismatching versions: "
+ "original meta: %lu, external file meta: %lu.",
+ PreviousContainerVersion, ContainerVersion);
// Process the meta from the separate file.
return processSeparateRemarksFileMeta(SeparateMetaHelper);
@@ -378,26 +468,26 @@ Error BitstreamRemarkParser::processExternalFilePath(
Error BitstreamRemarkParser::processStandaloneMeta(
BitstreamMetaParserHelper &Helper) {
- if (Error E = processStrTab(Helper))
+ if (Error E = processStrTab(*this, Helper.StrTabBuf))
return E;
- return processRemarkVersion(Helper);
+ return processRemarkVersion(*this, Helper.RemarkVersion);
}
Error BitstreamRemarkParser::processSeparateRemarksFileMeta(
BitstreamMetaParserHelper &Helper) {
- return processRemarkVersion(Helper);
+ return processRemarkVersion(*this, Helper.RemarkVersion);
}
Error BitstreamRemarkParser::processSeparateRemarksMetaMeta(
BitstreamMetaParserHelper &Helper) {
- if (Error E = processStrTab(Helper))
+ if (Error E = processStrTab(*this, Helper.StrTabBuf))
return E;
- return processExternalFilePath(Helper);
+ return processExternalFilePath(Helper.ExternalFilePath);
}
Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::parseRemark() {
BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream);
- if (Error E = RemarkHelper.parseNext())
+ if (Error E = RemarkHelper.parse())
return std::move(E);
return processRemark(RemarkHelper);
@@ -408,20 +498,28 @@ BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) {
std::unique_ptr<Remark> Result = std::make_unique<Remark>();
Remark &R = *Result;
- if (!StrTab)
- return Helper.error("Missing string table.");
+ if (StrTab == std::nullopt)
+ return createStringError(
+ std::make_error_code(std::errc::invalid_argument),
+ "Error while parsing BLOCK_REMARK: missing string table.");
if (!Helper.Type)
- return Helper.error("Missing remark type.");
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_REMARK: missing remark type.");
// Always >= Type::First since it's unsigned.
if (*Helper.Type > static_cast<uint8_t>(Type::Last))
- return Helper.error("Unknown remark type.");
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_REMARK: unknown remark type.");
R.RemarkType = static_cast<Type>(*Helper.Type);
if (!Helper.RemarkNameIdx)
- return Helper.error("Missing remark name.");
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_REMARK: missing remark name.");
if (Expected<StringRef> RemarkName = (*StrTab)[*Helper.RemarkNameIdx])
R.RemarkName = *RemarkName;
@@ -429,7 +527,9 @@ BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) {
return RemarkName.takeError();
if (!Helper.PassNameIdx)
- return Helper.error("Missing remark pass.");
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_REMARK: missing remark pass.");
if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx])
R.PassName = *PassName;
@@ -437,53 +537,61 @@ BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) {
return PassName.takeError();
if (!Helper.FunctionNameIdx)
- return Helper.error("Missing remark function name.");
-
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_REMARK: missing remark function name.");
if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx])
R.FunctionName = *FunctionName;
else
return FunctionName.takeError();
- if (Helper.Loc) {
- Expected<StringRef> SourceFileName =
- (*StrTab)[Helper.Loc->SourceFileNameIdx];
+ if (Helper.SourceFileNameIdx && Helper.SourceLine && Helper.SourceColumn) {
+ Expected<StringRef> SourceFileName = (*StrTab)[*Helper.SourceFileNameIdx];
if (!SourceFileName)
return SourceFileName.takeError();
R.Loc.emplace();
R.Loc->SourceFilePath = *SourceFileName;
- R.Loc->SourceLine = Helper.Loc->SourceLine;
- R.Loc->SourceColumn = Helper.Loc->SourceColumn;
+ R.Loc->SourceLine = *Helper.SourceLine;
+ R.Loc->SourceColumn = *Helper.SourceColumn;
}
if (Helper.Hotness)
R.Hotness = *Helper.Hotness;
- for (const BitstreamRemarkParserHelper::Argument &Arg : Helper.Args) {
+ if (!Helper.Args)
+ return std::move(Result);
+
+ for (const BitstreamRemarkParserHelper::Argument &Arg : *Helper.Args) {
if (!Arg.KeyIdx)
- return Helper.error("Missing key in remark argument.");
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_REMARK: missing key in remark argument.");
if (!Arg.ValueIdx)
- return Helper.error("Missing value in remark argument.");
+ return createStringError(
+ std::make_error_code(std::errc::illegal_byte_sequence),
+ "Error while parsing BLOCK_REMARK: missing value in remark "
+ "argument.");
// We have at least a key and a value, create an entry.
- auto &RArg = R.Args.emplace_back();
+ R.Args.emplace_back();
if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx])
- RArg.Key = *Key;
+ R.Args.back().Key = *Key;
else
return Key.takeError();
if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx])
- RArg.Val = *Value;
+ R.Args.back().Val = *Value;
else
return Value.takeError();
- if (Arg.Loc) {
+ if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) {
if (Expected<StringRef> SourceFileName =
- (*StrTab)[Arg.Loc->SourceFileNameIdx]) {
- RArg.Loc.emplace();
- RArg.Loc->SourceFilePath = *SourceFileName;
- RArg.Loc->SourceLine = Arg.Loc->SourceLine;
- RArg.Loc->SourceColumn = Arg.Loc->SourceColumn;
+ (*StrTab)[*Arg.SourceFileNameIdx]) {
+ R.Args.back().Loc.emplace();
+ R.Args.back().Loc->SourceFilePath = *SourceFileName;
+ R.Args.back().Loc->SourceLine = *Arg.SourceLine;
+ R.Args.back().Loc->SourceColumn = *Arg.SourceColumn;
} else
return SourceFileName.takeError();
}
diff --git a/llvm/lib/Remarks/BitstreamRemarkParser.h b/llvm/lib/Remarks/BitstreamRemarkParser.h
index 257ac46eb9495..cba805dc24b59 100644
--- a/llvm/lib/Remarks/BitstreamRemarkParser.h
+++ b/llvm/lib/Remarks/BitstreamRemarkParser.h
@@ -13,15 +13,14 @@
#ifndef LLVM_LIB_REMARKS_BITSTREAM_REMARK_PARSER_H
#define LLVM_LIB_REMARKS_BITSTREAM_REMARK_PARSER_H
+#include "llvm/ADT/ArrayRef.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 <array>
#include <cstdint>
#include <memory>
#include <optional>
@@ -29,156 +28,66 @@
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 can statically override this method.
- Error parseRecord(unsigned Code) { return unexpectedRecord(Code); }
-
- /// 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");
- }
- }
-};
+struct Remark;
/// Helper to parse a META_BLOCK for a bitstream remark container.
-class BitstreamMetaParserHelper
- : public BitstreamBlockParserHelper<BitstreamMetaParserHelper> {
- 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<ContainerInfo> Container;
- std::optional<uint64_t> RemarkVersion;
- std::optional<StringRef> ExternalFilePath;
+struct BitstreamMetaParserHelper {
+ /// The Bitstream reader.
+ BitstreamCursor &Stream;
+ /// Reference to the storage for the block info.
+ BitstreamBlockInfo &BlockInfo;
+ /// The parsed content: depending on the container type, some fields might be
+ /// empty.
+ std::optional<uint64_t> ContainerVersion;
+ std::optional<uint8_t> ContainerType;
std::optional<StringRef> StrTabBuf;
+ std::optional<StringRef> ExternalFilePath;
+ std::optional<uint64_t> RemarkVersion;
- BitstreamMetaParserHelper(BitstreamCursor &Stream)
- : BitstreamBlockParserHelper(Stream, META_BLOCK_ID, MetaBlockName) {}
+ /// Continue parsing with \p Stream. \p Stream is expected to contain a
+ /// ENTER_SUBBLOCK to the META_BLOCK at the current position.
+ /// \p Stream is expected to have a BLOCKINFO_BLOCK set.
+ BitstreamMetaParserHelper(BitstreamCursor &Stream,
+ BitstreamBlockInfo &BlockInfo);
-protected:
- Error parseRecord(unsigned Code);
+ /// Parse the META_BLOCK and fill the available entries.
+ /// This helper does not check for the validity of the fields.
+ Error parse();
};
/// Helper to parse a REMARK_BLOCK for a bitstream remark container.
-class BitstreamRemarkParserHelper
- : public BitstreamBlockParserHelper<BitstreamRemarkParserHelper> {
- friend class BitstreamBlockParserHelper;
-
-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) {}
- };
-
+struct BitstreamRemarkParserHelper {
+ /// The Bitstream reader.
+ BitstreamCursor &Stream;
/// 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> SourceFileNameIdx;
+ std::optional<uint32_t> SourceLine;
+ std::optional<uint32_t> SourceColumn;
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();
+ struct Argument {
+ std::optional<uint64_t> KeyIdx;
+ std::optional<uint64_t> ValueIdx;
+ std::optional<uint64_t> SourceFileNameIdx;
+ std::optional<uint32_t> SourceLine;
+ std::optional<uint32_t> SourceColumn;
+ };
+ std::optional<ArrayRef<Argument>> Args;
+ /// Avoid re-allocating a vector every time.
+ SmallVector<Argument, 8> TmpArgs;
+
+ /// Continue parsing with \p Stream. \p Stream is expected to contain a
+ /// ENTER_SUBBLOCK to the REMARK_BLOCK at the current position.
+ /// \p Stream is expected to have a BLOCKINFO_BLOCK set and to have already
+ /// parsed the META_BLOCK.
+ BitstreamRemarkParserHelper(BitstreamCursor &Stream);
+
+ /// Parse the REMARK_BLOCK and fill the available entries.
+ /// This helper does not check for the validity of the fields.
+ Error parse();
};
/// Helper to parse any bitstream remark container.
@@ -189,15 +98,21 @@ struct BitstreamParserHelper {
BitstreamBlockInfo BlockInfo;
/// Start parsing at \p Buffer.
BitstreamParserHelper(StringRef Buffer);
- /// Parse and validate the magic number.
- Error expectMagic();
- /// Advance to the meta block
- Error advanceToMetaBlock();
+ /// Parse the magic number.
+ Expected<std::array<char, 4>> parseMagic();
/// Parse the block info block containing all the abbrevs.
/// This needs to be called before calling any other parsing function.
Error parseBlockInfoBlock();
+ /// Return true if the next block is a META_BLOCK. This function does not move
+ /// the cursor.
+ Expected<bool> isMetaBlock();
+ /// Return true if the next block is a REMARK_BLOCK. This function does not
+ /// move the cursor.
+ Expected<bool> isRemarkBlock();
/// Return true if the parser reached the end of the stream.
bool atEndOfStream() { return Stream.AtEndOfStream(); }
+ /// Jump to the end of the stream, skipping everything.
+ void skipToEnd() { return Stream.skipToEnd(); }
};
/// Parses and holds the state of the latest parsed remark.
@@ -234,16 +149,14 @@ struct BitstreamRemarkParser : public RemarkParser {
Expected<std::unique_ptr<Remark>> parseRemark();
private:
+ /// Helper functions.
Error processCommonMeta(BitstreamMetaParserHelper &Helper);
Error processStandaloneMeta(BitstreamMetaParserHelper &Helper);
Error processSeparateRemarksFileMeta(BitstreamMetaParserHelper &Helper);
Error processSeparateRemarksMetaMeta(BitstreamMetaParserHelper &Helper);
- Error processExternalFilePath(BitstreamMetaParserHelper &Helper);
- Error processStrTab(BitstreamMetaParserHelper &Helper);
- Error processRemarkVersion(BitstreamMetaParserHelper &Helper);
-
Expected<std::unique_ptr<Remark>>
processRemark(BitstreamRemarkParserHelper &Helper);
+ Error processExternalFilePath(std::optional<StringRef> ExternalFilePath);
};
Expected<std::unique_ptr<BitstreamRemarkParser>> createBitstreamParserFromMeta(
More information about the llvm-commits
mailing list