605 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			605 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===- 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"
 | |
| 
 | |
| 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);
 | |
| }
 |