llvm.org GIT mirror llvm / 105b05e
Reland: [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 Fixed the tests by removing the usage of C++11 strings, which seems not to be supported by gcc 4.8.4 if they're used as a macro argument. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@344171 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 = "\n"
45 "\n";
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("\n"
58 "--- !Missed\n"
59 "Pass: inline\n"
60 "Name: NoDefinition\n"
61 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
62 "Function: foo\n"
63 "Args:\n"
64 " - Callee: bar\n"
65 " - String: ' will not be inlined into '\n"
66 " - Caller: foo\n"
67 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
68 " - String: ' because its definition is unavailable'\n"
69 ""));
70
71 // No debug loc should also pass.
72 EXPECT_TRUE(tryParse("\n"
73 "--- !Missed\n"
74 "Pass: inline\n"
75 "Name: NoDefinition\n"
76 "Function: foo\n"
77 "Args:\n"
78 " - Callee: bar\n"
79 " - String: ' will not be inlined into '\n"
80 " - Caller: foo\n"
81 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
82 " - String: ' because its definition is unavailable'\n"
83 ""));
84
85 // No args is also ok.
86 EXPECT_TRUE(tryParse("\n"
87 "--- !Missed\n"
88 "Pass: inline\n"
89 "Name: NoDefinition\n"
90 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
91 "Function: foo\n"
92 ""));
93
94 // Different order.
95 EXPECT_TRUE(tryParse("\n"
96 "--- !Missed\n"
97 "DebugLoc: { Line: 3, Column: 12, File: file.c }\n"
98 "Function: foo\n"
99 "Name: NoDefinition\n"
100 "Args:\n"
101 " - Callee: bar\n"
102 " - String: ' will not be inlined into '\n"
103 " - Caller: foo\n"
104 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
105 " - String: ' because its definition is unavailable'\n"
106 "Pass: inline\n"
107 ""));
108 }
109
110 // Mandatory common part of a remark.
111 #define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\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("\n"
132 "---\n"
133 "Pass: inline\n"
134 "Name: NoDefinition\n"
135 "Function: foo\n"
136 "",
137 "error: Type, Pass, Name or Function missing."));
138 // No pass.
139 EXPECT_TRUE(parseExpectError("\n"
140 "--- !Missed\n"
141 "Name: NoDefinition\n"
142 "Function: foo\n"
143 "",
144 "error: Type, Pass, Name or Function missing."));
145 // No name.
146 EXPECT_TRUE(parseExpectError("\n"
147 "--- !Missed\n"
148 "Pass: inline\n"
149 "Function: foo\n"
150 "",
151 "error: Type, Pass, Name or Function missing."));
152 // No function.
153 EXPECT_TRUE(parseExpectError("\n"
154 "--- !Missed\n"
155 "Pass: inline\n"
156 "Name: NoDefinition\n"
157 "",
158 "error: Type, Pass, Name or Function missing."));
159 // Debug loc but no file.
160 EXPECT_TRUE(parseExpectError("\n"
161 "--- !Missed\n"
162 "Pass: inline\n"
163 "Name: NoDefinition\n"
164 "Function: foo\n"
165 "DebugLoc: { Line: 3, Column: 12 }\n"
166 "",
167 "DebugLoc node incomplete."));
168 // Debug loc but no line.
169 EXPECT_TRUE(parseExpectError("\n"
170 "--- !Missed\n"
171 "Pass: inline\n"
172 "Name: NoDefinition\n"
173 "Function: foo\n"
174 "DebugLoc: { File: file.c, Column: 12 }\n"
175 "",
176 "DebugLoc node incomplete."));
177 // Debug loc but no column.
178 EXPECT_TRUE(parseExpectError("\n"
179 "--- !Missed\n"
180 "Pass: inline\n"
181 "Name: NoDefinition\n"
182 "Function: foo\n"
183 "DebugLoc: { File: file.c, Line: 3 }\n"
184 "",
185 "DebugLoc node incomplete."));
186 }
187
188 TEST(OptRemarks, OptRemarksParsingWrongTypes) {
189 // Wrong debug loc type.
190 EXPECT_TRUE(parseExpectError("\n"
191 "--- !Missed\n"
192 "Pass: inline\n"
193 "Name: NoDefinition\n"
194 "Function: foo\n"
195 "DebugLoc: foo\n"
196 "",
197 "expected a value of mapping type."));
198 // Wrong line type.
199 EXPECT_TRUE(parseExpectError("\n"
200 "--- !Missed\n"
201 "Pass: inline\n"
202 "Name: NoDefinition\n"
203 "Function: foo\n"
204 "DebugLoc: { File: file.c, Line: b, Column: 12 }\n"
205 "",
206 "expected a value of integer type."));
207 // Wrong column type.
208 EXPECT_TRUE(parseExpectError("\n"
209 "--- !Missed\n"
210 "Pass: inline\n"
211 "Name: NoDefinition\n"
212 "Function: foo\n"
213 "DebugLoc: { File: file.c, Line: 3, Column: c }\n"
214 "",
215 "expected a value of integer type."));
216 // Wrong args type.
217 EXPECT_TRUE(parseExpectError("\n"
218 "--- !Missed\n"
219 "Pass: inline\n"
220 "Name: NoDefinition\n"
221 "Function: foo\n"
222 "Args: foo\n"
223 "",
224 "wrong value type for key."));
225 // Wrong key type.
226 EXPECT_TRUE(parseExpectError("\n"
227 "--- !Missed\n"
228 "{ A: a }: inline\n"
229 "Name: NoDefinition\n"
230 "Function: foo\n"
231 "",
232 "key is not a string."));
233 // Debug loc with unknown entry.
234 EXPECT_TRUE(parseExpectError("\n"
235 "--- !Missed\n"
236 "Pass: inline\n"
237 "Name: NoDefinition\n"
238 "Function: foo\n"
239 "DebugLoc: { File: file.c, Column: 12, Unknown: 12 }\n"
240 "",
241 "unknown entry in DebugLoc map."));
242 // Unknown entry.
243 EXPECT_TRUE(parseExpectError("\n"
244 "--- !Missed\n"
245 "Unknown: inline\n"
246 "",
247 "unknown key."));
248 // Not a scalar.
249 EXPECT_TRUE(parseExpectError("\n"
250 "--- !Missed\n"
251 "Pass: { File: a, Line: 1, Column: 2 }\n"
252 "Name: NoDefinition\n"
253 "Function: foo\n"
254 "",
255 "expected a value of scalar type."));
256 // Not a string file in debug loc.
257 EXPECT_TRUE(parseExpectError("\n"
258 "--- !Missed\n"
259 "Pass: inline\n"
260 "Name: NoDefinition\n"
261 "Function: foo\n"
262 "DebugLoc: { File: { a: b }, Column: 12, Line: 12 }\n"
263 "",
264 "expected a value of scalar type."));
265 // Not a integer column in debug loc.
266 EXPECT_TRUE(parseExpectError("\n"
267 "--- !Missed\n"
268 "Pass: inline\n"
269 "Name: NoDefinition\n"
270 "Function: foo\n"
271 "DebugLoc: { File: file.c, Column: { a: b }, Line: 12 }\n"
272 "",
273 "expected a value of scalar type."));
274 // Not a integer line in debug loc.
275 EXPECT_TRUE(parseExpectError("\n"
276 "--- !Missed\n"
277 "Pass: inline\n"
278 "Name: NoDefinition\n"
279 "Function: foo\n"
280 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
281 "",
282 "expected a value of scalar type."));
283 // Not a mapping type value for args.
284 EXPECT_TRUE(parseExpectError("\n"
285 "--- !Missed\n"
286 "Pass: inline\n"
287 "Name: NoDefinition\n"
288 "Function: foo\n"
289 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
290 "",
291 "expected a value of scalar type."));
292 }
293
294 TEST(OptRemarks, OptRemarksParsingWrongArgs) {
295 // Multiple debug locs per arg.
296 EXPECT_TRUE(
297 parseExpectError("\n"
298 "--- !Missed\n"
299 "Pass: inline\n"
300 "Name: NoDefinition\n"
301 "Function: foo\n"
302 "Args:\n"
303 " - Str: string\n"
304 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
305 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
306 "",
307 "only one DebugLoc entry is allowed per argument."));
308 // Multiple strings per arg.
309 EXPECT_TRUE(
310 parseExpectError("\n"
311 "--- !Missed\n"
312 "Pass: inline\n"
313 "Name: NoDefinition\n"
314 "Function: foo\n"
315 "Args:\n"
316 " - Str: string\n"
317 " Str2: string\n"
318 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
319 "",
320 "only one string entry is allowed per argument."));
321 // No arg value.
322 EXPECT_TRUE(parseExpectError("\n"
323 "--- !Missed\n"
324 "Pass: inline\n"
325 "Name: NoDefinition\n"
326 "Function: foo\n"
327 "Args:\n"
328 " - Callee: ''\n"
329 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
330 "",
331 "argument value is missing."));
332 // No arg value.
333 EXPECT_TRUE(parseExpectError("\n"
334 "--- !Missed\n"
335 "Pass: inline\n"
336 "Name: NoDefinition\n"
337 "Function: foo\n"
338 "Args:\n"
339 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
340 "",
341 "argument key is missing."));
342
343 }
344
345 TEST(OptRemarks, OptRemarksGoodStruct) {
346 StringRef Buf = "\n"
347 "--- !Missed\n"
348 "Pass: inline\n"
349 "Name: NoDefinition\n"
350 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
351 "Function: foo\n"
352 "Args:\n"
353 " - Callee: bar\n"
354 " - String: ' will not be inlined into '\n"
355 " - Caller: foo\n"
356 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
357 " - String: ' because its definition is unavailable'\n"
358 "\n";
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 }