Author: Tobias Stadler Date: 2025-09-15T15:29:10+01:00 New Revision: d4cc49816151da4fb8825f5ee910a1bfa679460b
URL: https://github.com/llvm/llvm-project/commit/d4cc49816151da4fb8825f5ee910a1bfa679460b DIFF: https://github.com/llvm/llvm-project/commit/d4cc49816151da4fb8825f5ee910a1bfa679460b.diff LOG: Revert "[Remarks] BitstreamRemarkParser: Refactor error handling (#156511)" This reverts commit c723cc2a041d6e7e741b0ce6abc1f18d4ada9b4a. Added: Modified: llvm/lib/Remarks/BitstreamRemarkParser.cpp llvm/lib/Remarks/BitstreamRemarkParser.h Removed: ################################################################################ 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( _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits