1 //===- OptRemarksParser.cpp -----------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is dual licensed under the MIT and the University of Illinois Open
6 // Source Licenses. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file provides utility methods used by clients that want to use the
11 // parser for optimization remarks in LLVM.
13 //===----------------------------------------------------------------------===//
15 #include "llvm-c/OptRemarks.h"
16 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/Support/SourceMgr.h"
18 #include "llvm/Support/YAMLTraits.h"
24 /// Source manager for better error messages.
26 /// Stream for yaml parsing.
28 /// Storage for the error stream.
29 std::string ErrorString
;
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`.
41 /// Temporary parsing buffer for the arguments.
42 SmallVectorImpl
<LLVMOptRemarkArg
> *Args
;
48 Optional
<StringRef
> File
;
49 Optional
<unsigned> Line
;
50 Optional
<unsigned> Column
;
51 Optional
<unsigned> Hotness
;
53 ParseState(SmallVectorImpl
<LLVMOptRemarkArg
> &Args
) : Args(&Args
) {}
54 /// Use Args only as a **temporary** buffer.
55 ~ParseState() { Args
->clear(); }
60 /// Set to `true` if we had any errors during parsing.
61 bool HadAnyErrors
= false;
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);
69 /// Parse a YAML element.
70 Error
parseYAMLElement(yaml::Document
&Remark
);
73 /// Parse one key to a string.
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
);
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);
96 class ParseError
: public ErrorInfo
<ParseError
> {
100 ParseError(StringRef Message
, yaml::Node
&Node
)
101 : Message(Message
), Node(Node
) {}
103 void log(raw_ostream
&OS
) const override
{ OS
<< Message
; }
104 std::error_code
convertToErrorCode() const override
{
105 return inconvertibleErrorCode();
108 StringRef
getMessage() const { return Message
; }
109 yaml::Node
&getNode() const { return Node
; }
112 StringRef Message
; // No need to hold a full copy of the buffer.
116 char ParseError::ID
= 0;
118 static LLVMOptRemarkStringRef
toOptRemarkStr(StringRef Str
) {
119 return {Str
.data(), static_cast<uint32_t>(Str
.size())};
122 Error
RemarkParser::parseKey(StringRef
&Result
, yaml::KeyValueNode
&Node
) {
123 auto *Key
= dyn_cast
<yaml::ScalarNode
>(Node
.getKey());
125 return make_error
<ParseError
>("key is not a string.", Node
);
127 Result
= Key
->getRawValue();
128 return Error::success();
131 Error
RemarkParser::parseValue(StringRef
&Result
, yaml::KeyValueNode
&Node
) {
132 auto *Value
= dyn_cast
<yaml::ScalarNode
>(Node
.getValue());
134 return make_error
<ParseError
>("expected a value of scalar type.", Node
);
135 Result
= Value
->getRawValue();
137 if (Result
.front() == '\'')
138 Result
= Result
.drop_front();
140 if (Result
.back() == '\'')
141 Result
= Result
.drop_back();
143 return Error::success();
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());
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();
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());
165 return make_error
<ParseError
>("expected a value of mapping type.", Node
);
167 for (yaml::KeyValueNode
&DLNode
: *DebugLoc
) {
169 if (Error E
= parseKey(KeyName
, DLNode
))
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
))
176 } else if (KeyName
== "Column") {
177 if (Error E
= parseValue(Column
, DLNode
))
179 } else if (KeyName
== "Line") {
180 if (Error E
= parseValue(Line
, DLNode
))
183 return make_error
<ParseError
>("unknown entry in DebugLoc map.", DLNode
);
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
);
191 return Error::success();
194 Error
RemarkParser::parseArg(SmallVectorImpl
<LLVMOptRemarkArg
> &Args
,
196 auto *ArgMap
= dyn_cast
<yaml::MappingNode
>(&Node
);
198 return make_error
<ParseError
>("expected a value of mapping type.", Node
);
202 Optional
<StringRef
> File
;
203 Optional
<unsigned> Line
;
204 Optional
<unsigned> Column
;
206 for (yaml::KeyValueNode
&ArgEntry
: *ArgMap
) {
208 if (Error E
= parseKey(KeyName
, ArgEntry
))
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
);
218 if (Error E
= parseDebugLoc(File
, Line
, Column
, ArgEntry
))
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
);
228 // Try to parse a string.
229 if (Error E
= parseValue(ValueStr
, ArgEntry
))
232 // Keep the key from the string.
237 return make_error
<ParseError
>("argument key is missing.", *ArgMap
);
238 if (ValueStr
.empty())
239 return make_error
<ParseError
>("argument value is missing.", *ArgMap
);
241 Args
.push_back(LLVMOptRemarkArg
{
242 toOptRemarkStr(KeyStr
), toOptRemarkStr(ValueStr
),
243 LLVMOptRemarkDebugLoc
{toOptRemarkStr(File
.getValueOr(StringRef())),
244 Line
.getValueOr(0), Column
.getValueOr(0)}});
246 return Error::success();
249 Error
RemarkParser::parseYAMLElement(yaml::Document
&Remark
) {
250 // Parsing a new remark, clear the previous one.
252 State
= ParseState(TmpArgs
);
254 auto *Root
= dyn_cast
<yaml::MappingNode
>(Remark
.getRoot());
256 return make_error
<ParseError
>("document root is not of mapping type.",
259 State
.Type
= Root
->getRawTag();
261 for (yaml::KeyValueNode
&RemarkField
: *Root
) {
263 if (Error E
= parseKey(KeyName
, RemarkField
))
266 if (KeyName
== "Pass") {
267 if (Error E
= parseValue(State
.Pass
, RemarkField
))
269 } else if (KeyName
== "Name") {
270 if (Error E
= parseValue(State
.Name
, RemarkField
))
272 } else if (KeyName
== "Function") {
273 if (Error E
= parseValue(State
.Function
, RemarkField
))
275 } else if (KeyName
== "Hotness") {
276 if (Error E
= parseValue(State
.Hotness
, RemarkField
))
278 } else if (KeyName
== "DebugLoc") {
280 parseDebugLoc(State
.File
, State
.Line
, State
.Column
, RemarkField
))
282 } else if (KeyName
== "Args") {
283 auto *Args
= dyn_cast
<yaml::SequenceNode
>(RemarkField
.getValue());
285 return make_error
<ParseError
>("wrong value type for key.", RemarkField
);
287 for (yaml::Node
&Arg
: *Args
)
288 if (Error E
= parseArg(*State
.Args
, Arg
))
291 return make_error
<ParseError
>("unknown key.", RemarkField
);
295 // If the YAML parsing failed, don't even continue parsing. We might
296 // encounter malformed YAML.
298 return make_error
<ParseError
>("YAML parsing failed.", *Remark
.getRoot());
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.",
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()),
318 return Error::success();
322 // Create wrappers for C Binding types (see CBindingWrapping.h).
323 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RemarkParser
, LLVMOptRemarkParserRef
)
325 extern "C" LLVMOptRemarkParserRef
LLVMOptRemarkParserCreate(const void *Buf
,
328 new RemarkParser(StringRef(static_cast<const char *>(Buf
), Size
)));
331 extern "C" LLVMOptRemarkEntry
*
332 LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser
) {
333 RemarkParser
&TheParser
= *unwrap(Parser
);
335 if (TheParser
.HadAnyErrors
|| TheParser
.DI
== TheParser
.Stream
.end())
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;
351 // Return the just-parsed remark.
352 if (Optional
<LLVMOptRemarkEntry
> &Entry
= TheParser
.LastRemark
)
357 extern "C" LLVMBool
LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser
) {
358 return unwrap(Parser
)->HadAnyErrors
;
361 extern "C" const char *
362 LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser
) {
363 return unwrap(Parser
)->ErrorStream
.str().c_str();
366 extern "C" void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser
) {
367 delete unwrap(Parser
);