brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.9 KiB · f5973f5 Raw
402 lines · cpp
1//===- unittests/Support/BitstreamRemarksParsingTest.cpp - Parsing tests --===//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#include "llvm-c/Remarks.h"10#include "llvm/Remarks/Remark.h"11#include "llvm/Remarks/RemarkParser.h"12#include "llvm/Remarks/RemarkSerializer.h"13#include "gtest/gtest.h"14 15using namespace llvm;16 17template <size_t N> static void parseGood(const char (&Buf)[N]) {18  // 1. Parse the YAML remark -> FromYAMLRemark19  // 2. Serialize it to bitstream -> BSStream20  // 3. Parse it back -> FromBSRemark21  // 4. Compare the remark objects22  //23  // This testing methodology has the drawback of relying on both the YAML24  // remark parser and the bitstream remark serializer. It does simplify25  // testing a lot, since working directly with bitstream is not that easy.26 27  // 1.28  Expected<std::unique_ptr<remarks::RemarkParser>> MaybeParser =29      remarks::createRemarkParser(remarks::Format::YAML, {Buf, N - 1});30  EXPECT_FALSE(errorToBool(MaybeParser.takeError()));31  EXPECT_TRUE(*MaybeParser != nullptr);32 33  std::unique_ptr<remarks::Remark> FromYAMLRemark = nullptr;34  remarks::RemarkParser &Parser = **MaybeParser;35  Expected<std::unique_ptr<remarks::Remark>> Remark = Parser.next();36  EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors.37  EXPECT_TRUE(*Remark != nullptr);               // At least one remark.38  // Keep the previous remark around.39  FromYAMLRemark = std::move(*Remark);40  Remark = Parser.next();41  Error E = Remark.takeError();42  EXPECT_TRUE(E.isA<remarks::EndOfFileError>());43  EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.44 45  // 2.46  remarks::StringTable BSStrTab;47  BSStrTab.internalize(*FromYAMLRemark);48  std::string BSBuf;49  raw_string_ostream BSStream(BSBuf);50  Expected<std::unique_ptr<remarks::RemarkSerializer>> BSSerializer =51      remarks::createRemarkSerializer(remarks::Format::Bitstream, BSStream,52                                      std::move(BSStrTab));53  EXPECT_FALSE(errorToBool(BSSerializer.takeError()));54  (*BSSerializer)->emit(*FromYAMLRemark);55  (*BSSerializer)->finalize();56 57  // 3.58  Expected<std::unique_ptr<remarks::RemarkParser>> MaybeBSParser =59      remarks::createRemarkParser(remarks::Format::Bitstream, BSStream.str());60  EXPECT_FALSE(errorToBool(MaybeBSParser.takeError()));61  EXPECT_TRUE(*MaybeBSParser != nullptr);62 63  std::unique_ptr<remarks::Remark> FromBSRemark = nullptr;64  remarks::RemarkParser &BSParser = **MaybeBSParser;65  Expected<std::unique_ptr<remarks::Remark>> BSRemark = BSParser.next();66  EXPECT_FALSE(errorToBool(BSRemark.takeError())); // Check for parsing errors.67  EXPECT_TRUE(*BSRemark != nullptr);               // At least one remark.68  // Keep the previous remark around.69  FromBSRemark = std::move(*BSRemark);70  BSRemark = BSParser.next();71  Error BSE = BSRemark.takeError();72  EXPECT_TRUE(BSE.isA<remarks::EndOfFileError>());73  EXPECT_TRUE(errorToBool(std::move(BSE))); // Check for parsing errors.74 75  EXPECT_EQ(*FromYAMLRemark, *FromBSRemark);76}77 78TEST(BitstreamRemarks, ParsingGood) {79  parseGood("\n"80            "--- !Missed\n"81            "Pass: inline\n"82            "Name: NoDefinition\n"83            "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"84            "Function: foo\n"85            "Args:\n"86            "  - Callee: bar\n"87            "  - String: ' will not be inlined into '\n"88            "  - Caller: foo\n"89            "    DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"90            "  - String: ' because its definition is unavailable'\n"91            "");92 93  // No debug loc should also pass.94  parseGood("\n"95            "--- !Missed\n"96            "Pass: inline\n"97            "Name: NoDefinition\n"98            "Function: foo\n"99            "Args:\n"100            "  - Callee: bar\n"101            "  - String: ' will not be inlined into '\n"102            "  - Caller: foo\n"103            "    DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"104            "  - String: ' because its definition is unavailable'\n"105            "");106 107  // No args is also ok.108  parseGood("\n"109            "--- !Missed\n"110            "Pass: inline\n"111            "Name: NoDefinition\n"112            "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"113            "Function: foo\n"114            "");115}116 117// Mandatory common part of a remark.118#define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\n"119// Test all the types.120TEST(BitstreamRemarks, ParsingTypes) {121  // Type: Passed122  parseGood("--- !Passed" COMMON_REMARK);123  // Type: Missed124  parseGood("--- !Missed" COMMON_REMARK);125  // Type: Analysis126  parseGood("--- !Analysis" COMMON_REMARK);127  // Type: AnalysisFPCommute128  parseGood("--- !AnalysisFPCommute" COMMON_REMARK);129  // Type: AnalysisAliasing130  parseGood("--- !AnalysisAliasing" COMMON_REMARK);131  // Type: Failure132  parseGood("--- !Failure" COMMON_REMARK);133}134#undef COMMON_REMARK135 136static inline StringRef checkStr(StringRef Str, unsigned ExpectedLen) {137  const char *StrData = Str.data();138  unsigned StrLen = Str.size();139  EXPECT_EQ(StrLen, ExpectedLen);140  return StringRef(StrData, StrLen);141}142 143TEST(BitstreamRemarks, Contents) {144  StringRef Buf = "\n"145                  "--- !Missed\n"146                  "Pass: inline\n"147                  "Name: NoDefinition\n"148                  "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"149                  "Function: foo\n"150                  "Hotness: 4\n"151                  "Args:\n"152                  "  - Callee: bar\n"153                  "  - String: ' will not be inlined into '\n"154                  "  - Caller: foo\n"155                  "    DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"156                  "  - String: ' because its definition is unavailable'\n"157                  "\n";158 159  Expected<std::unique_ptr<remarks::RemarkParser>> MaybeParser =160      remarks::createRemarkParser(remarks::Format::YAML, Buf);161  EXPECT_FALSE(errorToBool(MaybeParser.takeError()));162  EXPECT_TRUE(*MaybeParser != nullptr);163 164  remarks::RemarkParser &Parser = **MaybeParser;165  Expected<std::unique_ptr<remarks::Remark>> MaybeRemark = Parser.next();166  EXPECT_FALSE(167      errorToBool(MaybeRemark.takeError())); // Check for parsing errors.168  EXPECT_TRUE(*MaybeRemark != nullptr);      // At least one remark.169 170  const remarks::Remark &Remark = **MaybeRemark;171  EXPECT_EQ(Remark.RemarkType, remarks::Type::Missed);172  EXPECT_EQ(checkStr(Remark.PassName, 6), "inline");173  EXPECT_EQ(checkStr(Remark.RemarkName, 12), "NoDefinition");174  EXPECT_EQ(checkStr(Remark.FunctionName, 3), "foo");175  EXPECT_TRUE(Remark.Loc);176  const remarks::RemarkLocation &RL = *Remark.Loc;177  EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c");178  EXPECT_EQ(RL.SourceLine, 3U);179  EXPECT_EQ(RL.SourceColumn, 12U);180  EXPECT_TRUE(Remark.Hotness);181  EXPECT_EQ(*Remark.Hotness, 4U);182  EXPECT_EQ(Remark.Args.size(), 4U);183 184  unsigned ArgID = 0;185  for (const remarks::Argument &Arg : Remark.Args) {186    switch (ArgID) {187    case 0:188      EXPECT_EQ(checkStr(Arg.Key, 6), "Callee");189      EXPECT_EQ(checkStr(Arg.Val, 3), "bar");190      EXPECT_FALSE(Arg.Loc);191      break;192    case 1:193      EXPECT_EQ(checkStr(Arg.Key, 6), "String");194      EXPECT_EQ(checkStr(Arg.Val, 26), " will not be inlined into ");195      EXPECT_FALSE(Arg.Loc);196      break;197    case 2: {198      EXPECT_EQ(checkStr(Arg.Key, 6), "Caller");199      EXPECT_EQ(checkStr(Arg.Val, 3), "foo");200      EXPECT_TRUE(Arg.Loc);201      const remarks::RemarkLocation &RL = *Arg.Loc;202      EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c");203      EXPECT_EQ(RL.SourceLine, 2U);204      EXPECT_EQ(RL.SourceColumn, 0U);205      break;206    }207    case 3:208      EXPECT_EQ(checkStr(Arg.Key, 6), "String");209      EXPECT_EQ(checkStr(Arg.Val, 38),210                " because its definition is unavailable");211      EXPECT_FALSE(Arg.Loc);212      break;213    default:214      break;215    }216    ++ArgID;217  }218 219  MaybeRemark = Parser.next();220  Error E = MaybeRemark.takeError();221  EXPECT_TRUE(E.isA<remarks::EndOfFileError>());222  EXPECT_TRUE(errorToBool(std::move(E))); // Check for parsing errors.223}224 225static inline StringRef checkStr(LLVMRemarkStringRef Str,226                                 unsigned ExpectedLen) {227  const char *StrData = LLVMRemarkStringGetData(Str);228  unsigned StrLen = LLVMRemarkStringGetLen(Str);229  EXPECT_EQ(StrLen, ExpectedLen);230  return StringRef(StrData, StrLen);231}232 233TEST(BitstreamRemarks, ContentsCAPI) {234  remarks::StringTable BSStrTab;235  remarks::Remark ToSerializeRemark;236  ToSerializeRemark.RemarkType = remarks::Type::Missed;237  ToSerializeRemark.PassName = "inline";238  ToSerializeRemark.RemarkName = "NoDefinition";239  ToSerializeRemark.FunctionName = "foo";240  ToSerializeRemark.Loc = remarks::RemarkLocation{"file.c", 3, 12};241  ToSerializeRemark.Hotness = 0;242  ToSerializeRemark.Args.emplace_back();243  ToSerializeRemark.Args.back().Key = "Callee";244  ToSerializeRemark.Args.back().Val = "bar";245  ToSerializeRemark.Args.emplace_back();246  ToSerializeRemark.Args.back().Key = "String";247  ToSerializeRemark.Args.back().Val = " will not be inlined into ";248  ToSerializeRemark.Args.emplace_back();249  ToSerializeRemark.Args.back().Key = "Caller";250  ToSerializeRemark.Args.back().Val = "foo";251  ToSerializeRemark.Args.back().Loc = remarks::RemarkLocation{"file.c", 2, 0};252  ToSerializeRemark.Args.emplace_back();253  ToSerializeRemark.Args.back().Key = "String";254  ToSerializeRemark.Args.back().Val = " because its definition is unavailable";255  BSStrTab.internalize(ToSerializeRemark);256  std::string BSBuf;257  raw_string_ostream BSStream(BSBuf);258  Expected<std::unique_ptr<remarks::RemarkSerializer>> BSSerializer =259      remarks::createRemarkSerializer(remarks::Format::Bitstream, BSStream,260                                      std::move(BSStrTab));261  EXPECT_FALSE(errorToBool(BSSerializer.takeError()));262  (*BSSerializer)->emit(ToSerializeRemark);263  (*BSSerializer)->finalize();264 265  StringRef Buf = BSStream.str();266  LLVMRemarkParserRef Parser =267      LLVMRemarkParserCreateBitstream(Buf.data(), Buf.size());268  LLVMRemarkEntryRef Remark = LLVMRemarkParserGetNext(Parser);269  EXPECT_FALSE(Remark == nullptr);270  EXPECT_EQ(LLVMRemarkEntryGetType(Remark), LLVMRemarkTypeMissed);271  EXPECT_EQ(checkStr(LLVMRemarkEntryGetPassName(Remark), 6), "inline");272  EXPECT_EQ(checkStr(LLVMRemarkEntryGetRemarkName(Remark), 12), "NoDefinition");273  EXPECT_EQ(checkStr(LLVMRemarkEntryGetFunctionName(Remark), 3), "foo");274  LLVMRemarkDebugLocRef DL = LLVMRemarkEntryGetDebugLoc(Remark);275  EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL), 6), "file.c");276  EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL), 3U);277  EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL), 12U);278  EXPECT_EQ(LLVMRemarkEntryGetHotness(Remark), 0U);279  EXPECT_EQ(LLVMRemarkEntryGetNumArgs(Remark), 4U);280 281  unsigned ArgID = 0;282  LLVMRemarkArgRef Arg = LLVMRemarkEntryGetFirstArg(Remark);283  do {284    switch (ArgID) {285    case 0:286      EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "Callee");287      EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 3), "bar");288      EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);289      break;290    case 1:291      EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "String");292      EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 26),293                " will not be inlined into ");294      EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);295      break;296    case 2: {297      EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "Caller");298      EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 3), "foo");299      LLVMRemarkDebugLocRef DL = LLVMRemarkArgGetDebugLoc(Arg);300      EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL), 6), "file.c");301      EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL), 2U);302      EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL), 0U);303      break;304    }305    case 3:306      EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "String");307      EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 38),308                " because its definition is unavailable");309      EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);310      break;311    default:312      break;313    }314    ++ArgID;315  } while ((Arg = LLVMRemarkEntryGetNextArg(Arg, Remark)));316 317  LLVMRemarkEntryDispose(Remark);318 319  EXPECT_EQ(LLVMRemarkParserGetNext(Parser), nullptr);320 321  EXPECT_FALSE(LLVMRemarkParserHasError(Parser));322  LLVMRemarkParserDispose(Parser);323}324 325static void parseBad(StringRef Input, const char *ErrorMsg) {326  Expected<std::unique_ptr<remarks::RemarkParser>> MaybeBSParser =327      remarks::createRemarkParser(remarks::Format::Bitstream, Input);328  EXPECT_FALSE(errorToBool(MaybeBSParser.takeError()));329  EXPECT_TRUE(*MaybeBSParser != nullptr);330 331  remarks::RemarkParser &BSParser = **MaybeBSParser;332  Expected<std::unique_ptr<remarks::Remark>> BSRemark = BSParser.next();333  EXPECT_EQ(ErrorMsg, toString(BSRemark.takeError())); // Expect an error.334}335 336TEST(BitstreamRemarks, ParsingEmpty) {337  parseBad(StringRef(), "End of file reached.");338}339 340TEST(BitstreamRemarks, ParsingBadMagic) {341  parseBad("KRMR", "Unknown magic number: expecting RMRK, got KRMR.");342}343 344// Testing malformed bitstream is not easy. We would need to replace bytes in345// the stream to create malformed and unknown records and blocks. There is no346// textual format for bitstream that can be decoded, modified and encoded347// back.348 349// FIXME: Add tests for the following error messages:350// * Error while parsing META_BLOCK: malformed record entry351// (RECORD_META_CONTAINER_INFO).352// * Error while parsing META_BLOCK: malformed record entry353// (RECORD_META_REMARK_VERSION).354// * Error while parsing META_BLOCK: malformed record entry355// (RECORD_META_STRTAB).356// * Error while parsing META_BLOCK: malformed record entry357// (RECORD_META_EXTERNAL_FILE).358// * Error while parsing META_BLOCK: unknown record entry (NUM).359// * Error while parsing REMARK_BLOCK: malformed record entry360// (RECORD_REMARK_HEADER).361// * Error while parsing REMARK_BLOCK: malformed record entry362// (RECORD_REMARK_DEBUG_LOC).363// * Error while parsing REMARK_BLOCK: malformed record entry364// (RECORD_REMARK_HOTNESS).365// * Error while parsing REMARK_BLOCK: malformed record entry366// (RECORD_REMARK_ARG_WITH_DEBUGLOC).367// * Error while parsing REMARK_BLOCK: malformed record entry368// (RECORD_REMARK_ARG_WITHOUT_DEBUGLOC).369// * Error while parsing REMARK_BLOCK: unknown record entry (NUM).370// * Error while parsing META_BLOCK: expecting [ENTER_SUBBLOCO, META_BLOCK,371// ...].372// * Error while entering META_BLOCK.373// * Error while parsing META_BLOCK: expecting records.374// * Error while parsing META_BLOCK: unterminated block.375// * Error while parsing REMARK_BLOCK: expecting [ENTER_SUBBLOCO, REMARK_BLOCK,376// ...].377// * Error while entering REMARK_BLOCK.378// * Error while parsing REMARK_BLOCK: expecting records.379// * Error while parsing REMARK_BLOCK: unterminated block.380// * Error while parsing BLOCKINFO_BLOCK: expecting [ENTER_SUBBLOCK,381// BLOCKINFO_BLOCK, ...].382// * Error while parsing BLOCKINFO_BLOCK.383// * Unexpected error while parsing bitstream.384// * Expecting META_BLOCK after the BLOCKINFO_BLOCK.385// * Error while parsing BLOCK_META: missing container version.386// * Error while parsing BLOCK_META: invalid container type.387// * Error while parsing BLOCK_META: missing container type.388// * Error while parsing BLOCK_META: missing string table.389// * Error while parsing BLOCK_META: missing remark version.390// * Error while parsing BLOCK_META: missing external file path.391// * Error while parsing external file's BLOCK_META: wrong container type.392// * Error while parsing external file's BLOCK_META: mismatching versions:393// original meta: NUM, external file meta: NUM.394// * Error while parsing BLOCK_REMARK: missing string table.395// * Error while parsing BLOCK_REMARK: missing remark type.396// * Error while parsing BLOCK_REMARK: unknown remark type.397// * Error while parsing BLOCK_REMARK: missing remark name.398// * Error while parsing BLOCK_REMARK: missing remark pass.399// * Error while parsing BLOCK_REMARK: missing remark function name.400// * Error while parsing BLOCK_REMARK: missing key in remark argument.401// * Error while parsing BLOCK_REMARK: missing value in remark argument.402