llvm.org GIT mirror llvm / 1cc98e6
[OptRemarks] Add library for parsing optimization remarks Add a library that parses optimization remarks (currently YAML, so based on the YAMLParser). The goal is to be able to provide tools a remark parser that is not completely dependent on YAML, in case we decide to change the format later. It exposes a C API which takes a handler that is called with the remark structure. It adds a libLLVMOptRemark.a static library, and it's used in-tree by the llvm-opt-report tool (from which the parser has been mostly moved out). Differential Revision: https://reviews.llvm.org/D52776 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@344162 91177308-0d34-0410-b5e6-96231b3b80d8 Francis Visoiu Mistrih 10 months ago
11 changed file(s) with 1076 addition(s) and 110 deletion(s). Raw diff Collapse all Expand all
0 /*===-- llvm-c/OptRemarks.h - OptRemarks Public C Interface -------*- C -*-===*\
1 |* *|
2 |* The LLVM Compiler Infrastructure *|
3 |* *|
4 |* This file is distributed under the University of Illinois Open Source *|
5 |* License. See LICENSE.TXT for details. *|
6 |* *|
7 |*===----------------------------------------------------------------------===*|
8 |* *|
9 |* This header provides a public interface to an opt-remark library. *|
10 |* LLVM provides an implementation of this interface. *|
11 |* *|
12 \*===----------------------------------------------------------------------===*/
13
14 #ifndef LLVM_C_OPT_REMARKS_H
15 #define LLVM_C_OPT_REMARKS_H
16
17 #include "llvm-c/Core.h"
18 #include "llvm-c/Types.h"
19 #ifdef __cplusplus
20 #include
21 extern "C" {
22 #else
23 #include
24 #endif /* !defined(__cplusplus) */
25
26 /**
27 * @defgroup LLVMCOPTREMARKS OptRemarks
28 * @ingroup LLVMC
29 *
30 * @{
31 */
32
33 #define OPT_REMARKS_API_VERSION 0
34
35 /**
36 * String containing a buffer and a length. The buffer is not guaranteed to be
37 * zero-terminated.
38 *
39 * \since OPT_REMARKS_API_VERSION=0
40 */
41 typedef struct {
42 const char *Str;
43 uint32_t Len;
44 } LLVMOptRemarkStringRef;
45
46 /**
47 * DebugLoc containing File, Line and Column.
48 *
49 * \since OPT_REMARKS_API_VERSION=0
50 */
51 typedef struct {
52 // File:
53 LLVMOptRemarkStringRef SourceFile;
54 // Line:
55 uint32_t SourceLineNumber;
56 // Column:
57 uint32_t SourceColumnNumber;
58 } LLVMOptRemarkDebugLoc;
59
60 /**
61 * Element of the "Args" list. The key might give more information about what
62 * are the semantics of the value, e.g. "Callee" will tell you that the value
63 * is a symbol that names a function.
64 *
65 * \since OPT_REMARKS_API_VERSION=0
66 */
67 typedef struct {
68 // e.g. "Callee"
69 LLVMOptRemarkStringRef Key;
70 // e.g. "malloc"
71 LLVMOptRemarkStringRef Value;
72
73 // "DebugLoc": Optional
74 LLVMOptRemarkDebugLoc DebugLoc;
75 } LLVMOptRemarkArg;
76
77 /**
78 * One remark entry.
79 *
80 * \since OPT_REMARKS_API_VERSION=0
81 */
82 typedef struct {
83 // e.g. !Missed, !Passed
84 LLVMOptRemarkStringRef RemarkType;
85 // "Pass": Required
86 LLVMOptRemarkStringRef PassName;
87 // "Name": Required
88 LLVMOptRemarkStringRef RemarkName;
89 // "Function": Required
90 LLVMOptRemarkStringRef FunctionName;
91
92 // "DebugLoc": Optional
93 LLVMOptRemarkDebugLoc DebugLoc;
94 // "Hotness": Optional
95 uint32_t Hotness;
96 // "Args": Optional. It is an array of `num_args` elements.
97 uint32_t NumArgs;
98 LLVMOptRemarkArg *Args;
99 } LLVMOptRemarkEntry;
100
101 typedef struct LLVMOptRemarkOpaqueParser *LLVMOptRemarkParserRef;
102
103 /**
104 * Creates a remark parser that can be used to read and parse the buffer located
105 * in \p Buf of size \p Size.
106 *
107 * \p Buf cannot be NULL.
108 *
109 * This function should be paired with LLVMOptRemarkParserDispose() to avoid
110 * leaking resources.
111 *
112 * \since OPT_REMARKS_API_VERSION=0
113 */
114 extern LLVMOptRemarkParserRef LLVMOptRemarkParserCreate(const void *Buf,
115 uint64_t Size);
116
117 /**
118 * Returns the next remark in the file.
119 *
120 * The value pointed to by the return value is invalidated by the next call to
121 * LLVMOptRemarkParserGetNext().
122 *
123 * If the parser reaches the end of the buffer, the return value will be NULL.
124 *
125 * In the case of an error, the return value will be NULL, and:
126 *
127 * 1) LLVMOptRemarkParserHasError() will return `1`.
128 *
129 * 2) LLVMOptRemarkParserGetErrorMessage() will return a descriptive error
130 * message.
131 *
132 * An error may occur if:
133 *
134 * 1) An argument is invalid.
135 *
136 * 2) There is a YAML parsing error. This type of error aborts parsing
137 * immediately and returns `1`. It can occur on malformed YAML.
138 *
139 * 3) Remark parsing error. If this type of error occurs, the parser won't call
140 * the handler and will continue to the next one. It can occur on malformed
141 * remarks, like missing or extra fields in the file.
142 *
143 * Here is a quick example of the usage:
144 *
145 * ```
146 * LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, Size);
147 * LLVMOptRemarkEntry *Remark = NULL;
148 * while ((Remark == LLVMOptRemarkParserGetNext(Parser))) {
149 * // use Remark
150 * }
151 * bool HasError = LLVMOptRemarkParserHasError(Parser);
152 * LLVMOptRemarkParserDispose(Parser);
153 * ```
154 *
155 * \since OPT_REMARKS_API_VERSION=0
156 */
157 extern LLVMOptRemarkEntry *
158 LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser);
159
160 /**
161 * Returns `1` if the parser encountered an error while parsing the buffer.
162 *
163 * \since OPT_REMARKS_API_VERSION=0
164 */
165 extern LLVMBool LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser);
166
167 /**
168 * Returns a null-terminated string containing an error message.
169 *
170 * In case of no error, the result is `NULL`.
171 *
172 * The memory of the string is bound to the lifetime of \p Parser. If
173 * LLVMOptRemarkParserDispose() is called, the memory of the string will be
174 * released.
175 *
176 * \since OPT_REMARKS_API_VERSION=0
177 */
178 extern const char *
179 LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser);
180
181 /**
182 * Releases all the resources used by \p Parser.
183 *
184 * \since OPT_REMARKS_API_VERSION=0
185 */
186 extern void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser);
187
188 /**
189 * @} // endgoup LLVMCOPTREMARKS
190 */
191
192 #ifdef __cplusplus
193 }
194 #endif /* !defined(__cplusplus) */
195
196 #endif /* LLVM_C_OPT_REMARKS_H */
1414 add_subdirectory(Object)
1515 add_subdirectory(ObjectYAML)
1616 add_subdirectory(Option)
17 add_subdirectory(OptRemarks)
1718 add_subdirectory(DebugInfo)
1819 add_subdirectory(ExecutionEngine)
1920 add_subdirectory(Target)
3434 BinaryFormat
3535 ObjectYAML
3636 Option
37 OptRemarks
3738 Passes
3839 ProfileData
3940 Support
0 add_llvm_library(LLVMOptRemarks
1 OptRemarksParser.cpp
2 )
0 ;===- ./lib/OptRemarks/LLVMBuild.txt ---------------------------*- Conf -*--===;
1 ;
2 ; The LLVM Compiler Infrastructure
3 ;
4 ; This file is distributed under the University of Illinois Open Source
5 ; License. See LICENSE.TXT for details.
6 ;
7 ;===------------------------------------------------------------------------===;
8 ;
9 ; This is an LLVMBuild description file for the components in this subdirectory.
10 ;
11 ; For more information on the LLVMBuild system, please see:
12 ;
13 ; http://llvm.org/docs/LLVMBuild.html
14 ;
15 ;===------------------------------------------------------------------------===;
16
17 [component_0]
18 type = Library
19 name = OptRemarks
20 parent = Libraries
21 required_libraries = Support
0 //===- OptRemarksParser.cpp -----------------------------------------------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is dual licensed under the MIT and the University of Illinois Open
5 // Source Licenses. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file provides utility methods used by clients that want to use the
10 // parser for optimization remarks in LLVM.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm-c/OptRemarks.h"
15 #include "llvm/ADT/STLExtras.h"
16 #include "llvm/Support/SourceMgr.h"
17 #include "llvm/Support/YAMLTraits.h"
18
19 using namespace llvm;
20
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 LastRemark;
35 /// Temporary parsing buffer for the arguments.
36 SmallVector 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 *Args;
42 StringRef Type;
43 StringRef Pass;
44 StringRef Name;
45 StringRef Function;
46 /// Optional.
47 Optional File;
48 Optional Line;
49 Optional Column;
50 Optional Hotness;
51
52 ParseState(SmallVectorImpl &Args) : Args(&Args) {}
53 /// Use Args only as a **temporary** buffer.
54 ~ParseState() { Args->clear(); }
55 };
56
57 ParseState State;
58
59 /// Set to `true` if we had any errors during parsing.
60 bool HadAnyErrors = false;
61
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);
66 }
67
68 /// Parse a YAML element.
69 Error parseYAMLElement(yaml::Document &Remark);
70
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 &Result, yaml::KeyValueNode &Node);
79 /// Parse a debug location.
80 Error parseDebugLoc(Optional &File, Optional &Line,
81 Optional &Column, yaml::KeyValueNode &Node);
82 /// Parse an argument.
83 Error parseArg(SmallVectorImpl &TmpArgs, yaml::Node &Node);
84
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(Ctx);
90 Diag.print(/*ProgName=*/nullptr, Parser->ErrorStream, /*ShowColors*/ false,
91 /*ShowKindLabels*/ true);
92 }
93 };
94
95 class ParseError : public ErrorInfo {
96 public:
97 static char ID;
98
99 ParseError(StringRef Message, yaml::Node &Node)
100 : Message(Message), Node(Node) {}
101
102 void log(raw_ostream &OS) const override { OS << Message; }
103 std::error_code convertToErrorCode() const override {
104 return inconvertibleErrorCode();
105 }
106
107 StringRef getMessage() const { return Message; }
108 yaml::Node &getNode() const { return Node; }
109
110 private:
111 StringRef Message; // No need to hold a full copy of the buffer.
112 yaml::Node &Node;
113 };
114
115 char ParseError::ID = 0;
116
117 static LLVMOptRemarkStringRef toOptRemarkStr(StringRef Str) {
118 return {Str.data(), static_cast(Str.size())};
119 }
120
121 Error RemarkParser::parseKey(StringRef &Result, yaml::KeyValueNode &Node) {
122 auto *Key = dyn_cast(Node.getKey());
123 if (!Key)
124 return make_error("key is not a string.", Node);
125
126 Result = Key->getRawValue();
127 return Error::success();
128 }
129
130 Error RemarkParser::parseValue(StringRef &Result, yaml::KeyValueNode &Node) {
131 auto *Value = dyn_cast(Node.getValue());
132 if (!Value)
133 return make_error("expected a value of scalar type.", Node);
134 Result = Value->getRawValue();
135
136 if (Result.front() == '\'')
137 Result = Result.drop_front();
138
139 if (Result.back() == '\'')
140 Result = Result.drop_back();
141
142 return Error::success();
143 }
144
145 Error RemarkParser::parseValue(Optional &Result,
146 yaml::KeyValueNode &Node) {
147 SmallVector Tmp;
148 auto *Value = dyn_cast(Node.getValue());
149 if (!Value)
150 return make_error("expected a value of scalar type.", Node);
151 unsigned UnsignedValue = 0;
152 if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue))
153 return make_error("expected a value of integer type.", *Value);
154 Result = UnsignedValue;
155 return Error::success();
156 }
157
158 Error RemarkParser::parseDebugLoc(Optional &File,
159 Optional &Line,
160 Optional &Column,
161 yaml::KeyValueNode &Node) {
162 auto *DebugLoc = dyn_cast(Node.getValue());
163 if (!DebugLoc)
164 return make_error("expected a value of mapping type.", Node);
165
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("unknown entry in DebugLoc map.", DLNode);
183 }
184 }
185
186 // If any of the debug loc fields is missing, return an error.
187 if (!File || !Line || !Column)
188 return make_error("DebugLoc node incomplete.", Node);
189
190 return Error::success();
191 }
192
193 Error RemarkParser::parseArg(SmallVectorImpl &Args,
194 yaml::Node &Node) {
195 auto *ArgMap = dyn_cast(&Node);
196 if (!ArgMap)
197 return make_error("expected a value of mapping type.", Node);
198
199 StringRef ValueStr;
200 StringRef KeyStr;
201 Optional File;
202 Optional Line;
203 Optional Column;
204
205 for (yaml::KeyValueNode &ArgEntry : *ArgMap) {
206 StringRef KeyName;
207 if (Error E = parseKey(KeyName, ArgEntry))
208 return E;
209
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(
215 "only one DebugLoc entry is allowed per argument.", ArgEntry);
216
217 if (Error E = parseDebugLoc(File, Line, Column, ArgEntry))
218 return E;
219 continue;
220 }
221
222 // If we already have a string, error out.
223 if (!ValueStr.empty())
224 return make_error(
225 "only one string entry is allowed per argument.", ArgEntry);
226
227 // Try to parse a string.
228 if (Error E = parseValue(ValueStr, ArgEntry))
229 return E;
230
231 // Keep the key from the string.
232 KeyStr = KeyName;
233 }
234
235 if (KeyStr.empty())
236 return make_error("argument key is missing.", *ArgMap);
237 if (ValueStr.empty())
238 return make_error("argument value is missing.", *ArgMap);
239
240 Args.push_back(LLVMOptRemarkArg{
241 toOptRemarkStr(KeyStr), toOptRemarkStr(ValueStr),
242 LLVMOptRemarkDebugLoc{toOptRemarkStr(File.getValueOr(StringRef())),
243 Line.getValueOr(0), Column.getValueOr(0)}});
244
245 return Error::success();
246 }
247
248 Error RemarkParser::parseYAMLElement(yaml::Document &Remark) {
249 // Parsing a new remark, clear the previous one.
250 LastRemark = None;
251 State = ParseState(TmpArgs);
252
253 auto *Root = dyn_cast(Remark.getRoot());
254 if (!Root)
255 return make_error("document root is not of mapping type.",
256 *Remark.getRoot());
257
258 State.Type = Root->getRawTag();
259
260 for (yaml::KeyValueNode &RemarkField : *Root) {
261 StringRef KeyName;
262 if (Error E = parseKey(KeyName, RemarkField))
263 return E;
264
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(RemarkField.getValue());
283 if (!Args)
284 return make_error("wrong value type for key.", RemarkField);
285
286 for (yaml::Node &Arg : *Args)
287 if (Error E = parseArg(*State.Args, Arg))
288 return E;
289 } else {
290 return make_error("unknown key.", RemarkField);
291 }
292 }
293
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("YAML parsing failed.", *Remark.getRoot());
298
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("Type, Pass, Name or Function missing.",
303 *Remark.getRoot());
304
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(State.Args->size()),
315 State.Args->data()};
316
317 return Error::success();
318 }
319 } // namespace
320
321 // Create wrappers for C Binding types (see CBindingWrapping.h).
322 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RemarkParser, LLVMOptRemarkParserRef);
323
324 extern "C" LLVMOptRemarkParserRef LLVMOptRemarkParserCreate(const void *Buf,
325 uint64_t Size) {
326 return wrap(
327 new RemarkParser(StringRef(static_cast(Buf), Size)));
328 }
329
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;
336
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;
343 });
344 return nullptr;
345 }
346
347 // Move on.
348 ++TheParser.DI;
349
350 // Return the just-parsed remark.
351 if (Optional &Entry = TheParser.LastRemark)
352 return &*Entry;
353 return nullptr;
354 }
355
356 extern "C" LLVMBool LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser) {
357 return unwrap(Parser)->HadAnyErrors;
358 }
359
360 extern "C" const char *
361 LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser) {
362 return unwrap(Parser)->ErrorStream.str().c_str();
363 }
364
365 extern "C" void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser) {
366 delete unwrap(Parser);
367 }
None set(LLVM_LINK_COMPONENTS Core Demangle Object Support)
0 set(LLVM_LINK_COMPONENTS Core Demangle Object OptRemarks Support)
11
22 add_llvm_tool(llvm-opt-report
33 OptReport.cpp
2727 #include "llvm/Support/WithColor.h"
2828 #include "llvm/Support/YAMLTraits.h"
2929 #include "llvm/Support/raw_ostream.h"
30 #include "llvm-c/OptRemarks.h"
3031 #include
3132 #include
3233 #include
141142 OptReportLocationInfo>>>> LocationInfoTy;
142143 } // anonymous namespace
143144
144 static void collectLocationInfo(yaml::Stream &Stream,
145 LocationInfoTy &LocationInfo) {
146 SmallVector Tmp;
147
148 // Note: We're using the YAML parser here directly, instead of using the
149 // YAMLTraits implementation, because the YAMLTraits implementation does not
150 // support a way to handle only a subset of the input keys (it will error out
151 // if there is an input key that you don't map to your class), and
152 // furthermore, it does not provide a way to handle the Args sequence of
153 // key/value pairs, where the order must be captured and the 'String' key
154 // might be repeated.
155 for (auto &Doc : Stream) {
156 auto *Root = dyn_cast(Doc.getRoot());
157 if (!Root)
158 continue;
159
160 bool Transformed = Root->getRawTag() == "!Passed";
161 std::string Pass, File, Function;
162 int Line = 0, Column = 1;
145 static bool readLocationInfo(LocationInfoTy &LocationInfo) {
146 ErrorOr> Buf =
147 MemoryBuffer::getFile(InputFileName.c_str());
148 if (std::error_code EC = Buf.getError()) {
149 WithColor::error() << "Can't open file " << InputFileName << ": "
150 << EC.message() << "\n";
151 return false;
152 }
153
154 StringRef Buffer = (*Buf)->getBuffer();
155 LLVMOptRemarkParserRef Parser =
156 LLVMOptRemarkParserCreate(Buffer.data(), Buffer.size());
157
158 LLVMOptRemarkEntry *Remark = nullptr;
159 while ((Remark = LLVMOptRemarkParserGetNext(Parser))) {
160 bool Transformed =
161 StringRef(Remark->RemarkType.Str, Remark->RemarkType.Len) == "!Passed";
162 StringRef Pass(Remark->PassName.Str, Remark->PassName.Len);
163 StringRef File(Remark->DebugLoc.SourceFile.Str,
164 Remark->DebugLoc.SourceFile.Len);
165 StringRef Function(Remark->FunctionName.Str, Remark->FunctionName.Len);
166 uint32_t Line = Remark->DebugLoc.SourceLineNumber;
167 uint32_t Column = Remark->DebugLoc.SourceColumnNumber;
168 ArrayRef Args(Remark->Args, Remark->NumArgs);
163169
164170 int VectorizationFactor = 1;
165171 int InterleaveCount = 1;
166172 int UnrollCount = 1;
167173
168 for (auto &RootChild : *Root) {
169 auto *Key = dyn_cast(RootChild.getKey());
170 if (!Key)
171 continue;
172 StringRef KeyName = Key->getValue(Tmp);
173 if (KeyName == "Pass") {
174 auto *Value = dyn_cast(RootChild.getValue());
175 if (!Value)
176 continue;
177 Pass = Value->getValue(Tmp);
178 } else if (KeyName == "Function") {
179 auto *Value = dyn_cast(RootChild.getValue());
180 if (!Value)
181 continue;
182 Function = Value->getValue(Tmp);
183 } else if (KeyName == "DebugLoc") {
184 auto *DebugLoc = dyn_cast(RootChild.getValue());
185 if (!DebugLoc)
186 continue;
187
188 for (auto &DLChild : *DebugLoc) {
189 auto *DLKey = dyn_cast(DLChild.getKey());
190 if (!DLKey)
191 continue;
192 StringRef DLKeyName = DLKey->getValue(Tmp);
193 if (DLKeyName == "File") {
194 auto *Value = dyn_cast(DLChild.getValue());
195 if (!Value)
196 continue;
197 File = Value->getValue(Tmp);
198 } else if (DLKeyName == "Line") {
199 auto *Value = dyn_cast(DLChild.getValue());
200 if (!Value)
201 continue;
202 Value->getValue(Tmp).getAsInteger(10, Line);
203 } else if (DLKeyName == "Column") {
204 auto *Value = dyn_cast(DLChild.getValue());
205 if (!Value)
206 continue;
207 Value->getValue(Tmp).getAsInteger(10, Column);
208 }
209 }
210 } else if (KeyName == "Args") {
211 auto *Args = dyn_cast(RootChild.getValue());
212 if (!Args)
213 continue;
214 for (auto &ArgChild : *Args) {
215 auto *ArgMap = dyn_cast(&ArgChild);
216 if (!ArgMap)
217 continue;
218 for (auto &ArgKV : *ArgMap) {
219 auto *ArgKey = dyn_cast(ArgKV.getKey());
220 if (!ArgKey)
221 continue;
222 StringRef ArgKeyName = ArgKey->getValue(Tmp);
223 if (ArgKeyName == "VectorizationFactor") {
224 auto *Value = dyn_cast(ArgKV.getValue());
225 if (!Value)
226 continue;
227 Value->getValue(Tmp).getAsInteger(10, VectorizationFactor);
228 } else if (ArgKeyName == "InterleaveCount") {
229 auto *Value = dyn_cast(ArgKV.getValue());
230 if (!Value)
231 continue;
232 Value->getValue(Tmp).getAsInteger(10, InterleaveCount);
233 } else if (ArgKeyName == "UnrollCount") {
234 auto *Value = dyn_cast(ArgKV.getValue());
235 if (!Value)
236 continue;
237 Value->getValue(Tmp).getAsInteger(10, UnrollCount);
238 }
239 }
240 }
241 }
174 for (const LLVMOptRemarkArg &Arg : Args) {
175 StringRef ArgKeyName(Arg.Key.Str, Arg.Key.Len);
176 StringRef ArgValue(Arg.Value.Str, Arg.Value.Len);
177 if (ArgKeyName == "VectorizationFactor")
178 ArgValue.getAsInteger(10, VectorizationFactor);
179 else if (ArgKeyName == "InterleaveCount")
180 ArgValue.getAsInteger(10, InterleaveCount);
181 else if (ArgKeyName == "UnrollCount")
182 ArgValue.getAsInteger(10, UnrollCount);
242183 }
243184
244185 if (Line < 1 || File.empty())
267208 UpdateLLII(LI.Vectorized);
268209 }
269210 }
270 }
271
272 static bool readLocationInfo(LocationInfoTy &LocationInfo) {
273 ErrorOr> Buf =
274 MemoryBuffer::getFileOrSTDIN(InputFileName);
275 if (std::error_code EC = Buf.getError()) {
276 WithColor::error() << "Can't open file " << InputFileName << ": "
277 << EC.message() << "\n";
278 return false;
279 }
280
281 SourceMgr SM;
282 yaml::Stream Stream(Buf.get()->getBuffer(), SM);
283 collectLocationInfo(Stream, LocationInfo);
284
285 return true;
211
212 bool HasError = LLVMOptRemarkParserHasError(Parser);
213 if (HasError)
214 WithColor::error() << LLVMOptRemarkParserGetErrorMessage(Parser) << "\n";
215
216 LLVMOptRemarkParserDispose(Parser);
217 return !HasError;
286218 }
287219
288220 static bool writeReport(LocationInfoTy &LocationInfo) {
2525 add_subdirectory(Object)
2626 add_subdirectory(ObjectYAML)
2727 add_subdirectory(Option)
28 add_subdirectory(OptRemarks)
2829 add_subdirectory(Passes)
2930 add_subdirectory(ProfileData)
3031 add_subdirectory(Support)
0 set(LLVM_LINK_COMPONENTS
1 OptRemarks
2 Support
3 )
4
5 add_llvm_unittest(OptRemarksTests
6 OptRemarksParsingTest.cpp
7 )
0 //===- unittest/Support/OptRemarksParsingTest.cpp - OptTable tests --------===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "llvm-c/OptRemarks.h"
10 #include "gtest/gtest.h"
11
12 using namespace llvm;
13
14 template bool tryParse(const char (&Buf)[N]) {
15 LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, N - 1);
16 LLVMOptRemarkEntry *Remark = nullptr;
17 while (LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(Parser)) {
18 EXPECT_TRUE(Remark == nullptr); // Only one remark per test.
19 Remark = NewRemark;
20 }
21 EXPECT_TRUE(Remark != nullptr); // We need *exactly* one remark per test.
22 bool HasError = LLVMOptRemarkParserHasError(Parser);
23 LLVMOptRemarkParserDispose(Parser);
24 return !HasError;
25 }
26
27 template
28 bool parseExpectError(const char (&Buf)[N], const char *Error) {
29 LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, N - 1);
30 LLVMOptRemarkEntry *Remark = nullptr;
31 while (LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(Parser)) {
32 EXPECT_FALSE(NewRemark);
33 }
34 EXPECT_TRUE(Remark == nullptr); // We are parsing only one malformed remark.
35 EXPECT_TRUE(LLVMOptRemarkParserHasError(Parser));
36 bool MatchesError =
37 StringRef(LLVMOptRemarkParserGetErrorMessage(Parser)).contains(Error);
38 LLVMOptRemarkParserDispose(Parser);
39
40 return MatchesError;
41 }
42
43 TEST(OptRemarks, OptRemarksParsingEmpty) {
44 StringRef Buf = R"YAML(
45 )YAML";
46 LLVMOptRemarkParserRef Parser =
47 LLVMOptRemarkParserCreate(Buf.data(), Buf.size());
48 LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(Parser);
49 EXPECT_TRUE(NewRemark == nullptr); // No remark expected.
50 EXPECT_TRUE(LLVMOptRemarkParserHasError(Parser));
51 EXPECT_TRUE(StringRef(LLVMOptRemarkParserGetErrorMessage(Parser))
52 .contains("document root is not of mapping type."));
53 LLVMOptRemarkParserDispose(Parser);
54 }
55
56 TEST(OptRemarks, OptRemarksParsingGood) {
57 EXPECT_TRUE(tryParse(R"YAML(
58 --- !Missed
59 Pass: inline
60 Name: NoDefinition
61 DebugLoc: { File: file.c, Line: 3, Column: 12 }
62 Function: foo
63 Args:
64 - Callee: bar
65 - String: ' will not be inlined into '
66 - Caller: foo
67 DebugLoc: { File: file.c, Line: 2, Column: 0 }
68 - String: ' because its definition is unavailable'
69 )YAML"));
70
71 // No debug loc should also pass.
72 EXPECT_TRUE(tryParse(R"YAML(
73 --- !Missed
74 Pass: inline
75 Name: NoDefinition
76 Function: foo
77 Args:
78 - Callee: bar
79 - String: ' will not be inlined into '
80 - Caller: foo
81 DebugLoc: { File: file.c, Line: 2, Column: 0 }
82 - String: ' because its definition is unavailable'
83 )YAML"));
84
85 // No args is also ok.
86 EXPECT_TRUE(tryParse(R"YAML(
87 --- !Missed
88 Pass: inline
89 Name: NoDefinition
90 DebugLoc: { File: file.c, Line: 3, Column: 12 }
91 Function: foo
92 )YAML"));
93
94 // Different order.
95 EXPECT_TRUE(tryParse(R"YAML(
96 --- !Missed
97 DebugLoc: { Line: 3, Column: 12, File: file.c }
98 Function: foo
99 Name: NoDefinition
100 Args:
101 - Callee: bar
102 - String: ' will not be inlined into '
103 - Caller: foo
104 DebugLoc: { File: file.c, Line: 2, Column: 0 }
105 - String: ' because its definition is unavailable'
106 Pass: inline
107 )YAML"));
108 }
109
110 // Mandatory common part of a remark.
111 #define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n"
112 // Test all the types.
113 TEST(OptRemarks, OptRemarksParsingTypes) {
114 // Type: Passed
115 EXPECT_TRUE(tryParse("--- !Passed" COMMON_REMARK));
116 // Type: Missed
117 EXPECT_TRUE(tryParse("--- !Missed" COMMON_REMARK));
118 // Type: Analysis
119 EXPECT_TRUE(tryParse("--- !Analysis" COMMON_REMARK));
120 // Type: AnalysisFPCompute
121 EXPECT_TRUE(tryParse("--- !AnalysisFPCompute" COMMON_REMARK));
122 // Type: AnalysisAliasing
123 EXPECT_TRUE(tryParse("--- !AnalysisAliasing" COMMON_REMARK));
124 // Type: Failure
125 EXPECT_TRUE(tryParse("--- !Failure" COMMON_REMARK));
126 }
127 #undef COMMON_REMARK
128
129 TEST(OptRemarks, OptRemarksParsingMissingFields) {
130 // No type.
131 EXPECT_TRUE(parseExpectError(R"YAML(
132 ---
133 Pass: inline
134 Name: NoDefinition
135 Function: foo
136 )YAML",
137 "error: Type, Pass, Name or Function missing."));
138 // No pass.
139 EXPECT_TRUE(parseExpectError(R"YAML(
140 --- !Missed
141 Name: NoDefinition
142 Function: foo
143 )YAML",
144 "error: Type, Pass, Name or Function missing."));
145 // No name.
146 EXPECT_TRUE(parseExpectError(R"YAML(
147 --- !Missed
148 Pass: inline
149 Function: foo
150 )YAML",
151 "error: Type, Pass, Name or Function missing."));
152 // No function.
153 EXPECT_TRUE(parseExpectError(R"YAML(
154 --- !Missed
155 Pass: inline
156 Name: NoDefinition
157 )YAML",
158 "error: Type, Pass, Name or Function missing."));
159 // Debug loc but no file.
160 EXPECT_TRUE(parseExpectError(R"YAML(
161 --- !Missed
162 Pass: inline
163 Name: NoDefinition
164 Function: foo
165 DebugLoc: { Line: 3, Column: 12 }
166 )YAML",
167 "DebugLoc node incomplete."));
168 // Debug loc but no line.
169 EXPECT_TRUE(parseExpectError(R"YAML(
170 --- !Missed
171 Pass: inline
172 Name: NoDefinition
173 Function: foo
174 DebugLoc: { File: file.c, Column: 12 }
175 )YAML",
176 "DebugLoc node incomplete."));
177 // Debug loc but no column.
178 EXPECT_TRUE(parseExpectError(R"YAML(
179 --- !Missed
180 Pass: inline
181 Name: NoDefinition
182 Function: foo
183 DebugLoc: { File: file.c, Line: 3 }
184 )YAML",
185 "DebugLoc node incomplete."));
186 }
187
188 TEST(OptRemarks, OptRemarksParsingWrongTypes) {
189 // Wrong debug loc type.
190 EXPECT_TRUE(parseExpectError(R"YAML(
191 --- !Missed
192 Pass: inline
193 Name: NoDefinition
194 Function: foo
195 DebugLoc: foo
196 )YAML",
197 "expected a value of mapping type."));
198 // Wrong line type.
199 EXPECT_TRUE(parseExpectError(R"YAML(
200 --- !Missed
201 Pass: inline
202 Name: NoDefinition
203 Function: foo
204 DebugLoc: { File: file.c, Line: b, Column: 12 }
205 )YAML",
206 "expected a value of integer type."));
207 // Wrong column type.
208 EXPECT_TRUE(parseExpectError(R"YAML(
209 --- !Missed
210 Pass: inline
211 Name: NoDefinition
212 Function: foo
213 DebugLoc: { File: file.c, Line: 3, Column: c }
214 )YAML",
215 "expected a value of integer type."));
216 // Wrong args type.
217 EXPECT_TRUE(parseExpectError(R"YAML(
218 --- !Missed
219 Pass: inline
220 Name: NoDefinition
221 Function: foo
222 Args: foo
223 )YAML",
224 "wrong value type for key."));
225 // Wrong key type.
226 EXPECT_TRUE(parseExpectError(R"YAML(
227 --- !Missed
228 { A: a }: inline
229 Name: NoDefinition
230 Function: foo
231 )YAML",
232 "key is not a string."));
233 // Debug loc with unknown entry.
234 EXPECT_TRUE(parseExpectError(R"YAML(
235 --- !Missed
236 Pass: inline
237 Name: NoDefinition
238 Function: foo
239 DebugLoc: { File: file.c, Column: 12, Unknown: 12 }
240 )YAML",
241 "unknown entry in DebugLoc map."));
242 // Unknown entry.
243 EXPECT_TRUE(parseExpectError(R"YAML(
244 --- !Missed
245 Unknown: inline
246 )YAML",
247 "unknown key."));
248 // Not a scalar.
249 EXPECT_TRUE(parseExpectError(R"YAML(
250 --- !Missed
251 Pass: { File: a, Line: 1, Column: 2 }
252 Name: NoDefinition
253 Function: foo
254 )YAML",
255 "expected a value of scalar type."));
256 // Not a string file in debug loc.
257 EXPECT_TRUE(parseExpectError(R"YAML(
258 --- !Missed
259 Pass: inline
260 Name: NoDefinition
261 Function: foo
262 DebugLoc: { File: { a: b }, Column: 12, Line: 12 }
263 )YAML",
264 "expected a value of scalar type."));
265 // Not a integer column in debug loc.
266 EXPECT_TRUE(parseExpectError(R"YAML(
267 --- !Missed
268 Pass: inline
269 Name: NoDefinition
270 Function: foo
271 DebugLoc: { File: file.c, Column: { a: b }, Line: 12 }
272 )YAML",
273 "expected a value of scalar type."));
274 // Not a integer line in debug loc.
275 EXPECT_TRUE(parseExpectError(R"YAML(
276 --- !Missed
277 Pass: inline
278 Name: NoDefinition
279 Function: foo
280 DebugLoc: { File: file.c, Column: 12, Line: { a: b } }
281 )YAML",
282 "expected a value of scalar type."));
283 // Not a mapping type value for args.
284 EXPECT_TRUE(parseExpectError(R"YAML(
285 --- !Missed
286 Pass: inline
287 Name: NoDefinition
288 Function: foo
289 DebugLoc: { File: file.c, Column: 12, Line: { a: b } }
290 )YAML",
291 "expected a value of scalar type."));
292 }
293
294 TEST(OptRemarks, OptRemarksParsingWrongArgs) {
295 // Multiple debug locs per arg.
296 EXPECT_TRUE(
297 parseExpectError(R"YAML(
298 --- !Missed
299 Pass: inline
300 Name: NoDefinition
301 Function: foo
302 Args:
303 - Str: string
304 DebugLoc: { File: a, Line: 1, Column: 2 }
305 DebugLoc: { File: a, Line: 1, Column: 2 }
306 )YAML",
307 "only one DebugLoc entry is allowed per argument."));
308 // Multiple strings per arg.
309 EXPECT_TRUE(
310 parseExpectError(R"YAML(
311 --- !Missed
312 Pass: inline
313 Name: NoDefinition
314 Function: foo
315 Args:
316 - Str: string
317 Str2: string
318 DebugLoc: { File: a, Line: 1, Column: 2 }
319 )YAML",
320 "only one string entry is allowed per argument."));
321 // No arg value.
322 EXPECT_TRUE(parseExpectError(R"YAML(
323 --- !Missed
324 Pass: inline
325 Name: NoDefinition
326 Function: foo
327 Args:
328 - Callee: ''
329 - DebugLoc: { File: a, Line: 1, Column: 2 }
330 )YAML",
331 "argument value is missing."));
332 // No arg value.
333 EXPECT_TRUE(parseExpectError(R"YAML(
334 --- !Missed
335 Pass: inline
336 Name: NoDefinition
337 Function: foo
338 Args:
339 - DebugLoc: { File: a, Line: 1, Column: 2 }
340 )YAML",
341 "argument key is missing."));
342
343 }
344
345 TEST(OptRemarks, OptRemarksGoodStruct) {
346 StringRef Buf = R"YAML(
347 --- !Missed
348 Pass: inline
349 Name: NoDefinition
350 DebugLoc: { File: file.c, Line: 3, Column: 12 }
351 Function: foo
352 Args:
353 - Callee: bar
354 - String: ' will not be inlined into '
355 - Caller: foo
356 DebugLoc: { File: file.c, Line: 2, Column: 0 }
357 - String: ' because its definition is unavailable'
358 )YAML";
359
360 LLVMOptRemarkParserRef Parser =
361 LLVMOptRemarkParserCreate(Buf.data(), Buf.size());
362 LLVMOptRemarkEntry *Remark = LLVMOptRemarkParserGetNext(Parser);
363 EXPECT_FALSE(Remark == nullptr);
364 EXPECT_EQ(StringRef(Remark->RemarkType.Str, 7), "!Missed");
365 EXPECT_EQ(Remark->RemarkType.Len, 7U);
366 EXPECT_EQ(StringRef(Remark->PassName.Str, 6), "inline");
367 EXPECT_EQ(Remark->PassName.Len, 6U);
368 EXPECT_EQ(StringRef(Remark->RemarkName.Str, 12), "NoDefinition");
369 EXPECT_EQ(Remark->RemarkName.Len, 12U);
370 EXPECT_EQ(StringRef(Remark->FunctionName.Str, 3), "foo");
371 EXPECT_EQ(Remark->FunctionName.Len, 3U);
372 EXPECT_EQ(StringRef(Remark->DebugLoc.SourceFile.Str, 6), "file.c");
373 EXPECT_EQ(Remark->DebugLoc.SourceFile.Len, 6U);
374 EXPECT_EQ(Remark->DebugLoc.SourceLineNumber, 3U);
375 EXPECT_EQ(Remark->DebugLoc.SourceColumnNumber, 12U);
376 EXPECT_EQ(Remark->Hotness, 0U);
377 EXPECT_EQ(Remark->NumArgs, 4U);
378 // Arg 0
379 {
380 LLVMOptRemarkArg &Arg = Remark->Args[0];
381 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Callee");
382 EXPECT_EQ(Arg.Key.Len, 6U);
383 EXPECT_EQ(StringRef(Arg.Value.Str, 3), "bar");
384 EXPECT_EQ(Arg.Value.Len, 3U);
385 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), "");
386 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U);
387 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U);
388 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
389 }
390 // Arg 1
391 {
392 LLVMOptRemarkArg &Arg = Remark->Args[1];
393 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String");
394 EXPECT_EQ(Arg.Key.Len, 6U);
395 EXPECT_EQ(StringRef(Arg.Value.Str, 26), " will not be inlined into ");
396 EXPECT_EQ(Arg.Value.Len, 26U);
397 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), "");
398 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U);
399 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U);
400 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
401 }
402 // Arg 2
403 {
404 LLVMOptRemarkArg &Arg = Remark->Args[2];
405 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Caller");
406 EXPECT_EQ(Arg.Key.Len, 6U);
407 EXPECT_EQ(StringRef(Arg.Value.Str, 3), "foo");
408 EXPECT_EQ(Arg.Value.Len, 3U);
409 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 6), "file.c");
410 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 6U);
411 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 2U);
412 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
413 }
414 // Arg 3
415 {
416 LLVMOptRemarkArg &Arg = Remark->Args[3];
417 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String");
418 EXPECT_EQ(Arg.Key.Len, 6U);
419 EXPECT_EQ(StringRef(Arg.Value.Str, 38),
420 " because its definition is unavailable");
421 EXPECT_EQ(Arg.Value.Len, 38U);
422 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), "");
423 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U);
424 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U);
425 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
426 }
427
428 EXPECT_EQ(LLVMOptRemarkParserGetNext(Parser), nullptr);
429
430 EXPECT_FALSE(LLVMOptRemarkParserHasError(Parser));
431 LLVMOptRemarkParserDispose(Parser);
432 }