diff options
author | orivej <orivej@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:45:01 +0300 |
commit | 2d37894b1b037cf24231090eda8589bbb44fb6fc (patch) | |
tree | be835aa92c6248212e705f25388ebafcf84bc7a1 /contrib/libs/llvm12/lib/Remarks/BitstreamRemarkParser.cpp | |
parent | 718c552901d703c502ccbefdfc3c9028d608b947 (diff) | |
download | ydb-2d37894b1b037cf24231090eda8589bbb44fb6fc.tar.gz |
Restoring authorship annotation for <orivej@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/lib/Remarks/BitstreamRemarkParser.cpp')
-rw-r--r-- | contrib/libs/llvm12/lib/Remarks/BitstreamRemarkParser.cpp | 1206 |
1 files changed, 603 insertions, 603 deletions
diff --git a/contrib/libs/llvm12/lib/Remarks/BitstreamRemarkParser.cpp b/contrib/libs/llvm12/lib/Remarks/BitstreamRemarkParser.cpp index b23b41a50b..3d586a2479 100644 --- a/contrib/libs/llvm12/lib/Remarks/BitstreamRemarkParser.cpp +++ b/contrib/libs/llvm12/lib/Remarks/BitstreamRemarkParser.cpp @@ -1,603 +1,603 @@ -//===- BitstreamRemarkParser.cpp ------------------------------------------===// -// -// 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 utility methods used by clients that want to use the -// parser for remark diagnostics in LLVM. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Remarks/BitstreamRemarkParser.h" -#include "BitstreamRemarkParser.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" - -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); -} - -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); -} - -BitstreamMetaParserHelper::BitstreamMetaParserHelper( - BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo) - : Stream(Stream), BlockInfo(BlockInfo) {} - -/// 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; - StringRef Blob; - Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob); - if (!RecordID) - return RecordID.takeError(); - - 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]; - break; - } - case RECORD_META_REMARK_VERSION: { - if (Record.size() != 1) - return malformedRecord("BLOCK_META", "RECORD_META_REMARK_VERSION"); - Parser.RemarkVersion = Record[0]; - break; - } - case RECORD_META_STRTAB: { - if (Record.size() != 0) - return malformedRecord("BLOCK_META", "RECORD_META_STRTAB"); - Parser.StrTabBuf = Blob; - break; - } - case RECORD_META_EXTERNAL_FILE: { - if (Record.size() != 0) - return malformedRecord("BLOCK_META", "RECORD_META_EXTERNAL_FILE"); - Parser.ExternalFilePath = Blob; - break; - } - default: - return unknownRecord("BLOCK_META", *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<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("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("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("BLOCK_REMARK", "RECORD_REMARK_HOTNESS"); - Parser.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<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs); - 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<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs); - break; - } - default: - return unknownRecord("BLOCK_REMARK", *RecordID); - } - return Error::success(); -} - -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"); -} - -Error BitstreamRemarkParserHelper::parse() { - return parseBlock(*this, REMARK_BLOCK_ID, "REMARK_BLOCK"); -} - -BitstreamParserHelper::BitstreamParserHelper(StringRef Buffer) - : Stream(Buffer) {} - -Expected<std::array<char, 4>> BitstreamParserHelper::parseMagic() { - std::array<char, 4> Result; - for (unsigned i = 0; i < 4; ++i) - if (Expected<unsigned> R = Stream.Read(8)) - Result[i] = *R; - else - return R.takeError(); - return Result; -} - -Error BitstreamParserHelper::parseBlockInfoBlock() { - Expected<BitstreamEntry> Next = Stream.advance(); - if (!Next) - 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), - "Error while parsing BLOCKINFO_BLOCK: expecting [ENTER_SUBBLOCK, " - "BLOCKINFO_BLOCK, ...]."); - - Expected<Optional<BitstreamBlockInfo>> MaybeBlockInfo = - Stream.ReadBlockInfoBlock(); - if (!MaybeBlockInfo) - return MaybeBlockInfo.takeError(); - - if (!*MaybeBlockInfo) - return createStringError( - std::make_error_code(std::errc::illegal_byte_sequence), - "Error while parsing BLOCKINFO_BLOCK."); - - BlockInfo = **MaybeBlockInfo; - - Stream.setBlockInfo(&BlockInfo); - return Error::success(); -} - -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 = 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, Optional<ParsedStringTable> StrTab, - 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 = - StrTab ? std::make_unique<BitstreamRemarkParser>(Buf, std::move(*StrTab)) - : std::make_unique<BitstreamRemarkParser>(Buf); - - if (ExternalFilePrependPath) - Parser->ExternalFilePrependPath = std::string(*ExternalFilePrependPath); - - return std::move(Parser); -} - -Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() { - if (ParserHelper.atEndOfStream()) - return make_error<EndOfFileError>(); - - if (!ReadyToParseRemarks) { - if (Error E = parseMeta()) - return std::move(E); - ReadyToParseRemarks = true; - } - - return parseRemark(); -} - -Error BitstreamRemarkParser::parseMeta() { - // Advance and to the meta block. - if (Error E = advanceToMetaBlock(ParserHelper)) - return E; - - BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream, - ParserHelper.BlockInfo); - if (Error E = MetaHelper.parse()) - return E; - - if (Error E = processCommonMeta(MetaHelper)) - return E; - - switch (ContainerType) { - case BitstreamRemarkContainerType::Standalone: - return processStandaloneMeta(MetaHelper); - case BitstreamRemarkContainerType::SeparateRemarksFile: - return processSeparateRemarksFileMeta(MetaHelper); - case BitstreamRemarkContainerType::SeparateRemarksMeta: - return processSeparateRemarksMetaMeta(MetaHelper); - } - llvm_unreachable("Unknown BitstreamRemarkContainerType enum"); -} - -Error BitstreamRemarkParser::processCommonMeta( - BitstreamMetaParserHelper &Helper) { - if (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 (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(); -} - -static Error processStrTab(BitstreamRemarkParser &P, - 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. - P.StrTab.emplace(*StrTabBuf); - return Error::success(); -} - -static Error processRemarkVersion(BitstreamRemarkParser &P, - 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( - 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); - - // External file: open the external file, parse it, check if its metadata - // matches the one from the separate metadata, then replace the current parser - // with the one parsing the remarks. - ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = - MemoryBuffer::getFile(FullPath); - if (std::error_code EC = BufferOrErr.getError()) - return createFileError(FullPath, EC); - - TmpRemarkBuffer = std::move(*BufferOrErr); - - // Don't try to parse the file if it's empty. - if (TmpRemarkBuffer->getBufferSize() == 0) - return make_error<EndOfFileError>(); - - // 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)) - 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()) - 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); - - // Process the meta from the separate file. - return processSeparateRemarksFileMeta(SeparateMetaHelper); -} - -Error BitstreamRemarkParser::processStandaloneMeta( - BitstreamMetaParserHelper &Helper) { - if (Error E = processStrTab(*this, Helper.StrTabBuf)) - return E; - return processRemarkVersion(*this, Helper.RemarkVersion); -} - -Error BitstreamRemarkParser::processSeparateRemarksFileMeta( - BitstreamMetaParserHelper &Helper) { - return processRemarkVersion(*this, Helper.RemarkVersion); -} - -Error BitstreamRemarkParser::processSeparateRemarksMetaMeta( - BitstreamMetaParserHelper &Helper) { - if (Error E = processStrTab(*this, Helper.StrTabBuf)) - return E; - return processExternalFilePath(Helper.ExternalFilePath); -} - -Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::parseRemark() { - BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream); - if (Error E = RemarkHelper.parse()) - return std::move(E); - - return processRemark(RemarkHelper); -} - -Expected<std::unique_ptr<Remark>> -BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) { - std::unique_ptr<Remark> Result = std::make_unique<Remark>(); - Remark &R = *Result; - - if (StrTab == None) - return createStringError( - std::make_error_code(std::errc::invalid_argument), - "Error while parsing BLOCK_REMARK: 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."); - - // Always >= Type::First since it's unsigned. - if (*Helper.Type > static_cast<uint8_t>(Type::Last)) - 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 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; - else - 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."); - - if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx]) - R.PassName = *PassName; - else - 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."); - if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx]) - R.FunctionName = *FunctionName; - else - return FunctionName.takeError(); - - 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.SourceLine; - R.Loc->SourceColumn = *Helper.SourceColumn; - } - - if (Helper.Hotness) - R.Hotness = *Helper.Hotness; - - if (!Helper.Args) - return std::move(Result); - - 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."); - if (!Arg.ValueIdx) - 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. - R.Args.emplace_back(); - - if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx]) - R.Args.back().Key = *Key; - else - return Key.takeError(); - - if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx]) - R.Args.back().Val = *Value; - else - return Value.takeError(); - - if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) { - if (Expected<StringRef> 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; - } else - return SourceFileName.takeError(); - } - } - - return std::move(Result); -} +//===- BitstreamRemarkParser.cpp ------------------------------------------===// +// +// 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 utility methods used by clients that want to use the +// parser for remark diagnostics in LLVM. +// +//===----------------------------------------------------------------------===// + +#include "llvm/Remarks/BitstreamRemarkParser.h" +#include "BitstreamRemarkParser.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" + +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); +} + +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); +} + +BitstreamMetaParserHelper::BitstreamMetaParserHelper( + BitstreamCursor &Stream, BitstreamBlockInfo &BlockInfo) + : Stream(Stream), BlockInfo(BlockInfo) {} + +/// 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; + StringRef Blob; + Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob); + if (!RecordID) + return RecordID.takeError(); + + 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]; + break; + } + case RECORD_META_REMARK_VERSION: { + if (Record.size() != 1) + return malformedRecord("BLOCK_META", "RECORD_META_REMARK_VERSION"); + Parser.RemarkVersion = Record[0]; + break; + } + case RECORD_META_STRTAB: { + if (Record.size() != 0) + return malformedRecord("BLOCK_META", "RECORD_META_STRTAB"); + Parser.StrTabBuf = Blob; + break; + } + case RECORD_META_EXTERNAL_FILE: { + if (Record.size() != 0) + return malformedRecord("BLOCK_META", "RECORD_META_EXTERNAL_FILE"); + Parser.ExternalFilePath = Blob; + break; + } + default: + return unknownRecord("BLOCK_META", *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<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("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("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("BLOCK_REMARK", "RECORD_REMARK_HOTNESS"); + Parser.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<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs); + 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<BitstreamRemarkParserHelper::Argument>(Parser.TmpArgs); + break; + } + default: + return unknownRecord("BLOCK_REMARK", *RecordID); + } + return Error::success(); +} + +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"); +} + +Error BitstreamRemarkParserHelper::parse() { + return parseBlock(*this, REMARK_BLOCK_ID, "REMARK_BLOCK"); +} + +BitstreamParserHelper::BitstreamParserHelper(StringRef Buffer) + : Stream(Buffer) {} + +Expected<std::array<char, 4>> BitstreamParserHelper::parseMagic() { + std::array<char, 4> Result; + for (unsigned i = 0; i < 4; ++i) + if (Expected<unsigned> R = Stream.Read(8)) + Result[i] = *R; + else + return R.takeError(); + return Result; +} + +Error BitstreamParserHelper::parseBlockInfoBlock() { + Expected<BitstreamEntry> Next = Stream.advance(); + if (!Next) + 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), + "Error while parsing BLOCKINFO_BLOCK: expecting [ENTER_SUBBLOCK, " + "BLOCKINFO_BLOCK, ...]."); + + Expected<Optional<BitstreamBlockInfo>> MaybeBlockInfo = + Stream.ReadBlockInfoBlock(); + if (!MaybeBlockInfo) + return MaybeBlockInfo.takeError(); + + if (!*MaybeBlockInfo) + return createStringError( + std::make_error_code(std::errc::illegal_byte_sequence), + "Error while parsing BLOCKINFO_BLOCK."); + + BlockInfo = **MaybeBlockInfo; + + Stream.setBlockInfo(&BlockInfo); + return Error::success(); +} + +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 = 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, Optional<ParsedStringTable> StrTab, + 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 = + StrTab ? std::make_unique<BitstreamRemarkParser>(Buf, std::move(*StrTab)) + : std::make_unique<BitstreamRemarkParser>(Buf); + + if (ExternalFilePrependPath) + Parser->ExternalFilePrependPath = std::string(*ExternalFilePrependPath); + + return std::move(Parser); +} + +Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() { + if (ParserHelper.atEndOfStream()) + return make_error<EndOfFileError>(); + + if (!ReadyToParseRemarks) { + if (Error E = parseMeta()) + return std::move(E); + ReadyToParseRemarks = true; + } + + return parseRemark(); +} + +Error BitstreamRemarkParser::parseMeta() { + // Advance and to the meta block. + if (Error E = advanceToMetaBlock(ParserHelper)) + return E; + + BitstreamMetaParserHelper MetaHelper(ParserHelper.Stream, + ParserHelper.BlockInfo); + if (Error E = MetaHelper.parse()) + return E; + + if (Error E = processCommonMeta(MetaHelper)) + return E; + + switch (ContainerType) { + case BitstreamRemarkContainerType::Standalone: + return processStandaloneMeta(MetaHelper); + case BitstreamRemarkContainerType::SeparateRemarksFile: + return processSeparateRemarksFileMeta(MetaHelper); + case BitstreamRemarkContainerType::SeparateRemarksMeta: + return processSeparateRemarksMetaMeta(MetaHelper); + } + llvm_unreachable("Unknown BitstreamRemarkContainerType enum"); +} + +Error BitstreamRemarkParser::processCommonMeta( + BitstreamMetaParserHelper &Helper) { + if (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 (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(); +} + +static Error processStrTab(BitstreamRemarkParser &P, + 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. + P.StrTab.emplace(*StrTabBuf); + return Error::success(); +} + +static Error processRemarkVersion(BitstreamRemarkParser &P, + 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( + 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); + + // External file: open the external file, parse it, check if its metadata + // matches the one from the separate metadata, then replace the current parser + // with the one parsing the remarks. + ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr = + MemoryBuffer::getFile(FullPath); + if (std::error_code EC = BufferOrErr.getError()) + return createFileError(FullPath, EC); + + TmpRemarkBuffer = std::move(*BufferOrErr); + + // Don't try to parse the file if it's empty. + if (TmpRemarkBuffer->getBufferSize() == 0) + return make_error<EndOfFileError>(); + + // 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)) + 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()) + 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); + + // Process the meta from the separate file. + return processSeparateRemarksFileMeta(SeparateMetaHelper); +} + +Error BitstreamRemarkParser::processStandaloneMeta( + BitstreamMetaParserHelper &Helper) { + if (Error E = processStrTab(*this, Helper.StrTabBuf)) + return E; + return processRemarkVersion(*this, Helper.RemarkVersion); +} + +Error BitstreamRemarkParser::processSeparateRemarksFileMeta( + BitstreamMetaParserHelper &Helper) { + return processRemarkVersion(*this, Helper.RemarkVersion); +} + +Error BitstreamRemarkParser::processSeparateRemarksMetaMeta( + BitstreamMetaParserHelper &Helper) { + if (Error E = processStrTab(*this, Helper.StrTabBuf)) + return E; + return processExternalFilePath(Helper.ExternalFilePath); +} + +Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::parseRemark() { + BitstreamRemarkParserHelper RemarkHelper(ParserHelper.Stream); + if (Error E = RemarkHelper.parse()) + return std::move(E); + + return processRemark(RemarkHelper); +} + +Expected<std::unique_ptr<Remark>> +BitstreamRemarkParser::processRemark(BitstreamRemarkParserHelper &Helper) { + std::unique_ptr<Remark> Result = std::make_unique<Remark>(); + Remark &R = *Result; + + if (StrTab == None) + return createStringError( + std::make_error_code(std::errc::invalid_argument), + "Error while parsing BLOCK_REMARK: 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."); + + // Always >= Type::First since it's unsigned. + if (*Helper.Type > static_cast<uint8_t>(Type::Last)) + 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 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; + else + 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."); + + if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx]) + R.PassName = *PassName; + else + 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."); + if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx]) + R.FunctionName = *FunctionName; + else + return FunctionName.takeError(); + + 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.SourceLine; + R.Loc->SourceColumn = *Helper.SourceColumn; + } + + if (Helper.Hotness) + R.Hotness = *Helper.Hotness; + + if (!Helper.Args) + return std::move(Result); + + 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."); + if (!Arg.ValueIdx) + 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. + R.Args.emplace_back(); + + if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx]) + R.Args.back().Key = *Key; + else + return Key.takeError(); + + if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx]) + R.Args.back().Val = *Value; + else + return Value.takeError(); + + if (Arg.SourceFileNameIdx && Arg.SourceLine && Arg.SourceColumn) { + if (Expected<StringRef> 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; + } else + return SourceFileName.takeError(); + } + } + + return std::move(Result); +} |