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 
ParseState__anondd70ad610111::RemarkParser::ParseState53     ParseState(SmallVectorImpl<LLVMOptRemarkArg> &Args) : Args(&Args) {}
54     /// Use Args only as a **temporary** buffer.
~ParseState__anondd70ad610111::RemarkParser::ParseState55     ~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 
RemarkParser__anondd70ad610111::RemarkParser63   RemarkParser(StringRef Buf)
64       : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString),
65         DI(Stream.begin()), LastRemark(), TmpArgs(), State(TmpArgs) {
66     SM.setDiagHandler(RemarkParser::HandleDiagnostic, this);
67   }
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.
HandleDiagnostic__anondd70ad610111::RemarkParser88   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     Diag.print(/*ProgName=*/nullptr, Parser->ErrorStream, /*ShowColors*/ false,
92                /*ShowKindLabels*/ true);
93   }
94 };
95 
96 class ParseError : public ErrorInfo<ParseError> {
97 public:
98   static char ID;
99 
ParseError(StringRef Message,yaml::Node & Node)100   ParseError(StringRef Message, yaml::Node &Node)
101       : Message(Message), Node(Node) {}
102 
log(raw_ostream & OS) const103   void log(raw_ostream &OS) const override { OS << Message; }
convertToErrorCode() const104   std::error_code convertToErrorCode() const override {
105     return inconvertibleErrorCode();
106   }
107 
getMessage() const108   StringRef getMessage() const { return Message; }
getNode() const109   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 
toOptRemarkStr(StringRef Str)118 static LLVMOptRemarkStringRef toOptRemarkStr(StringRef Str) {
119   return {Str.data(), static_cast<uint32_t>(Str.size())};
120 }
121 
parseKey(StringRef & Result,yaml::KeyValueNode & Node)122 Error RemarkParser::parseKey(StringRef &Result, yaml::KeyValueNode &Node) {
123   auto *Key = dyn_cast<yaml::ScalarNode>(Node.getKey());
124   if (!Key)
125     return make_error<ParseError>("key is not a string.", Node);
126 
127   Result = Key->getRawValue();
128   return Error::success();
129 }
130 
parseValue(StringRef & Result,yaml::KeyValueNode & Node)131 Error RemarkParser::parseValue(StringRef &Result, yaml::KeyValueNode &Node) {
132   auto *Value = dyn_cast<yaml::ScalarNode>(Node.getValue());
133   if (!Value)
134     return make_error<ParseError>("expected a value of scalar type.", Node);
135   Result = Value->getRawValue();
136 
137   if (Result.front() == '\'')
138     Result = Result.drop_front();
139 
140   if (Result.back() == '\'')
141     Result = Result.drop_back();
142 
143   return Error::success();
144 }
145 
parseValue(Optional<unsigned> & Result,yaml::KeyValueNode & Node)146 Error RemarkParser::parseValue(Optional<unsigned> &Result,
147                                yaml::KeyValueNode &Node) {
148   SmallVector<char, 4> Tmp;
149   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   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 
parseDebugLoc(Optional<StringRef> & File,Optional<unsigned> & Line,Optional<unsigned> & Column,yaml::KeyValueNode & Node)159 Error RemarkParser::parseDebugLoc(Optional<StringRef> &File,
160                                   Optional<unsigned> &Line,
161                                   Optional<unsigned> &Column,
162                                   yaml::KeyValueNode &Node) {
163   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   for (yaml::KeyValueNode &DLNode : *DebugLoc) {
168     StringRef KeyName;
169     if (Error E = parseKey(KeyName, DLNode))
170       return E;
171     if (KeyName == "File") {
172       File = StringRef(); // Set the optional to contain a default constructed
173                           // value, to be passed to the parsing function.
174       if (Error E = parseValue(*File, DLNode))
175         return E;
176     } else if (KeyName == "Column") {
177       if (Error E = parseValue(Column, DLNode))
178         return E;
179     } else if (KeyName == "Line") {
180       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   if (!File || !Line || !Column)
189     return make_error<ParseError>("DebugLoc node incomplete.", Node);
190 
191   return Error::success();
192 }
193 
parseArg(SmallVectorImpl<LLVMOptRemarkArg> & Args,yaml::Node & Node)194 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   StringRef ValueStr;
201   StringRef KeyStr;
202   Optional<StringRef> File;
203   Optional<unsigned> Line;
204   Optional<unsigned> Column;
205 
206   for (yaml::KeyValueNode &ArgEntry : *ArgMap) {
207     StringRef KeyName;
208     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       if (File || Line || Column)
215         return make_error<ParseError>(
216             "only one DebugLoc entry is allowed per argument.", ArgEntry);
217 
218       if (Error E = parseDebugLoc(File, Line, Column, ArgEntry))
219         return E;
220       continue;
221     }
222 
223     // If we already have a string, error out.
224     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     if (Error E = parseValue(ValueStr, ArgEntry))
230       return E;
231 
232     // Keep the key from the string.
233     KeyStr = KeyName;
234   }
235 
236   if (KeyStr.empty())
237     return make_error<ParseError>("argument key is missing.", *ArgMap);
238   if (ValueStr.empty())
239     return make_error<ParseError>("argument value is missing.", *ArgMap);
240 
241   Args.push_back(LLVMOptRemarkArg{
242       toOptRemarkStr(KeyStr), toOptRemarkStr(ValueStr),
243       LLVMOptRemarkDebugLoc{toOptRemarkStr(File.getValueOr(StringRef())),
244                             Line.getValueOr(0), Column.getValueOr(0)}});
245 
246   return Error::success();
247 }
248 
parseYAMLElement(yaml::Document & Remark)249 Error RemarkParser::parseYAMLElement(yaml::Document &Remark) {
250   // Parsing a new remark, clear the previous one.
251   LastRemark = None;
252   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   State.Type = Root->getRawTag();
260 
261   for (yaml::KeyValueNode &RemarkField : *Root) {
262     StringRef KeyName;
263     if (Error E = parseKey(KeyName, RemarkField))
264       return E;
265 
266     if (KeyName == "Pass") {
267       if (Error E = parseValue(State.Pass, RemarkField))
268         return E;
269     } else if (KeyName == "Name") {
270       if (Error E = parseValue(State.Name, RemarkField))
271         return E;
272     } else if (KeyName == "Function") {
273       if (Error E = parseValue(State.Function, RemarkField))
274         return E;
275     } else if (KeyName == "Hotness") {
276       if (Error E = parseValue(State.Hotness, RemarkField))
277         return E;
278     } else if (KeyName == "DebugLoc") {
279       if (Error E =
280               parseDebugLoc(State.File, State.Line, State.Column, RemarkField))
281         return E;
282     } else if (KeyName == "Args") {
283       auto *Args = dyn_cast<yaml::SequenceNode>(RemarkField.getValue());
284       if (!Args)
285         return make_error<ParseError>("wrong value type for key.", RemarkField);
286 
287       for (yaml::Node &Arg : *Args)
288         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   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   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       static_cast<uint32_t>(State.Args->size()),
316       State.Args->data()};
317 
318   return Error::success();
319 }
320 } // namespace
321 
322 // Create wrappers for C Binding types (see CBindingWrapping.h).
DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RemarkParser,LLVMOptRemarkParserRef)323 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RemarkParser, LLVMOptRemarkParserRef)
324 
325 extern "C" LLVMOptRemarkParserRef LLVMOptRemarkParserCreate(const void *Buf,
326                                                             uint64_t Size) {
327   return wrap(
328       new RemarkParser(StringRef(static_cast<const char *>(Buf), Size)));
329 }
330 
331 extern "C" LLVMOptRemarkEntry *
LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser)332 LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser) {
333   RemarkParser &TheParser = *unwrap(Parser);
334   // Check for EOF.
335   if (TheParser.HadAnyErrors || TheParser.DI == TheParser.Stream.end())
336     return nullptr;
337 
338   // Try to parse an entry.
339   if (Error E = TheParser.parseYAMLElement(*TheParser.DI)) {
340     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   ++TheParser.DI;
350 
351   // Return the just-parsed remark.
352   if (Optional<LLVMOptRemarkEntry> &Entry = TheParser.LastRemark)
353     return &*Entry;
354   return nullptr;
355 }
356 
LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser)357 extern "C" LLVMBool LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser) {
358   return unwrap(Parser)->HadAnyErrors;
359 }
360 
361 extern "C" const char *
LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser)362 LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser) {
363   return unwrap(Parser)->ErrorStream.str().c_str();
364 }
365 
LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser)366 extern "C" void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser) {
367   delete unwrap(Parser);
368 }
369