brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.2 KiB · 33eedd6 Raw
508 lines · cpp
1//===- BitstreamRemarkParser.cpp ------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file provides utility methods used by clients that want to use the10// parser for remark diagnostics in LLVM.11//12//===----------------------------------------------------------------------===//13 14#include "BitstreamRemarkParser.h"15#include "llvm/Support/MemoryBuffer.h"16#include "llvm/Support/Path.h"17#include <optional>18 19using namespace llvm;20using namespace llvm::remarks;21 22namespace {23 24template <typename... Ts> Error error(char const *Fmt, const Ts &...Vals) {25  std::string Buffer;26  raw_string_ostream OS(Buffer);27  OS << formatv(Fmt, Vals...);28  return make_error<StringError>(29      std::move(Buffer),30      std::make_error_code(std::errc::illegal_byte_sequence));31}32 33} // namespace34 35Error BitstreamBlockParserHelperBase::unknownRecord(unsigned AbbrevID) {36  return error("Unknown record entry ({}).", AbbrevID);37}38 39Error BitstreamBlockParserHelperBase::unexpectedRecord(StringRef RecordName) {40  return error("Unexpected record entry ({}).", RecordName);41}42 43Error BitstreamBlockParserHelperBase::malformedRecord(StringRef RecordName) {44  return error("Malformed record entry ({}).", RecordName);45}46 47Error BitstreamBlockParserHelperBase::unexpectedBlock(unsigned Code) {48  return error("Unexpected subblock ({}).", Code);49}50 51static Expected<unsigned> expectSubBlock(BitstreamCursor &Stream) {52  Expected<BitstreamEntry> Next = Stream.advance();53  if (!Next)54    return Next.takeError();55  switch (Next->Kind) {56  case BitstreamEntry::SubBlock:57    return Next->ID;58  case BitstreamEntry::Record:59  case BitstreamEntry::EndBlock:60    return error("Expected subblock, but got unexpected record.");61  case BitstreamEntry::Error:62    return error("Expected subblock, but got unexpected end of bitstream.");63  }64  llvm_unreachable("Unexpected BitstreamEntry");65}66 67Error BitstreamBlockParserHelperBase::expectBlock() {68  auto MaybeBlockID = expectSubBlock(Stream);69  if (!MaybeBlockID)70    return MaybeBlockID.takeError();71  if (*MaybeBlockID != BlockID)72    return error("Expected {} block, but got unexpected block ({}).", BlockName,73                 *MaybeBlockID);74  return Error::success();75}76 77Error BitstreamBlockParserHelperBase::enterBlock() {78  if (Stream.EnterSubBlock(BlockID))79    return error("Error while entering {} block.", BlockName);80  return Error::success();81}82 83Error BitstreamMetaParserHelper::parseRecord(unsigned Code) {84  // Note: 2 is used here because it's the max number of fields we have per85  // record.86  SmallVector<uint64_t, 2> Record;87  StringRef Blob;88  Expected<unsigned> RecordID = Stream.readRecord(Code, Record, &Blob);89  if (!RecordID)90    return RecordID.takeError();91 92  switch (*RecordID) {93  case RECORD_META_CONTAINER_INFO: {94    if (Record.size() != 2)95      return malformedRecord(MetaContainerInfoName);96    Container = {Record[0], Record[1]};97    // Error immediately if container version is outdated, so the user sees an98    // explanation instead of a parser error.99    if (Container->Version != CurrentContainerVersion) {100      return ::error(101          "Unsupported remark container version (expected: {}, read: {}). "102          "Please upgrade/downgrade your toolchain to read this container.",103          CurrentContainerVersion, Container->Version);104    }105    break;106  }107  case RECORD_META_REMARK_VERSION: {108    if (Record.size() != 1)109      return malformedRecord(MetaRemarkVersionName);110    RemarkVersion = Record[0];111    // Error immediately if remark version is outdated, so the user sees an112    // explanation instead of a parser error.113    if (*RemarkVersion != CurrentRemarkVersion) {114      return ::error(115          "Unsupported remark version in container (expected: {}, read: {}). "116          "Please upgrade/downgrade your toolchain to read this container.",117          CurrentRemarkVersion, *RemarkVersion);118    }119    break;120  }121  case RECORD_META_STRTAB: {122    if (Record.size() != 0)123      return malformedRecord(MetaStrTabName);124    StrTabBuf = Blob;125    break;126  }127  case RECORD_META_EXTERNAL_FILE: {128    if (Record.size() != 0)129      return malformedRecord(MetaExternalFileName);130    ExternalFilePath = Blob;131    break;132  }133  default:134    return unknownRecord(*RecordID);135  }136  return Error::success();137}138 139Error BitstreamRemarkParserHelper::parseRecord(unsigned Code) {140  Record.clear();141  Expected<unsigned> MaybeRecordID =142      Stream.readRecord(Code, Record, &RecordBlob);143  if (!MaybeRecordID)144    return MaybeRecordID.takeError();145  RecordID = *MaybeRecordID;146  return handleRecord();147}148 149Error BitstreamRemarkParserHelper::handleRecord() {150  switch (RecordID) {151  case RECORD_REMARK_HEADER: {152    if (Record.size() != 4)153      return malformedRecord(RemarkHeaderName);154    Type = Record[0];155    RemarkNameIdx = Record[1];156    PassNameIdx = Record[2];157    FunctionNameIdx = Record[3];158    break;159  }160  case RECORD_REMARK_DEBUG_LOC: {161    if (Record.size() != 3)162      return malformedRecord(RemarkDebugLocName);163    Loc = {Record[0], Record[1], Record[2]};164    break;165  }166  case RECORD_REMARK_HOTNESS: {167    if (Record.size() != 1)168      return malformedRecord(RemarkHotnessName);169    Hotness = Record[0];170    break;171  }172  case RECORD_REMARK_ARG_WITH_DEBUGLOC: {173    if (Record.size() != 5)174      return malformedRecord(RemarkArgWithDebugLocName);175    auto &Arg = Args.emplace_back(Record[0], Record[1]);176    Arg.Loc = {Record[2], Record[3], Record[4]};177    break;178  }179  case RECORD_REMARK_ARG_WITHOUT_DEBUGLOC: {180    if (Record.size() != 2)181      return malformedRecord(RemarkArgWithoutDebugLocName);182    Args.emplace_back(Record[0], Record[1]);183    break;184  }185  default:186    return unknownRecord(RecordID);187  }188  return Error::success();189}190 191Error BitstreamRemarkParserHelper::parseNext() {192  Type.reset();193  RemarkNameIdx.reset();194  PassNameIdx.reset();195  FunctionNameIdx.reset();196  Hotness.reset();197  Loc.reset();198  Args.clear();199 200  return parseBlock();201}202 203Error BitstreamParserHelper::expectMagic() {204  std::array<char, 4> Result;205  for (unsigned I = 0; I < 4; ++I)206    if (Expected<unsigned> R = Stream.Read(8))207      Result[I] = *R;208    else209      return R.takeError();210 211  StringRef MagicNumber{Result.data(), Result.size()};212  if (MagicNumber != remarks::ContainerMagic)213    return error("Unknown magic number: expecting {}, got {}.",214                 remarks::ContainerMagic, MagicNumber);215  return Error::success();216}217 218Error BitstreamParserHelper::parseBlockInfoBlock() {219  Expected<BitstreamEntry> Next = Stream.advance();220  if (!Next)221    return Next.takeError();222  if (Next->Kind != BitstreamEntry::SubBlock ||223      Next->ID != llvm::bitc::BLOCKINFO_BLOCK_ID)224    return error(225        "Error while parsing BLOCKINFO_BLOCK: expecting [ENTER_SUBBLOCK, "226        "BLOCKINFO_BLOCK, ...].");227 228  Expected<std::optional<BitstreamBlockInfo>> MaybeBlockInfo =229      Stream.ReadBlockInfoBlock();230  if (!MaybeBlockInfo)231    return MaybeBlockInfo.takeError();232 233  if (!*MaybeBlockInfo)234    return error("Missing BLOCKINFO_BLOCK.");235 236  BlockInfo = **MaybeBlockInfo;237 238  Stream.setBlockInfo(&BlockInfo);239  return Error::success();240}241 242Error BitstreamParserHelper::parseMeta() {243  if (Error E = expectMagic())244    return E;245  if (Error E = parseBlockInfoBlock())246    return E;247 248  // Parse early meta block.249  if (Error E = MetaHelper.expectBlock())250    return E;251  if (Error E = MetaHelper.parseBlock())252    return E;253 254  // Skip all Remarks blocks.255  while (!Stream.AtEndOfStream()) {256    auto MaybeBlockID = expectSubBlock(Stream);257    if (!MaybeBlockID)258      return MaybeBlockID.takeError();259    if (*MaybeBlockID == META_BLOCK_ID)260      break;261    if (*MaybeBlockID != REMARK_BLOCK_ID)262      return error("Unexpected block between meta blocks.");263    // Remember first remark block.264    if (!RemarkStartBitPos)265      RemarkStartBitPos = Stream.GetCurrentBitNo();266    if (Error E = Stream.SkipBlock())267      return E;268  }269 270  // Late meta block is optional if there are no remarks.271  if (Stream.AtEndOfStream())272    return Error::success();273 274  // Parse late meta block.275  if (Error E = MetaHelper.parseBlock())276    return E;277  return Error::success();278}279 280Error BitstreamParserHelper::parseRemark() {281  if (RemarkStartBitPos) {282    RemarkStartBitPos.reset();283  } else {284    auto MaybeBlockID = expectSubBlock(Stream);285    if (!MaybeBlockID)286      return MaybeBlockID.takeError();287    if (*MaybeBlockID != REMARK_BLOCK_ID)288      return make_error<EndOfFileError>();289  }290  return RemarksHelper->parseNext();291}292 293Expected<std::unique_ptr<BitstreamRemarkParser>>294remarks::createBitstreamParserFromMeta(295    StringRef Buf, std::optional<StringRef> ExternalFilePrependPath) {296  auto Parser = std::make_unique<BitstreamRemarkParser>(Buf);297 298  if (ExternalFilePrependPath)299    Parser->ExternalFilePrependPath = std::string(*ExternalFilePrependPath);300 301  return std::move(Parser);302}303 304BitstreamRemarkParser::BitstreamRemarkParser(StringRef Buf)305    : RemarkParser(Format::Bitstream), ParserHelper(Buf) {}306 307Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::next() {308  if (!IsMetaReady) {309    // Container is completely empty.310    if (ParserHelper->Stream.AtEndOfStream())311      return make_error<EndOfFileError>();312 313    if (Error E = parseMeta())314      return std::move(E);315    IsMetaReady = true;316 317    // Container has meta, but no remarks blocks.318    if (!ParserHelper->RemarkStartBitPos)319      return error(320          "Container is non-empty, but does not contain any remarks blocks.");321 322    if (Error E =323            ParserHelper->Stream.JumpToBit(*ParserHelper->RemarkStartBitPos))324      return std::move(E);325    ParserHelper->RemarksHelper.emplace(ParserHelper->Stream);326  }327 328  if (Error E = ParserHelper->parseRemark())329    return std::move(E);330  return processRemark();331}332 333Error BitstreamRemarkParser::parseMeta() {334  if (Error E = ParserHelper->parseMeta())335    return E;336  if (Error E = processCommonMeta())337    return E;338 339  switch (ContainerType) {340  case BitstreamRemarkContainerType::RemarksFileExternal:341    return processExternalFilePath();342  case BitstreamRemarkContainerType::RemarksFile:343    return processFileContainerMeta();344  }345  llvm_unreachable("Unknown BitstreamRemarkContainerType enum");346}347 348Error BitstreamRemarkParser::processCommonMeta() {349  auto &Helper = ParserHelper->MetaHelper;350  if (!Helper.Container)351    return Helper.error("Missing container info.");352  auto &Container = *Helper.Container;353  ContainerVersion = Container.Version;354  // Always >= BitstreamRemarkContainerType::First since it's unsigned.355  if (Container.Type > static_cast<uint8_t>(BitstreamRemarkContainerType::Last))356    return Helper.error("Invalid container type.");357  ContainerType = static_cast<BitstreamRemarkContainerType>(Container.Type);358  return Error::success();359}360 361Error BitstreamRemarkParser::processFileContainerMeta() {362  if (Error E = processRemarkVersion())363    return E;364  if (Error E = processStrTab())365    return E;366  return Error::success();367}368 369Error BitstreamRemarkParser::processStrTab() {370  auto &Helper = ParserHelper->MetaHelper;371  if (!Helper.StrTabBuf)372    return Helper.error("Missing string table.");373  // Parse and assign the string table.374  StrTab.emplace(*Helper.StrTabBuf);375  return Error::success();376}377 378Error BitstreamRemarkParser::processRemarkVersion() {379  auto &Helper = ParserHelper->MetaHelper;380  if (!Helper.RemarkVersion)381    return Helper.error("Missing remark version.");382  RemarkVersion = *Helper.RemarkVersion;383  return Error::success();384}385 386Error BitstreamRemarkParser::processExternalFilePath() {387  auto &Helper = ParserHelper->MetaHelper;388  if (!Helper.ExternalFilePath)389    return Helper.error("Missing external file path.");390 391  SmallString<80> FullPath(ExternalFilePrependPath);392  sys::path::append(FullPath, *Helper.ExternalFilePath);393 394  // External file: open the external file, parse it, check if its metadata395  // matches the one from the separate metadata, then replace the current396  // parser with the one parsing the remarks.397  ErrorOr<std::unique_ptr<MemoryBuffer>> BufferOrErr =398      MemoryBuffer::getFile(FullPath);399  if (std::error_code EC = BufferOrErr.getError())400    return createFileError(FullPath, EC);401 402  TmpRemarkBuffer = std::move(*BufferOrErr);403 404  // Don't try to parse the file if it's empty.405  if (TmpRemarkBuffer->getBufferSize() == 0)406    return make_error<EndOfFileError>();407 408  // Create a separate parser used for parsing the separate file.409  ParserHelper.emplace(TmpRemarkBuffer->getBuffer());410  if (Error E = parseMeta())411    return E;412 413  if (ContainerType != BitstreamRemarkContainerType::RemarksFile)414    return ParserHelper->MetaHelper.error(415        "Wrong container type in external file.");416 417  return Error::success();418}419 420Expected<std::unique_ptr<Remark>> BitstreamRemarkParser::processRemark() {421  auto &Helper = *ParserHelper->RemarksHelper;422  std::unique_ptr<Remark> Result = std::make_unique<Remark>();423  Remark &R = *Result;424 425  if (!StrTab)426    return Helper.error("Missing string table.");427 428  if (!Helper.Type)429    return Helper.error("Missing remark type.");430 431  // Always >= Type::First since it's unsigned.432  if (*Helper.Type > static_cast<uint8_t>(Type::Last))433    return Helper.error("Unknown remark type.");434 435  R.RemarkType = static_cast<Type>(*Helper.Type);436 437  if (!Helper.RemarkNameIdx)438    return Helper.error("Missing remark name.");439 440  if (Expected<StringRef> RemarkName = (*StrTab)[*Helper.RemarkNameIdx])441    R.RemarkName = *RemarkName;442  else443    return RemarkName.takeError();444 445  if (!Helper.PassNameIdx)446    return Helper.error("Missing remark pass.");447 448  if (Expected<StringRef> PassName = (*StrTab)[*Helper.PassNameIdx])449    R.PassName = *PassName;450  else451    return PassName.takeError();452 453  if (!Helper.FunctionNameIdx)454    return Helper.error("Missing remark function name.");455 456  if (Expected<StringRef> FunctionName = (*StrTab)[*Helper.FunctionNameIdx])457    R.FunctionName = *FunctionName;458  else459    return FunctionName.takeError();460 461  if (Helper.Loc) {462    Expected<StringRef> SourceFileName =463        (*StrTab)[Helper.Loc->SourceFileNameIdx];464    if (!SourceFileName)465      return SourceFileName.takeError();466    R.Loc.emplace();467    R.Loc->SourceFilePath = *SourceFileName;468    R.Loc->SourceLine = Helper.Loc->SourceLine;469    R.Loc->SourceColumn = Helper.Loc->SourceColumn;470  }471 472  if (Helper.Hotness)473    R.Hotness = *Helper.Hotness;474 475  for (const BitstreamRemarkParserHelper::Argument &Arg : Helper.Args) {476    if (!Arg.KeyIdx)477      return Helper.error("Missing key in remark argument.");478    if (!Arg.ValueIdx)479      return Helper.error("Missing value in remark argument.");480 481    // We have at least a key and a value, create an entry.482    auto &RArg = R.Args.emplace_back();483 484    if (Expected<StringRef> Key = (*StrTab)[*Arg.KeyIdx])485      RArg.Key = *Key;486    else487      return Key.takeError();488 489    if (Expected<StringRef> Value = (*StrTab)[*Arg.ValueIdx])490      RArg.Val = *Value;491    else492      return Value.takeError();493 494    if (Arg.Loc) {495      if (Expected<StringRef> SourceFileName =496              (*StrTab)[Arg.Loc->SourceFileNameIdx]) {497        RArg.Loc.emplace();498        RArg.Loc->SourceFilePath = *SourceFileName;499        RArg.Loc->SourceLine = Arg.Loc->SourceLine;500        RArg.Loc->SourceColumn = Arg.Loc->SourceColumn;501      } else502        return SourceFileName.takeError();503    }504  }505 506  return std::move(Result);507}508