Fix uninitialized variable
[llvm-core.git] / lib / OptRemarks / OptRemarksParser.cpp
blob0478d2bfbfa600521bc9385cc79d614638c748c0
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.
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"
20 using namespace llvm;
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;
53 ParseState(SmallVectorImpl<LLVMOptRemarkArg> &Args) : Args(&Args) {}
54 /// Use Args only as a **temporary** buffer.
55 ~ParseState() { Args->clear(); }
58 ParseState State;
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);
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);
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> {
97 public:
98 static char ID;
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; }
111 private:
112 StringRef Message; // No need to hold a full copy of the buffer.
113 yaml::Node &Node;
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());
124 if (!Key)
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());
133 if (!Value)
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());
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();
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);
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);
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,
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);
200 StringRef ValueStr;
201 StringRef KeyStr;
202 Optional<StringRef> File;
203 Optional<unsigned> Line;
204 Optional<unsigned> Column;
206 for (yaml::KeyValueNode &ArgEntry : *ArgMap) {
207 StringRef KeyName;
208 if (Error E = parseKey(KeyName, ArgEntry))
209 return E;
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))
219 return E;
220 continue;
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))
230 return E;
232 // Keep the key from the string.
233 KeyStr = KeyName;
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);
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.
251 LastRemark = None;
252 State = ParseState(TmpArgs);
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());
259 State.Type = Root->getRawTag();
261 for (yaml::KeyValueNode &RemarkField : *Root) {
262 StringRef KeyName;
263 if (Error E = parseKey(KeyName, RemarkField))
264 return E;
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);
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);
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());
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());
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()};
318 return Error::success();
320 } // namespace
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,
326 uint64_t Size) {
327 return wrap(
328 new RemarkParser(StringRef(static_cast<const char *>(Buf), Size)));
331 extern "C" LLVMOptRemarkEntry *
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;
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;
345 return nullptr;
348 // Move on.
349 ++TheParser.DI;
351 // Return the just-parsed remark.
352 if (Optional<LLVMOptRemarkEntry> &Entry = TheParser.LastRemark)
353 return &*Entry;
354 return nullptr;
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);