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