From 4d4b49d662f328e052d8349a13c8ceecac24ab57 Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Wed, 3 Sep 2025 18:02:25 +0100 Subject: [PATCH 1/5] [spr] changes to main this commit is based on Created using spr 1.3.7-wip [skip ci] --- .../llvm/Remarks/BitstreamRemarkContainer.h | 24 +- .../llvm/Remarks/BitstreamRemarkParser.h | 116 ---- llvm/lib/Remarks/BitstreamRemarkParser.cpp | 513 +++++++----------- llvm/lib/Remarks/BitstreamRemarkParser.h | 174 +++++- 4 files changed, 391 insertions(+), 436 deletions(-) delete mode 100644 llvm/include/llvm/Remarks/BitstreamRemarkParser.h diff --git a/llvm/include/llvm/Remarks/BitstreamRemarkContainer.h b/llvm/include/llvm/Remarks/BitstreamRemarkContainer.h index cc4df5845b67c..48a148a3adc13 100644 --- a/llvm/include/llvm/Remarks/BitstreamRemarkContainer.h +++ b/llvm/include/llvm/Remarks/BitstreamRemarkContainer.h @@ -67,8 +67,8 @@ enum BlockIDs { REMARK_BLOCK_ID }; -constexpr StringRef MetaBlockName = StringRef("Meta", 4); -constexpr StringRef RemarkBlockName = StringRef("Remark", 6); +constexpr StringLiteral MetaBlockName("Meta"); +constexpr StringLiteral RemarkBlockName("Remark"); /// The possible records that can be encountered in the previously described /// blocks. @@ -89,16 +89,16 @@ enum RecordIDs { RECORD_LAST = RECORD_REMARK_ARG_WITHOUT_DEBUGLOC }; -constexpr StringRef MetaContainerInfoName = StringRef("Container info", 14); -constexpr StringRef MetaRemarkVersionName = StringRef("Remark version", 14); -constexpr StringRef MetaStrTabName = StringRef("String table", 12); -constexpr StringRef MetaExternalFileName = StringRef("External File", 13); -constexpr StringRef RemarkHeaderName = StringRef("Remark header", 13); -constexpr StringRef RemarkDebugLocName = StringRef("Remark debug location", 21); -constexpr StringRef RemarkHotnessName = StringRef("Remark hotness", 14); -constexpr StringRef RemarkArgWithDebugLocName = - StringRef("Argument with debug location", 28); -constexpr StringRef RemarkArgWithoutDebugLocName = StringRef("Argument", 8); +constexpr StringLiteral MetaContainerInfoName("Container info"); +constexpr StringLiteral MetaRemarkVersionName("Remark version"); +constexpr StringLiteral MetaStrTabName("String table"); +constexpr StringLiteral MetaExternalFileName("External File"); +constexpr StringLiteral RemarkHeaderName("Remark header"); +constexpr StringLiteral RemarkDebugLocName("Remark debug location"); +constexpr StringLiteral RemarkHotnessName("Remark hotness"); +constexpr StringLiteral + RemarkArgWithDebugLocName("Argument with debug location"); +constexpr StringLiteral RemarkArgWithoutDebugLocName("Argument"); } // end namespace remarks } // end namespace llvm diff --git a/llvm/include/llvm/Remarks/BitstreamRemarkParser.h b/llvm/include/llvm/Remarks/BitstreamRemarkParser.h deleted file mode 100644 index bfa60332d1a90..0000000000000 --- a/llvm/include/llvm/Remarks/BitstreamRemarkParser.h +++ /dev/null @@ -1,116 +0,0 @@ -//===-- BitstreamRemarkParser.h - Bitstream parser --------------*- 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 an implementation of the remark parser using the LLVM -// Bitstream format. -// -//===----------------------------------------------------------------------===// - -#ifndef LLVM_REMARKS_BITSTREAMREMARKPARSER_H -#define LLVM_REMARKS_BITSTREAMREMARKPARSER_H - -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Bitstream/BitstreamReader.h" -#include "llvm/Support/Error.h" -#include -#include -#include - -namespace llvm { -namespace remarks { - -/// Helper to parse a META_BLOCK for a bitstream remark container. -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 ContainerVersion; - std::optional ContainerType; - std::optional StrTabBuf; - std::optional ExternalFilePath; - std::optional RemarkVersion; - - /// 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); - - /// 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. -struct BitstreamRemarkParserHelper { - /// The Bitstream reader. - BitstreamCursor &Stream; - /// 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 SourceFileNameIdx; - std::optional SourceLine; - std::optional SourceColumn; - std::optional Hotness; - struct Argument { - std::optional KeyIdx; - std::optional ValueIdx; - std::optional SourceFileNameIdx; - std::optional SourceLine; - std::optional SourceColumn; - }; - std::optional> Args; - /// Avoid re-allocating a vector every time. - SmallVector 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. -struct BitstreamParserHelper { - /// The Bitstream reader. - BitstreamCursor Stream; - /// The block info block. - BitstreamBlockInfo BlockInfo; - /// Start parsing at \p Buffer. - BitstreamParserHelper(StringRef Buffer); - /// Parse the magic number. - Expected> 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 isMetaBlock(); - /// Return true if the next block is a REMARK_BLOCK. This function does not - /// move the cursor. - Expected 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(); } -}; - -} // end namespace remarks -} // end namespace llvm - -#endif // LLVM_REMARKS_BITSTREAMREMARKPARSER_H diff --git a/llvm/lib/Remarks/BitstreamRemarkParser.cpp b/llvm/lib/Remarks/BitstreamRemarkParser.cpp index 20a8ebbadc681..af6a858aaa91a 100644 --- a/llvm/lib/Remarks/BitstreamRemarkParser.cpp +++ b/llvm/lib/Remarks/BitstreamRemarkParser.cpp @@ -11,37 +11,76 @@ // //===----------------------------------------------------------------------===// -#include "llvm/Remarks/BitstreamRemarkParser.h" #include "BitstreamRemarkParser.h" -#include "llvm/Remarks/Remark.h" #include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/Path.h" +#include #include using namespace llvm; using namespace llvm::remarks; -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); +namespace { + +template Error error(char const *Fmt, const Ts &...Vals) { + std::string Buffer; + raw_string_ostream OS(Buffer); + OS << formatv(Fmt, Vals...); + return make_error( + Buffer, std::make_error_code(std::errc::illegal_byte_sequence)); +} + +} // namespace + +Error BitstreamBlockParserHelperBase::unknownRecord(unsigned AbbrevID) { + return error("Unknown record entry ({}).", AbbrevID); } -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::unexpectedRecord(StringRef RecordName) { + return error("Unexpected record entry ({}).", RecordName); } -BitstreamMetaParserHelper::BitstreamMetaParserHelper( - BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo) - : Stream(Stream), BlockInfo(BlockInfo) {} +Error BitstreamBlockParserHelperBase::malformedRecord(StringRef RecordName) { + return error("Malformed record entry ({}).", RecordName); +} + +Error BitstreamBlockParserHelperBase::unexpectedBlock(unsigned Code) { + return error("Unexpected subblock ({}).", Code); +} + +static Expected expectSubBlock(BitstreamCursor &Stream) { + Expected 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."); + } +} + +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(); +} + +Error BitstreamBlockParserHelperBase::enterBlock() { + if (Stream.EnterSubBlock(BlockID)) + return error("Error while entering {} block.", BlockName); + return Error::success(); +} /// Parse a record and fill in the fields in the parser. -static Error parseRecord(BitstreamMetaParserHelper &Parser, unsigned Code) { - BitstreamCursor &Stream = Parser.Stream; +Error BitstreamMetaParserHelper::parseRecord(unsigned Code) { // Note: 2 is used here because it's the max number of fields we have per // record. SmallVector Record; @@ -53,171 +92,144 @@ static Error parseRecord(BitstreamMetaParserHelper &Parser, unsigned Code) { switch (*RecordID) { case RECORD_META_CONTAINER_INFO: { if (Record.size() != 2) - return malformedRecord("BLOCK_META", "RECORD_META_CONTAINER_INFO"); - Parser.ContainerVersion = Record[0]; - Parser.ContainerType = Record[1]; + return malformedRecord(MetaContainerInfoName); + Container.emplace(); + Container->Version = Record[0]; + Container->Type = 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); + } break; } case RECORD_META_REMARK_VERSION: { if (Record.size() != 1) - return malformedRecord("BLOCK_META", "RECORD_META_REMARK_VERSION"); - Parser.RemarkVersion = Record[0]; + 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); + } break; } case RECORD_META_STRTAB: { if (Record.size() != 0) - return malformedRecord("BLOCK_META", "RECORD_META_STRTAB"); - Parser.StrTabBuf = Blob; + return malformedRecord(MetaStrTabName); + StrTabBuf = Blob; break; } case RECORD_META_EXTERNAL_FILE: { if (Record.size() != 0) - return malformedRecord("BLOCK_META", "RECORD_META_EXTERNAL_FILE"); - Parser.ExternalFilePath = Blob; + return malformedRecord(MetaExternalFileName); + ExternalFilePath = Blob; break; } default: - return unknownRecord("BLOCK_META", *RecordID); + return unknownRecord(*RecordID); } return Error::success(); } -BitstreamRemarkParserHelper::BitstreamRemarkParserHelper( - BitstreamCursor &Stream) - : Stream(Stream) {} - -/// 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 Record; - StringRef Blob; - Expected RecordID = Stream.readRecord(Code, Record, &Blob); - if (!RecordID) - return RecordID.takeError(); +Error BitstreamRemarkParserHelper::parseRecord(unsigned Code) { + Record.clear(); + Expected MaybeRecordID = + Stream.readRecord(Code, Record, &RecordBlob); + if (!MaybeRecordID) + return MaybeRecordID.takeError(); + RecordID = *MaybeRecordID; + return handleRecord(); +} - switch (*RecordID) { +Error BitstreamRemarkParserHelper::handleRecord() { + switch (RecordID) { case RECORD_REMARK_HEADER: { if (Record.size() != 4) - return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HEADER"); - Parser.Type = Record[0]; - Parser.RemarkNameIdx = Record[1]; - Parser.PassNameIdx = Record[2]; - Parser.FunctionNameIdx = Record[3]; + return malformedRecord(RemarkHeaderName); + Type = Record[0]; + RemarkNameIdx = Record[1]; + PassNameIdx = Record[2]; + FunctionNameIdx = Record[3]; break; } case RECORD_REMARK_DEBUG_LOC: { if (Record.size() != 3) - return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_DEBUG_LOC"); - Parser.SourceFileNameIdx = Record[0]; - Parser.SourceLine = Record[1]; - Parser.SourceColumn = Record[2]; + return malformedRecord(RemarkDebugLocName); + Loc.emplace(); + Loc->SourceFileNameIdx = Record[0]; + Loc->SourceLine = Record[1]; + Loc->SourceColumn = Record[2]; break; } case RECORD_REMARK_HOTNESS: { if (Record.size() != 1) - return malformedRecord("BLOCK_REMARK", "RECORD_REMARK_HOTNESS"); - Parser.Hotness = Record[0]; + return malformedRecord(RemarkHotnessName); + Hotness = Record[0]; break; } case RECORD_REMARK_ARG_WITH_DEBUGLOC: { if (Record.size() != 5) - 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(Parser.TmpArgs); + return malformedRecord(RemarkArgWithDebugLocName); + auto &Arg = Args.emplace_back(); + Arg.KeyIdx = Record[0]; + Arg.ValueIdx = Record[1]; + Arg.Loc.emplace(); + Arg.Loc->SourceFileNameIdx = Record[2]; + Arg.Loc->SourceLine = Record[3]; + Arg.Loc->SourceColumn = Record[4]; break; } case RECORD_REMARK_ARG_WITHOUT_DEBUGLOC: { if (Record.size() != 2) - 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(Parser.TmpArgs); + return malformedRecord(RemarkArgWithoutDebugLocName); + auto &Arg = Args.emplace_back(); + Arg.KeyIdx = Record[0]; + Arg.ValueIdx = Record[1]; break; } default: - return unknownRecord("BLOCK_REMARK", *RecordID); + return unknownRecord(RecordID); } return Error::success(); } -template -static Error parseBlock(T &ParserHelper, unsigned BlockID, - const char *BlockName) { - BitstreamCursor &Stream = ParserHelper.Stream; - Expected 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"); -} +Error BitstreamRemarkParserHelper::parseNext() { + Type.reset(); + RemarkNameIdx.reset(); + PassNameIdx.reset(); + FunctionNameIdx.reset(); + Hotness.reset(); + Loc.reset(); + Args.clear(); -Error BitstreamRemarkParserHelper::parse() { - return parseBlock(*this, REMARK_BLOCK_ID, "REMARK_BLOCK"); + if (Error E = expectBlock()) + return E; + return parseBlock(); } BitstreamParserHelper::BitstreamParserHelper(StringRef Buffer) : Stream(Buffer) {} -Expected> BitstreamParserHelper::parseMagic() { +Error BitstreamParserHelper::expectMagic() { std::array Result; - for (unsigned i = 0; i < 4; ++i) + for (unsigned I = 0; I < 4; ++I) if (Expected R = Stream.Read(8)) - Result[i] = *R; + Result[I] = *R; else return R.takeError(); - return Result; + + StringRef MagicNumber{Result.data(), Result.size()}; + if (MagicNumber != remarks::ContainerMagic) + return error("Unknown magic number: expecting {}, got {}.", + remarks::ContainerMagic, MagicNumber); + return Error::success(); } Error BitstreamParserHelper::parseBlockInfoBlock() { @@ -226,8 +238,7 @@ Error BitstreamParserHelper::parseBlockInfoBlock() { return Next.takeError(); if (Next->Kind != BitstreamEntry::SubBlock || Next->ID != llvm::bitc::BLOCKINFO_BLOCK_ID) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), + return error( "Error while parsing BLOCKINFO_BLOCK: expecting [ENTER_SUBBLOCK, " "BLOCKINFO_BLOCK, ...]."); @@ -237,9 +248,7 @@ Error BitstreamParserHelper::parseBlockInfoBlock() { return MaybeBlockInfo.takeError(); if (!*MaybeBlockInfo) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCKINFO_BLOCK."); + return error("Missing BLOCKINFO_BLOCK."); BlockInfo = **MaybeBlockInfo; @@ -247,77 +256,17 @@ Error BitstreamParserHelper::parseBlockInfoBlock() { return Error::success(); } -static Expected isBlock(BitstreamCursor &Stream, unsigned BlockID) { - bool Result = false; - uint64_t PreviousBitNo = Stream.GetCurrentBitNo(); - Expected 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 BitstreamParserHelper::isMetaBlock() { - return isBlock(Stream, META_BLOCK_ID); -} - -Expected 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> MagicNumber = Helper.parseMagic(); - if (!MagicNumber) - return MagicNumber.takeError(); - if (Error E = validateMagicNumber( - StringRef(MagicNumber->data(), MagicNumber->size()))) +Error BitstreamParserHelper::advanceToMetaBlock() { + if (Error E = expectMagic()) return E; - if (Error E = Helper.parseBlockInfoBlock()) + if (Error E = parseBlockInfoBlock()) return E; - Expected 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> remarks::createBitstreamParserFromMeta( StringRef Buf, std::optional ExternalFilePrependPath) { - BitstreamParserHelper Helper(Buf); - Expected> 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(Buf); if (ExternalFilePrependPath) @@ -340,13 +289,13 @@ Expected> BitstreamRemarkParser::next() { } Error BitstreamRemarkParser::parseMeta() { - // Advance and to the meta block. - if (Error E = advanceToMetaBlock(ParserHelper)) + if (Error E = ParserHelper.advanceToMetaBlock()) return E; - BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream, - ParserHelper.BlockInfo); - if (Error E = MetaHelper.parse()) + BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream); + if (Error E = MetaHelper.expectBlock()) + return E; + if (Error E = MetaHelper.parseBlock()) return E; if (Error E = processCommonMeta(MetaHelper)) @@ -365,59 +314,43 @@ Error BitstreamRemarkParser::parseMeta() { Error BitstreamRemarkParser::processCommonMeta( BitstreamMetaParserHelper &Helper) { - if (std::optional 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 Type = Helper.ContainerType) { + if (auto Container = Helper.Container) { + ContainerVersion = Container->Version; // Always >= BitstreamRemarkContainerType::First since it's unsigned. - if (*Type > static_cast(BitstreamRemarkContainerType::Last)) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCK_META: invalid container type."); - - ContainerType = static_cast(*Type); - } else - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCK_META: missing container type."); - + if (Container->Type > + static_cast(BitstreamRemarkContainerType::Last)) + return Helper.error("Invalid container type."); + ContainerType = static_cast(Container->Type); + } else { + return Helper.error("Missing container info."); + } return Error::success(); } -static Error processStrTab(BitstreamRemarkParser &P, - std::optional StrTabBuf) { - if (!StrTabBuf) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCK_META: missing string table."); +Error BitstreamRemarkParser::processStrTab(BitstreamMetaParserHelper &Helper) { + if (!Helper.StrTabBuf) + return Helper.error("Missing string table."); // Parse and assign the string table. - P.StrTab.emplace(*StrTabBuf); + StrTab.emplace(*Helper.StrTabBuf); return Error::success(); } -static Error processRemarkVersion(BitstreamRemarkParser &P, - std::optional 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; +Error BitstreamRemarkParser::processRemarkVersion( + BitstreamMetaParserHelper &Helper) { + if (!Helper.RemarkVersion) + return Helper.error("Missing remark version."); + RemarkVersion = *Helper.RemarkVersion; return Error::success(); } Error BitstreamRemarkParser::processExternalFilePath( - std::optional ExternalFilePath) { - if (!ExternalFilePath) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCK_META: missing external file path."); + BitstreamMetaParserHelper &Helper) { + if (!Helper.ExternalFilePath) + return Helper.error("Missing external file path."); + StringRef ExternalFilePath = *Helper.ExternalFilePath; 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 @@ -436,32 +369,22 @@ 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 = advanceToMetaBlock(ParserHelper)) + if (Error E = ParserHelper.advanceToMetaBlock()) 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, - ParserHelper.BlockInfo); - if (Error E = SeparateMetaHelper.parse()) + BitstreamMetaParserHelper SeparateMetaHelper(ParserHelper.Stream); + if (Error E = SeparateMetaHelper.expectBlock()) + return E; + if (Error E = SeparateMetaHelper.parseBlock()) return E; - uint64_t PreviousContainerVersion = ContainerVersion; if (Error E = processCommonMeta(SeparateMetaHelper)) return E; if (ContainerType != BitstreamRemarkContainerType::SeparateRemarksFile) - 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); + return SeparateMetaHelper.error("Wrong container type in external file."); // Process the meta from the separate file. return processSeparateRemarksFileMeta(SeparateMetaHelper); @@ -469,26 +392,26 @@ Error BitstreamRemarkParser::processExternalFilePath( Error BitstreamRemarkParser::processStandaloneMeta( BitstreamMetaParserHelper &Helper) { - if (Error E = processStrTab(*this, Helper.StrTabBuf)) + if (Error E = processStrTab(Helper)) return E; - return processRemarkVersion(*this, Helper.RemarkVersion); + return processRemarkVersion(Helper); } Error BitstreamRemarkParser::processSeparateRemarksFileMeta( BitstreamMetaParserHelper &Helper) { - return processRemarkVersion(*this, Helper.RemarkVersion); + return processRemarkVersion(Helper); } Error BitstreamRemarkParser::processSeparateRemarksMetaMeta( BitstreamMetaParserHelper &Helper) { - if (Error E = processStrTab(*this, Helper.StrTabBuf)) + if (Error E = processStrTab(Helper)) return E; - return processExternalFilePath(Helper.ExternalFilePath); + return processExternalFilePath(Helper); } Expected> BitstreamRemarkParser::parseRemark() { BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream); - if (Error E = RemarkHelper.parse()) + if (Error E = RemarkHelper.parseNext()) return std::move(E); return processRemark(RemarkHelper); @@ -499,28 +422,20 @@ BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) { std::unique_ptr Result = std::make_unique(); Remark &R = *Result; - if (StrTab == std::nullopt) - return createStringError( - std::make_error_code(std::errc::invalid_argument), - "Error while parsing BLOCK_REMARK: missing string table."); + if (!StrTab) + return Helper.error("Missing string table."); if (!Helper.Type) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCK_REMARK: missing remark type."); + return Helper.error("Missing remark type."); // Always >= Type::First since it's unsigned. if (*Helper.Type > static_cast(Type::Last)) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCK_REMARK: unknown remark type."); + return Helper.error("Unknown remark type."); R.RemarkType = static_cast(*Helper.Type); if (!Helper.RemarkNameIdx) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCK_REMARK: missing remark name."); + return Helper.error("Missing remark name."); if (Expected RemarkName = (*StrTab)[*Helper.RemarkNameIdx]) R.RemarkName = *RemarkName; @@ -528,9 +443,7 @@ BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) { return RemarkName.takeError(); if (!Helper.PassNameIdx) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCK_REMARK: missing remark pass."); + return Helper.error("Missing remark pass."); if (Expected PassName = (*StrTab)[*Helper.PassNameIdx]) R.PassName = *PassName; @@ -538,61 +451,53 @@ BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) { return PassName.takeError(); if (!Helper.FunctionNameIdx) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCK_REMARK: missing remark function name."); + return Helper.error("Missing remark function name."); + if (Expected FunctionName = (*StrTab)[*Helper.FunctionNameIdx]) R.FunctionName = *FunctionName; else return FunctionName.takeError(); - if (Helper.SourceFileNameIdx && Helper.SourceLine && Helper.SourceColumn) { - Expected SourceFileName = (*StrTab)[*Helper.SourceFileNameIdx]; + if (Helper.Loc) { + Expected SourceFileName = + (*StrTab)[Helper.Loc->SourceFileNameIdx]; if (!SourceFileName) return SourceFileName.takeError(); R.Loc.emplace(); R.Loc->SourceFilePath = *SourceFileName; - R.Loc->SourceLine = *Helper.SourceLine; - R.Loc->SourceColumn = *Helper.SourceColumn; + R.Loc->SourceLine = Helper.Loc->SourceLine; + R.Loc->SourceColumn = Helper.Loc->SourceColumn; } if (Helper.Hotness) R.Hotness = *Helper.Hotness; - if (!Helper.Args) - return std::move(Result); - - for (const BitstreamRemarkParserHelper::Argument &Arg : *Helper.Args) { + for (const BitstreamRemarkParserHelper::Argument &Arg : Helper.Args) { if (!Arg.KeyIdx) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCK_REMARK: missing key in remark argument."); + return Helper.error("Missing key in remark argument."); if (!Arg.ValueIdx) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCK_REMARK: missing value in remark " - "argument."); + return Helper.error("Missing value in remark argument."); // We have at least a key and a value, create an entry. - R.Args.emplace_back(); + auto &RArg = R.Args.emplace_back(); if (Expected Key = (*StrTab)[*Arg.KeyIdx]) - R.Args.back().Key = *Key; + RArg.Key = *Key; else return Key.takeError(); if (Expected Value = (*StrTab)[*Arg.ValueIdx]) - R.Args.back().Val = *Value; + RArg.Val = *Value; else return Value.takeError(); - if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) { + if (Arg.Loc) { if (Expected SourceFileName = - (*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; + (*StrTab)[Arg.Loc->SourceFileNameIdx]) { + RArg.Loc.emplace(); + RArg.Loc->SourceFilePath = *SourceFileName; + RArg.Loc->SourceLine = Arg.Loc->SourceLine; + RArg.Loc->SourceColumn = Arg.Loc->SourceColumn; } else return SourceFileName.takeError(); } diff --git a/llvm/lib/Remarks/BitstreamRemarkParser.h b/llvm/lib/Remarks/BitstreamRemarkParser.h index 061206471fee4..031c188ac230a 100644 --- a/llvm/lib/Remarks/BitstreamRemarkParser.h +++ b/llvm/lib/Remarks/BitstreamRemarkParser.h @@ -13,10 +13,15 @@ #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/BitstreamRemarkParser.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 @@ -24,7 +29,166 @@ namespace llvm { namespace remarks { -struct Remark; +class BitstreamBlockParserHelperBase { +protected: + BitstreamCursor &Stream; + + unsigned BlockID; + StringRef BlockName; + +public: + BitstreamBlockParserHelperBase(BitstreamCursor &Stream, unsigned BlockID, + StringRef BlockName) + : Stream(Stream), BlockID(BlockID), BlockName(BlockName) {} + + 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( + 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); } + + Error parseRecord(unsigned Code) { return unexpectedRecord(Code); } + 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."); + } + } + } +}; + +/// 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: + unsigned RecordID; + SmallVector Record; + StringRef RecordBlob; + +public: + struct RemarkLoc { + uint64_t SourceFileNameIdx; + uint64_t SourceLine; + uint64_t SourceColumn; + }; + + struct Argument { + std::optional KeyIdx; + std::optional ValueIdx; + std::optional Loc; + }; + + /// 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; + /// 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 block info block containing all the abbrevs. + /// This needs to be called before calling any other parsing function. + Error parseBlockInfoBlock(); + /// Return true if the parser reached the end of the stream. + bool atEndOfStream() { return Stream.AtEndOfStream(); } +}; /// Parses and holds the state of the latest parsed remark. struct BitstreamRemarkParser : public RemarkParser { @@ -60,14 +224,16 @@ struct BitstreamRemarkParser : public RemarkParser { Expected> 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> processRemark(BitstreamRemarkParserHelper &Helper); - Error processExternalFilePath(std::optional ExternalFilePath); }; Expected> createBitstreamParserFromMeta( From d33b31f01aeeb9005581b0a2a1f21c898463aa02 Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Thu, 18 Sep 2025 12:34:55 +0100 Subject: [PATCH 2/5] Replace bitstream blobs by yaml Created using spr 1.3.7-wip --- llvm/lib/Remarks/BitstreamRemarkParser.cpp | 5 +- .../dsymutil/ARM/remarks-linking-bundle.test | 13 +- .../basic1.macho.remarks.arm64.opt.bitstream | Bin 824 -> 0 bytes .../basic1.macho.remarks.arm64.opt.yaml | 47 +++++ ...c1.macho.remarks.empty.arm64.opt.bitstream | 0 .../basic2.macho.remarks.arm64.opt.bitstream | Bin 1696 -> 0 bytes .../basic2.macho.remarks.arm64.opt.yaml | 194 ++++++++++++++++++ ...c2.macho.remarks.empty.arm64.opt.bitstream | 0 .../basic3.macho.remarks.arm64.opt.bitstream | Bin 1500 -> 0 bytes .../basic3.macho.remarks.arm64.opt.yaml | 181 ++++++++++++++++ ...c3.macho.remarks.empty.arm64.opt.bitstream | 0 .../fat.macho.remarks.x86_64.opt.bitstream | Bin 820 -> 0 bytes .../remarks/fat.macho.remarks.x86_64.opt.yaml | 53 +++++ .../fat.macho.remarks.x86_64h.opt.bitstream | Bin 820 -> 0 bytes .../fat.macho.remarks.x86_64h.opt.yaml | 53 +++++ .../X86/remarks-linking-fat-bundle.test | 8 +- 16 files changed, 543 insertions(+), 11 deletions(-) delete mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.bitstream create mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.yaml delete mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.empty.arm64.opt.bitstream delete mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.bitstream create mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.yaml delete mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.empty.arm64.opt.bitstream delete mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.bitstream create mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.yaml delete mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.empty.arm64.opt.bitstream delete mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64.opt.bitstream create mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64.opt.yaml delete mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64h.opt.bitstream create mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64h.opt.yaml diff --git a/llvm/lib/Remarks/BitstreamRemarkParser.cpp b/llvm/lib/Remarks/BitstreamRemarkParser.cpp index 63b16bd2df0ec..2b27a0f661d88 100644 --- a/llvm/lib/Remarks/BitstreamRemarkParser.cpp +++ b/llvm/lib/Remarks/BitstreamRemarkParser.cpp @@ -411,9 +411,8 @@ Error BitstreamRemarkParser::processExternalFilePath() { return E; if (ContainerType != BitstreamRemarkContainerType::RemarksFile) - return error( - "Error while parsing external file's BLOCK_META: wrong container " - "type."); + return ParserHelper->MetaHelper.error( + "Wrong container type in external file."); return Error::success(); } diff --git a/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test b/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test index 09a60d7d044c6..e1b04455b0d9d 100644 --- a/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test +++ b/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle.test @@ -1,22 +1,25 @@ RUN: rm -rf %t -RUN: mkdir -p %t +RUN: mkdir -p %t/private/tmp/remarks RUN: cat %p/../Inputs/remarks/basic.macho.remarks.arm64> %t/basic.macho.remarks.arm64 +RUN: llvm-remarkutil yaml2bitstream %p/../Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.yaml -o %t/private/tmp/remarks/basic1.macho.remarks.arm64.opt.bitstream +RUN: llvm-remarkutil yaml2bitstream %p/../Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.yaml -o %t/private/tmp/remarks/basic2.macho.remarks.arm64.opt.bitstream +RUN: llvm-remarkutil yaml2bitstream %p/../Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.yaml -o %t/private/tmp/remarks/basic3.macho.remarks.arm64.opt.bitstream -RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.arm64 +RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/basic.macho.remarks.arm64 Check that the remark file in the bundle exists and is sane: RUN: llvm-bcanalyzer -dump %t/basic.macho.remarks.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64 | FileCheck %s -RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.arm64 +RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/basic.macho.remarks.arm64 Check that the remark file in the bundle exists and is sane: RUN: llvm-bcanalyzer -dump %t/basic.macho.remarks.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64 | FileCheck %s Now emit it in a different format: YAML. -RUN: dsymutil -remarks-output-format=yaml -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.arm64 +RUN: dsymutil -remarks-output-format=yaml -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/basic.macho.remarks.arm64 RUN: cat %t/basic.macho.remarks.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64 | FileCheck %s --check-prefix=CHECK-YAML -RUN: dsymutil --linker parallel -remarks-output-format=yaml -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.arm64 +RUN: dsymutil --linker parallel -remarks-output-format=yaml -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/basic.macho.remarks.arm64 RUN: cat %t/basic.macho.remarks.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64 | FileCheck %s --check-prefix=CHECK-YAML CHECK: k50Jv`yPFHZR2* zdNamw@Yp3DF!5wKc;LWTObGFS#CR~qIOBmB{|LVw2=kk?-}il=&-e5Fy!Wzm**k$w zfEfT_0`C&rsmVhj#`Cq29Vd>f*G_!X;qBzqduMW|p0s1Z&I^|#k>tgLYIrXh`4Z^; zQ)PdNk)uZVTk>AQTPtil@R)L%DaDwm=jtJ5b%gm4xYhZxL-^Ozs9n!j*{>Y-g?Ax* zz_I(N(IDy3p8N|=IIfMK!!~=6WPdl%cSkpc_%nxp+dk;k z2q?t;Bi4xZcxfOKw*ewmZy60MJOzCji6WpfW z@a)Kbee$z_M@BKJEj$HWFF-rq4JO#a&yOo1fNspgB($~O1z@)U?Dlv2v}R1Oeca&Y zY2k4JpC80>Lhj#6BEK2qLk0bZUlhP-W8Cw7KExcn1d!3D#f8$hT@imJFOQbo)uGU|!a@;t4` zpc|T^Ey+5?KV*t4O(a#eWD}x5OrJ+`eu;C)Vo{ZRzvLR+K3&2!m{m>7C^msPx(1@T zazjVEmTW-EKTAr{q~$5nQh=;lMj4-HLCDT5+|Oq66p%2RnO}I+vNhH!Eoep6@*TE} PGXY(l4gb#~-ZH>ndrko0 diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.yaml b/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.yaml new file mode 100644 index 0000000000000..9aa711a9068c2 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.arm64.opt.yaml @@ -0,0 +1,47 @@ +--- !Missed +Pass: inline +Name: NoDefinition +DebugLoc: { File: basic1.c, Line: 38, Column: 10 } +Function: main +Args: + - Callee: foo + DebugLoc: { File: basic1.c, Line: 0, Column: 0 } + - String: ' will not be inlined into ' + - Caller: main + DebugLoc: { File: basic1.c, Line: 37, Column: 0 } + - String: ' because its definition is unavailable' +... +--- !Analysis +Pass: prologepilog +Name: StackSize +DebugLoc: { File: basic1.c, Line: 37, Column: 0 } +Function: main +Args: + - NumStackBytes: '0' + - String: ' stack bytes in function ''' + - Function: main + - String: '''' +... +--- !Analysis +Pass: asm-printer +Name: InstructionMix +DebugLoc: { File: basic1.c, Line: 38, Column: 10 } +Function: main +Args: + - String: 'BasicBlock: ' + - BasicBlock: entry + - String: "\n" + - String: TCRETURNdi + - String: ': ' + - INST_TCRETURNdi: '1' + - String: "\n" +... +--- !Analysis +Pass: asm-printer +Name: InstructionCount +DebugLoc: { File: basic1.c, Line: 37, Column: 0 } +Function: main +Args: + - NumInstructions: '1' + - String: ' instructions in function' +... diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.empty.arm64.opt.bitstream b/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.empty.arm64.opt.bitstream deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.bitstream b/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.arm64.opt.bitstream deleted file mode 100644 index 0a0f8e0ffd4cf2f7b39250267d23adc03b48acd4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1696 zcmaJ>&u<%55T0#_os=YmDj;X;glCkJ6s5>coYrw1VS8OjzzxAMYB=Gwy~%F7*|m1p zNgOV2oq9P`6+%Ju(8F5d5FsQ`l|v6bB(*A{s0R~891ubTai{}1-3xq;DLyt=nh`ugOY?MO9Nbpf<{Bbo>3^>|) zUhnUZyt-HEdlKpYiRt*e;{Jp0-#_g8CGug|S{2J5Th79ib0y&PT4t`>xjf{2%1pL> z(aJSz4tFkQEAF2?Sl71=eS04FF7`MiQ^PN2KlgCYcSerWMfYCB{pX>3yV&`kkqmUG1%ffVn1`TF$u!rBA1vYhkCC zm|C~FhRRarip$Jdrm^Z=sl_bLwEGQA5A9aR4>+`p%`#{Dg5c=@Xu)@b8*Ji-t_$4& zXK^1O-J3gS0JaftzkHU`?B#cNd0az{!16H1{Mk*W6`)9KPV+0S_-Xz*3^y*+`C$hJ ztm|E|!`&d&ehaLpy-YnSIvi}jSWLxkm)jF>ir-s@w;ipl_x_I-Q##+p25r6V$Q}4+ zZgU4!()qxKUFRzNx?}&#cndXyy6B=>n_Q~Z4*rKrrEQIdTW+yU!>RY~lwW!Hf|#;< zHS>4aroq%VG~d(6cVfN&$|}|mBclE+rtIrw7euR4DPQhH@CZSGf?Whb1W2-bQ+ZpH zw6-~$d}lgdvvUM|Mrx@UN?8VNDhpafe^LUy1aFxz4W`swd^B%~lt}C8R!})Lxq^ zBK0n%+V^hzM~%n+$p>t>^b*Rmzgs`xe$NLmqsD{X<2{;RfTDLY!(JlKn4a+_Zy_M43WT4M%9f;;P45Td}ChU7z`6b)C65rm{Nf*$6Gl~{~3cy#!XKv0(YXamnRaO^;oPJEu4^}!ziHeBYCG>;PBXWO>fS&v3=AS)4(Gzmpqo#z?hrYj(HSE5uXa0mWiqTk|M8RAV%QT^W&_1BR|7`mk<-l*8|H-D^=z000 zWN;sqIQ)zspxWoNA%h!^E@7@2;9Tc)5E$Zf=OCR`hH@<-@FJBk73{Q}db| z=xotk^_j)0X{>oxTbU|rTJ^5Zgr6Qx{KVqOSd70En1ox7mI221j@Uos zkXk44?Im#8QQ7TghQ;z?W^4Cy?oIJ=wY}x;W+I>dSanriA7myizi#Bl{(i0AbVRU~ z7QO8(YVCRKe7^3Y{phmuo1Ods9>t>Ju1$s@isMslZilWgIdQ(m?d%UBC?fcRf--_H z5g^Ix-Hm%}f@(XLa`I?*m$7m$(;U{_VJMrf|I~eq<-WPlpn)gf*$wF3cD(H{5!8pB z8Ub|jGZGJ|^aXB=YGxdE`s7)Q0uF)Nnrz0nDixVOdfnLsAux6j@RPC@CdfC`4h2(6xAS0011?-{0jMcUPAvC~4=wiJP?PZ7r!n~>*)4<{zu8)mJ#>Qck7@{WVqAC}rVW9)z zt#KFu!Wo1|-@0T71SVmYP8LPETv}0JEDBRN3&%gmOB(_dHC0yc3q=XvFjrc!GU;_g z&>;dur#!MmL-am* Nh*fl$pdTWxe*yBar_cZZ diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.yaml b/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.yaml new file mode 100644 index 0000000000000..8570049fab6b0 --- /dev/null +++ b/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.arm64.opt.yaml @@ -0,0 +1,181 @@ +--- !Missed +Pass: inline +Name: NoDefinition +DebugLoc: { File: basic3.c, Line: 8, Column: 10 } +Function: unused2 +Args: + - Callee: foo + DebugLoc: { File: basic3.c, Line: 0, Column: 0 } + - String: ' will not be inlined into ' + - Caller: unused2 + DebugLoc: { File: basic3.c, Line: 7, Column: 0 } + - String: ' because its definition is unavailable' +... +--- !Missed +Pass: inline +Name: NoDefinition +DebugLoc: { File: basic3.c, Line: 19, Column: 10 } +Function: bar +Args: + - Callee: foo + DebugLoc: { File: basic3.c, Line: 0, Column: 0 } + - String: ' will not be inlined into ' + - Caller: bar + DebugLoc: { File: basic3.c, Line: 16, Column: 0 } + - String: ' because its definition is unavailable' +... +--- !Passed +Pass: inline +Name: Inlined +DebugLoc: { File: basic3.c, Line: 18, Column: 12 } +Function: bar +Args: + - String: '''' + - Callee: inc + DebugLoc: { File: basic3.c, Line: 11, Column: 0 } + - String: ''' inlined into ''' + - Caller: bar + DebugLoc: { File: basic3.c, Line: 16, Column: 0 } + - String: '''' + - String: ' with ' + - String: '(cost=' + - Cost: '-15015' + - String: ', threshold=' + - Threshold: '75' + - String: ')' + - String: ' at callsite ' + - String: bar + - String: ':' + - Line: '2' + - String: ':' + - Column: '12' + - String: ';' +... +--- !Analysis +Pass: prologepilog +Name: StackSize +DebugLoc: { File: basic3.c, Line: 7, Column: 0 } +Function: unused2 +Args: + - NumStackBytes: '0' + - String: ' stack bytes in function ''' + - Function: unused2 + - String: '''' +... +--- !Analysis +Pass: prologepilog +Name: StackSize +DebugLoc: { File: basic3.c, Line: 16, Column: 0 } +Function: bar +Args: + - NumStackBytes: '0' + - String: ' stack bytes in function ''' + - Function: bar + - String: '''' +... +--- !Analysis +Pass: asm-printer +Name: InstructionMix +DebugLoc: { File: basic3.c, Line: 8, Column: 14 } +Function: unused2 +Args: + - String: 'BasicBlock: ' + - BasicBlock: entry + - String: "\n" + - String: ADRP + - String: ': ' + - INST_ADRP: '1' + - String: "\n" + - String: LDRWui + - String: ': ' + - INST_LDRWui: '1' + - String: "\n" + - String: TCRETURNdi + - String: ': ' + - INST_TCRETURNdi: '1' + - String: "\n" +... +--- !Analysis +Pass: asm-printer +Name: InstructionCount +DebugLoc: { File: basic3.c, Line: 7, Column: 0 } +Function: unused2 +Args: + - NumInstructions: '3' + - String: ' instructions in function' +... +--- !Analysis +Pass: asm-printer +Name: InstructionMix +DebugLoc: { File: basic3.c, Line: 0, Column: 0 } +Function: bar +Args: + - String: 'BasicBlock: ' + - BasicBlock: entry + - String: "\n" + - String: ADRP + - String: ': ' + - INST_ADRP: '1' + - String: "\n" + - String: Bcc + - String: ': ' + - INST_Bcc: '1' + - String: "\n" + - String: LDRWui + - String: ': ' + - INST_LDRWui: '1' + - String: "\n" + - String: SUBSWri + - String: ': ' + - INST_SUBSWri: '1' + - String: "\n" +... +--- !Analysis +Pass: asm-printer +Name: InstructionMix +DebugLoc: { File: basic3.c, Line: 12, Column: 10 } +Function: bar +Args: + - String: 'BasicBlock: ' + - BasicBlock: if.then + - String: "\n" + - String: ADDWri + - String: ': ' + - INST_ADDWri: '1' + - String: "\n" + - String: RET + - String: ': ' + - INST_RET: '1' + - String: "\n" + - String: STRWui + - String: ': ' + - INST_STRWui: '1' + - String: "\n" +... +--- !Analysis +Pass: asm-printer +Name: InstructionMix +DebugLoc: { File: basic3.c, Line: 19, Column: 18 } +Function: bar +Args: + - String: 'BasicBlock: ' + - BasicBlock: if.end + - String: "\n" + - String: ADDWrs + - String: ': ' + - INST_ADDWrs: '1' + - String: "\n" + - String: TCRETURNdi + - String: ': ' + - INST_TCRETURNdi: '1' + - String: "\n" +... +--- !Analysis +Pass: asm-printer +Name: InstructionCount +DebugLoc: { File: basic3.c, Line: 16, Column: 0 } +Function: bar +Args: + - NumInstructions: '9' + - String: ' instructions in function' +... diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.empty.arm64.opt.bitstream b/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.empty.arm64.opt.bitstream deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64.opt.bitstream b/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/fat.macho.remarks.x86_64.opt.bitstream deleted file mode 100644 index c2f33a8a6e3ab112b2d7cbe7911f821f623f8ac8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 820 zcmY+BQESss6vt2Pw$wRBr=kPXl8R#!XPsNA*%~2foOH;x+D=grT+FgHY)wj%y0(I3 zM3y%Z*#}6$hduZtKKQVQZABQvhcd(m5uxIPh#$gp+ileg$^D)4&-veTZZgxEJH7zG zBmhvpcl`V0cwJ;UZf9uANg%y(5*rR@3lkrl@vWL*vt5C+7sFxU+#dQ`9O;jd*S$NIe~*KKgD3UU!N|HI1Fi3sw4S1nWZE5ZaH> zd+5<%Qp2YfUPZ)TJELvcruPNW6+ z*lUgZjx>8*Ji3)<6)T3-=fk+*~6fS*N>mER(d?J6d`lreaDT z@AqHmjd67l#EyY82t2|S0`myh2-pZ?1U!Tr1hx?p2*j40)k(bczV=zq`CPyU&E6iN z7C#S=wIq2tt5y^!82XC7q!d(qLtaufSd^@2UXpWq)KK!0v1~?5Y&#dQ`9O;jd*S$NIe~*KKgD3UU!N|HI1Fi3sw4S1nWZE5ZaH> zd+5<%Qp2YfUPZ)TJELvcruPNW6+ z*lUgZjx>8*Ji3)<6)T3-=fk+*~6fS*N>mER(d?J6d`lreaDT z@AqHmjd67l#EyY82t2|S0`myh2-pZ?1U!Tr1hx?p2*j40)k(bczV=zq`CPyU&E6iN z7C#S=wIq2tt5y^!82XC7q!d(qLtaufSd^@2UXpWq)KK!0v1~?5Y& %t/fat.macho.remarks.x86 +RUN: llvm-remarkutil yaml2bitstream %p/../Inputs/private/tmp/remarks/fat.macho.remarks.x86_64.opt.yaml -o %t/private/tmp/remarks/fat.macho.remarks.x86_64.opt.bitstream +RUN: llvm-remarkutil yaml2bitstream %p/../Inputs/private/tmp/remarks/fat.macho.remarks.x86_64h.opt.yaml -o %t/private/tmp/remarks/fat.macho.remarks.x86_64h.opt.bitstream -RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/fat.macho.remarks.x86 +RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/fat.macho.remarks.x86 Check that the remark files in the bundle exist and are all sane: RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-x86_64h | FileCheck %s RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-x86_64 | FileCheck %s -RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/fat.macho.remarks.x86 +RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%t %t/fat.macho.remarks.x86 Check that the remark files in the bundle exist and are all sane: RUN: llvm-bcanalyzer -dump %t/fat.macho.remarks.x86.dSYM/Contents/Resources/Remarks/fat.macho.remarks.x86-x86_64h | FileCheck %s From 271edb99edd35357c18ceda276464c419af27e17 Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Thu, 18 Sep 2025 14:58:33 +0100 Subject: [PATCH 3/5] Readd empty bitstream files Created using spr 1.3.7-wip --- .../tmp/remarks/basic1.macho.remarks.empty.arm64.opt.bitstream | 0 .../tmp/remarks/basic2.macho.remarks.empty.arm64.opt.bitstream | 0 .../tmp/remarks/basic3.macho.remarks.empty.arm64.opt.bitstream | 0 3 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.empty.arm64.opt.bitstream create mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.empty.arm64.opt.bitstream create mode 100644 llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.empty.arm64.opt.bitstream diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.empty.arm64.opt.bitstream b/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic1.macho.remarks.empty.arm64.opt.bitstream new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.empty.arm64.opt.bitstream b/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic2.macho.remarks.empty.arm64.opt.bitstream new file mode 100644 index 0000000000000..e69de29bb2d1d diff --git a/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.empty.arm64.opt.bitstream b/llvm/test/tools/dsymutil/Inputs/private/tmp/remarks/basic3.macho.remarks.empty.arm64.opt.bitstream new file mode 100644 index 0000000000000..e69de29bb2d1d From 37b751bbe67da31ddbbf953b52e976a03ebffb12 Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Thu, 18 Sep 2025 15:09:50 +0100 Subject: [PATCH 4/5] Remove dbg cmd in test Created using spr 1.3.7-wip --- llvm/test/tools/dsymutil/ARM/remarks-linking-bundle-empty.test | 1 - 1 file changed, 1 deletion(-) diff --git a/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle-empty.test b/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle-empty.test index 2e46e4a8b8d22..0a89fa1ddee3c 100644 --- a/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle-empty.test +++ b/llvm/test/tools/dsymutil/ARM/remarks-linking-bundle-empty.test @@ -6,7 +6,6 @@ RUN: dsymutil -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs Check that the remark file in the bundle does not exist: RUN: not cat %t/basic.macho.remarks.empty.arm64.dSYM/Contents/Resources/Remarks/basic.macho.remarks.arm64 2>&1 -RUN: ls %t/basic.macho.remarks.empty.arm64.dSYM/ 2>&1 > %t/goof.txt RUN: dsymutil --linker parallel -oso-prepend-path=%p/../Inputs -remarks-prepend-path=%p/../Inputs %t/basic.macho.remarks.empty.arm64 From 63b50b6c0ecf4f571e06ea8919262505b9ecf3df Mon Sep 17 00:00:00 2001 From: Tobias Stadler Date: Mon, 22 Sep 2025 15:09:45 +0100 Subject: [PATCH 5/5] Nit Created using spr 1.3.7-wip --- llvm/lib/Remarks/BitstreamRemarkParser.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/llvm/lib/Remarks/BitstreamRemarkParser.cpp b/llvm/lib/Remarks/BitstreamRemarkParser.cpp index 2a9032b5b8ac0..33eedd6042c37 100644 --- a/llvm/lib/Remarks/BitstreamRemarkParser.cpp +++ b/llvm/lib/Remarks/BitstreamRemarkParser.cpp @@ -260,7 +260,7 @@ Error BitstreamParserHelper::parseMeta() { break; if (*MaybeBlockID != REMARK_BLOCK_ID) return error("Unexpected block between meta blocks."); - // Remember first remark block + // Remember first remark block. if (!RemarkStartBitPos) RemarkStartBitPos = Stream.GetCurrentBitNo(); if (Error E = Stream.SkipBlock())