| //===- 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/Remarks/Remark.h" | 
 | #include "llvm/Support/MemoryBuffer.h" | 
 | #include "llvm/Support/Path.h" | 
 | #include <optional> | 
 |  | 
 | 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<std::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, std::optional<ParsedStringTable> StrTab, | 
 |     std::optional<StringRef> ExternalFilePrependPath) { | 
 |   BitstreamParserHelper Helper(Buf); | 
 |   Expected<std::array<char, 4>> MagicNumber = Helper.parseMagic(); | 
 |   if (!MagicNumber) | 
 |     return MagicNumber.takeError(); | 
 |  | 
 |   if (Error E = validateMagicNumber( | 
 |           StringRef(MagicNumber->data(), MagicNumber->size()))) | 
 |     return std::move(E); | 
 |  | 
 |   auto Parser = | 
 |       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 (std::optional<uint64_t> Version = Helper.ContainerVersion) | 
 |     ContainerVersion = *Version; | 
 |   else | 
 |     return createStringError( | 
 |         std::make_error_code(std::errc::illegal_byte_sequence), | 
 |         "Error while parsing BLOCK_META: missing container version."); | 
 |  | 
 |   if (std::optional<uint8_t> Type = Helper.ContainerType) { | 
 |     // Always >= BitstreamRemarkContainerType::First since it's unsigned. | 
 |     if (*Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last)) | 
 |       return createStringError( | 
 |           std::make_error_code(std::errc::illegal_byte_sequence), | 
 |           "Error while parsing BLOCK_META: invalid container type."); | 
 |  | 
 |     ContainerType = static_cast<BitstreamRemarkContainerType>(*Type); | 
 |   } else | 
 |     return createStringError( | 
 |         std::make_error_code(std::errc::illegal_byte_sequence), | 
 |         "Error while parsing BLOCK_META: missing container type."); | 
 |  | 
 |   return Error::success(); | 
 | } | 
 |  | 
 | static Error processStrTab(BitstreamRemarkParser &P, | 
 |                            std::optional<StringRef> StrTabBuf) { | 
 |   if (!StrTabBuf) | 
 |     return createStringError( | 
 |         std::make_error_code(std::errc::illegal_byte_sequence), | 
 |         "Error while parsing BLOCK_META: missing string table."); | 
 |   // Parse and assign the string table. | 
 |   P.StrTab.emplace(*StrTabBuf); | 
 |   return Error::success(); | 
 | } | 
 |  | 
 | static Error processRemarkVersion(BitstreamRemarkParser &P, | 
 |                                   std::optional<uint64_t> RemarkVersion) { | 
 |   if (!RemarkVersion) | 
 |     return createStringError( | 
 |         std::make_error_code(std::errc::illegal_byte_sequence), | 
 |         "Error while parsing BLOCK_META: missing remark version."); | 
 |   P.RemarkVersion = *RemarkVersion; | 
 |   return Error::success(); | 
 | } | 
 |  | 
 | Error BitstreamRemarkParser::processExternalFilePath( | 
 |     std::optional<StringRef> ExternalFilePath) { | 
 |   if (!ExternalFilePath) | 
 |     return createStringError( | 
 |         std::make_error_code(std::errc::illegal_byte_sequence), | 
 |         "Error while parsing BLOCK_META: missing external file path."); | 
 |  | 
 |   SmallString<80> FullPath(ExternalFilePrependPath); | 
 |   sys::path::append(FullPath, *ExternalFilePath); | 
 |  | 
 |   // 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 == std::nullopt) | 
 |     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); | 
 | } |