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 : }
|