llvm.org GIT mirror llvm / f43cce5
[OptRemarks] Make OptRemarks more generic: rename OptRemarks to Remarks Getting rid of the name "optimization remarks" for anything that involves handling remarks on the client side. It's safer to do this now, before we get stuck with that name in all the APIs and public interfaces we decide to export to users in the future. This renames llvm/tools/opt-remarks to llvm/tools/remarks-shlib, and now generates `libRemarks.dylib` instead of `libOptRemarks.dylib`. Differential Revision: https://reviews.llvm.org/D58535 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@355439 91177308-0d34-0410-b5e6-96231b3b80d8 Francis Visoiu Mistrih 5 months ago
24 changed file(s) with 1098 addition(s) and 1097 deletion(s). Raw diff Collapse all Expand all
644644 set_property(GLOBAL APPEND PROPERTY LLVM_EXPORTS_BUILDTREE_ONLY ${name})
645645 else()
646646 if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ${name} STREQUAL "LTO" OR
647 ${name} STREQUAL "OptRemarks" OR
647 ${name} STREQUAL "Remarks" OR
648648 (LLVM_LINK_LLVM_DYLIB AND ${name} STREQUAL "LLVM"))
649649 set(install_dir lib${LLVM_LIBDIR_SUFFIX})
650650 if(ARG_MODULE OR ARG_SHARED OR BUILD_SHARED_LIBS)
+0
-204
include/llvm-c/OptRemarks.h less more
None /*===-- llvm-c/OptRemarks.h - OptRemarks Public C Interface -------*- C -*-===*\
1 |* *|
2 |* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
3 |* Exceptions. *|
4 |* See https://llvm.org/LICENSE.txt for license information. *|
5 |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
6 |* *|
7 |*===----------------------------------------------------------------------===*|
8 |* *|
9 |* This header provides a public interface to an opt-remark library. *|
10 |* LLVM provides an implementation of this interface. *|
11 |* *|
12 \*===----------------------------------------------------------------------===*/
13
14 #ifndef LLVM_C_OPT_REMARKS_H
15 #define LLVM_C_OPT_REMARKS_H
16
17 #include "llvm-c/Core.h"
18 #include "llvm-c/Types.h"
19 #ifdef __cplusplus
20 #include
21 extern "C" {
22 #else
23 #include
24 #endif /* !defined(__cplusplus) */
25
26 /**
27 * @defgroup LLVMCOPTREMARKS OptRemarks
28 * @ingroup LLVMC
29 *
30 * @{
31 */
32
33 #define OPT_REMARKS_API_VERSION 0
34
35 /**
36 * String containing a buffer and a length. The buffer is not guaranteed to be
37 * zero-terminated.
38 *
39 * \since OPT_REMARKS_API_VERSION=0
40 */
41 typedef struct {
42 const char *Str;
43 uint32_t Len;
44 } LLVMOptRemarkStringRef;
45
46 /**
47 * DebugLoc containing File, Line and Column.
48 *
49 * \since OPT_REMARKS_API_VERSION=0
50 */
51 typedef struct {
52 // File:
53 LLVMOptRemarkStringRef SourceFile;
54 // Line:
55 uint32_t SourceLineNumber;
56 // Column:
57 uint32_t SourceColumnNumber;
58 } LLVMOptRemarkDebugLoc;
59
60 /**
61 * Element of the "Args" list. The key might give more information about what
62 * are the semantics of the value, e.g. "Callee" will tell you that the value
63 * is a symbol that names a function.
64 *
65 * \since OPT_REMARKS_API_VERSION=0
66 */
67 typedef struct {
68 // e.g. "Callee"
69 LLVMOptRemarkStringRef Key;
70 // e.g. "malloc"
71 LLVMOptRemarkStringRef Value;
72
73 // "DebugLoc": Optional
74 LLVMOptRemarkDebugLoc DebugLoc;
75 } LLVMOptRemarkArg;
76
77 /**
78 * One remark entry.
79 *
80 * \since OPT_REMARKS_API_VERSION=0
81 */
82 typedef struct {
83 // e.g. !Missed, !Passed
84 LLVMOptRemarkStringRef RemarkType;
85 // "Pass": Required
86 LLVMOptRemarkStringRef PassName;
87 // "Name": Required
88 LLVMOptRemarkStringRef RemarkName;
89 // "Function": Required
90 LLVMOptRemarkStringRef FunctionName;
91
92 // "DebugLoc": Optional
93 LLVMOptRemarkDebugLoc DebugLoc;
94 // "Hotness": Optional
95 uint32_t Hotness;
96 // "Args": Optional. It is an array of `num_args` elements.
97 uint32_t NumArgs;
98 LLVMOptRemarkArg *Args;
99 } LLVMOptRemarkEntry;
100
101 typedef struct LLVMOptRemarkOpaqueParser *LLVMOptRemarkParserRef;
102
103 /**
104 * Creates a remark parser that can be used to read and parse the buffer located
105 * in \p Buf of size \p Size.
106 *
107 * \p Buf cannot be NULL.
108 *
109 * This function should be paired with LLVMOptRemarkParserDispose() to avoid
110 * leaking resources.
111 *
112 * \since OPT_REMARKS_API_VERSION=0
113 */
114 extern LLVMOptRemarkParserRef LLVMOptRemarkParserCreate(const void *Buf,
115 uint64_t Size);
116
117 /**
118 * Returns the next remark in the file.
119 *
120 * The value pointed to by the return value is invalidated by the next call to
121 * LLVMOptRemarkParserGetNext().
122 *
123 * If the parser reaches the end of the buffer, the return value will be NULL.
124 *
125 * In the case of an error, the return value will be NULL, and:
126 *
127 * 1) LLVMOptRemarkParserHasError() will return `1`.
128 *
129 * 2) LLVMOptRemarkParserGetErrorMessage() will return a descriptive error
130 * message.
131 *
132 * An error may occur if:
133 *
134 * 1) An argument is invalid.
135 *
136 * 2) There is a YAML parsing error. This type of error aborts parsing
137 * immediately and returns `1`. It can occur on malformed YAML.
138 *
139 * 3) Remark parsing error. If this type of error occurs, the parser won't call
140 * the handler and will continue to the next one. It can occur on malformed
141 * remarks, like missing or extra fields in the file.
142 *
143 * Here is a quick example of the usage:
144 *
145 * ```
146 * LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, Size);
147 * LLVMOptRemarkEntry *Remark = NULL;
148 * while ((Remark == LLVMOptRemarkParserGetNext(Parser))) {
149 * // use Remark
150 * }
151 * bool HasError = LLVMOptRemarkParserHasError(Parser);
152 * LLVMOptRemarkParserDispose(Parser);
153 * ```
154 *
155 * \since OPT_REMARKS_API_VERSION=0
156 */
157 extern LLVMOptRemarkEntry *
158 LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser);
159
160 /**
161 * Returns `1` if the parser encountered an error while parsing the buffer.
162 *
163 * \since OPT_REMARKS_API_VERSION=0
164 */
165 extern LLVMBool LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser);
166
167 /**
168 * Returns a null-terminated string containing an error message.
169 *
170 * In case of no error, the result is `NULL`.
171 *
172 * The memory of the string is bound to the lifetime of \p Parser. If
173 * LLVMOptRemarkParserDispose() is called, the memory of the string will be
174 * released.
175 *
176 * \since OPT_REMARKS_API_VERSION=0
177 */
178 extern const char *
179 LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser);
180
181 /**
182 * Releases all the resources used by \p Parser.
183 *
184 * \since OPT_REMARKS_API_VERSION=0
185 */
186 extern void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser);
187
188 /**
189 * Returns the version of the opt-remarks dylib.
190 *
191 * \since OPT_REMARKS_API_VERSION=0
192 */
193 extern uint32_t LLVMOptRemarkVersion(void);
194
195 /**
196 * @} // endgoup LLVMCOPTREMARKS
197 */
198
199 #ifdef __cplusplus
200 }
201 #endif /* !defined(__cplusplus) */
202
203 #endif /* LLVM_C_OPT_REMARKS_H */
0 /*===-- llvm-c/Remarks.h - Remarks Public C Interface -------------*- C -*-===*\
1 |* *|
2 |* Part of the LLVM Project, under the Apache License v2.0 with LLVM *|
3 |* Exceptions. *|
4 |* See https://llvm.org/LICENSE.txt for license information. *|
5 |* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception *|
6 |* *|
7 |*===----------------------------------------------------------------------===*|
8 |* *|
9 |* This header provides a public interface to a remark diagnostics library. *|
10 |* LLVM provides an implementation of this interface. *|
11 |* *|
12 \*===----------------------------------------------------------------------===*/
13
14 #ifndef LLVM_C_REMARKS_H
15 #define LLVM_C_REMARKS_H
16
17 #include "llvm-c/Core.h"
18 #include "llvm-c/Types.h"
19 #ifdef __cplusplus
20 #include
21 extern "C" {
22 #else
23 #include
24 #endif /* !defined(__cplusplus) */
25
26 /**
27 * @defgroup LLVMCREMARKS Remarks
28 * @ingroup LLVMC
29 *
30 * @{
31 */
32
33 #define REMARKS_API_VERSION 0
34
35 /**
36 * String containing a buffer and a length. The buffer is not guaranteed to be
37 * zero-terminated.
38 *
39 * \since REMARKS_API_VERSION=0
40 */
41 typedef struct {
42 const char *Str;
43 uint32_t Len;
44 } LLVMRemarkStringRef;
45
46 /**
47 * DebugLoc containing File, Line and Column.
48 *
49 * \since REMARKS_API_VERSION=0
50 */
51 typedef struct {
52 // File:
53 LLVMRemarkStringRef SourceFile;
54 // Line:
55 uint32_t SourceLineNumber;
56 // Column:
57 uint32_t SourceColumnNumber;
58 } LLVMRemarkDebugLoc;
59
60 /**
61 * Element of the "Args" list. The key might give more information about what
62 * are the semantics of the value, e.g. "Callee" will tell you that the value
63 * is a symbol that names a function.
64 *
65 * \since REMARKS_API_VERSION=0
66 */
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;
100
101 typedef struct LLVMRemarkOpaqueParser *LLVMRemarkParserRef;
102
103 /**
104 * Creates a remark parser that can be used to read and parse the buffer located
105 * in \p Buf of size \p Size.
106 *
107 * \p Buf cannot be NULL.
108 *
109 * This function should be paired with LLVMRemarkParserDispose() to avoid
110 * leaking resources.
111 *
112 * \since REMARKS_API_VERSION=0
113 */
114 extern LLVMRemarkParserRef LLVMRemarkParserCreate(const void *Buf,
115 uint64_t Size);
116
117 /**
118 * Returns the next remark in the file.
119 *
120 * The value pointed to by the return value is invalidated by the next call to
121 * LLVMRemarkParserGetNext().
122 *
123 * If the parser reaches the end of the buffer, the return value will be NULL.
124 *
125 * In the case of an error, the return value will be NULL, and:
126 *
127 * 1) LLVMRemarkParserHasError() will return `1`.
128 *
129 * 2) LLVMRemarkParserGetErrorMessage() will return a descriptive error
130 * message.
131 *
132 * An error may occur if:
133 *
134 * 1) An argument is invalid.
135 *
136 * 2) There is a YAML parsing error. This type of error aborts parsing
137 * immediately and returns `1`. It can occur on malformed YAML.
138 *
139 * 3) Remark parsing error. If this type of error occurs, the parser won't call
140 * the handler and will continue to the next one. It can occur on malformed
141 * remarks, like missing or extra fields in the file.
142 *
143 * Here is a quick example of the usage:
144 *
145 * ```
146 * LLVMRemarkParserRef Parser = LLVMRemarkParserCreate(Buf, Size);
147 * LLVMRemarkEntry *Remark = NULL;
148 * while ((Remark == LLVMRemarkParserGetNext(Parser))) {
149 * // use Remark
150 * }
151 * bool HasError = LLVMRemarkParserHasError(Parser);
152 * LLVMRemarkParserDispose(Parser);
153 * ```
154 *
155 * \since REMARKS_API_VERSION=0
156 */
157 extern LLVMRemarkEntry *LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser);
158
159 /**
160 * Returns `1` if the parser encountered an error while parsing the buffer.
161 *
162 * \since REMARKS_API_VERSION=0
163 */
164 extern LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser);
165
166 /**
167 * Returns a null-terminated string containing an error message.
168 *
169 * In case of no error, the result is `NULL`.
170 *
171 * The memory of the string is bound to the lifetime of \p Parser. If
172 * LLVMRemarkParserDispose() is called, the memory of the string will be
173 * released.
174 *
175 * \since REMARKS_API_VERSION=0
176 */
177 extern const char *LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser);
178
179 /**
180 * Releases all the resources used by \p Parser.
181 *
182 * \since REMARKS_API_VERSION=0
183 */
184 extern void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser);
185
186 /**
187 * Returns the version of the remarks dylib.
188 *
189 * \since REMARKS_API_VERSION=0
190 */
191 extern uint32_t LLVMRemarkVersion(void);
192
193 /**
194 * @} // endgoup LLVMCREMARKS
195 */
196
197 #ifdef __cplusplus
198 }
199 #endif /* !defined(__cplusplus) */
200
201 #endif /* LLVM_C_REMARKS_H */
1515 add_subdirectory(Object)
1616 add_subdirectory(ObjectYAML)
1717 add_subdirectory(Option)
18 add_subdirectory(OptRemarks)
18 add_subdirectory(Remarks)
1919 add_subdirectory(DebugInfo)
2020 add_subdirectory(ExecutionEngine)
2121 add_subdirectory(Target)
3434 BinaryFormat
3535 ObjectYAML
3636 Option
37 OptRemarks
37 Remarks
3838 Passes
3939 ProfileData
4040 Support
+0
-3
lib/OptRemarks/CMakeLists.txt less more
None add_llvm_library(LLVMOptRemarks
1 OptRemarksParser.cpp
2 )
+0
-21
lib/OptRemarks/LLVMBuild.txt less more
None ;===- ./lib/OptRemarks/LLVMBuild.txt ---------------------------*- Conf -*--===;
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 is an LLVMBuild description file for the components in this subdirectory.
9 ;
10 ; For more information on the LLVMBuild system, please see:
11 ;
12 ; http://llvm.org/docs/LLVMBuild.html
13 ;
14 ;===------------------------------------------------------------------------===;
15
16 [component_0]
17 type = Library
18 name = OptRemarks
19 parent = Libraries
20 required_libraries = Support
+0
-367
lib/OptRemarks/OptRemarksParser.cpp less more
None //===- OptRemarksParser.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 optimization remarks in LLVM.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #include "llvm-c/OptRemarks.h"
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "llvm/Support/YAMLTraits.h"
17
18 using namespace llvm;
19
20 namespace {
21 struct RemarkParser {
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 RemarkParser(StringRef Buf)
62 : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString),
63 DI(Stream.begin()), LastRemark(), TmpArgs(), State(TmpArgs) {
64 SM.setDiagHandler(RemarkParser::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 /// RemarkParser 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 LLVMOptRemarkStringRef toOptRemarkStr(StringRef Str) {
117 return {Str.data(), static_cast(Str.size())};
118 }
119
120 Error RemarkParser::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 RemarkParser::parseValue(StringRef &Result, yaml::KeyValueNode &Node) {
130 auto *Value = dyn_cast(Node.getValue());
131 if (!Value)
132 return make_error("expected a value of scalar type.", Node);
133 Result = Value->getRawValue();
134
135 if (Result.front() == '\'')
136 Result = Result.drop_front();
137
138 if (Result.back() == '\'')
139 Result = Result.drop_back();
140
141 return Error::success();
142 }
143
144 Error RemarkParser::parseValue(Optional &Result,
145 yaml::KeyValueNode &Node) {
146 SmallVector Tmp;
147 auto *Value = dyn_cast(Node.getValue());
148 if (!Value)
149 return make_error("expected a value of scalar type.", Node);
150 unsigned UnsignedValue = 0;
151 if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue))
152 return make_error("expected a value of integer type.", *Value);
153 Result = UnsignedValue;
154 return Error::success();
155 }
156
157 Error RemarkParser::parseDebugLoc(Optional &File,
158 Optional &Line,
159 Optional &Column,
160 yaml::KeyValueNode &Node) {
161 auto *DebugLoc = dyn_cast(Node.getValue());
162 if (!DebugLoc)
163 return make_error("expected a value of mapping type.", Node);
164
165 for (yaml::KeyValueNode &DLNode : *DebugLoc) {
166 StringRef KeyName;
167 if (Error E = parseKey(KeyName, DLNode))
168 return E;
169 if (KeyName == "File") {
170 File = StringRef(); // Set the optional to contain a default constructed
171 // value, to be passed to the parsing function.
172 if (Error E = parseValue(*File, DLNode))
173 return E;
174 } else if (KeyName == "Column") {
175 if (Error E = parseValue(Column, DLNode))
176 return E;
177 } else if (KeyName == "Line") {
178 if (Error E = parseValue(Line, DLNode))
179 return E;
180 } else {
181 return make_error("unknown entry in DebugLoc map.", DLNode);
182 }
183 }
184
185 // If any of the debug loc fields is missing, return an error.
186 if (!File || !Line || !Column)
187 return make_error("DebugLoc node incomplete.", Node);
188
189 return Error::success();
190 }
191
192 Error RemarkParser::parseArg(SmallVectorImpl &Args,
193 yaml::Node &Node) {
194 auto *ArgMap = dyn_cast(&Node);
195 if (!ArgMap)
196 return make_error("expected a value of mapping type.", Node);
197
198 StringRef ValueStr;
199 StringRef KeyStr;
200 Optional File;
201 Optional Line;
202 Optional Column;
203
204 for (yaml::KeyValueNode &ArgEntry : *ArgMap) {
205 StringRef KeyName;
206 if (Error E = parseKey(KeyName, ArgEntry))
207 return E;
208
209 // Try to parse debug locs.
210 if (KeyName == "DebugLoc") {
211 // Can't have multiple DebugLoc entries per argument.
212 if (File || Line || Column)
213 return make_error(
214 "only one DebugLoc entry is allowed per argument.", ArgEntry);
215
216 if (Error E = parseDebugLoc(File, Line, Column, ArgEntry))
217 return E;
218 continue;
219 }
220
221 // If we already have a string, error out.
222 if (!ValueStr.empty())
223 return make_error(
224 "only one string entry is allowed per argument.", ArgEntry);
225
226 // Try to parse a string.
227 if (Error E = parseValue(ValueStr, ArgEntry))
228 return E;
229
230 // Keep the key from the string.
231 KeyStr = KeyName;
232 }
233
234 if (KeyStr.empty())
235 return make_error("argument key is missing.", *ArgMap);
236 if (ValueStr.empty())
237 return make_error("argument value is missing.", *ArgMap);
238
239 Args.push_back(LLVMOptRemarkArg{
240 toOptRemarkStr(KeyStr), toOptRemarkStr(ValueStr),
241 LLVMOptRemarkDebugLoc{toOptRemarkStr(File.getValueOr(StringRef())),
242 Line.getValueOr(0), Column.getValueOr(0)}});
243
244 return Error::success();
245 }
246
247 Error RemarkParser::parseYAMLElement(yaml::Document &Remark) {
248 // Parsing a new remark, clear the previous one.
249 LastRemark = None;
250 State = ParseState(TmpArgs);
251
252 auto *Root = dyn_cast(Remark.getRoot());
253 if (!Root)
254 return make_error("document root is not of mapping type.",
255 *Remark.getRoot());
256
257 State.Type = Root->getRawTag();
258
259 for (yaml::KeyValueNode &RemarkField : *Root) {
260 StringRef KeyName;
261 if (Error E = parseKey(KeyName, RemarkField))
262 return E;
263
264 if (KeyName == "Pass") {
265 if (Error E = parseValue(State.Pass, RemarkField))
266 return E;
267 } else if (KeyName == "Name") {
268 if (Error E = parseValue(State.Name, RemarkField))
269 return E;
270 } else if (KeyName == "Function") {
271 if (Error E = parseValue(State.Function, RemarkField))
272 return E;
273 } else if (KeyName == "Hotness") {
274 if (Error E = parseValue(State.Hotness, RemarkField))
275 return E;
276 } else if (KeyName == "DebugLoc") {
277 if (Error E =
278 parseDebugLoc(State.File, State.Line, State.Column, RemarkField))
279 return E;
280 } else if (KeyName == "Args") {
281 auto *Args = dyn_cast(RemarkField.getValue());
282 if (!Args)
283 return make_error("wrong value type for key.", RemarkField);
284
285 for (yaml::Node &Arg : *Args)
286 if (Error E = parseArg(*State.Args, Arg))
287 return E;
288 } else {
289 return make_error("unknown key.", RemarkField);
290 }
291 }
292
293 // If the YAML parsing failed, don't even continue parsing. We might
294 // encounter malformed YAML.
295 if (Stream.failed())
296 return make_error("YAML parsing failed.", *Remark.getRoot());
297
298 // Check if any of the mandatory fields are missing.
299 if (State.Type.empty() || State.Pass.empty() || State.Name.empty() ||
300 State.Function.empty())
301 return make_error("Type, Pass, Name or Function missing.",
302 *Remark.getRoot());
303
304 LastRemark = LLVMOptRemarkEntry{
305 toOptRemarkStr(State.Type),
306 toOptRemarkStr(State.Pass),
307 toOptRemarkStr(State.Name),
308 toOptRemarkStr(State.Function),
309 LLVMOptRemarkDebugLoc{toOptRemarkStr(State.File.getValueOr(StringRef())),
310 State.Line.getValueOr(0),
311 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(RemarkParser, LLVMOptRemarkParserRef)
322
323 extern "C" LLVMOptRemarkParserRef LLVMOptRemarkParserCreate(const void *Buf,
324 uint64_t Size) {
325 return wrap(
326 new RemarkParser(StringRef(static_cast(Buf), Size)));
327 }
328
329 extern "C" LLVMOptRemarkEntry *
330 LLVMOptRemarkParserGetNext(LLVMOptRemarkParserRef Parser) {
331 RemarkParser &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 });
343 return nullptr;
344 }
345
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;
353 }
354
355 extern "C" LLVMBool LLVMOptRemarkParserHasError(LLVMOptRemarkParserRef Parser) {
356 return unwrap(Parser)->HadAnyErrors;
357 }
358
359 extern "C" const char *
360 LLVMOptRemarkParserGetErrorMessage(LLVMOptRemarkParserRef Parser) {
361 return unwrap(Parser)->ErrorStream.str().c_str();
362 }
363
364 extern "C" void LLVMOptRemarkParserDispose(LLVMOptRemarkParserRef Parser) {
365 delete unwrap(Parser);
366 }
0 add_llvm_library(LLVMRemarks
1 RemarkParser.cpp
2 )
0 ;===- ./lib/Remarks/LLVMBuild.txt ------------------------------*- Conf -*--===;
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 is an LLVMBuild description file for the components in this subdirectory.
9 ;
10 ; For more information on the LLVMBuild system, please see:
11 ;
12 ; http://llvm.org/docs/LLVMBuild.html
13 ;
14 ;===------------------------------------------------------------------------===;
15
16 [component_0]
17 type = Library
18 name = Remarks
19 parent = Libraries
20 required_libraries = Support
0 //===- RemarkParser.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 "llvm-c/Remarks.h"
14 #include "llvm/ADT/STLExtras.h"
15 #include "llvm/Support/SourceMgr.h"
16 #include "llvm/Support/YAMLTraits.h"
17
18 using namespace llvm;
19
20 namespace {
21 struct RemarkParser {
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 RemarkParser(StringRef Buf)
62 : SM(), Stream(Buf, SM), ErrorString(), ErrorStream(ErrorString),
63 DI(Stream.begin()), LastRemark(), TmpArgs(), State(TmpArgs) {
64 SM.setDiagHandler(RemarkParser::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 /// RemarkParser 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 RemarkParser::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 RemarkParser::parseValue(StringRef &Result, yaml::KeyValueNode &Node) {
130 auto *Value = dyn_cast(Node.getValue());
131 if (!Value)
132 return make_error("expected a value of scalar type.", Node);
133 Result = Value->getRawValue();
134
135 if (Result.front() == '\'')
136 Result = Result.drop_front();
137
138 if (Result.back() == '\'')
139 Result = Result.drop_back();
140
141 return Error::success();
142 }
143
144 Error RemarkParser::parseValue(Optional &Result,
145 yaml::KeyValueNode &Node) {
146 SmallVector Tmp;
147 auto *Value = dyn_cast(Node.getValue());
148 if (!Value)
149 return make_error("expected a value of scalar type.", Node);
150 unsigned UnsignedValue = 0;
151 if (Value->getValue(Tmp).getAsInteger(10, UnsignedValue))
152 return make_error("expected a value of integer type.", *Value);
153 Result = UnsignedValue;
154 return Error::success();
155 }
156
157 Error RemarkParser::parseDebugLoc(Optional &File,
158 Optional &Line,
159 Optional &Column,
160 yaml::KeyValueNode &Node) {
161 auto *DebugLoc = dyn_cast(Node.getValue());
162 if (!DebugLoc)
163 return make_error("expected a value of mapping type.", Node);
164
165 for (yaml::KeyValueNode &DLNode : *DebugLoc) {
166 StringRef KeyName;
167 if (Error E = parseKey(KeyName, DLNode))
168 return E;
169 if (KeyName == "File") {
170 File = StringRef(); // Set the optional to contain a default constructed
171 // value, to be passed to the parsing function.
172 if (Error E = parseValue(*File, DLNode))
173 return E;
174 } else if (KeyName == "Column") {
175 if (Error E = parseValue(Column, DLNode))
176 return E;
177 } else if (KeyName == "Line") {
178 if (Error E = parseValue(Line, DLNode))
179 return E;
180 } else {
181 return make_error("unknown entry in DebugLoc map.", DLNode);
182 }
183 }
184
185 // If any of the debug loc fields is missing, return an error.
186 if (!File || !Line || !Column)
187 return make_error("DebugLoc node incomplete.", Node);
188
189 return Error::success();
190 }
191
192 Error RemarkParser::parseArg(SmallVectorImpl &Args,
193 yaml::Node &Node) {
194 auto *ArgMap = dyn_cast(&Node);
195 if (!ArgMap)
196 return make_error("expected a value of mapping type.", Node);
197
198 StringRef ValueStr;
199 StringRef KeyStr;
200 Optional File;
201 Optional Line;
202 Optional Column;
203
204 for (yaml::KeyValueNode &ArgEntry : *ArgMap) {
205 StringRef KeyName;
206 if (Error E = parseKey(KeyName, ArgEntry))
207 return E;
208
209 // Try to parse debug locs.
210 if (KeyName == "DebugLoc") {
211 // Can't have multiple DebugLoc entries per argument.
212 if (File || Line || Column)
213 return make_error(
214 "only one DebugLoc entry is allowed per argument.", ArgEntry);
215
216 if (Error E = parseDebugLoc(File, Line, Column, ArgEntry))
217 return E;
218 continue;
219 }
220
221 // If we already have a string, error out.
222 if (!ValueStr.empty())
223 return make_error(
224 "only one string entry is allowed per argument.", ArgEntry);
225
226 // Try to parse a string.
227 if (Error E = parseValue(ValueStr, ArgEntry))
228 return E;
229
230 // Keep the key from the string.
231 KeyStr = KeyName;
232 }
233
234 if (KeyStr.empty())
235 return make_error("argument key is missing.", *ArgMap);
236 if (ValueStr.empty())
237 return make_error("argument value is missing.", *ArgMap);
238
239 Args.push_back(LLVMRemarkArg{
240 toRemarkStr(KeyStr), toRemarkStr(ValueStr),
241 LLVMRemarkDebugLoc{toRemarkStr(File.getValueOr(StringRef())),
242 Line.getValueOr(0), Column.getValueOr(0)}});
243
244 return Error::success();
245 }
246
247 Error RemarkParser::parseYAMLElement(yaml::Document &Remark) {
248 // Parsing a new remark, clear the previous one.
249 LastRemark = None;
250 State = ParseState(TmpArgs);
251
252 auto *Root = dyn_cast(Remark.getRoot());
253 if (!Root)
254 return make_error("document root is not of mapping type.",
255 *Remark.getRoot());
256
257 State.Type = Root->getRawTag();
258
259 for (yaml::KeyValueNode &RemarkField : *Root) {
260 StringRef KeyName;
261 if (Error E = parseKey(KeyName, RemarkField))
262 return E;
263
264 if (KeyName == "Pass") {
265 if (Error E = parseValue(State.Pass, RemarkField))
266 return E;
267 } else if (KeyName == "Name") {
268 if (Error E = parseValue(State.Name, RemarkField))
269 return E;
270 } else if (KeyName == "Function") {
271 if (Error E = parseValue(State.Function, RemarkField))
272 return E;
273 } else if (KeyName == "Hotness") {
274 if (Error E = parseValue(State.Hotness, RemarkField))
275 return E;
276 } else if (KeyName == "DebugLoc") {
277 if (Error E =
278 parseDebugLoc(State.File, State.Line, State.Column, RemarkField))
279 return E;
280 } else if (KeyName == "Args") {
281 auto *Args = dyn_cast(RemarkField.getValue());
282 if (!Args)
283 return make_error("wrong value type for key.", RemarkField);
284
285 for (yaml::Node &Arg : *Args)
286 if (Error E = parseArg(*State.Args, Arg))
287 return E;
288 } else {
289 return make_error("unknown key.", RemarkField);
290 }
291 }
292
293 // If the YAML parsing failed, don't even continue parsing. We might
294 // encounter malformed YAML.
295 if (Stream.failed())
296 return make_error("YAML parsing failed.", *Remark.getRoot());
297
298 // Check if any of the mandatory fields are missing.
299 if (State.Type.empty() || State.Pass.empty() || State.Name.empty() ||
300 State.Function.empty())
301 return make_error("Type, Pass, Name or Function missing.",
302 *Remark.getRoot());
303
304 LastRemark = LLVMRemarkEntry{
305 toRemarkStr(State.Type),
306 toRemarkStr(State.Pass),
307 toRemarkStr(State.Name),
308 toRemarkStr(State.Function),
309 LLVMRemarkDebugLoc{toRemarkStr(State.File.getValueOr(StringRef())),
310 State.Line.getValueOr(0), State.Column.getValueOr(0)},
311 State.Hotness.getValueOr(0),
312 static_cast(State.Args->size()),
313 State.Args->data()};
314
315 return Error::success();
316 }
317 } // namespace
318
319 // Create wrappers for C Binding types (see CBindingWrapping.h).
320 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RemarkParser, LLVMRemarkParserRef)
321
322 extern "C" LLVMRemarkParserRef LLVMRemarkParserCreate(const void *Buf,
323 uint64_t Size) {
324 return wrap(
325 new RemarkParser(StringRef(static_cast(Buf), Size)));
326 }
327
328 extern "C" LLVMRemarkEntry *
329 LLVMRemarkParserGetNext(LLVMRemarkParserRef Parser) {
330 RemarkParser &TheParser = *unwrap(Parser);
331 // Check for EOF.
332 if (TheParser.HadAnyErrors || TheParser.DI == TheParser.Stream.end())
333 return nullptr;
334
335 // Try to parse an entry.
336 if (Error E = TheParser.parseYAMLElement(*TheParser.DI)) {
337 handleAllErrors(std::move(E), [&](const ParseError &PE) {
338 TheParser.Stream.printError(&PE.getNode(),
339 Twine(PE.getMessage()) + Twine('\n'));
340 TheParser.HadAnyErrors = true;
341 });
342 return nullptr;
343 }
344
345 // Move on.
346 ++TheParser.DI;
347
348 // Return the just-parsed remark.
349 if (Optional &Entry = TheParser.LastRemark)
350 return &*Entry;
351 return nullptr;
352 }
353
354 extern "C" LLVMBool LLVMRemarkParserHasError(LLVMRemarkParserRef Parser) {
355 return unwrap(Parser)->HadAnyErrors;
356 }
357
358 extern "C" const char *
359 LLVMRemarkParserGetErrorMessage(LLVMRemarkParserRef Parser) {
360 return unwrap(Parser)->ErrorStream.str().c_str();
361 }
362
363 extern "C" void LLVMRemarkParserDispose(LLVMRemarkParserRef Parser) {
364 delete unwrap(Parser);
365 }
None set(LLVM_LINK_COMPONENTS Core Demangle Object OptRemarks Support)
0 set(LLVM_LINK_COMPONENTS Core Demangle Object Remarks Support)
11
22 add_llvm_tool(llvm-opt-report
33 OptReport.cpp
1212 ///
1313 //===----------------------------------------------------------------------===//
1414
15 #include "llvm-c/OptRemarks.h"
15 #include "llvm-c/Remarks.h"
1616 #include "llvm/Demangle/Demangle.h"
1717 #include "llvm/Support/CommandLine.h"
1818 #include "llvm/Support/Error.h"
151151 }
152152
153153 StringRef Buffer = (*Buf)->getBuffer();
154 LLVMOptRemarkParserRef Parser =
155 LLVMOptRemarkParserCreate(Buffer.data(), Buffer.size());
156
157 LLVMOptRemarkEntry *Remark = nullptr;
158 while ((Remark = LLVMOptRemarkParserGetNext(Parser))) {
154 LLVMRemarkParserRef Parser =
155 LLVMRemarkParserCreate(Buffer.data(), Buffer.size());
156
157 LLVMRemarkEntry *Remark = nullptr;
158 while ((Remark = LLVMRemarkParserGetNext(Parser))) {
159159 bool Transformed =
160160 StringRef(Remark->RemarkType.Str, Remark->RemarkType.Len) == "!Passed";
161161 StringRef Pass(Remark->PassName.Str, Remark->PassName.Len);
164164 StringRef Function(Remark->FunctionName.Str, Remark->FunctionName.Len);
165165 uint32_t Line = Remark->DebugLoc.SourceLineNumber;
166166 uint32_t Column = Remark->DebugLoc.SourceColumnNumber;
167 ArrayRefOptRemarkArg> Args(Remark->Args, Remark->NumArgs);
167 ArrayRefRemarkArg> Args(Remark->Args, Remark->NumArgs);
168168
169169 int VectorizationFactor = 1;
170170 int InterleaveCount = 1;
171171 int UnrollCount = 1;
172172
173 for (const LLVMOptRemarkArg &Arg : Args) {
173 for (const LLVMRemarkArg &Arg : Args) {
174174 StringRef ArgKeyName(Arg.Key.Str, Arg.Key.Len);
175175 StringRef ArgValue(Arg.Value.Str, Arg.Value.Len);
176176 if (ArgKeyName == "VectorizationFactor")
208208 }
209209 }
210210
211 bool HasError = LLVMOptRemarkParserHasError(Parser);
211 bool HasError = LLVMRemarkParserHasError(Parser);
212212 if (HasError)
213 WithColor::error() << LLVMOptRemarkParserGetErrorMessage(Parser) << "\n";
214
215 LLVMOptRemarkParserDispose(Parser);
213 WithColor::error() << LLVMRemarkParserGetErrorMessage(Parser) << "\n";
214
215 LLVMRemarkParserDispose(Parser);
216216 return !HasError;
217217 }
218218
+0
-22
tools/opt-remarks/CMakeLists.txt less more
None set(LLVM_LINK_COMPONENTS
1 OptRemarks
2 )
3
4 set(SOURCES
5 liboptremarks.cpp
6 )
7
8 set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/OptRemarks.exports)
9
10 add_llvm_library(OptRemarks SHARED ${SOURCES})
11
12 install(FILES ${LLVM_MAIN_INCLUDE_DIR}/llvm-c/OptRemarks.h
13 DESTINATION include/llvm-c
14 COMPONENT OptRemarks)
15
16 if (APPLE)
17 set(OPTREMARKS_VERSION ${LLVM_VERSION_MAJOR})
18 set_property(TARGET OptRemarks APPEND_STRING PROPERTY
19 LINK_FLAGS
20 " -compatibility_version 1 -current_version ${OPTREMARKS_VERSION}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
21 endif()
+0
-6
tools/opt-remarks/OptRemarks.exports less more
None LLVMOptRemarkParserCreate
1 LLVMOptRemarkParserGetNext
2 LLVMOptRemarkParserHasError
3 LLVMOptRemarkParserGetErrorMessage
4 LLVMOptRemarkParserDispose
5 LLVMOptRemarkVersion
+0
-17
tools/opt-remarks/liboptremarks.cpp less more
None //===-liboptremarks.cpp - LLVM Opt-Remarks Shared Library -----------------===//
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 // Provide a library to work with optimization remarks.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #include "llvm-c/OptRemarks.h"
13
14 extern uint32_t LLVMOptRemarkVersion(void) {
15 return OPT_REMARKS_API_VERSION;
16 }
0 set(LLVM_LINK_COMPONENTS
1 Remarks
2 )
3
4 set(SOURCES
5 libremarks.cpp
6 )
7
8 set(LLVM_EXPORTED_SYMBOL_FILE ${CMAKE_CURRENT_SOURCE_DIR}/Remarks.exports)
9
10 add_llvm_library(Remarks SHARED ${SOURCES})
11
12 install(FILES ${LLVM_MAIN_INCLUDE_DIR}/llvm-c/Remarks.h
13 DESTINATION include/llvm-c
14 COMPONENT Remarks)
15
16 if (APPLE)
17 set(REMARKS_VERSION ${LLVM_VERSION_MAJOR})
18 set_property(TARGET Remarks APPEND_STRING PROPERTY
19 LINK_FLAGS
20 " -compatibility_version 1 -current_version ${REMARKS_VERSION}.${LLVM_VERSION_MINOR}.${LLVM_VERSION_PATCH}")
21 endif()
0 LLVMRemarkParserCreate
1 LLVMRemarkParserGetNext
2 LLVMRemarkParserHasError
3 LLVMRemarkParserGetErrorMessage
4 LLVMRemarkParserDispose
5 LLVMRemarkVersion
0 //===-libremarks.cpp - LLVM Remarks Shared Library ------------------------===//
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 // Provide a library to work with remark diagnostics.
9 //
10 //===----------------------------------------------------------------------===//
11
12 #include "llvm-c/Remarks.h"
13
14 extern uint32_t LLVMRemarkVersion(void) {
15 return REMARKS_API_VERSION;
16 }
2525 add_subdirectory(Object)
2626 add_subdirectory(ObjectYAML)
2727 add_subdirectory(Option)
28 add_subdirectory(OptRemarks)
28 add_subdirectory(Remarks)
2929 add_subdirectory(Passes)
3030 add_subdirectory(ProfileData)
3131 add_subdirectory(Support)
+0
-8
unittests/OptRemarks/CMakeLists.txt less more
None set(LLVM_LINK_COMPONENTS
1 OptRemarks
2 Support
3 )
4
5 add_llvm_unittest(OptRemarksTests
6 OptRemarksParsingTest.cpp
7 )
+0
-432
unittests/OptRemarks/OptRemarksParsingTest.cpp less more
None //===- unittest/Support/OptRemarksParsingTest.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/OptRemarks.h"
9 #include "gtest/gtest.h"
10
11 using namespace llvm;
12
13 template bool tryParse(const char (&Buf)[N]) {
14 LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, N - 1);
15 LLVMOptRemarkEntry *Remark = nullptr;
16 while (LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(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 = LLVMOptRemarkParserHasError(Parser);
22 LLVMOptRemarkParserDispose(Parser);
23 return !HasError;
24 }
25
26 template
27 bool parseExpectError(const char (&Buf)[N], const char *Error) {
28 LLVMOptRemarkParserRef Parser = LLVMOptRemarkParserCreate(Buf, N - 1);
29 LLVMOptRemarkEntry *Remark = nullptr;
30 while (LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(Parser)) {
31 EXPECT_FALSE(NewRemark);
32 }
33 EXPECT_TRUE(Remark == nullptr); // We are parsing only one malformed remark.
34 EXPECT_TRUE(LLVMOptRemarkParserHasError(Parser));
35 bool MatchesError =
36 StringRef(LLVMOptRemarkParserGetErrorMessage(Parser)).contains(Error);
37 LLVMOptRemarkParserDispose(Parser);
38
39 return MatchesError;
40 }
41
42 TEST(OptRemarks, OptRemarksParsingEmpty) {
43 StringRef Buf = "\n"
44 "\n";
45 LLVMOptRemarkParserRef Parser =
46 LLVMOptRemarkParserCreate(Buf.data(), Buf.size());
47 LLVMOptRemarkEntry *NewRemark = LLVMOptRemarkParserGetNext(Parser);
48 EXPECT_TRUE(NewRemark == nullptr); // No remark expected.
49 EXPECT_TRUE(LLVMOptRemarkParserHasError(Parser));
50 EXPECT_TRUE(StringRef(LLVMOptRemarkParserGetErrorMessage(Parser))
51 .contains("document root is not of mapping type."));
52 LLVMOptRemarkParserDispose(Parser);
53 }
54
55 TEST(OptRemarks, OptRemarksParsingGood) {
56 EXPECT_TRUE(tryParse("\n"
57 "--- !Missed\n"
58 "Pass: inline\n"
59 "Name: NoDefinition\n"
60 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
61 "Function: foo\n"
62 "Args:\n"
63 " - Callee: bar\n"
64 " - String: ' will not be inlined into '\n"
65 " - Caller: foo\n"
66 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
67 " - String: ' because its definition is unavailable'\n"
68 ""));
69
70 // No debug loc should also pass.
71 EXPECT_TRUE(tryParse("\n"
72 "--- !Missed\n"
73 "Pass: inline\n"
74 "Name: NoDefinition\n"
75 "Function: foo\n"
76 "Args:\n"
77 " - Callee: bar\n"
78 " - String: ' will not be inlined into '\n"
79 " - Caller: foo\n"
80 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
81 " - String: ' because its definition is unavailable'\n"
82 ""));
83
84 // No args is also ok.
85 EXPECT_TRUE(tryParse("\n"
86 "--- !Missed\n"
87 "Pass: inline\n"
88 "Name: NoDefinition\n"
89 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
90 "Function: foo\n"
91 ""));
92
93 // Different order.
94 EXPECT_TRUE(tryParse("\n"
95 "--- !Missed\n"
96 "DebugLoc: { Line: 3, Column: 12, File: file.c }\n"
97 "Function: foo\n"
98 "Name: NoDefinition\n"
99 "Args:\n"
100 " - Callee: bar\n"
101 " - String: ' will not be inlined into '\n"
102 " - Caller: foo\n"
103 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
104 " - String: ' because its definition is unavailable'\n"
105 "Pass: inline\n"
106 ""));
107 }
108
109 // Mandatory common part of a remark.
110 #define COMMON_REMARK "\nPass: inline\nName: NoDefinition\nFunction: foo\n\n"
111 // Test all the types.
112 TEST(OptRemarks, OptRemarksParsingTypes) {
113 // Type: Passed
114 EXPECT_TRUE(tryParse("--- !Passed" COMMON_REMARK));
115 // Type: Missed
116 EXPECT_TRUE(tryParse("--- !Missed" COMMON_REMARK));
117 // Type: Analysis
118 EXPECT_TRUE(tryParse("--- !Analysis" COMMON_REMARK));
119 // Type: AnalysisFPCompute
120 EXPECT_TRUE(tryParse("--- !AnalysisFPCompute" COMMON_REMARK));
121 // Type: AnalysisAliasing
122 EXPECT_TRUE(tryParse("--- !AnalysisAliasing" COMMON_REMARK));
123 // Type: Failure
124 EXPECT_TRUE(tryParse("--- !Failure" COMMON_REMARK));
125 }
126 #undef COMMON_REMARK
127
128 TEST(OptRemarks, OptRemarksParsingMissingFields) {
129 // No type.
130 EXPECT_TRUE(parseExpectError("\n"
131 "---\n"
132 "Pass: inline\n"
133 "Name: NoDefinition\n"
134 "Function: foo\n"
135 "",
136 "error: Type, Pass, Name or Function missing."));
137 // No pass.
138 EXPECT_TRUE(parseExpectError("\n"
139 "--- !Missed\n"
140 "Name: NoDefinition\n"
141 "Function: foo\n"
142 "",
143 "error: Type, Pass, Name or Function missing."));
144 // No name.
145 EXPECT_TRUE(parseExpectError("\n"
146 "--- !Missed\n"
147 "Pass: inline\n"
148 "Function: foo\n"
149 "",
150 "error: Type, Pass, Name or Function missing."));
151 // No function.
152 EXPECT_TRUE(parseExpectError("\n"
153 "--- !Missed\n"
154 "Pass: inline\n"
155 "Name: NoDefinition\n"
156 "",
157 "error: Type, Pass, Name or Function missing."));
158 // Debug loc but no file.
159 EXPECT_TRUE(parseExpectError("\n"
160 "--- !Missed\n"
161 "Pass: inline\n"
162 "Name: NoDefinition\n"
163 "Function: foo\n"
164 "DebugLoc: { Line: 3, Column: 12 }\n"
165 "",
166 "DebugLoc node incomplete."));
167 // Debug loc but no line.
168 EXPECT_TRUE(parseExpectError("\n"
169 "--- !Missed\n"
170 "Pass: inline\n"
171 "Name: NoDefinition\n"
172 "Function: foo\n"
173 "DebugLoc: { File: file.c, Column: 12 }\n"
174 "",
175 "DebugLoc node incomplete."));
176 // Debug loc but no column.
177 EXPECT_TRUE(parseExpectError("\n"
178 "--- !Missed\n"
179 "Pass: inline\n"
180 "Name: NoDefinition\n"
181 "Function: foo\n"
182 "DebugLoc: { File: file.c, Line: 3 }\n"
183 "",
184 "DebugLoc node incomplete."));
185 }
186
187 TEST(OptRemarks, OptRemarksParsingWrongTypes) {
188 // Wrong debug loc type.
189 EXPECT_TRUE(parseExpectError("\n"
190 "--- !Missed\n"
191 "Pass: inline\n"
192 "Name: NoDefinition\n"
193 "Function: foo\n"
194 "DebugLoc: foo\n"
195 "",
196 "expected a value of mapping type."));
197 // Wrong line type.
198 EXPECT_TRUE(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(parseExpectError("\n"
208 "--- !Missed\n"
209 "Pass: inline\n"
210 "Name: NoDefinition\n"
211 "Function: foo\n"
212 "DebugLoc: { File: file.c, Line: 3, Column: c }\n"
213 "",
214 "expected a value of integer type."));
215 // Wrong args type.
216 EXPECT_TRUE(parseExpectError("\n"
217 "--- !Missed\n"
218 "Pass: inline\n"
219 "Name: NoDefinition\n"
220 "Function: foo\n"
221 "Args: foo\n"
222 "",
223 "wrong value type for key."));
224 // Wrong key type.
225 EXPECT_TRUE(parseExpectError("\n"
226 "--- !Missed\n"
227 "{ A: a }: inline\n"
228 "Name: NoDefinition\n"
229 "Function: foo\n"
230 "",
231 "key is not a string."));
232 // Debug loc with unknown entry.
233 EXPECT_TRUE(parseExpectError("\n"
234 "--- !Missed\n"
235 "Pass: inline\n"
236 "Name: NoDefinition\n"
237 "Function: foo\n"
238 "DebugLoc: { File: file.c, Column: 12, Unknown: 12 }\n"
239 "",
240 "unknown entry in DebugLoc map."));
241 // Unknown entry.
242 EXPECT_TRUE(parseExpectError("\n"
243 "--- !Missed\n"
244 "Unknown: inline\n"
245 "",
246 "unknown key."));
247 // Not a scalar.
248 EXPECT_TRUE(parseExpectError("\n"
249 "--- !Missed\n"
250 "Pass: { File: a, Line: 1, Column: 2 }\n"
251 "Name: NoDefinition\n"
252 "Function: foo\n"
253 "",
254 "expected a value of scalar type."));
255 // Not a string file in debug loc.
256 EXPECT_TRUE(parseExpectError("\n"
257 "--- !Missed\n"
258 "Pass: inline\n"
259 "Name: NoDefinition\n"
260 "Function: foo\n"
261 "DebugLoc: { File: { a: b }, Column: 12, Line: 12 }\n"
262 "",
263 "expected a value of scalar type."));
264 // Not a integer column in debug loc.
265 EXPECT_TRUE(parseExpectError("\n"
266 "--- !Missed\n"
267 "Pass: inline\n"
268 "Name: NoDefinition\n"
269 "Function: foo\n"
270 "DebugLoc: { File: file.c, Column: { a: b }, Line: 12 }\n"
271 "",
272 "expected a value of scalar type."));
273 // Not a integer line in debug loc.
274 EXPECT_TRUE(parseExpectError("\n"
275 "--- !Missed\n"
276 "Pass: inline\n"
277 "Name: NoDefinition\n"
278 "Function: foo\n"
279 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
280 "",
281 "expected a value of scalar type."));
282 // Not a mapping type value for args.
283 EXPECT_TRUE(parseExpectError("\n"
284 "--- !Missed\n"
285 "Pass: inline\n"
286 "Name: NoDefinition\n"
287 "Function: foo\n"
288 "DebugLoc: { File: file.c, Column: 12, Line: { a: b } }\n"
289 "",
290 "expected a value of scalar type."));
291 }
292
293 TEST(OptRemarks, OptRemarksParsingWrongArgs) {
294 // Multiple debug locs per arg.
295 EXPECT_TRUE(
296 parseExpectError("\n"
297 "--- !Missed\n"
298 "Pass: inline\n"
299 "Name: NoDefinition\n"
300 "Function: foo\n"
301 "Args:\n"
302 " - Str: string\n"
303 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
304 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
305 "",
306 "only one DebugLoc entry is allowed per argument."));
307 // Multiple strings per arg.
308 EXPECT_TRUE(
309 parseExpectError("\n"
310 "--- !Missed\n"
311 "Pass: inline\n"
312 "Name: NoDefinition\n"
313 "Function: foo\n"
314 "Args:\n"
315 " - Str: string\n"
316 " Str2: string\n"
317 " DebugLoc: { File: a, Line: 1, Column: 2 }\n"
318 "",
319 "only one string entry is allowed per argument."));
320 // No arg value.
321 EXPECT_TRUE(parseExpectError("\n"
322 "--- !Missed\n"
323 "Pass: inline\n"
324 "Name: NoDefinition\n"
325 "Function: foo\n"
326 "Args:\n"
327 " - Callee: ''\n"
328 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
329 "",
330 "argument value is missing."));
331 // No arg value.
332 EXPECT_TRUE(parseExpectError("\n"
333 "--- !Missed\n"
334 "Pass: inline\n"
335 "Name: NoDefinition\n"
336 "Function: foo\n"
337 "Args:\n"
338 " - DebugLoc: { File: a, Line: 1, Column: 2 }\n"
339 "",
340 "argument key is missing."));
341
342 }
343
344 TEST(OptRemarks, OptRemarksGoodStruct) {
345 StringRef Buf = "\n"
346 "--- !Missed\n"
347 "Pass: inline\n"
348 "Name: NoDefinition\n"
349 "DebugLoc: { File: file.c, Line: 3, Column: 12 }\n"
350 "Function: foo\n"
351 "Args:\n"
352 " - Callee: bar\n"
353 " - String: ' will not be inlined into '\n"
354 " - Caller: foo\n"
355 " DebugLoc: { File: file.c, Line: 2, Column: 0 }\n"
356 " - String: ' because its definition is unavailable'\n"
357 "\n";
358
359 LLVMOptRemarkParserRef Parser =
360 LLVMOptRemarkParserCreate(Buf.data(), Buf.size());
361 LLVMOptRemarkEntry *Remark = LLVMOptRemarkParserGetNext(Parser);
362 EXPECT_FALSE(Remark == nullptr);
363 EXPECT_EQ(StringRef(Remark->RemarkType.Str, 7), "!Missed");
364 EXPECT_EQ(Remark->RemarkType.Len, 7U);
365 EXPECT_EQ(StringRef(Remark->PassName.Str, 6), "inline");
366 EXPECT_EQ(Remark->PassName.Len, 6U);
367 EXPECT_EQ(StringRef(Remark->RemarkName.Str, 12), "NoDefinition");
368 EXPECT_EQ(Remark->RemarkName.Len, 12U);
369 EXPECT_EQ(StringRef(Remark->FunctionName.Str, 3), "foo");
370 EXPECT_EQ(Remark->FunctionName.Len, 3U);
371 EXPECT_EQ(StringRef(Remark->DebugLoc.SourceFile.Str, 6), "file.c");
372 EXPECT_EQ(Remark->DebugLoc.SourceFile.Len, 6U);
373 EXPECT_EQ(Remark->DebugLoc.SourceLineNumber, 3U);
374 EXPECT_EQ(Remark->DebugLoc.SourceColumnNumber, 12U);
375 EXPECT_EQ(Remark->Hotness, 0U);
376 EXPECT_EQ(Remark->NumArgs, 4U);
377 // Arg 0
378 {
379 LLVMOptRemarkArg &Arg = Remark->Args[0];
380 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Callee");
381 EXPECT_EQ(Arg.Key.Len, 6U);
382 EXPECT_EQ(StringRef(Arg.Value.Str, 3), "bar");
383 EXPECT_EQ(Arg.Value.Len, 3U);
384 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), "");
385 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U);
386 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U);
387 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
388 }
389 // Arg 1
390 {
391 LLVMOptRemarkArg &Arg = Remark->Args[1];
392 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String");
393 EXPECT_EQ(Arg.Key.Len, 6U);
394 EXPECT_EQ(StringRef(Arg.Value.Str, 26), " will not be inlined into ");
395 EXPECT_EQ(Arg.Value.Len, 26U);
396 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), "");
397 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U);
398 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U);
399 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
400 }
401 // Arg 2
402 {
403 LLVMOptRemarkArg &Arg = Remark->Args[2];
404 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "Caller");
405 EXPECT_EQ(Arg.Key.Len, 6U);
406 EXPECT_EQ(StringRef(Arg.Value.Str, 3), "foo");
407 EXPECT_EQ(Arg.Value.Len, 3U);
408 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 6), "file.c");
409 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 6U);
410 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 2U);
411 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
412 }
413 // Arg 3
414 {
415 LLVMOptRemarkArg &Arg = Remark->Args[3];
416 EXPECT_EQ(StringRef(Arg.Key.Str, 6), "String");
417 EXPECT_EQ(Arg.Key.Len, 6U);
418 EXPECT_EQ(StringRef(Arg.Value.Str, 38),
419 " because its definition is unavailable");
420 EXPECT_EQ(Arg.Value.Len, 38U);
421 EXPECT_EQ(StringRef(Arg.DebugLoc.SourceFile.Str, 0), "");
422 EXPECT_EQ(Arg.DebugLoc.SourceFile.Len, 0U);
423 EXPECT_EQ(Arg.DebugLoc.SourceLineNumber, 0U);
424 EXPECT_EQ(Arg.DebugLoc.SourceColumnNumber, 0U);
425 }
426
427 EXPECT_EQ(LLVMOptRemarkParserGetNext(Parser), nullptr);
428
429 EXPECT_FALSE(LLVMOptRemarkParserHasError(Parser));
430 LLVMOptRemarkParserDispose(Parser);
431 }
0 set(LLVM_LINK_COMPONENTS
1 Remarks
2 Support
3 )
4
5 add_llvm_unittest(RemarksTests
6 RemarksParsingTest.cpp
7 )
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 }