LLVM  8.0.1
OptRemarksParser.cpp
Go to the documentation of this file.
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"
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.
34  /// The parsed remark (if any).
36  /// Temporary parsing buffer for the arguments.
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.
47  /// Optional.
49  Optional<unsigned> Line;
50  Optional<unsigned> Column;
51  Optional<unsigned> Hotness;
52 
53  ParseState(SmallVectorImpl<LLVMOptRemarkArg> &Args) : Args(&Args) {}
54  /// Use Args only as a **temporary** buffer.
55  ~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  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.
88  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 
100  ParseError(StringRef Message, yaml::Node &Node)
101  : Message(Message), Node(Node) {}
102 
103  void log(raw_ostream &OS) const override { OS << Message; }
104  std::error_code convertToErrorCode() const override {
105  return inconvertibleErrorCode();
106  }
107 
108  StringRef getMessage() const { return Message; }
109  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  return {Str.data(), static_cast<uint32_t>(Str.size())};
120 }
121 
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 
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 
146 Error RemarkParser::parseValue(Optional<unsigned> &Result,
147  yaml::KeyValueNode &Node) {
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 
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 
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;
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 
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 
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).
324 
326  uint64_t Size) {
327  return wrap(
328  new RemarkParser(StringRef(static_cast<const char *>(Buf), Size)));
329 }
330 
331 extern "C" LLVMOptRemarkEntry *
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 
358  return unwrap(Parser)->HadAnyErrors;
359 }
360 
361 extern "C" const char *
363  return unwrap(Parser)->ErrorStream.str().c_str();
364 }
365 
367  delete unwrap(Parser);
368 }
uint64_t CallInst * C
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
Definition: Path.cpp:250
This class represents lattice values for constants.
Definition: AllocatorList.h:24
void print(const char *ProgName, raw_ostream &S, bool ShowColors=true, bool ShowKindLabel=true) const
Definition: SourceMgr.cpp:374
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE size_t size() const
size - Get the string size.
Definition: StringRef.h:138
constexpr T getValueOr(U &&value) const LLVM_LVALUE_FUNCTION
Definition: Optional.h:172
LLVMOptRemarkEntry * LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser)
Returns the next remark in the file.
Represents a YAML sequence created from either a block sequence for a flow sequence.
Definition: YAMLParser.h:453
Node * getKey()
Parse and return the key.
A debug info location.
Definition: DebugLoc.h:34
void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser)
Releases all the resources used by Parser.
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE const char * data() const
data - Get a pointer to the start of the string (which may not be null terminated).
Definition: StringRef.h:128
LLVMOptRemarkParserRef LLVMOptRemarkParserCreate(const void *Buf, uint64_t Size)
Creates a remark parser that can be used to read and parse the buffer located in Buf of size Size...
amdgpu Simplify well known AMD library false Value Value const Twine & Name
#define DEFINE_SIMPLE_CONVERSION_FUNCTIONS(ty, ref)
Twine - A lightweight data structure for efficiently representing the concatenation of temporary valu...
Definition: Twine.h:81
Attribute unwrap(LLVMAttributeRef Attr)
Definition: Attributes.h:195
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
Definition: APFloat.h:42
String containing a buffer and a length.
Definition: OptRemarks.h:42
Key
PAL metadata keys.
A key and value pair.
Definition: YAMLParser.h:280
Node * getRoot()
Parse and return the root level node.
Definition: YAMLParser.h:535
LLVM_NODISCARD LLVM_ATTRIBUTE_ALWAYS_INLINE bool empty() const
empty - Check if the string is empty.
Definition: StringRef.h:133
struct LLVMOptRemarkOpaqueParser * LLVMOptRemarkParserRef
Definition: OptRemarks.h:102
One remark entry.
Definition: OptRemarks.h:83
void setDiagHandler(DiagHandlerTy DH, void *Ctx=nullptr)
Specify a diagnostic handler to be invoked every time PrintMessage is called.
Definition: SourceMgr.h:118
The instances of the Type class are immutable: once they are created, they are never changed...
Definition: Type.h:46
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
LLVMBool LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser)
Returns 1 if the parser encountered an error while parsing the buffer.
Element of the "Args" list.
Definition: OptRemarks.h:68
This owns the files read by a parser, handles include stacks, and handles diagnostic wrangling...
Definition: SourceMgr.h:42
int LLVMBool
Definition: Types.h:29
A scalar node is an opaque datum that can be presented as a series of zero or more Unicode scalar val...
Definition: YAMLParser.h:207
void handleAllErrors(Error E, HandlerTs &&... Handlers)
Behaves the same as handleErrors, except that by contract all errors must be handled by the given han...
Definition: Error.h:905
print lazy value Lazy Value Info Printer Pass
static ErrorSuccess success()
Create a success value.
Definition: Error.h:327
Node * getValue()
Parse and return the value.
const char * LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser)
Returns a null-terminated string containing an error message.
DebugLoc containing File, Line and Column.
Definition: OptRemarks.h:52
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:847
This class represents a YAML stream potentially containing multiple documents.
Definition: YAMLParser.h:84
Base class for user error types.
Definition: Error.h:345
amdgpu Simplify well known AMD library false Value Value * Arg
LLVMAttributeRef wrap(Attribute Attr)
Definition: Attributes.h:190
LLVM_NODISCARD std::enable_if<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type >::type dyn_cast(const Y &Val)
Definition: Casting.h:323
uint32_t Size
Definition: Profile.cpp:47
Represents a YAML map created from either a block map for a flow map.
Definition: YAMLParser.h:405
Iterator abstraction for Documents over a Stream.
Definition: YAMLParser.h:580
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
A raw_ostream that writes to an std::string.
Definition: raw_ostream.h:483
aarch64 promote const
LLVM Value Representation.
Definition: Value.h:73
Lightweight error class with error context and mandatory checking.
Definition: Error.h:158
This class implements an extremely fast bulk output stream that can only output to a stream...
Definition: raw_ostream.h:46
StringRef - Represent a constant reference to a string, i.e.
Definition: StringRef.h:49
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
A YAML Stream is a sequence of Documents.
Definition: YAMLParser.h:523
std::error_code inconvertibleErrorCode()
The value returned by this function can be returned from convertToErrorCode for Error values where no...
Definition: Error.cpp:78
Abstract base class for all Nodes.
Definition: YAMLParser.h:114
Instances of this class encapsulate one diagnostic report, allowing printing to a raw_ostream as a ca...
Definition: SourceMgr.h:260