llvm.org GIT mirror llvm / 7feeb42
Revert "[Remarks] Add a new Remark / RemarkParser abstraction" This reverts commit 51dc6a8c84cd6a58562e320e1828a0158dbbf750. Breaks http://lab.llvm.org:8011/builders/clang-cmake-x86_64-sde-avx512-linux/builds/20034/steps/build%20stage%201/logs/stdio. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@356492 91177308-0d34-0410-b5e6-96231b3b80d8 Francis Visoiu Mistrih 5 months ago
14 changed file(s) with 869 addition(s) and 1506 deletion(s). Raw diff Collapse all Expand all
+0
-98
include/llvm/Remarks/Remark.h less more
None //===-- 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
-46
include/llvm/Remarks/RemarkParser.h less more
None //===-- 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 /**
4936 * String containing a buffer and a length. The buffer is not guaranteed to be
5037 * zero-terminated.
5138 *
5239 * \since REMARKS_API_VERSION=0
5340 */
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);
41 typedef struct {
42 const char *Str;
43 uint32_t Len;
44 } LLVMRemarkStringRef;
6945
7046 /**
7147 * DebugLoc containing File, Line and Column.
7248 *
7349 * \since REMARKS_API_VERSION=0
7450 */
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);
51 typedef struct {
52 // File:
53 LLVMRemarkStringRef SourceFile;
54 // Line:
55 uint32_t SourceLineNumber;
56 // Column:
57 uint32_t SourceColumnNumber;
58 } LLVMRemarkDebugLoc;
9859
9960 /**
10061 * Element of the "Args" list. The key might give more information about what
101 * the semantics of the value are, e.g. "Callee" will tell you that the value
62 * are the semantics of the value, e.g. "Callee" will tell you that the value
10263 * is a symbol that names a function.
10364 *
10465 * \since REMARKS_API_VERSION=0
10566 */
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);
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;
215100
216101 typedef struct LLVMRemarkOpaqueParser *LLVMRemarkParserRef;
217102
218103 /**
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`.
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.
223108 *
224109 * This function should be paired with LLVMRemarkParserDispose() to avoid
225110 * leaking resources.
226111 *
227112 * \since REMARKS_API_VERSION=0
228113 */
229 extern LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf,
230 uint64_t Size);
114 extern LLVMRemarkParserRef LLVMRemarkParserCreate(const void *Buf,
115 uint64_t Size);
231116
232117 /**
233118 * Returns the next remark in the file.
235120 * The value pointed to by the return value is invalidated by the next call to
236121 * LLVMRemarkParserGetNext().
237122 *
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:
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:
241126 *
242127 * 1) LLVMRemarkParserHasError() will return `1`.
243128 *
248133 *
249134 * 1) An argument is invalid.
250135 *
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.
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.
255142 *
256143 * Here is a quick example of the usage:
257144 *
258145 * ```
259 * LLVMRemarkParserRef Parser = LLVMRemarkParserCreateYAML(Buf, Size);
260 * LLVMRemarkEntryRef Remark = NULL;
146 * LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf, Size);
147 * LLVMRemarkEntry *Remark = NULL;
261148 * while ((Remark == LLVMRemarkParserGetNext(Parser))) {
262149 * // use Remark
263150 * }
267154 *
268155 * \since REMARKS_API_VERSION=0
269156 */
270 extern LLVMRemarkEntryRef LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser);
157 extern LLVMRemarkEntry *LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser);
271158
272159 /**
273160 * Returns `1` if the parser encountered an error while parsing the buffer.
297184 extern void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser);
298185
299186 /**
300 * Returns the version of the remarks library.
187 * Returns the version of the remarks dylib.
301188 *
302189 * \since REMARKS_API_VERSION=0
303190 */
0 add_llvm_library(LLVMRemarks
1 Remark.cpp
21 RemarkParser.cpp
3 YAMLRemarkParser.cpp
42 )
+0
-128
lib/Remarks/Remark.cpp less more
None //===- 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"
1513 #include "llvm-c/Remarks.h"
1614 #include "llvm/ADT/STLExtras.h"
17 #include "llvm/Support/CBindingWrapping.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "llvm/Support/YAMLTraits.h"
1817
1918 using namespace llvm;
20 using namespace llvm::remarks;
21
22 Parser::Parser(StringRef Buf) : Impl(llvm::make_unique(Buf)) {}
23
24 Parser::~Parser() = default;
25
26 static Expected getNextYAML(YAMLParserImpl &Impl) {
27 YAMLRemarkParser &YAMLParser = Impl.YAMLParser;
19
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;
50
51 ParseState(SmallVectorImpl &Args) : Args(&Args) {}
52 /// Use Args only as a **temporary** buffer.
53 ~ParseState() { Args->clear(); }
54 };
55
56 ParseState State;
57
58 /// Set to `true` if we had any errors during parsing.
59 bool HadAnyErrors = false;
60
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);
65 }
66
67 /// Parse a YAML element.
68 Error parseYAMLElement(yaml::Document &Remark);
69
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())};
118 }
119
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();
127 }
128
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();
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 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();
156 }
157
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);
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 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);
28332 // Check for EOF.
29 if (Impl.YAMLIt == Impl.YAMLParser.Stream.end())
333 if (TheParser.HadAnyErrors || TheParser.DI == TheParser.Stream.end())
30334 return nullptr;
31335
32 auto CurrentIt = Impl.YAMLIt;
33
34336 // 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);
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 });
343 return nullptr;
39344 }
40345
41346 // Move on.
42 ++Impl.YAMLIt;
347 ++TheParser.DI;
43348
44349 // 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.");
50 }
51
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.");
56 }
57
58 // Create wrappers for C Binding types (see CBindingWrapping.h).
59 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(remarks::Parser, LLVMRemarkParserRef)
60
61 extern "C" LLVMRemarkParserRef LLVMRemarkParserCreateYAML(const void *Buf,
62 uint64_t Size) {
63 return wrap(
64 new remarks::Parser(StringRef(static_cast(Buf), Size)));
65 }
66
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); });
76 }
77
78 extern "C" LLVMRemarkEntryRef
79 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) {
80 remarks::Parser &TheParser = *unwrap(Parser);
81
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.");
89 return nullptr;
90 }
91
92 if (*RemarkOrErr == nullptr)
93 return nullptr;
94 // Valid remark.
95 return wrap(*RemarkOrErr);
350 if (Optional &Entry = TheParser.LastRemark)
351 return &*Entry;
352 return nullptr;
96353 }
97354
98355 extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) {
99 if (auto *Impl =
100 dyn_cast(unwrap(Parser)->Impl.get()))
101 return Impl->HasErrors;
102 llvm_unreachable("unkown parser implementation.");
356 return unwrap(Parser)->HadAnyErrors;
103357 }
104358
105359 extern "C" const char *
106360 LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) {
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.");
361 return unwrap(Parser)->ErrorStream.str().c_str();
111362 }
112363
113364 extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) {
+0
-29
lib/Remarks/RemarkParserImpl.h less more
None //===-- 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
-261
lib/Remarks/YAMLRemarkParser.cpp less more
None //===- 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
-136
lib/Remarks/YAMLRemarkParser.h less more
None //===-- 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"
1817 #include "llvm/Support/CommandLine.h"
1918 #include "llvm/Support/Error.h"
2019 #include "llvm/Support/ErrorOr.h"
151150 return false;
152151 }
153152
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;
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);
170168
171169 int VectorizationFactor = 1;
172170 int InterleaveCount = 1;
173171 int UnrollCount = 1;
174172
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);
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);
182182 }
183183
184 const Optional &Loc = Remark.Loc;
185 if (!Loc)
184 if (Line < 1 || File.empty())
186185 continue;
187
188 StringRef File = Loc->SourceFilePath;
189 unsigned Line = Loc->SourceLine;
190 unsigned Column = Loc->SourceColumn;
191186
192187 // We track information on both actual and potential transformations. This
193188 // way, if there are multiple possible things on a line that are, or could
198193 LLII.Transformed = true;
199194 };
200195
201 if (Remark.PassName == "inline") {
202 auto &LI = LocationInfo[File][Line][Remark.FunctionName][Column];
196 if (Pass == "inline") {
197 auto &LI = LocationInfo[File][Line][Function][Column];
203198 UpdateLLII(LI.Inlined);
204 } else if (Remark.PassName == "loop-unroll") {
205 auto &LI = LocationInfo[File][Line][Remark.FunctionName][Column];
199 } else if (Pass == "loop-unroll") {
200 auto &LI = LocationInfo[File][Line][Function][Column];
206201 LI.UnrollCount = UnrollCount;
207202 UpdateLLII(LI.Unrolled);
208 } else if (Remark.PassName == "loop-vectorize") {
209 auto &LI = LocationInfo[File][Line][Remark.FunctionName][Column];
203 } else if (Pass == "loop-vectorize") {
204 auto &LI = LocationInfo[File][Line][Function][Column];
210205 LI.VectorizationFactor = VectorizationFactor;
211206 LI.InterleaveCount = InterleaveCount;
212207 UpdateLLII(LI.Vectorized);
213208 }
214209 }
215210
216 return true;
211 bool HasError = LLVMRemarkParserHasError(Parser);
212 if (HasError)
213 WithColor::error() << LLVMRemarkParserGetErrorMessage(Parser) << "\n";
214
215 LLVMRemarkParserDispose(Parser);
216 return !HasError;
217217 }
218218
219219 static bool writeReport(LocationInfoTy &LocationInfo) {
None 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
0 LLVMRemarkParserCreate
181 LLVMRemarkParserGetNext
192 LLVMRemarkParserHasError
203 LLVMRemarkParserGetErrorMessage
33 )
44
55 add_llvm_unittest(RemarksTests
6 YAMLRemarksParsingTest.cpp
6 RemarksParsingTest.cpp
77 )
0 //===- 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
-494
unittests/Remarks/YAMLRemarksParsingTest.cpp less more
None //===- 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 }