LCOV - code coverage report
Current view: top level - lib/OptRemarks - OptRemarksParser.cpp (source / functions) Hit Total Coverage
Test: llvm-toolchain.info Lines: 46 92 50.0 %
Date: 2018-10-20 13:21:21 Functions: 8 17 47.1 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : //===- OptRemarksParser.cpp -----------------------------------------------===//
       2             : //
       3             : //                     The LLVM Compiler Infrastructure
       4             : //
       5             : // This file is dual licensed under the MIT and the University of Illinois Open
       6             : // Source Licenses. See LICENSE.TXT for details.
       7             : //
       8             : //===----------------------------------------------------------------------===//
       9             : //
      10             : // This file provides utility methods used by clients that want to use the
      11             : // parser for optimization remarks in LLVM.
      12             : //
      13             : //===----------------------------------------------------------------------===//
      14             : 
      15             : #include "llvm-c/OptRemarks.h"
      16             : #include "llvm/ADT/STLExtras.h"
      17             : #include "llvm/Support/SourceMgr.h"
      18             : #include "llvm/Support/YAMLTraits.h"
      19             : 
      20             : using namespace llvm;
      21             : 
      22             : namespace {
      23             : struct RemarkParser {
      24             :   /// Source manager for better error messages.
      25             :   SourceMgr SM;
      26             :   /// Stream for yaml parsing.
      27             :   yaml::Stream Stream;
      28             :   /// Storage for the error stream.
      29             :   std::string ErrorString;
      30             :   /// The error stream.
      31             :   raw_string_ostream ErrorStream;
      32             :   /// Iterator in the YAML stream.
      33             :   yaml::document_iterator DI;
      34             :   /// The parsed remark (if any).
      35             :   Optional<LLVMOptRemarkEntry> LastRemark;
      36             :   /// Temporary parsing buffer for the arguments.
      37             :   SmallVector<LLVMOptRemarkArg, 8> TmpArgs;
      38             :   /// The state used by the parser to parse a remark entry. Invalidated with
      39             :   /// every call to `parseYAMLElement`.
      40             :   struct ParseState {
      41             :     /// Temporary parsing buffer for the arguments.
      42             :     SmallVectorImpl<LLVMOptRemarkArg> *Args;
      43             :     StringRef Type;
      44             :     StringRef Pass;
      45             :     StringRef Name;
      46             :     StringRef Function;
      47             :     /// Optional.
      48             :     Optional<StringRef> File;
      49             :     Optional<unsigned> Line;
      50             :     Optional<unsigned> Column;
      51             :     Optional<unsigned> Hotness;
      52             : 
      53         212 :     ParseState(SmallVectorImpl<LLVMOptRemarkArg> &Args) : Args(&Args) {}
      54             :     /// Use Args only as a **temporary** buffer.
      55         164 :     ~ParseState() { Args->clear(); }
      56             :   };
      57             : 
      58             :   ParseState State;
      59             : 
      60             :   /// Set to `true` if we had any errors during parsing.
      61             :   bool HadAnyErrors = false;
      62             : 
      63          48 :   RemarkParser(StringRef Buf)
      64          48 :       : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString),
      65          96 :         DI(Stream.begin()), LastRemark(), TmpArgs(), State(TmpArgs) {
      66             :     SM.setDiagHandler(RemarkParser::HandleDiagnostic, this);
      67          48 :   }
      68             : 
      69             :   /// Parse a YAML element.
      70             :   Error parseYAMLElement(yaml::Document &Remark);
      71             : 
      72             : private:
      73             :   /// Parse one key to a string.
      74             :   /// otherwise.
      75             :   Error parseKey(StringRef &Result, yaml::KeyValueNode &Node);
      76             :   /// Parse one value to a string.
      77             :   Error parseValue(StringRef &Result, yaml::KeyValueNode &Node);
      78             :   /// Parse one value to an unsigned.
      79             :   Error parseValue(Optional<unsigned> &Result, yaml::KeyValueNode &Node);
      80             :   /// Parse a debug location.
      81             :   Error parseDebugLoc(Optional<StringRef> &File, Optional<unsigned> &Line,
      82             :                       Optional<unsigned> &Column, yaml::KeyValueNode &Node);
      83             :   /// Parse an argument.
      84             :   Error parseArg(SmallVectorImpl<LLVMOptRemarkArg> &TmpArgs, yaml::Node &Node);
      85             : 
      86             :   /// Handle a diagnostic from the YAML stream. Records the error in the
      87             :   /// RemarkParser class.
      88          24 :   static void HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx) {
      89             :     assert(Ctx && "Expected non-null Ctx in diagnostic handler.");
      90             :     auto *Parser = static_cast<RemarkParser *>(Ctx);
      91          24 :     Diag.print(/*ProgName=*/nullptr, Parser->ErrorStream, /*ShowColors*/ false,
      92             :                /*ShowKindLabels*/ true);
      93          24 :   }
      94             : };
      95             : 
      96           0 : class ParseError : public ErrorInfo<ParseError> {
      97             : public:
      98             :   static char ID;
      99             : 
     100             :   ParseError(StringRef Message, yaml::Node &Node)
     101          24 :       : Message(Message), Node(Node) {}
     102             : 
     103           0 :   void log(raw_ostream &OS) const override { OS << Message; }
     104           0 :   std::error_code convertToErrorCode() const override {
     105           0 :     return inconvertibleErrorCode();
     106             :   }
     107             : 
     108           0 :   StringRef getMessage() const { return Message; }
     109           0 :   yaml::Node &getNode() const { return Node; }
     110             : 
     111             : private:
     112             :   StringRef Message; // No need to hold a full copy of the buffer.
     113             :   yaml::Node &Node;
     114             : };
     115             : 
     116             : char ParseError::ID = 0;
     117             : 
     118             : static LLVMOptRemarkStringRef toOptRemarkStr(StringRef Str) {
     119         273 :   return {Str.data(), static_cast<uint32_t>(Str.size())};
     120             : }
     121             : 
     122           0 : Error RemarkParser::parseKey(StringRef &Result, yaml::KeyValueNode &Node) {
     123           0 :   auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey());
     124             :   if (!Key)
     125             :     return make_error<ParseError>("key is not a string.", Node);
     126             : 
     127           0 :   Result = Key->getRawValue();
     128             :   return Error::success();
     129             : }
     130             : 
     131           0 : Error RemarkParser::parseValue(StringRef &Result, yaml::KeyValueNode &Node) {
     132           0 :   auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
     133             :   if (!Value)
     134             :     return make_error<ParseError>("expected a value of scalar type.", Node);
     135           0 :   Result = Value->getRawValue();
     136             : 
     137           0 :   if (Result.front() == '\'')
     138           0 :     Result = Result.drop_front();
     139             : 
     140           0 :   if (Result.back() == '\'')
     141           0 :     Result = Result.drop_back();
     142             : 
     143             :   return Error::success();
     144             : }
     145             : 
     146           0 : Error RemarkParser::parseValue(Optional<unsigned> &Result,
     147             :                                yaml::KeyValueNode &Node) {
     148             :   SmallVector<char, 4> Tmp;
     149           0 :   auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
     150             :   if (!Value)
     151             :     return make_error<ParseError>("expected a value of scalar type.", Node);
     152             :   unsigned UnsignedValue = 0;
     153           0 :   if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue))
     154             :     return make_error<ParseError>("expected a value of integer type.", *Value);
     155             :   Result = UnsignedValue;
     156             :   return Error::success();
     157             : }
     158             : 
     159           0 : Error RemarkParser::parseDebugLoc(Optional<StringRef> &File,
     160             :                                   Optional<unsigned> &Line,
     161             :                                   Optional<unsigned> &Column,
     162             :                                   yaml::KeyValueNode &Node) {
     163           0 :   auto *DebugLoc = dyn_cast<yaml::MappingNode>(Node.getValue());
     164             :   if (!DebugLoc)
     165             :     return make_error<ParseError>("expected a value of mapping type.", Node);
     166             : 
     167           0 :   for (yaml::KeyValueNode &DLNode : *DebugLoc) {
     168           0 :     StringRef KeyName;
     169           0 :     if (Error E = parseKey(KeyName, DLNode))
     170             :       return E;
     171             :     if (KeyName == "File") {
     172           0 :       File = StringRef(); // Set the optional to contain a default constructed
     173             :                           // value, to be passed to the parsing function.
     174           0 :       if (Error E = parseValue(*File, DLNode))
     175             :         return E;
     176             :     } else if (KeyName == "Column") {
     177           0 :       if (Error E = parseValue(Column, DLNode))
     178             :         return E;
     179             :     } else if (KeyName == "Line") {
     180           0 :       if (Error E = parseValue(Line, DLNode))
     181             :         return E;
     182             :     } else {
     183             :       return make_error<ParseError>("unknown entry in DebugLoc map.", DLNode);
     184             :     }
     185             :   }
     186             : 
     187             :   // If any of the debug loc fields is missing, return an error.
     188           0 :   if (!File || !Line || !Column)
     189             :     return make_error<ParseError>("DebugLoc node incomplete.", Node);
     190             : 
     191             :   return Error::success();
     192             : }
     193             : 
     194           0 : Error RemarkParser::parseArg(SmallVectorImpl<LLVMOptRemarkArg> &Args,
     195             :                              yaml::Node &Node) {
     196             :   auto *ArgMap = dyn_cast<yaml::MappingNode>(&Node);
     197             :   if (!ArgMap)
     198             :     return make_error<ParseError>("expected a value of mapping type.", Node);
     199             : 
     200           0 :   StringRef ValueStr;
     201             :   StringRef KeyStr;
     202             :   Optional<StringRef> File;
     203             :   Optional<unsigned> Line;
     204             :   Optional<unsigned> Column;
     205             : 
     206           0 :   for (yaml::KeyValueNode &ArgEntry : *ArgMap) {
     207           0 :     StringRef KeyName;
     208           0 :     if (Error E = parseKey(KeyName, ArgEntry))
     209             :       return E;
     210             : 
     211             :     // Try to parse debug locs.
     212             :     if (KeyName == "DebugLoc") {
     213             :       // Can't have multiple DebugLoc entries per argument.
     214           0 :       if (File || Line || Column)
     215             :         return make_error<ParseError>(
     216             :             "only one DebugLoc entry is allowed per argument.", ArgEntry);
     217             : 
     218           0 :       if (Error E = parseDebugLoc(File, Line, Column, ArgEntry))
     219             :         return E;
     220           0 :       continue;
     221             :     }
     222             : 
     223             :     // If we already have a string, error out.
     224           0 :     if (!ValueStr.empty())
     225             :       return make_error<ParseError>(
     226             :           "only one string entry is allowed per argument.", ArgEntry);
     227             : 
     228             :     // Try to parse a string.
     229           0 :     if (Error E = parseValue(ValueStr, ArgEntry))
     230             :       return E;
     231             : 
     232             :     // Keep the key from the string.
     233           0 :     KeyStr = KeyName;
     234             :   }
     235             : 
     236           0 :   if (KeyStr.empty())
     237             :     return make_error<ParseError>("argument key is missing.", *ArgMap);
     238           0 :   if (ValueStr.empty())
     239             :     return make_error<ParseError>("argument value is missing.", *ArgMap);
     240             : 
     241           0 :   Args.push_back(LLVMOptRemarkArg{
     242           0 :       toOptRemarkStr(KeyStr), toOptRemarkStr(ValueStr),
     243           0 :       LLVMOptRemarkDebugLoc{toOptRemarkStr(File.getValueOr(StringRef())),
     244             :                             Line.getValueOr(0), Column.getValueOr(0)}});
     245             : 
     246             :   return Error::success();
     247             : }
     248             : 
     249         164 : Error RemarkParser::parseYAMLElement(yaml::Document &Remark) {
     250             :   // Parsing a new remark, clear the previous one.
     251             :   LastRemark = None;
     252         328 :   State = ParseState(TmpArgs);
     253             : 
     254             :   auto *Root = dyn_cast<yaml::MappingNode>(Remark.getRoot());
     255             :   if (!Root)
     256             :     return make_error<ParseError>("document root is not of mapping type.",
     257             :                                   *Remark.getRoot());
     258             : 
     259         163 :   State.Type = Root->getRawTag();
     260             : 
     261         906 :   for (yaml::KeyValueNode &RemarkField : *Root) {
     262         762 :     StringRef KeyName;
     263        1524 :     if (Error E = parseKey(KeyName, RemarkField))
     264             :       return E;
     265             : 
     266             :     if (KeyName == "Pass") {
     267         320 :       if (Error E = parseValue(State.Pass, RemarkField))
     268             :         return E;
     269             :     } else if (KeyName == "Name") {
     270         318 :       if (Error E = parseValue(State.Name, RemarkField))
     271             :         return E;
     272             :     } else if (KeyName == "Function") {
     273         318 :       if (Error E = parseValue(State.Function, RemarkField))
     274             :         return E;
     275             :     } else if (KeyName == "Hotness") {
     276           0 :       if (Error E = parseValue(State.Hotness, RemarkField))
     277             :         return E;
     278             :     } else if (KeyName == "DebugLoc") {
     279         144 :       if (Error E =
     280         144 :               parseDebugLoc(State.File, State.Line, State.Column, RemarkField))
     281             :         return E;
     282             :     } else if (KeyName == "Args") {
     283         138 :       auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue());
     284             :       if (!Args)
     285             :         return make_error<ParseError>("wrong value type for key.", RemarkField);
     286             : 
     287         687 :       for (yaml::Node &Arg : *Args)
     288        1108 :         if (Error E = parseArg(*State.Args, Arg))
     289             :           return E;
     290             :     } else {
     291             :       return make_error<ParseError>("unknown key.", RemarkField);
     292             :     }
     293             :   }
     294             : 
     295             :   // If the YAML parsing failed, don't even continue parsing. We might
     296             :   // encounter malformed YAML.
     297         144 :   if (Stream.failed())
     298             :     return make_error<ParseError>("YAML parsing failed.", *Remark.getRoot());
     299             : 
     300             :   // Check if any of the mandatory fields are missing.
     301         144 :   if (State.Type.empty() || State.Pass.empty() || State.Name.empty() ||
     302             :       State.Function.empty())
     303             :     return make_error<ParseError>("Type, Pass, Name or Function missing.",
     304             :                                   *Remark.getRoot());
     305             : 
     306             :   LastRemark = LLVMOptRemarkEntry{
     307             :       toOptRemarkStr(State.Type),
     308             :       toOptRemarkStr(State.Pass),
     309             :       toOptRemarkStr(State.Name),
     310             :       toOptRemarkStr(State.Function),
     311             :       LLVMOptRemarkDebugLoc{toOptRemarkStr(State.File.getValueOr(StringRef())),
     312             :                             State.Line.getValueOr(0),
     313             :                             State.Column.getValueOr(0)},
     314             :       State.Hotness.getValueOr(0),
     315         140 :       static_cast<uint32_t>(State.Args->size()),
     316         140 :       State.Args->data()};
     317             : 
     318             :   return Error::success();
     319             : }
     320             : } // namespace
     321             : 
     322             : // Create wrappers for C Binding types (see CBindingWrapping.h).
     323             : DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RemarkParser, LLVMOptRemarkParserRef)
     324             : 
     325          48 : extern "C" LLVMOptRemarkParserRef LLVMOptRemarkParserCreate(const void *Buf,
     326             :                                                             uint64_t Size) {
     327             :   return wrap(
     328          48 :       new RemarkParser(StringRef(static_cast<const char *>(Buf), Size)));
     329             : }
     330             : 
     331             : extern "C" LLVMOptRemarkEntry *
     332         188 : LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser) {
     333             :   RemarkParser &TheParser = *unwrap(Parser);
     334             :   // Check for EOF.
     335         188 :   if (TheParser.HadAnyErrors || TheParser.DI == TheParser.Stream.end())
     336          24 :     return nullptr;
     337             : 
     338             :   // Try to parse an entry.
     339         492 :   if (Error E = TheParser.parseYAMLElement(*TheParser.DI)) {
     340          72 :     handleAllErrors(std::move(E), [&](const ParseError &PE) {
     341             :       TheParser.Stream.printError(&PE.getNode(),
     342             :                                   Twine(PE.getMessage()) + Twine('\n'));
     343             :       TheParser.HadAnyErrors = true;
     344             :     });
     345             :     return nullptr;
     346             :   }
     347             : 
     348             :   // Move on.
     349         140 :   ++TheParser.DI;
     350             : 
     351             :   // Return the just-parsed remark.
     352         140 :   if (Optional<LLVMOptRemarkEntry> &Entry = TheParser.LastRemark)
     353         140 :     return &*Entry;
     354             :   return nullptr;
     355             : }
     356             : 
     357          48 : extern "C" LLVMBool LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser) {
     358          48 :   return unwrap(Parser)->HadAnyErrors;
     359             : }
     360             : 
     361             : extern "C" const char *
     362          24 : LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser) {
     363          24 :   return unwrap(Parser)->ErrorStream.str().c_str();
     364             : }
     365             : 
     366          48 : extern "C" void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser) {
     367          48 :   delete unwrap(Parser);
     368          48 : }

Generated by: LCOV version 1.13