llvm.org GIT mirror llvm / 2e8758f
[Remarks] Add a new Remark / RemarkParser abstraction This adds a Remark class that allows us to share code when working with remarks. The C API has been updated to reflect this. Instead of the parser generating C structs, it's now using a C++ object that is used through opaque pointers in C. This gives us much more flexibility on what changes we can make to the internal state of the object and interacts much better with scenarios where the library is used through dlopen. * C API updates: * move from C structs to opaque pointers and functions * the remark type is now an enum instead of a string * unit tests updates: * use mostly the C++ API * keep one test for the C API * rename to YAMLRemarksParsingTest * a typo was fixed: AnalysisFPCompute -> AnalysisFPCommute. * a new error message was added: "expected a remark tag." * llvm-opt-report has been updated to use the C++ parser instead of the C API Differential Revision: https://reviews.llvm.org/D59049 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@356491 91177308-0d34-0410-b5e6-96231b3b80d8 Francis Visoiu Mistrih 5 months ago
14 changed file(s) with 1494 addition(s) and 857 deletion(s). Raw diff Collapse all Expand all
0 //===-- llvm/Remarks/Remark.h - The remark type -----------------*- C++/-*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file defines an abstraction for handling remarks.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_REMARKS_REMARK_H
13 #define LLVM_REMARKS_REMARK_H
14
15 #include "llvm-c/Remarks.h"
16 #include "llvm/ADT/ArrayRef.h"
17 #include "llvm/ADT/Optional.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/CBindingWrapping.h"
20 #include
21
22 namespace llvm {
23 namespace remarks {
24
25 /// The debug location used to track a remark back to the source file.
26 struct RemarkLocation {
27 /// Absolute path of the source file corresponding to this remark.
28 StringRef SourceFilePath;
29 unsigned SourceLine;
30 unsigned SourceColumn;
31 };
32
33 // Create wrappers for C Binding types (see CBindingWrapping.h).
34 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RemarkLocation, LLVMRemarkDebugLocRef)
35
36 /// A key-value pair with a debug location that is used to display the remarks
37 /// at the right place in the source.
38 struct Argument {
39 StringRef Key;
40 // FIXME: We might want to be able to store other types than strings here.
41 StringRef Val;
42 // If set, the debug location corresponding to the value.
43 Optional Loc;
44 };
45
46 // Create wrappers for C Binding types (see CBindingWrapping.h).
47 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Argument, LLVMRemarkArgRef)
48
49 /// The type of the remark.
50 enum class Type {
51 Unknown,
52 Passed,
53 Missed,
54 Analysis,
55 AnalysisFPCommute,
56 AnalysisAliasing,
57 Failure,
58 LastTypeValue = Failure
59 };
60
61 /// A remark type used for both emission and parsing.
62 struct Remark {
63 /// The type of the remark.
64 enum Type RemarkType = Type::Unknown;
65
66 /// Name of the pass that triggers the emission of this remark.
67 StringRef PassName;
68
69 /// Textual identifier for the remark (single-word, camel-case). Can be used
70 /// by external tools reading the output file for remarks to identify the
71 /// remark.
72 StringRef RemarkName;
73
74 /// Mangled name of the function that triggers the emssion of this remark.
75 StringRef FunctionName;
76
77 /// The location in the source file of the remark.
78 Optional Loc;
79
80 /// If profile information is available, this is the number of times the
81 /// corresponding code was executed in a profile instrumentation run.
82 Optional Hotness;
83
84 /// Arguments collected via the streaming interface.
85 ArrayRef Args;
86
87 /// Return a message composed from the arguments as a string.
88 std::string getArgsAsMsg() const;
89 };
90
91 // Create wrappers for C Binding types (see CBindingWrapping.h).
92 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Remark, LLVMRemarkEntryRef)
93
94 } // end namespace remarks
95 } // end namespace llvm
96
97 #endif /* LLVM_REMARKS_REMARK_H */
0 //===-- llvm/Remarks/Remark.h - The remark type -----------------*- C++/-*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file provides an interface for parsing remarks in LLVM.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_REMARKS_REMARK_PARSER_H
13 #define LLVM_REMARKS_REMARK_PARSER_H
14
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Remarks/Remark.h"
17 #include "llvm/Support/Error.h"
18 #include
19
20 namespace llvm {
21 namespace remarks {
22
23 struct ParserImpl;
24
25 /// Parser used to parse a raw buffer to remarks::Remark objects.
26 struct Parser {
27 /// The hidden implementation of the parser.
28 std::unique_ptr Impl;
29
30 /// Create a parser parsing \p Buffer to Remark objects.
31 /// This constructor should be only used for parsing YAML remarks.
32 Parser(StringRef Buffer);
33
34 // Needed because ParserImpl is an incomplete type.
35 ~Parser();
36
37 /// Returns an empty Optional if it reached the end.
38 /// Returns a valid remark otherwise.
39 Expected getNext() const;
40 };
41
42 } // end namespace remarks
43 } // end namespace llvm
44
45 #endif /* LLVM_REMARKS_REMARK_PARSER_H */
3333 #define REMARKS_API_VERSION 0
3434
3535 /**
36 * The type of the emitted remark.
37 */
38 enum LLVMRemarkType {
39 LLVMRemarkTypeUnknown,
40 LLVMRemarkTypePassed,
41 LLVMRemarkTypeMissed,
42 LLVMRemarkTypeAnalysis,
43 LLVMRemarkTypeAnalysisFPCommute,
44 LLVMRemarkTypeAnalysisAliasing,
45 LLVMRemarkTypeFailure
46 };
47
48 /**
3649 * String containing a buffer and a length. The buffer is not guaranteed to be
3750 * zero-terminated.
3851 *
3952 * \since REMARKS_API_VERSION=0
4053 */
41 typedef struct {
42 const char *Str;
43 uint32_t Len;
44 } LLVMRemarkStringRef;
54 typedef struct LLVMRemarkOpaqueString *LLVMRemarkStringRef;
55
56 /**
57 * Returns the buffer holding the string.
58 *
59 * \since REMARKS_API_VERSION=0
60 */
61 extern const char *LLVMRemarkStringGetData(LLVMRemarkStringRef String);
62
63 /**
64 * Returns the size of the string.
65 *
66 * \since REMARKS_API_VERSION=0
67 */
68 extern uint32_t LLVMRemarkStringGetLen(LLVMRemarkStringRef String);
4569
4670 /**
4771 * DebugLoc containing File, Line and Column.
4872 *
4973 * \since REMARKS_API_VERSION=0
5074 */
51 typedef struct {
52 // File:
53 LLVMRemarkStringRef SourceFile;
54 // Line:
55 uint32_t SourceLineNumber;
56 // Column:
57 uint32_t SourceColumnNumber;
58 } LLVMRemarkDebugLoc;
75 typedef struct LLVMRemarkOpaqueDebugLoc *LLVMRemarkDebugLocRef;
76
77 /**
78 * Return the path to the source file for a debug location.
79 *
80 * \since REMARKS_API_VERSION=0
81 */
82 extern LLVMRemarkStringRef
83 LLVMRemarkDebugLocGetSourceFilePath(LLVMRemarkDebugLocRef DL);
84
85 /**
86 * Return the line in the source file for a debug location.
87 *
88 * \since REMARKS_API_VERSION=0
89 */
90 extern uint32_t LLVMRemarkDebugLocGetSourceLine(LLVMRemarkDebugLocRef DL);
91
92 /**
93 * Return the column in the source file for a debug location.
94 *
95 * \since REMARKS_API_VERSION=0
96 */
97 extern uint32_t LLVMRemarkDebugLocGetSourceColumn(LLVMRemarkDebugLocRef DL);
5998
6099 /**
61100 * 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
101 * the semantics of the value are, e.g. "Callee" will tell you that the value
63102 * is a symbol that names a function.
64103 *
65104 * \since REMARKS_API_VERSION=0
66105 */
67 typedef struct {
68 // e.g. "Callee"
69 LLVMRemarkStringRef Key;
70 // e.g. "malloc"
71 LLVMRemarkStringRef Value;
72
73 // "DebugLoc": Optional
74 LLVMRemarkDebugLoc DebugLoc;
75 } LLVMRemarkArg;
76
77 /**
78 * One remark entry.
79 *
80 * \since REMARKS_API_VERSION=0
81 */
82 typedef struct {
83 // e.g. !Missed, !Passed
84 LLVMRemarkStringRef RemarkType;
85 // "Pass": Required
86 LLVMRemarkStringRef PassName;
87 // "Name": Required
88 LLVMRemarkStringRef RemarkName;
89 // "Function": Required
90 LLVMRemarkStringRef FunctionName;
91
92 // "DebugLoc": Optional
93 LLVMRemarkDebugLoc DebugLoc;
94 // "Hotness": Optional
95 uint32_t Hotness;
96 // "Args": Optional. It is an array of `num_args` elements.
97 uint32_t NumArgs;
98 LLVMRemarkArg *Args;
99 } LLVMRemarkEntry;
106 typedef struct LLVMRemarkOpaqueArg *LLVMRemarkArgRef;
107
108 /**
109 * Returns the key of an argument. The key defines what the value is, and the
110 * same key can appear multiple times in the list of arguments.
111 *
112 * \since REMARKS_API_VERSION=0
113 */
114 extern LLVMRemarkStringRef LLVMRemarkArgGetKey(LLVMRemarkArgRef Arg);
115
116 /**
117 * Returns the value of an argument. This is a string that can contain newlines.
118 *
119 * \since REMARKS_API_VERSION=0
120 */
121 extern LLVMRemarkStringRef LLVMRemarkArgGetValue(LLVMRemarkArgRef Arg);
122
123 /**
124 * Returns the debug location that is attached to the value of this argument.
125 *
126 * If there is no debug location, the return value will be `NULL`.
127 *
128 * \since REMARKS_API_VERSION=0
129 */
130 extern LLVMRemarkDebugLocRef LLVMRemarkArgGetDebugLoc(LLVMRemarkArgRef Arg);
131
132 /**
133 * A remark emitted by the compiler.
134 *
135 * \since REMARKS_API_VERSION=0
136 */
137 typedef struct LLVMRemarkOpaqueEntry *LLVMRemarkEntryRef;
138
139 /**
140 * The type of the remark. For example, it can allow users to only keep the
141 * missed optimizations from the compiler.
142 *
143 * \since REMARKS_API_VERSION=0
144 */
145 extern enum LLVMRemarkType LLVMRemarkEntryGetType(LLVMRemarkEntryRef Remark);
146
147 /**
148 * Get the name of the pass that emitted this remark.
149 *
150 * \since REMARKS_API_VERSION=0
151 */
152 extern LLVMRemarkStringRef
153 LLVMRemarkEntryGetPassName(LLVMRemarkEntryRef Remark);
154
155 /**
156 * Get an identifier of the remark.
157 *
158 * \since REMARKS_API_VERSION=0
159 */
160 extern LLVMRemarkStringRef
161 LLVMRemarkEntryGetRemarkName(LLVMRemarkEntryRef Remark);
162
163 /**
164 * Get the name of the function being processsed when the remark was emitted.
165 *
166 * \since REMARKS_API_VERSION=0
167 */
168 extern LLVMRemarkStringRef
169 LLVMRemarkEntryGetFunctionName(LLVMRemarkEntryRef Remark);
170
171 /**
172 * Returns the debug location that is attached to this remark.
173 *
174 * If there is no debug location, the return value will be `NULL`.
175 *
176 * \since REMARKS_API_VERSION=0
177 */
178 extern LLVMRemarkDebugLocRef
179 LLVMRemarkEntryGetDebugLoc(LLVMRemarkEntryRef Remark);
180
181 /**
182 * Return the hotness of the remark.
183 *
184 * A hotness of `0` means this value is not set.
185 *
186 * \since REMARKS_API_VERSION=0
187 */
188 extern uint64_t LLVMRemarkEntryGetHotness(LLVMRemarkEntryRef Remark);
189
190 /**
191 * The number of arguments the remark holds.
192 *
193 * \since REMARKS_API_VERSION=0
194 */
195 extern uint32_t LLVMRemarkEntryGetNumArgs(LLVMRemarkEntryRef Remark);
196
197 /**
198 * Get a new iterator to iterate over a remark's argument.
199 *
200 * If there are no arguments in \p Remark, the return value will be `NULL`.
201 *
202 * \since REMARKS_API_VERSION=0
203 */
204 extern LLVMRemarkArgRef LLVMRemarkEntryGetFirstArg(LLVMRemarkEntryRef Remark);
205
206 /**
207 * Get the next argument in \p Remark from the position of \p It.
208 *
209 * Returns `NULL` if there are no more arguments available.
210 *
211 * \since REMARKS_API_VERSION=0
212 */
213 extern LLVMRemarkArgRef LLVMRemarkEntryGetNextArg(LLVMRemarkArgRef It,
214 LLVMRemarkEntryRef Remark);
100215
101216 typedef struct LLVMRemarkOpaqueParser *LLVMRemarkParserRef;
102217
103218 /**
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.
219 * Creates a remark parser that can be used to parse the buffer located in \p
220 * Buf of size \p Size bytes.
221 *
222 * \p Buf cannot be `NULL`.
108223 *
109224 * This function should be paired with LLVMRemarkParserDispose() to avoid
110225 * leaking resources.
111226 *
112227 * \since REMARKS_API_VERSION=0
113228 */
114 extern LLVMRemarkParserRef LLVMRemarkParserCreate(const void *Buf,
115 uint64_t Size);
229 extern LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf,
230 uint64_t Size);
116231
117232 /**
118233 * Returns the next remark in the file.
120235 * The value pointed to by the return value is invalidated by the next call to
121236 * LLVMRemarkParserGetNext().
122237 *
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:
238 * If the parser reaches the end of the buffer, the return value will be `NULL`.
239 *
240 * In the case of an error, the return value will be `NULL`, and:
126241 *
127242 * 1) LLVMRemarkParserHasError() will return `1`.
128243 *
133248 *
134249 * 1) An argument is invalid.
135250 *
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.
251 * 2) There is a parsing error. This can occur on things like malformed YAML.
252 *
253 * 3) There is a Remark semantic error. This can occur on well-formed files with
254 * missing or extra fields.
142255 *
143256 * Here is a quick example of the usage:
144257 *
145258 * ```
146 * LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf, Size);
147 * LLVMRemarkEntry *Remark = NULL;
259 * LLVMRemarkParserRef Parser = LLVMRemarkParserCreateYAML(Buf, Size);
260 * LLVMRemarkEntryRef Remark = NULL;
148261 * while ((Remark == LLVMRemarkParserGetNext(Parser))) {
149262 * // use Remark
150263 * }
154267 *
155268 * \since REMARKS_API_VERSION=0
156269 */
157 extern LLVMRemarkEntry *LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser);
270 extern LLVMRemarkEntryRef LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser);
158271
159272 /**
160273 * Returns `1` if the parser encountered an error while parsing the buffer.
184297 extern void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser);
185298
186299 /**
187 * Returns the version of the remarks dylib.
300 * Returns the version of the remarks library.
188301 *
189302 * \since REMARKS_API_VERSION=0
190303 */
0 add_llvm_library(LLVMRemarks
1 Remark.cpp
12 RemarkParser.cpp
3 YAMLRemarkParser.cpp
24 )
0 //===- Remark.cpp ---------------------------------------------------------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // Implementation of the Remark type and the C API.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #include "llvm/Remarks/Remark.h"
13 #include "llvm-c/Remarks.h"
14 #include "llvm/Support/CBindingWrapping.h"
15 #include "llvm/Support/raw_ostream.h"
16
17 using namespace llvm;
18 using namespace llvm::remarks;
19
20 std::string Remark::getArgsAsMsg() const {
21 std::string Str;
22 raw_string_ostream OS(Str);
23 for (const Argument &Arg : Args)
24 OS << Arg.Val;
25 return OS.str();
26 }
27
28 // Create wrappers for C Binding types (see CBindingWrapping.h).
29 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(StringRef, LLVMRemarkStringRef)
30
31 extern "C" const char *LLVMRemarkStringGetData(LLVMRemarkStringRef String) {
32 return unwrap(String)->data();
33 }
34
35 extern "C" uint32_t LLVMRemarkStringGetLen(LLVMRemarkStringRef String) {
36 return unwrap(String)->size();
37 }
38
39 extern "C" LLVMRemarkStringRef
40 LLVMRemarkDebugLocGetSourceFilePath(LLVMRemarkDebugLocRef DL) {
41 return wrap(&unwrap(DL)->SourceFilePath);
42 }
43
44 extern "C" uint32_t LLVMRemarkDebugLocGetSourceLine(LLVMRemarkDebugLocRef DL) {
45 return unwrap(DL)->SourceLine;
46 }
47
48 extern "C" uint32_t
49 LLVMRemarkDebugLocGetSourceColumn(LLVMRemarkDebugLocRef DL) {
50 return unwrap(DL)->SourceColumn;
51 }
52
53 extern "C" LLVMRemarkStringRef LLVMRemarkArgGetKey(LLVMRemarkArgRef Arg) {
54 return wrap(&unwrap(Arg)->Key);
55 }
56
57 extern "C" LLVMRemarkStringRef LLVMRemarkArgGetValue(LLVMRemarkArgRef Arg) {
58 return wrap(&unwrap(Arg)->Val);
59 }
60
61 extern "C" LLVMRemarkDebugLocRef
62 LLVMRemarkArgGetDebugLoc(LLVMRemarkArgRef Arg) {
63 if (const Optional &Loc = unwrap(Arg)->Loc)
64 return wrap(&*Loc);
65 return nullptr;
66 }
67
68 extern "C" LLVMRemarkType LLVMRemarkEntryGetType(LLVMRemarkEntryRef Remark) {
69 // Assume here that the enums can be converted both ways.
70 return static_cast(unwrap(Remark)->RemarkType);
71 }
72
73 extern "C" LLVMRemarkStringRef
74 LLVMRemarkEntryGetPassName(LLVMRemarkEntryRef Remark) {
75 return wrap(&unwrap(Remark)->PassName);
76 }
77
78 extern "C" LLVMRemarkStringRef
79 LLVMRemarkEntryGetRemarkName(LLVMRemarkEntryRef Remark) {
80 return wrap(&unwrap(Remark)->RemarkName);
81 }
82
83 extern "C" LLVMRemarkStringRef
84 LLVMRemarkEntryGetFunctionName(LLVMRemarkEntryRef Remark) {
85 return wrap(&unwrap(Remark)->FunctionName);
86 }
87
88 extern "C" LLVMRemarkDebugLocRef
89 LLVMRemarkEntryGetDebugLoc(LLVMRemarkEntryRef Remark) {
90 if (const Optional &Loc = unwrap(Remark)->Loc)
91 return wrap(&*Loc);
92 return nullptr;
93 }
94
95 extern "C" uint64_t LLVMRemarkEntryGetHotness(LLVMRemarkEntryRef Remark) {
96 if (const Optional &Hotness = unwrap(Remark)->Hotness)
97 return *Hotness;
98 return 0;
99 }
100
101 extern "C" uint32_t LLVMRemarkEntryGetNumArgs(LLVMRemarkEntryRef Remark) {
102 return unwrap(Remark)->Args.size();
103 }
104
105 extern "C" LLVMRemarkArgRef
106 LLVMRemarkEntryGetFirstArg(LLVMRemarkEntryRef Remark) {
107 ArrayRef Args = unwrap(Remark)->Args;
108 // No arguments to iterate on.
109 if (Args.empty())
110 return NULL;
111 return reinterpret_cast(
112 const_cast(Args.begin()));
113 }
114
115 extern "C" LLVMRemarkArgRef
116 LLVMRemarkEntryGetNextArg(LLVMRemarkArgRef ArgIt, LLVMRemarkEntryRef Remark) {
117 // No more arguments to iterate on.
118 if (ArgIt == NULL)
119 return NULL;
120
121 auto It = (ArrayRef::const_iterator)ArgIt;
122 auto Next = std::next(It);
123 if (Next == unwrap(Remark)->Args.end())
124 return NULL;
125
126 return reinterpret_cast(const_cast(Next));
127 }
1010 //
1111 //===----------------------------------------------------------------------===//
1212
13 #include "llvm/Remarks/RemarkParser.h"
14 #include "YAMLRemarkParser.h"
1315 #include "llvm-c/Remarks.h"
1416 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "llvm/Support/YAMLTraits.h"
17 #include "llvm/Support/CBindingWrapping.h"
1718
1819 using namespace llvm;
20 using namespace llvm::remarks;
1921
20 namespace {
21 struct YAMLRemarkParser {
22 /// Source manager for better error messages.
23 SourceMgr SM;
24 /// Stream for yaml parsing.
25 yaml::Stream Stream;
26 /// Storage for the error stream.
27 std::string ErrorString;
28 /// The error stream.
29 raw_string_ostream ErrorStream;
30 /// Iterator in the YAML stream.
31 yaml::document_iterator DI;
32 /// The parsed remark (if any).
33 Optional LastRemark;
34 /// Temporary parsing buffer for the arguments.
35 SmallVector TmpArgs;
36 /// The state used by the parser to parse a remark entry. Invalidated with
37 /// every call to `parseYAMLElement`.
38 struct ParseState {
39 /// Temporary parsing buffer for the arguments.
40 SmallVectorImpl *Args;
41 StringRef Type;
42 StringRef Pass;
43 StringRef Name;
44 StringRef Function;
45 /// Optional.
46 Optional File;
47 Optional Line;
48 Optional Column;
49 Optional Hotness;
22 Parser::Parser(StringRef Buf) : Impl(llvm::make_unique(Buf)) {}
5023
51 ParseState(SmallVectorImpl &Args) : Args(&Args) {}
52 /// Use Args only as a **temporary** buffer.
53 ~ParseState() { Args->clear(); }
54 };
24 Parser::~Parser() = default;
5525
56 ParseState State;
26 static Expected getNextYAML(YAMLParserImpl &Impl) {
27 YAMLRemarkParser &YAMLParser = Impl.YAMLParser;
28 // Check for EOF.
29 if (Impl.YAMLIt == Impl.YAMLParser.Stream.end())
30 return nullptr;
5731
58 /// Set to `true` if we had any errors during parsing.
59 bool HadAnyErrors = false;
32 auto CurrentIt = Impl.YAMLIt;
6033
61 YAMLRemarkParser(StringRef Buf)
62 : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString),
63 DI(Stream.begin()), LastRemark(), TmpArgs(), State(TmpArgs) {
64 SM.setDiagHandler(YAMLRemarkParser::HandleDiagnostic, this);
34 // Try to parse an entry.
35 if (Error E = YAMLParser.parseYAMLElement(*CurrentIt)) {
36 // Set the iterator to the end, in case the user calls getNext again.
37 Impl.YAMLIt = Impl.YAMLParser.Stream.end();
38 return std::move(E);
6539 }
6640
67 /// Parse a YAML element.
68 Error parseYAMLElement(yaml::Document &Remark);
41 // Move on.
42 ++Impl.YAMLIt;
6943
70 private:
71 /// Parse one key to a string.
72 /// otherwise.
73 Error parseKey(StringRef &Result, yaml::KeyValueNode &Node);
74 /// Parse one value to a string.
75 Error parseValue(StringRef &Result, yaml::KeyValueNode &Node);
76 /// Parse one value to an unsigned.
77 Error parseValue(Optional &Result, yaml::KeyValueNode &Node);
78 /// Parse a debug location.
79 Error parseDebugLoc(Optional &File, Optional &Line,
80 Optional &Column, yaml::KeyValueNode &Node);
81 /// Parse an argument.
82 Error parseArg(SmallVectorImpl &TmpArgs, yaml::Node &Node);
83
84 /// Handle a diagnostic from the YAML stream. Records the error in the
85 /// YAMLRemarkParser class.
86 static void HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx) {
87 assert(Ctx && "Expected non-null Ctx in diagnostic handler.");
88 auto *Parser = static_cast(Ctx);
89 Diag.print(/*ProgName=*/nullptr, Parser->ErrorStream, /*ShowColors*/ false,
90 /*ShowKindLabels*/ true);
91 }
92 };
93
94 class ParseError : public ErrorInfo {
95 public:
96 static char ID;
97
98 ParseError(StringRef Message, yaml::Node &Node)
99 : Message(Message), Node(Node) {}
100
101 void log(raw_ostream &OS) const override { OS << Message; }
102 std::error_code convertToErrorCode() const override {
103 return inconvertibleErrorCode();
104 }
105
106 StringRef getMessage() const { return Message; }
107 yaml::Node &getNode() const { return Node; }
108
109 private:
110 StringRef Message; // No need to hold a full copy of the buffer.
111 yaml::Node &Node;
112 };
113
114 char ParseError::ID = 0;
115
116 static LLVMRemarkStringRef toRemarkStr(StringRef Str) {
117 return {Str.data(), static_cast(Str.size())};
44 // Return the just-parsed remark.
45 if (const Optional &State = YAMLParser.State)
46 return &State->Remark;
47 else
48 return createStringError(std::make_error_code(std::errc::invalid_argument),
49 "unexpected error while parsing.");
11850 }
11951
120 Error YAMLRemarkParser::parseKey(StringRef &Result, yaml::KeyValueNode &Node) {
121 auto *Key = dyn_cast(Node.getKey());
122 if (!Key)
123 return make_error("key is not a string.", Node);
124
125 Result = Key->getRawValue();
126 return Error::success();
52 Expected Parser::getNext() const {
53 if (auto *Impl = dyn_cast(this->Impl.get()))
54 return getNextYAML(*Impl);
55 llvm_unreachable("Get next called with an unknown parsing implementation.");
12756 }
12857
129 Error YAMLRemarkParser::parseValue(StringRef &Result,
130 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();
58 // Create wrappers for C Binding types (see CBindingWrapping.h).
59 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(remarks::Parser, LLVMRemarkParserRef)
13560
136 if (Result.front() == '\'')
137 Result = Result.drop_front();
138
139 if (Result.back() == '\'')
140 Result = Result.drop_back();
141
142 return Error::success();
61 extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf,
62 uint64_t Size) {
63 return wrap(
64 new remarks::Parser(StringRef(static_cast(Buf), Size)));
14365 }
14466
145 Error YAMLRemarkParser::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();
67 static void handleYAMLError(remarks::YAMLParserImpl &Impl, Error E) {
68 handleAllErrors(
69 std::move(E),
70 [&](const YAMLParseError &PE) {
71 Impl.YAMLParser.Stream.printError(&PE.getNode(),
72 Twine(PE.getMessage()) + Twine('\n'));
73 Impl.HasErrors = true;
74 },
75 [&](const StringError &PE) { PE.log(Impl.YAMLParser.ErrorStream); });
15676 }
15777
158 Error YAMLRemarkParser::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);
78 extern "C" LLVMRemarkEntryRef
79 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) {
80 remarks::Parser &TheParser = *unwrap(Parser);
16581
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 YAMLRemarkParser::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(LLVMRemarkArg{
241 toRemarkStr(KeyStr), toRemarkStr(ValueStr),
242 LLVMRemarkDebugLoc{toRemarkStr(File.getValueOr(StringRef())),
243 Line.getValueOr(0), Column.getValueOr(0)}});
244
245 return Error::success();
246 }
247
248 Error YAMLRemarkParser::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 = LLVMRemarkEntry{
306 toRemarkStr(State.Type),
307 toRemarkStr(State.Pass),
308 toRemarkStr(State.Name),
309 toRemarkStr(State.Function),
310 LLVMRemarkDebugLoc{toRemarkStr(State.File.getValueOr(StringRef())),
311 State.Line.getValueOr(0), State.Column.getValueOr(0)},
312 State.Hotness.getValueOr(0),
313 static_cast(State.Args->size()),
314 State.Args->data()};
315
316 return Error::success();
317 }
318 } // namespace
319
320 // Create wrappers for C Binding types (see CBindingWrapping.h).
321 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(YAMLRemarkParser, LLVMRemarkParserRef)
322
323 extern "C" LLVMRemarkParserRef LLVMRemarkParserCreate(const void *Buf,
324 uint64_t Size) {
325 return wrap(
326 new YAMLRemarkParser(StringRef(static_cast(Buf), Size)));
327 }
328
329 extern "C" LLVMRemarkEntry *
330 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) {
331 YAMLRemarkParser &TheParser = *unwrap(Parser);
332 // Check for EOF.
333 if (TheParser.HadAnyErrors || TheParser.DI == TheParser.Stream.end())
334 return nullptr;
335
336 // Try to parse an entry.
337 if (Error E = TheParser.parseYAMLElement(*TheParser.DI)) {
338 handleAllErrors(std::move(E), [&](const ParseError &PE) {
339 TheParser.Stream.printError(&PE.getNode(),
340 Twine(PE.getMessage()) + Twine('\n'));
341 TheParser.HadAnyErrors = true;
342 });
82 Expected RemarkOrErr = TheParser.getNext();
83 if (!RemarkOrErr) {
84 // Error during parsing.
85 if (auto *Impl = dyn_cast(TheParser.Impl.get()))
86 handleYAMLError(*Impl, RemarkOrErr.takeError());
87 else
88 llvm_unreachable("unkown parser implementation.");
34389 return nullptr;
34490 }
34591
346 // Move on.
347 ++TheParser.DI;
348
349 // Return the just-parsed remark.
350 if (Optional &Entry = TheParser.LastRemark)
351 return &*Entry;
352 return nullptr;
92 if (*RemarkOrErr == nullptr)
93 return nullptr;
94 // Valid remark.
95 return wrap(*RemarkOrErr);
35396 }
35497
35598 extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) {
356 return unwrap(Parser)->HadAnyErrors;
99 if (auto *Impl =
100 dyn_cast(unwrap(Parser)->Impl.get()))
101 return Impl->HasErrors;
102 llvm_unreachable("unkown parser implementation.");
357103 }
358104
359105 extern "C" const char *
360106 LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) {
361 return unwrap(Parser)->ErrorStream.str().c_str();
107 if (auto *Impl =
108 dyn_cast(unwrap(Parser)->Impl.get()))
109 return Impl->YAMLParser.ErrorStream.str().c_str();
110 llvm_unreachable("unkown parser implementation.");
362111 }
363112
364113 extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) {
0 //===-- RemarkParserImpl.h - Implementation details -------------*- C++/-*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file provides implementation details for the remark parser.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_REMARKS_REMARK_PARSER_IMPL_H
13 #define LLVM_REMARKS_REMARK_PARSER_IMPL_H
14
15 namespace llvm {
16 namespace remarks {
17 /// This is used as a base for any parser implementation.
18 struct ParserImpl {
19 enum class Kind { YAML };
20
21 // The parser kind. This is used as a tag to safely cast between
22 // implementations.
23 enum Kind Kind;
24 };
25 } // end namespace remarks
26 } // end namespace llvm
27
28 #endif /* LLVM_REMARKS_REMARK_PARSER_IMPL_H */
0 //===- YAMLRemarkParser.cpp -----------------------------------------------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file provides utility methods used by clients that want to use the
9 // parser for remark diagnostics in LLVM.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "YAMLRemarkParser.h"
14 #include "llvm/ADT/StringSwitch.h"
15 #include "llvm/Remarks/RemarkParser.h"
16
17 using namespace llvm;
18 using namespace llvm::remarks;
19
20 char YAMLParseError::ID = 0;
21
22 Error YAMLRemarkParser::parseKey(StringRef &Result, yaml::KeyValueNode &Node) {
23 if (auto *Key = dyn_cast(Node.getKey())) {
24 Result = Key->getRawValue();
25 return Error::success();
26 }
27
28 return make_error("key is not a string.", Node);
29 }
30
31 template
32 Error YAMLRemarkParser::parseStr(T &Result, yaml::KeyValueNode &Node) {
33 auto *Value = dyn_cast(Node.getValue());
34 if (!Value)
35 return make_error("expected a value of scalar type.", Node);
36 StringRef Tmp = Value->getRawValue();
37
38 if (Tmp.front() == '\'')
39 Tmp = Tmp.drop_front();
40
41 if (Tmp.back() == '\'')
42 Tmp = Tmp.drop_back();
43
44 Result = Tmp;
45
46 return Error::success();
47 }
48
49 template
50 Error YAMLRemarkParser::parseUnsigned(T &Result, yaml::KeyValueNode &Node) {
51 SmallVector Tmp;
52 auto *Value = dyn_cast(Node.getValue());
53 if (!Value)
54 return make_error("expected a value of scalar type.", Node);
55 unsigned UnsignedValue = 0;
56 if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue))
57 return make_error("expected a value of integer type.",
58 *Value);
59 Result = UnsignedValue;
60 return Error::success();
61 }
62
63 Error YAMLRemarkParser::parseType(Type &Result, yaml::MappingNode &Node) {
64 auto Type = StringSwitch(Node.getRawTag())
65 .Case("!Passed", Type::Passed)
66 .Case("!Missed", Type::Missed)
67 .Case("!Analysis", Type::Analysis)
68 .Case("!AnalysisFPCommute", Type::AnalysisFPCommute)
69 .Case("!AnalysisAliasing", Type::AnalysisAliasing)
70 .Case("!Failure", Type::Failure)
71 .Default(Type::Unknown);
72 if (Type == Type::Unknown)
73 return make_error("expected a remark tag.", Node);
74 Result = Type;
75 return Error::success();
76 }
77
78 Error YAMLRemarkParser::parseDebugLoc(Optional &Result,
79 yaml::KeyValueNode &Node) {
80 auto *DebugLoc = dyn_cast(Node.getValue());
81 if (!DebugLoc)
82 return make_error("expected a value of mapping type.",
83 Node);
84
85 Optional File;
86 Optional Line;
87 Optional Column;
88
89 for (yaml::KeyValueNode &DLNode : *DebugLoc) {
90 StringRef KeyName;
91 if (Error E = parseKey(KeyName, DLNode))
92 return E;
93 if (KeyName == "File") {
94 if (Error E = parseStr(File, DLNode))
95 return E;
96 } else if (KeyName == "Column") {
97 if (Error E = parseUnsigned(Column, DLNode))
98 return E;
99 } else if (KeyName == "Line") {
100 if (Error E = parseUnsigned(Line, DLNode))
101 return E;
102 } else {
103 return make_error("unknown entry in DebugLoc map.",
104 DLNode);
105 }
106 }
107
108 // If any of the debug loc fields is missing, return an error.
109 if (!File || !Line || !Column)
110 return make_error("DebugLoc node incomplete.", Node);
111
112 Result = RemarkLocation{*File, *Line, *Column};
113
114 return Error::success();
115 }
116
117 Error YAMLRemarkParser::parseRemarkField(yaml::KeyValueNode &RemarkField) {
118
119 StringRef KeyName;
120 if (Error E = parseKey(KeyName, RemarkField))
121 return E;
122
123 if (KeyName == "Pass") {
124 if (Error E = parseStr(State->Remark.PassName, RemarkField))
125 return E;
126 } else if (KeyName == "Name") {
127 if (Error E = parseStr(State->Remark.RemarkName, RemarkField))
128 return E;
129 } else if (KeyName == "Function") {
130 if (Error E = parseStr(State->Remark.FunctionName, RemarkField))
131 return E;
132 } else if (KeyName == "Hotness") {
133 State->Remark.Hotness = 0;
134 if (Error E = parseUnsigned(*State->Remark.Hotness, RemarkField))
135 return E;
136 } else if (KeyName == "DebugLoc") {
137 if (Error E = parseDebugLoc(State->Remark.Loc, RemarkField))
138 return E;
139 } else if (KeyName == "Args") {
140 auto *Args = dyn_cast(RemarkField.getValue());
141 if (!Args)
142 return make_error("wrong value type for key.",
143 RemarkField);
144
145 for (yaml::Node &Arg : *Args)
146 if (Error E = parseArg(State->Args, Arg))
147 return E;
148
149 State->Remark.Args = State->Args;
150 } else {
151 return make_error("unknown key.", RemarkField);
152 }
153
154 return Error::success();
155 }
156
157 Error YAMLRemarkParser::parseArg(SmallVectorImpl &Args,
158 yaml::Node &Node) {
159 auto *ArgMap = dyn_cast(&Node);
160 if (!ArgMap)
161 return make_error("expected a value of mapping type.",
162 Node);
163
164 StringRef KeyStr;
165 StringRef ValueStr;
166 Optional Loc;
167
168 for (yaml::KeyValueNode &ArgEntry : *ArgMap)
169 if (Error E = parseArgEntry(ArgEntry, KeyStr, ValueStr, Loc))
170 return E;
171
172 if (KeyStr.empty())
173 return make_error("argument key is missing.", *ArgMap);
174 if (ValueStr.empty())
175 return make_error("argument value is missing.", *ArgMap);
176
177 Args.push_back(Argument{KeyStr, ValueStr, Loc});
178
179 return Error::success();
180 }
181
182 Error YAMLRemarkParser::parseArgEntry(yaml::KeyValueNode &ArgEntry,
183 StringRef &KeyStr, StringRef &ValueStr,
184 Optional &Loc) {
185 StringRef KeyName;
186 if (Error E = parseKey(KeyName, ArgEntry))
187 return E;
188
189 // Try to parse debug locs.
190 if (KeyName == "DebugLoc") {
191 // Can't have multiple DebugLoc entries per argument.
192 if (Loc)
193 return make_error(
194 "only one DebugLoc entry is allowed per argument.", ArgEntry);
195
196 if (Error E = parseDebugLoc(Loc, ArgEntry))
197 return E;
198 return Error::success();
199 }
200
201 // If we already have a string, error out.
202 if (!ValueStr.empty())
203 return make_error(
204 "only one string entry is allowed per argument.", ArgEntry);
205
206 // Try to parse a string.
207 if (Error E = parseStr(ValueStr, ArgEntry))
208 return E;
209
210 // Keep the key from the string.
211 KeyStr = KeyName;
212 return Error::success();
213 }
214
215 Error YAMLRemarkParser::parseYAMLElement(yaml::Document &Remark) {
216 // Parsing a new remark, clear the previous one by re-constructing the state
217 // in-place in the Optional.
218 State.emplace(TmpArgs);
219
220 yaml::Node *YAMLRoot = Remark.getRoot();
221 if (!YAMLRoot)
222 return createStringError(std::make_error_code(std::errc::invalid_argument),
223 "not a valid YAML file.");
224
225 auto *Root = dyn_cast(YAMLRoot);
226 if (!Root)
227 return make_error("document root is not of mapping type.",
228 *YAMLRoot);
229
230 if (Error E = parseType(State->Remark.RemarkType, *Root))
231 return E;
232
233 for (yaml::KeyValueNode &RemarkField : *Root)
234 if (Error E = parseRemarkField(RemarkField))
235 return E;
236
237 // If the YAML parsing failed, don't even continue parsing. We might
238 // encounter malformed YAML.
239 if (Stream.failed())
240 return make_error("YAML parsing failed.",
241 *Remark.getRoot());
242
243 // Check if any of the mandatory fields are missing.
244 if (State->Remark.RemarkType == Type::Unknown ||
245 State->Remark.PassName.empty() || State->Remark.RemarkName.empty() ||
246 State->Remark.FunctionName.empty())
247 return make_error("Type, Pass, Name or Function missing.",
248 *Remark.getRoot());
249
250 return Error::success();
251 }
252
253 /// Handle a diagnostic from the YAML stream. Records the error in the
254 /// YAMLRemarkParser class.
255 void YAMLRemarkParser::HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx) {
256 assert(Ctx && "Expected non-null Ctx in diagnostic handler.");
257 auto *Parser = static_cast(Ctx);
258 Diag.print(/*ProgName=*/nullptr, Parser->ErrorStream, /*ShowColors*/ false,
259 /*ShowKindLabels*/ true);
260 }
0 //===-- YAMLRemarkParser.h - Parser for YAML remarks ------------*- C++/-*-===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7 //
8 // This file provides the impementation of the YAML remark parser.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #ifndef LLVM_REMARKS_YAML_REMARK_PARSER_H
13 #define LLVM_REMARKS_YAML_REMARK_PARSER_H
14
15 #include "RemarkParserImpl.h"
16 #include "llvm/ADT/Optional.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/Remarks/Remark.h"
19 #include "llvm/Support/Error.h"
20 #include "llvm/Support/SourceMgr.h"
21 #include "llvm/Support/YAMLParser.h"
22 #include "llvm/Support/YAMLTraits.h"
23 #include "llvm/Support/raw_ostream.h"
24 #include
25
26 namespace llvm {
27 namespace remarks {
28 /// Parses and holds the state of the latest parsed remark.
29 struct YAMLRemarkParser {
30 /// Source manager for better error messages.
31 SourceMgr SM;
32 /// Stream for yaml parsing.
33 yaml::Stream Stream;
34 /// Storage for the error stream.
35 std::string ErrorString;
36 /// The error stream.
37 raw_string_ostream ErrorStream;
38 /// Temporary parsing buffer for the arguments.
39 SmallVector TmpArgs;
40
41 /// The state used by the parser to parse a remark entry. Invalidated with
42 /// every call to `parseYAMLElement`.
43 struct ParseState {
44 /// Temporary parsing buffer for the arguments.
45 /// The parser itself is owning this buffer in order to reduce the number of
46 /// allocations.
47 SmallVectorImpl &Args;
48 Remark Remark;
49
50 ParseState(SmallVectorImpl &Args) : Args(Args) {}
51 /// Use Args only as a **temporary** buffer.
52 ~ParseState() { Args.clear(); }
53 };
54
55 /// The current state of the parser. If the parsing didn't start yet, it will
56 /// not be containing any value.
57 Optional State;
58
59 YAMLRemarkParser(StringRef Buf)
60 : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString),
61 TmpArgs() {
62 SM.setDiagHandler(YAMLRemarkParser::HandleDiagnostic, this);
63 }
64
65 /// Parse a YAML element.
66 Error parseYAMLElement(yaml::Document &Remark);
67
68 private:
69 /// Parse one key to a string.
70 /// otherwise.
71 Error parseKey(StringRef &Result, yaml::KeyValueNode &Node);
72 /// Parse one value to a string.
73 template Error parseStr(T &Result, yaml::KeyValueNode &Node);
74 /// Parse one value to an unsigned.
75 template
76 Error parseUnsigned(T &Result, yaml::KeyValueNode &Node);
77 /// Parse the type of a remark to an enum type.
78 Error parseType(Type &Result, yaml::MappingNode &Node);
79 /// Parse a debug location.
80 Error parseDebugLoc(Optional &Result,
81 yaml::KeyValueNode &Node);
82 /// Parse a remark field and update the parsing state.
83 Error parseRemarkField(yaml::KeyValueNode &RemarkField);
84 /// Parse an argument.
85 Error parseArg(SmallVectorImpl &TmpArgs, yaml::Node &Node);
86 /// Parse an entry from the contents of an argument.
87 Error parseArgEntry(yaml::KeyValueNode &ArgEntry, StringRef &KeyStr,
88 StringRef &ValueStr, Optional &Loc);
89
90 /// Handle a diagnostic from the YAML stream. Records the error in the
91 /// YAMLRemarkParser class.
92 static void HandleDiagnostic(const SMDiagnostic &Diag, void *Ctx);
93 };
94
95 class YAMLParseError : public ErrorInfo {
96 public:
97 static char ID;
98
99 YAMLParseError(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 /// Regular YAML to Remark parser.
116 struct YAMLParserImpl : public ParserImpl {
117 /// The object parsing the YAML.
118 YAMLRemarkParser YAMLParser;
119 /// Iterator in the YAML stream.
120 yaml::document_iterator YAMLIt;
121 /// Set to `true` if we had any errors during parsing.
122 bool HasErrors = false;
123
124 YAMLParserImpl(StringRef Buf)
125 : ParserImpl{ParserImpl::Kind::YAML}, YAMLParser(Buf),
126 YAMLIt(YAMLParser.Stream.begin()), HasErrors(false) {}
127
128 static bool classof(const ParserImpl *PI) {
129 return PI->Kind == ParserImpl::Kind::YAML;
130 }
131 };
132 } // end namespace remarks
133 } // end namespace llvm
134
135 #endif /* LLVM_REMARKS_YAML_REMARK_PARSER_H */
1414
1515 #include "llvm-c/Remarks.h"
1616 #include "llvm/Demangle/Demangle.h"
17 #include "llvm/Remarks/RemarkParser.h"
1718 #include "llvm/Support/CommandLine.h"
1819 #include "llvm/Support/Error.h"
1920 #include "llvm/Support/ErrorOr.h"
150151 return false;
151152 }
152153
153 StringRef Buffer = (*Buf)->getBuffer();
154 LLVMRemarkParserRef Parser =
155 LLVMRemarkParserCreate(Buffer.data(), Buffer.size());
156
157 LLVMRemarkEntry *Remark = nullptr;
158 while ((Remark = LLVMRemarkParserGetNext(Parser))) {
159 bool Transformed =
160 StringRef(Remark->RemarkType.Str, Remark->RemarkType.Len) == "!Passed";
161 StringRef Pass(Remark->PassName.Str, Remark->PassName.Len);
162 StringRef File(Remark->DebugLoc.SourceFile.Str,
163 Remark->DebugLoc.SourceFile.Len);
164 StringRef Function(Remark->FunctionName.Str, Remark->FunctionName.Len);
165 uint32_t Line = Remark->DebugLoc.SourceLineNumber;
166 uint32_t Column = Remark->DebugLoc.SourceColumnNumber;
167 ArrayRef Args(Remark->Args, Remark->NumArgs);
154 remarks::Parser Parser((*Buf)->getBuffer());
155
156 while (true) {
157 Expected RemarkOrErr = Parser.getNext();
158 if (!RemarkOrErr) {
159 handleAllErrors(RemarkOrErr.takeError(), [&](const ErrorInfoBase &PE) {
160 PE.log(WithColor::error());
161 });
162 return false;
163 }
164 if (!*RemarkOrErr) // End of file.
165 break;
166
167 const remarks::Remark &Remark = **RemarkOrErr;
168
169 bool Transformed = Remark.RemarkType == remarks::Type::Passed;
168170
169171 int VectorizationFactor = 1;
170172 int InterleaveCount = 1;
171173 int UnrollCount = 1;
172174
173 for (const LLVMRemarkArg &Arg : Args) {
174 StringRef ArgKeyName(Arg.Key.Str, Arg.Key.Len);
175 StringRef ArgValue(Arg.Value.Str, Arg.Value.Len);
176 if (ArgKeyName == "VectorizationFactor")
177 ArgValue.getAsInteger(10, VectorizationFactor);
178 else if (ArgKeyName == "InterleaveCount")
179 ArgValue.getAsInteger(10, InterleaveCount);
180 else if (ArgKeyName == "UnrollCount")
181 ArgValue.getAsInteger(10, UnrollCount);
175 for (const remarks::Argument &Arg : Remark.Args) {
176 if (Arg.Key == "VectorizationFactor")
177 Arg.Val.getAsInteger(10, VectorizationFactor);
178 else if (Arg.Key == "InterleaveCount")
179 Arg.Val.getAsInteger(10, InterleaveCount);
180 else if (Arg.Key == "UnrollCount")
181 Arg.Val.getAsInteger(10, UnrollCount);
182182 }
183183
184 if (Line < 1 || File.empty())
184 const Optional &Loc = Remark.Loc;
185 if (!Loc)
185186 continue;
187
188 StringRef File = Loc->SourceFilePath;
189 unsigned Line = Loc->SourceLine;
190 unsigned Column = Loc->SourceColumn;
186191
187192 // We track information on both actual and potential transformations. This
188193 // way, if there are multiple possible things on a line that are, or could
193198 LLII.Transformed = true;
194199 };
195200
196 if (Pass == "inline") {
197 auto &LI = LocationInfo[File][Line][Function][Column];
201 if (Remark.PassName == "inline") {
202 auto &LI = LocationInfo[File][Line][Remark.FunctionName][Column];
198203 UpdateLLII(LI.Inlined);
199 } else if (Pass == "loop-unroll") {
200 auto &LI = LocationInfo[File][Line][Function][Column];
204 } else if (Remark.PassName == "loop-unroll") {
205 auto &LI = LocationInfo[File][Line][Remark.FunctionName][Column];
201206 LI.UnrollCount = UnrollCount;
202207 UpdateLLII(LI.Unrolled);
203 } else if (Pass == "loop-vectorize") {
204 auto &LI = LocationInfo[File][Line][Function][Column];
208 } else if (Remark.PassName == "loop-vectorize") {
209 auto &LI = LocationInfo[File][Line][Remark.FunctionName][Column];
205210 LI.VectorizationFactor = VectorizationFactor;
206211 LI.InterleaveCount = InterleaveCount;
207212 UpdateLLII(LI.Vectorized);
208213 }
209214 }
210215
211 bool HasError = LLVMRemarkParserHasError(Parser);
212 if (HasError)
213 WithColor::error() << LLVMRemarkParserGetErrorMessage(Parser) << "\n";
214
215 LLVMRemarkParserDispose(Parser);
216 return !HasError;
216 return true;
217217 }
218218
219219 static bool writeReport(LocationInfoTy &LocationInfo) {
None LLVMRemarkParserCreate
0 LLVMRemarkStringGetData
1 LLVMRemarkStringGetLen
2 LLVMRemarkDebugLocGetSourceFilePath
3 LLVMRemarkDebugLocGetSourceLine
4 LLVMRemarkDebugLocGetSourceColumn
5 LLVMRemarkArgGetKey
6 LLVMRemarkArgGetValue
7 LLVMRemarkArgGetDebugLoc
8 LLVMRemarkEntryGetType
9 LLVMRemarkEntryGetPassName
10 LLVMRemarkEntryGetRemarkName
11 LLVMRemarkEntryGetFunctionName
12 LLVMRemarkEntryGetDebugLoc
13 LLVMRemarkEntryGetHotness
14 LLVMRemarkEntryGetNumArgs
15 LLVMRemarkEntryGetFirstArg
16 LLVMRemarkEntryGetNextArg
17 LLVMRemarkParserCreateYAML
118 LLVMRemarkParserGetNext
219 LLVMRemarkParserHasError
320 LLVMRemarkParserGetErrorMessage
33 )
44
55 add_llvm_unittest(RemarksTests
6 RemarksParsingTest.cpp
6 YAMLRemarksParsingTest.cpp
77 )
+0
-436
unittests/Remarks/RemarksParsingTest.cpp less more
None //===- unittest/Support/RemarksParsingTest.cpp - OptTable tests --------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "llvm-c/Remarks.h"
9 #include "gtest/gtest.h"
10
11 using namespace llvm;
12
13 template bool tryParse(const char (&Buf)[N]) {
14 LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf, N - 1);
15 LLVMRemarkEntry *Remark = nullptr;
16 while (LLVMRemarkEntry *NewRemark = LLVMRemarkParserGetNext(Parser)) {
17 EXPECT_TRUE(Remark == nullptr); // Only one remark per test.
18 Remark = NewRemark;
19 }
20 EXPECT_TRUE(Remark != nullptr); // We need *exactly* one remark per test.
21 bool HasError = LLVMRemarkParserHasError(Parser);
22 LLVMRemarkParserDispose(Parser);
23 return !HasError;
24 }
25
26 template
27 bool parseExpectError(const char (&Buf)[N], const char *Error) {
28 LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf, N - 1);
29 LLVMRemarkEntry *Remark = nullptr;
30 while (LLVMRemarkEntry *NewRemark = LLVMRemarkParserGetNext(Parser)) {
31 EXPECT_FALSE(NewRemark);
32 }
33 EXPECT_TRUE(Remark == nullptr); // We are parsing only one malformed remark.
34 EXPECT_TRUE(LLVMRemarkParserHasError(Parser));
35 bool MatchesError =
36 StringRef(LLVMRemarkParserGetErrorMessage(Parser)).contains(Error);
37 LLVMRemarkParserDispose(Parser);
38
39 return MatchesError;
40 }
41
42 TEST(Remarks, RemarksParsingEmpty) {
43 StringRef Buf = "\n"
44 "\n";
45 LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf.data(), Buf.size());
46 LLVMRemarkEntry *NewRemark = LLVMRemarkParserGetNext(Parser);
47 EXPECT_TRUE(NewRemark == nullptr); // No remark expected.
48 EXPECT_TRUE(LLVMRemarkParserHasError(Parser));
49 EXPECT_TRUE(StringRef(LLVMRemarkParserGetErrorMessage(Parser))
50 .contains("document root is not of mapping type."));
51 LLVMRemarkParserDispose(Parser);
52 }
53
54 TEST(Remarks, RemarksParsingGood) {
55 EXPECT_TRUE(tryParse("\n"
56 "--- !Missed\n"
57 "Pass: inline\n"
58 "Name: NoDefinition\n"
59 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
60 "Function: foo\n"
61 "Args:\n"
62 " - Callee: bar\n"
63 " - String: ' will not be inlined into '\n"
64 " - Caller: foo\n"
65 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
66 " - String: ' because its definition is unavailable'\n"
67 ""));
68
69 // No debug loc should also pass.
70 EXPECT_TRUE(tryParse("\n"
71 "--- !Missed\n"
72 "Pass: inline\n"
73 "Name: NoDefinition\n"
74 "Function: foo\n"
75 "Args:\n"
76 " - Callee: bar\n"
77 " - String: ' will not be inlined into '\n"
78 " - Caller: foo\n"
79 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
80 " - String: ' because its definition is unavailable'\n"
81 ""));
82
83 // No args is also ok.
84 EXPECT_TRUE(tryParse("\n"
85 "--- !Missed\n"
86 "Pass: inline\n"
87 "Name: NoDefinition\n"
88 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
89 "Function: foo\n"
90 ""));
91
92 // Different order.
93 EXPECT_TRUE(tryParse("\n"
94 "--- !Missed\n"
95 "DebugLoc: { Line: 3, Column: 12, File: file.c }\n"
96 "Function: foo\n"
97 "Name: NoDefinition\n"
98 "Args:\n"
99 " - Callee: bar\n"
100 " - String: ' will not be inlined into '\n"
101 " - Caller: foo\n"
102 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
103 " - String: ' because its definition is unavailable'\n"
104 "Pass: inline\n"
105 ""));
106 }
107
108 // Mandatory common part of a remark.
109 #define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\n"
110 // Test all the types.
111 TEST(Remarks, RemarksParsingTypes) {
112 // Type: Passed
113 EXPECT_TRUE(tryParse("--- !Passed" COMMON_REMARK));
114 // Type: Missed
115 EXPECT_TRUE(tryParse("--- !Missed" COMMON_REMARK));
116 // Type: Analysis
117 EXPECT_TRUE(tryParse("--- !Analysis" COMMON_REMARK));
118 // Type: AnalysisFPCompute
119 EXPECT_TRUE(tryParse("--- !AnalysisFPCompute" COMMON_REMARK));
120 // Type: AnalysisAliasing
121 EXPECT_TRUE(tryParse("--- !AnalysisAliasing" COMMON_REMARK));
122 // Type: Failure
123 EXPECT_TRUE(tryParse("--- !Failure" COMMON_REMARK));
124 }
125 #undef COMMON_REMARK
126
127 TEST(Remarks, RemarksParsingMissingFields) {
128 // No type.
129 EXPECT_TRUE(parseExpectError("\n"
130 "---\n"
131 "Pass: inline\n"
132 "Name: NoDefinition\n"
133 "Function: foo\n"
134 "",
135 "error: Type, Pass, Name or Function missing."));
136 // No pass.
137 EXPECT_TRUE(parseExpectError("\n"
138 "--- !Missed\n"
139 "Name: NoDefinition\n"
140 "Function: foo\n"
141 "",
142 "error: Type, Pass, Name or Function missing."));
143 // No name.
144 EXPECT_TRUE(parseExpectError("\n"
145 "--- !Missed\n"
146 "Pass: inline\n"
147 "Function: foo\n"
148 "",
149 "error: Type, Pass, Name or Function missing."));
150 // No function.
151 EXPECT_TRUE(parseExpectError("\n"
152 "--- !Missed\n"
153 "Pass: inline\n"
154 "Name: NoDefinition\n"
155 "",
156 "error: Type, Pass, Name or Function missing."));
157 // Debug loc but no file.
158 EXPECT_TRUE(parseExpectError("\n"
159 "--- !Missed\n"
160 "Pass: inline\n"
161 "Name: NoDefinition\n"
162 "Function: foo\n"
163 "DebugLoc: { Line: 3, Column: 12 }\n"
164 "",
165 "DebugLoc node incomplete."));
166 // Debug loc but no line.
167 EXPECT_TRUE(parseExpectError("\n"
168 "--- !Missed\n"
169 "Pass: inline\n"
170 "Name: NoDefinition\n"
171 "Function: foo\n"
172 "DebugLoc: { File: file.c, Column: 12 }\n"
173 "",
174 "DebugLoc node incomplete."));
175 // Debug loc but no column.
176 EXPECT_TRUE(parseExpectError("\n"
177 "--- !Missed\n"
178 "Pass: inline\n"
179 "Name: NoDefinition\n"
180 "Function: foo\n"
181 "DebugLoc: { File: file.c, Line: 3 }\n"
182 "",
183 "DebugLoc node incomplete."));
184 }
185
186 TEST(Remarks, RemarksParsingWrongTypes) {
187 // Wrong debug loc type.
188 EXPECT_TRUE(parseExpectError("\n"
189 "--- !Missed\n"
190 "Pass: inline\n"
191 "Name: NoDefinition\n"
192 "Function: foo\n"
193 "DebugLoc: foo\n"
194 "",
195 "expected a value of mapping type."));
196 // Wrong line type.
197 EXPECT_TRUE(
198 parseExpectError("\n"
199 "--- !Missed\n"
200 "Pass: inline\n"
201 "Name: NoDefinition\n"
202 "Function: foo\n"
203 "DebugLoc: { File: file.c, Line: b, Column: 12 }\n"
204 "",
205 "expected a value of integer type."));
206 // Wrong column type.
207 EXPECT_TRUE(
208 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(
235 parseExpectError("\n"
236 "--- !Missed\n"
237 "Pass: inline\n"
238 "Name: NoDefinition\n"
239 "Function: foo\n"
240 "DebugLoc: { File: file.c, Column: 12, Unknown: 12 }\n"
241 "",
242 "unknown entry in DebugLoc map."));
243 // Unknown entry.
244 EXPECT_TRUE(parseExpectError("\n"
245 "--- !Missed\n"
246 "Unknown: inline\n"
247 "",
248 "unknown key."));
249 // Not a scalar.
250 EXPECT_TRUE(parseExpectError("\n"
251 "--- !Missed\n"
252 "Pass: { File: a, Line: 1, Column: 2 }\n"
253 "Name: NoDefinition\n"
254 "Function: foo\n"
255 "",
256 "expected a value of scalar type."));
257 // Not a string file in debug loc.
258 EXPECT_TRUE(
259 parseExpectError("\n"
260 "--- !Missed\n"
261 "Pass: inline\n"
262 "Name: NoDefinition\n"
263 "Function: foo\n"
264 "DebugLoc: { File: { a: b }, Column: 12, Line: 12 }\n"
265 "",
266 "expected a value of scalar type."));
267 // Not a integer column in debug loc.
268 EXPECT_TRUE(parseExpectError(
269 "\n"
270 "--- !Missed\n"
271 "Pass: inline\n"
272 "Name: NoDefinition\n"
273 "Function: foo\n"
274 "DebugLoc: { File: file.c, Column: { a: b }, Line: 12 }\n"
275 "",
276 "expected a value of scalar type."));
277 // Not a integer line in debug loc.
278 EXPECT_TRUE(parseExpectError(
279 "\n"
280 "--- !Missed\n"
281 "Pass: inline\n"
282 "Name: NoDefinition\n"
283 "Function: foo\n"
284 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
285 "",
286 "expected a value of scalar type."));
287 // Not a mapping type value for args.
288 EXPECT_TRUE(parseExpectError(
289 "\n"
290 "--- !Missed\n"
291 "Pass: inline\n"
292 "Name: NoDefinition\n"
293 "Function: foo\n"
294 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
295 "",
296 "expected a value of scalar type."));
297 }
298
299 TEST(Remarks, RemarksParsingWrongArgs) {
300 // Multiple debug locs per arg.
301 EXPECT_TRUE(
302 parseExpectError("\n"
303 "--- !Missed\n"
304 "Pass: inline\n"
305 "Name: NoDefinition\n"
306 "Function: foo\n"
307 "Args:\n"
308 " - Str: string\n"
309 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
310 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
311 "",
312 "only one DebugLoc entry is allowed per argument."));
313 // Multiple strings per arg.
314 EXPECT_TRUE(
315 parseExpectError("\n"
316 "--- !Missed\n"
317 "Pass: inline\n"
318 "Name: NoDefinition\n"
319 "Function: foo\n"
320 "Args:\n"
321 " - Str: string\n"
322 " Str2: string\n"
323 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
324 "",
325 "only one string entry is allowed per argument."));
326 // No arg value.
327 EXPECT_TRUE(parseExpectError("\n"
328 "--- !Missed\n"
329 "Pass: inline\n"
330 "Name: NoDefinition\n"
331 "Function: foo\n"
332 "Args:\n"
333 " - Callee: ''\n"
334 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
335 "",
336 "argument value is missing."));
337 // No arg value.
338 EXPECT_TRUE(parseExpectError("\n"
339 "--- !Missed\n"
340 "Pass: inline\n"
341 "Name: NoDefinition\n"
342 "Function: foo\n"
343 "Args:\n"
344 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
345 "",
346 "argument key is missing."));
347 }
348
349 TEST(Remarks, RemarksGoodStruct) {
350 StringRef Buf = "\n"
351 "--- !Missed\n"
352 "Pass: inline\n"
353 "Name: NoDefinition\n"
354 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
355 "Function: foo\n"
356 "Args:\n"
357 " - Callee: bar\n"
358 " - String: ' will not be inlined into '\n"
359 " - Caller: foo\n"
360 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
361 " - String: ' because its definition is unavailable'\n"
362 "\n";
363
364 LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf.data(), Buf.size());
365 LLVMRemarkEntry *Remark = LLVMRemarkParserGetNext(Parser);
366 EXPECT_FALSE(Remark == nullptr);
367 EXPECT_EQ(StringRef(Remark->RemarkType.Str, 7), "!Missed");
368 EXPECT_EQ(Remark->RemarkType.Len, 7U);
369 EXPECT_EQ(StringRef(Remark->PassName.Str, 6), "inline");
370 EXPECT_EQ(Remark->PassName.Len, 6U);
371 EXPECT_EQ(StringRef(Remark->RemarkName.Str, 12), "NoDefinition");
372 EXPECT_EQ(Remark->RemarkName.Len, 12U);
373 EXPECT_EQ(StringRef(Remark->FunctionName.Str, 3), "foo");
374 EXPECT_EQ(Remark->FunctionName.Len, 3U);
375 EXPECT_EQ(StringRef(Remark->DebugLoc.SourceFile.Str, 6), "file.c");
376 EXPECT_EQ(Remark->DebugLoc.SourceFile.Len, 6U);
377 EXPECT_EQ(Remark->DebugLoc.SourceLineNumber, 3U);
378 EXPECT_EQ(Remark->DebugLoc.SourceColumnNumber, 12U);
379 EXPECT_EQ(Remark->Hotness, 0U);
380 EXPECT_EQ(Remark->NumArgs, 4U);
381 // Arg 0
382 {
383 LLVMRemarkArg &Arg = Remark->Args[0];
384 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Callee");
385 EXPECT_EQ(Arg.Key.Len, 6U);
386 EXPECT_EQ(StringRef(Arg.Value.Str, 3), "bar");
387 EXPECT_EQ(Arg.Value.Len, 3U);
388 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), "");
389 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U);
390 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U);
391 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
392 }
393 // Arg 1
394 {
395 LLVMRemarkArg &Arg = Remark->Args[1];
396 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String");
397 EXPECT_EQ(Arg.Key.Len, 6U);
398 EXPECT_EQ(StringRef(Arg.Value.Str, 26), " will not be inlined into ");
399 EXPECT_EQ(Arg.Value.Len, 26U);
400 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), "");
401 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U);
402 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U);
403 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
404 }
405 // Arg 2
406 {
407 LLVMRemarkArg &Arg = Remark->Args[2];
408 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Caller");
409 EXPECT_EQ(Arg.Key.Len, 6U);
410 EXPECT_EQ(StringRef(Arg.Value.Str, 3), "foo");
411 EXPECT_EQ(Arg.Value.Len, 3U);
412 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 6), "file.c");
413 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 6U);
414 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 2U);
415 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
416 }
417 // Arg 3
418 {
419 LLVMRemarkArg &Arg = Remark->Args[3];
420 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String");
421 EXPECT_EQ(Arg.Key.Len, 6U);
422 EXPECT_EQ(StringRef(Arg.Value.Str, 38),
423 " because its definition is unavailable");
424 EXPECT_EQ(Arg.Value.Len, 38U);
425 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), "");
426 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U);
427 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U);
428 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
429 }
430
431 EXPECT_EQ(LLVMRemarkParserGetNext(Parser), nullptr);
432
433 EXPECT_FALSE(LLVMRemarkParserHasError(Parser));
434 LLVMRemarkParserDispose(Parser);
435 }
0 //===- unittest/Support/YAMLRemarksParsingTest.cpp - OptTable tests -------===//
1 //
2 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
3 // See https://llvm.org/LICENSE.txt for license information.
4 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5 //
6 //===----------------------------------------------------------------------===//
7
8 #include "llvm-c/Remarks.h"
9 #include "llvm/Remarks/Remark.h"
10 #include "llvm/Remarks/RemarkParser.h"
11 #include "gtest/gtest.h"
12
13 using namespace llvm;
14
15 template void parseGood(const char (&Buf)[N]) {
16 remarks::Parser Parser({Buf, N - 1});
17 Expected Remark = Parser.getNext();
18 EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors.
19 EXPECT_TRUE(*Remark != nullptr); // At least one remark.
20 Remark = Parser.getNext();
21 EXPECT_FALSE(errorToBool(Remark.takeError())); // Check for parsing errors.
22 EXPECT_TRUE(*Remark == nullptr); // Check that there are no more remarks.
23 }
24
25 template
26 bool parseExpectError(const char (&Buf)[N], const char *Error) {
27 remarks::Parser Parser({Buf, N - 1});
28 Expected Remark = Parser.getNext();
29 EXPECT_FALSE(Remark); // Expect an error here.
30
31 std::string ErrorStr;
32 raw_string_ostream Stream(ErrorStr);
33 handleAllErrors(Remark.takeError(),
34 [&](const ErrorInfoBase &EIB) { EIB.log(Stream); });
35 return StringRef(Stream.str()).contains(Error);
36 }
37
38 TEST(YAMLRemarks, ParsingEmpty) {
39 EXPECT_TRUE(parseExpectError("\n\n", "document root is not of mapping type."));
40 }
41
42 TEST(YAMLRemarks, ParsingNotYAML) {
43 EXPECT_TRUE(
44 parseExpectError("\x01\x02\x03\x04\x05\x06", "not a valid YAML file."));
45 }
46
47 TEST(YAMLRemarks, ParsingGood) {
48 parseGood("\n"
49 "--- !Missed\n"
50 "Pass: inline\n"
51 "Name: NoDefinition\n"
52 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
53 "Function: foo\n"
54 "Args:\n"
55 " - Callee: bar\n"
56 " - String: ' will not be inlined into '\n"
57 " - Caller: foo\n"
58 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
59 " - String: ' because its definition is unavailable'\n"
60 "");
61
62 // No debug loc should also pass.
63 parseGood("\n"
64 "--- !Missed\n"
65 "Pass: inline\n"
66 "Name: NoDefinition\n"
67 "Function: foo\n"
68 "Args:\n"
69 " - Callee: bar\n"
70 " - String: ' will not be inlined into '\n"
71 " - Caller: foo\n"
72 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
73 " - String: ' because its definition is unavailable'\n"
74 "");
75
76 // No args is also ok.
77 parseGood("\n"
78 "--- !Missed\n"
79 "Pass: inline\n"
80 "Name: NoDefinition\n"
81 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
82 "Function: foo\n"
83 "");
84
85 // Different order.
86 parseGood("\n"
87 "--- !Missed\n"
88 "DebugLoc: { Line: 3, Column: 12, File: file.c }\n"
89 "Function: foo\n"
90 "Name: NoDefinition\n"
91 "Args:\n"
92 " - Callee: bar\n"
93 " - String: ' will not be inlined into '\n"
94 " - Caller: foo\n"
95 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
96 " - String: ' because its definition is unavailable'\n"
97 "Pass: inline\n"
98 "");
99 }
100
101 // Mandatory common part of a remark.
102 #define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\n"
103 // Test all the types.
104 TEST(YAMLRemarks, ParsingTypes) {
105 // Type: Passed
106 parseGood("--- !Passed" COMMON_REMARK);
107 // Type: Missed
108 parseGood("--- !Missed" COMMON_REMARK);
109 // Type: Analysis
110 parseGood("--- !Analysis" COMMON_REMARK);
111 // Type: AnalysisFPCommute
112 parseGood("--- !AnalysisFPCommute" COMMON_REMARK);
113 // Type: AnalysisAliasing
114 parseGood("--- !AnalysisAliasing" COMMON_REMARK);
115 // Type: Failure
116 parseGood("--- !Failure" COMMON_REMARK);
117 }
118 #undef COMMON_REMARK
119
120 TEST(YAMLRemarks, ParsingMissingFields) {
121 // No type.
122 EXPECT_TRUE(parseExpectError("\n"
123 "---\n"
124 "Pass: inline\n"
125 "Name: NoDefinition\n"
126 "Function: foo\n"
127 "",
128 "expected a remark tag."));
129 // No pass.
130 EXPECT_TRUE(parseExpectError("\n"
131 "--- !Missed\n"
132 "Name: NoDefinition\n"
133 "Function: foo\n"
134 "",
135 "Type, Pass, Name or Function missing."));
136 // No name.
137 EXPECT_TRUE(parseExpectError("\n"
138 "--- !Missed\n"
139 "Pass: inline\n"
140 "Function: foo\n"
141 "",
142 "Type, Pass, Name or Function missing."));
143 // No function.
144 EXPECT_TRUE(parseExpectError("\n"
145 "--- !Missed\n"
146 "Pass: inline\n"
147 "Name: NoDefinition\n"
148 "",
149 "Type, Pass, Name or Function missing."));
150 // Debug loc but no file.
151 EXPECT_TRUE(parseExpectError("\n"
152 "--- !Missed\n"
153 "Pass: inline\n"
154 "Name: NoDefinition\n"
155 "Function: foo\n"
156 "DebugLoc: { Line: 3, Column: 12 }\n"
157 "",
158 "DebugLoc node incomplete."));
159 // Debug loc but no line.
160 EXPECT_TRUE(parseExpectError("\n"
161 "--- !Missed\n"
162 "Pass: inline\n"
163 "Name: NoDefinition\n"
164 "Function: foo\n"
165 "DebugLoc: { File: file.c, Column: 12 }\n"
166 "",
167 "DebugLoc node incomplete."));
168 // Debug loc but no column.
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, Line: 3 }\n"
175 "",
176 "DebugLoc node incomplete."));
177 }
178
179 TEST(YAMLRemarks, ParsingWrongTypes) {
180 // Wrong debug loc type.
181 EXPECT_TRUE(parseExpectError("\n"
182 "--- !Missed\n"
183 "Pass: inline\n"
184 "Name: NoDefinition\n"
185 "Function: foo\n"
186 "DebugLoc: foo\n"
187 "",
188 "expected a value of mapping type."));
189 // Wrong line type.
190 EXPECT_TRUE(parseExpectError("\n"
191 "--- !Missed\n"
192 "Pass: inline\n"
193 "Name: NoDefinition\n"
194 "Function: foo\n"
195 "DebugLoc: { File: file.c, Line: b, Column: 12 }\n"
196 "",
197 "expected a value of integer type."));
198 // Wrong column 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: 3, Column: c }\n"
205 "",
206 "expected a value of integer type."));
207 // Wrong args type.
208 EXPECT_TRUE(parseExpectError("\n"
209 "--- !Missed\n"
210 "Pass: inline\n"
211 "Name: NoDefinition\n"
212 "Function: foo\n"
213 "Args: foo\n"
214 "",
215 "wrong value type for key."));
216 // Wrong key type.
217 EXPECT_TRUE(parseExpectError("\n"
218 "--- !Missed\n"
219 "{ A: a }: inline\n"
220 "Name: NoDefinition\n"
221 "Function: foo\n"
222 "",
223 "key is not a string."));
224 // Debug loc with unknown entry.
225 EXPECT_TRUE(parseExpectError("\n"
226 "--- !Missed\n"
227 "Pass: inline\n"
228 "Name: NoDefinition\n"
229 "Function: foo\n"
230 "DebugLoc: { File: file.c, Column: 12, Unknown: 12 }\n"
231 "",
232 "unknown entry in DebugLoc map."));
233 // Unknown entry.
234 EXPECT_TRUE(parseExpectError("\n"
235 "--- !Missed\n"
236 "Unknown: inline\n"
237 "",
238 "unknown key."));
239 // Not a scalar.
240 EXPECT_TRUE(parseExpectError("\n"
241 "--- !Missed\n"
242 "Pass: { File: a, Line: 1, Column: 2 }\n"
243 "Name: NoDefinition\n"
244 "Function: foo\n"
245 "",
246 "expected a value of scalar type."));
247 // Not a string file in debug loc.
248 EXPECT_TRUE(parseExpectError("\n"
249 "--- !Missed\n"
250 "Pass: inline\n"
251 "Name: NoDefinition\n"
252 "Function: foo\n"
253 "DebugLoc: { File: { a: b }, Column: 12, Line: 12 }\n"
254 "",
255 "expected a value of scalar type."));
256 // Not a integer column 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: file.c, Column: { a: b }, Line: 12 }\n"
263 "",
264 "expected a value of scalar type."));
265 // Not a integer line 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: 12, Line: { a: b } }\n"
272 "",
273 "expected a value of scalar type."));
274 // Not a mapping type value for args.
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 }
284
285 TEST(YAMLRemarks, ParsingWrongArgs) {
286 // Multiple debug locs per arg.
287 EXPECT_TRUE(parseExpectError("\n"
288 "--- !Missed\n"
289 "Pass: inline\n"
290 "Name: NoDefinition\n"
291 "Function: foo\n"
292 "Args:\n"
293 " - Str: string\n"
294 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
295 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
296 "",
297 "only one DebugLoc entry is allowed per argument."));
298 // Multiple strings per arg.
299 EXPECT_TRUE(parseExpectError("\n"
300 "--- !Missed\n"
301 "Pass: inline\n"
302 "Name: NoDefinition\n"
303 "Function: foo\n"
304 "Args:\n"
305 " - Str: string\n"
306 " Str2: string\n"
307 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
308 "",
309 "only one string entry is allowed per argument."));
310 // No arg value.
311 EXPECT_TRUE(parseExpectError("\n"
312 "--- !Missed\n"
313 "Pass: inline\n"
314 "Name: NoDefinition\n"
315 "Function: foo\n"
316 "Args:\n"
317 " - Callee: ''\n"
318 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
319 "",
320 "argument value is missing."));
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 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
329 "",
330 "argument key is missing."));
331 }
332
333 static inline StringRef checkStr(StringRef Str, unsigned ExpectedLen) {
334 const char *StrData = Str.data();
335 unsigned StrLen = Str.size();
336 EXPECT_EQ(StrLen, ExpectedLen);
337 return StringRef(StrData, StrLen);
338 }
339
340 TEST(YAMLRemarks, Contents) {
341 StringRef Buf = "\n"
342 "--- !Missed\n"
343 "Pass: inline\n"
344 "Name: NoDefinition\n"
345 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
346 "Function: foo\n"
347 "Hotness: 4\n"
348 "Args:\n"
349 " - Callee: bar\n"
350 " - String: ' will not be inlined into '\n"
351 " - Caller: foo\n"
352 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
353 " - String: ' because its definition is unavailable'\n"
354 "\n";
355
356 remarks::Parser Parser(Buf);
357 Expected RemarkOrErr = Parser.getNext();
358 EXPECT_FALSE(errorToBool(RemarkOrErr.takeError()));
359 EXPECT_TRUE(*RemarkOrErr != nullptr);
360
361 const remarks::Remark &Remark = **RemarkOrErr;
362 EXPECT_EQ(Remark.RemarkType, remarks::Type::Missed);
363 EXPECT_EQ(checkStr(Remark.PassName, 6), "inline");
364 EXPECT_EQ(checkStr(Remark.RemarkName, 12), "NoDefinition");
365 EXPECT_EQ(checkStr(Remark.FunctionName, 3), "foo");
366 EXPECT_TRUE(Remark.Loc);
367 const remarks::RemarkLocation &RL = *Remark.Loc;
368 EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c");
369 EXPECT_EQ(RL.SourceLine, 3U);
370 EXPECT_EQ(RL.SourceColumn, 12U);
371 EXPECT_TRUE(Remark.Hotness);
372 EXPECT_EQ(*Remark.Hotness, 4U);
373 EXPECT_EQ(Remark.Args.size(), 4U);
374
375 unsigned ArgID = 0;
376 for (const remarks::Argument &Arg : Remark.Args) {
377 switch (ArgID) {
378 case 0:
379 EXPECT_EQ(checkStr(Arg.Key, 6), "Callee");
380 EXPECT_EQ(checkStr(Arg.Val, 3), "bar");
381 EXPECT_FALSE(Arg.Loc);
382 break;
383 case 1:
384 EXPECT_EQ(checkStr(Arg.Key, 6), "String");
385 EXPECT_EQ(checkStr(Arg.Val, 26), " will not be inlined into ");
386 EXPECT_FALSE(Arg.Loc);
387 break;
388 case 2: {
389 EXPECT_EQ(checkStr(Arg.Key, 6), "Caller");
390 EXPECT_EQ(checkStr(Arg.Val, 3), "foo");
391 EXPECT_TRUE(Arg.Loc);
392 const remarks::RemarkLocation &RL = *Arg.Loc;
393 EXPECT_EQ(checkStr(RL.SourceFilePath, 6), "file.c");
394 EXPECT_EQ(RL.SourceLine, 2U);
395 EXPECT_EQ(RL.SourceColumn, 0U);
396 break;
397 }
398 case 3:
399 EXPECT_EQ(checkStr(Arg.Key, 6), "String");
400 EXPECT_EQ(checkStr(Arg.Val, 38),
401 " because its definition is unavailable");
402 EXPECT_FALSE(Arg.Loc);
403 break;
404 default:
405 break;
406 }
407 ++ArgID;
408 }
409
410 RemarkOrErr = Parser.getNext();
411 EXPECT_FALSE(errorToBool(RemarkOrErr.takeError()));
412 EXPECT_EQ(*RemarkOrErr, nullptr);
413 }
414
415 static inline StringRef checkStr(LLVMRemarkStringRef Str,
416 unsigned ExpectedLen) {
417 const char *StrData = LLVMRemarkStringGetData(Str);
418 unsigned StrLen = LLVMRemarkStringGetLen(Str);
419 EXPECT_EQ(StrLen, ExpectedLen);
420 return StringRef(StrData, StrLen);
421 }
422
423 TEST(YAMLRemarks, ContentsCAPI) {
424 StringRef Buf = "\n"
425 "--- !Missed\n"
426 "Pass: inline\n"
427 "Name: NoDefinition\n"
428 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
429 "Function: foo\n"
430 "Args:\n"
431 " - Callee: bar\n"
432 " - String: ' will not be inlined into '\n"
433 " - Caller: foo\n"
434 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
435 " - String: ' because its definition is unavailable'\n"
436 "\n";
437
438 LLVMRemarkParserRef Parser =
439 LLVMRemarkParserCreateYAML(Buf.data(), Buf.size());
440 LLVMRemarkEntryRef Remark = LLVMRemarkParserGetNext(Parser);
441 EXPECT_FALSE(Remark == nullptr);
442 EXPECT_EQ(LLVMRemarkEntryGetType(Remark), LLVMRemarkTypeMissed);
443 EXPECT_EQ(checkStr(LLVMRemarkEntryGetPassName(Remark), 6), "inline");
444 EXPECT_EQ(checkStr(LLVMRemarkEntryGetRemarkName(Remark), 12), "NoDefinition");
445 EXPECT_EQ(checkStr(LLVMRemarkEntryGetFunctionName(Remark), 3), "foo");
446 LLVMRemarkDebugLocRef DL = LLVMRemarkEntryGetDebugLoc(Remark);
447 EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL), 6), "file.c");
448 EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL), 3U);
449 EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL), 12U);
450 EXPECT_EQ(LLVMRemarkEntryGetHotness(Remark), 0U);
451 EXPECT_EQ(LLVMRemarkEntryGetNumArgs(Remark), 4U);
452
453 unsigned ArgID = 0;
454 LLVMRemarkArgRef Arg = LLVMRemarkEntryGetFirstArg(Remark);
455 do {
456 switch (ArgID) {
457 case 0:
458 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "Callee");
459 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 3), "bar");
460 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);
461 break;
462 case 1:
463 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "String");
464 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 26),
465 " will not be inlined into ");
466 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);
467 break;
468 case 2: {
469 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "Caller");
470 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 3), "foo");
471 LLVMRemarkDebugLocRef DL = LLVMRemarkArgGetDebugLoc(Arg);
472 EXPECT_EQ(checkStr(LLVMRemarkDebugLocGetSourceFilePath(DL), 6), "file.c");
473 EXPECT_EQ(LLVMRemarkDebugLocGetSourceLine(DL), 2U);
474 EXPECT_EQ(LLVMRemarkDebugLocGetSourceColumn(DL), 0U);
475 break;
476 }
477 case 3:
478 EXPECT_EQ(checkStr(LLVMRemarkArgGetKey(Arg), 6), "String");
479 EXPECT_EQ(checkStr(LLVMRemarkArgGetValue(Arg), 38),
480 " because its definition is unavailable");
481 EXPECT_EQ(LLVMRemarkArgGetDebugLoc(Arg), nullptr);
482 break;
483 default:
484 break;
485 }
486 ++ArgID;
487 } while ((Arg = LLVMRemarkEntryGetNextArg(Arg, Remark)));
488
489 EXPECT_EQ(LLVMRemarkParserGetNext(Parser), nullptr);
490
491 EXPECT_FALSE(LLVMRemarkParserHasError(Parser));
492 LLVMRemarkParserDispose(Parser);
493 }