1 //===-- llvm/Remarks/Remark.h - The remark type -----------------*- C++/-*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM 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 file defines an abstraction for handling remarks.
10 //
11 //===----------------------------------------------------------------------===//
12
13 #ifndef LLVM_REMARKS_REMARK_H
14 #define LLVM_REMARKS_REMARK_H
15
16 #include "llvm-c/Remarks.h"
17 #include "llvm/ADT/SmallVector.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/CBindingWrapping.h"
20 #include "llvm/Support/Compiler.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include <optional>
23 #include <string>
24
25 namespace llvm {
26 namespace remarks {
27
28 /// The current version of the remark entry.
29 constexpr uint64_t CurrentRemarkVersion = 0;
30
31 /// The debug location used to track a remark back to the source file.
32 struct RemarkLocation {
33 /// Absolute path of the source file corresponding to this remark.
34 StringRef SourceFilePath;
35 unsigned SourceLine = 0;
36 unsigned SourceColumn = 0;
37
38 /// Implement operator<< on RemarkLocation.
39 LLVM_ABI void print(raw_ostream &OS) const;
40 };
41
42 // Create wrappers for C Binding types (see CBindingWrapping.h).
43 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(RemarkLocation, LLVMRemarkDebugLocRef)
44
45 /// A key-value pair with a debug location that is used to display the remarks
46 /// at the right place in the source.
47 struct Argument {
48 StringRef Key;
49 // FIXME: We might want to be able to store other types than strings here.
50 StringRef Val;
51 // If set, the debug location corresponding to the value.
52 std::optional<RemarkLocation> Loc;
53
54 /// Implement operator<< on Argument.
55 LLVM_ABI void print(raw_ostream &OS) const;
56 /// Return the value of argument as int.
57 LLVM_ABI std::optional<int> getValAsInt() const;
58 /// Check if the argument value can be parsed as int.
59 LLVM_ABI bool isValInt() const;
60 };
61
62 // Create wrappers for C Binding types (see CBindingWrapping.h).
63 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Argument, LLVMRemarkArgRef)
64
65 /// The type of the remark.
66 enum class Type {
67 Unknown,
68 Passed,
69 Missed,
70 Analysis,
71 AnalysisFPCommute,
72 AnalysisAliasing,
73 Failure,
74 First = Unknown,
75 Last = Failure
76 };
77
typeToStr(Type Ty)78 inline StringRef typeToStr(Type Ty) {
79 switch (Ty) {
80 case Type::Unknown:
81 return "Unknown";
82 case Type::Missed:
83 return "Missed";
84 case Type::Passed:
85 return "Passed";
86 case Type::Analysis:
87 return "Analysis";
88 case Type::AnalysisFPCommute:
89 return "AnalysisFPCommute";
90 case Type::AnalysisAliasing:
91 return "AnalysisAliasing";
92 default:
93 return "Failure";
94 }
95 }
96
97 /// A remark type used for both emission and parsing.
98 struct Remark {
99 /// The type of the remark.
100 Type RemarkType = Type::Unknown;
101
102 /// Name of the pass that triggers the emission of this remark.
103 StringRef PassName;
104
105 /// Textual identifier for the remark (single-word, camel-case). Can be used
106 /// by external tools reading the output file for remarks to identify the
107 /// remark.
108 StringRef RemarkName;
109
110 /// Mangled name of the function that triggers the emssion of this remark.
111 StringRef FunctionName;
112
113 /// The location in the source file of the remark.
114 std::optional<RemarkLocation> Loc;
115
116 /// If profile information is available, this is the number of times the
117 /// corresponding code was executed in a profile instrumentation run.
118 std::optional<uint64_t> Hotness;
119
120 /// Arguments collected via the streaming interface.
121 SmallVector<Argument, 5> Args;
122
123 Remark() = default;
124 Remark(Remark &&) = default;
125 Remark &operator=(Remark &&) = default;
126
127 /// Return a message composed from the arguments as a string.
128 LLVM_ABI std::string getArgsAsMsg() const;
129
130 /// Clone this remark to explicitly ask for a copy.
cloneRemark131 Remark clone() const { return *this; }
132
133 /// Implement operator<< on Remark.
134 LLVM_ABI void print(raw_ostream &OS) const;
135
136 private:
137 /// In order to avoid unwanted copies, "delete" the copy constructor.
138 /// If a copy is needed, it should be done through `Remark::clone()`.
139 Remark(const Remark &) = default;
140 Remark& operator=(const Remark &) = default;
141 };
142
143 // Create wrappers for C Binding types (see CBindingWrapping.h).
144 DEFINE_SIMPLE_CONVERSION_FUNCTIONS(Remark, LLVMRemarkEntryRef)
145
146 /// Comparison operators for Remark objects and dependent objects.
147
148 template <typename T>
149 bool operator<(const std::optional<T> &LHS, const std::optional<T> &RHS) {
150 // Sorting based on optionals should result in all `None` entries to appear
151 // before the valid entries. For example, remarks with no debug location will
152 // appear first.
153 if (!LHS && !RHS)
154 return false;
155 if (!LHS && RHS)
156 return true;
157 if (LHS && !RHS)
158 return false;
159 return *LHS < *RHS;
160 }
161
162 inline bool operator==(const RemarkLocation &LHS, const RemarkLocation &RHS) {
163 return LHS.SourceFilePath == RHS.SourceFilePath &&
164 LHS.SourceLine == RHS.SourceLine &&
165 LHS.SourceColumn == RHS.SourceColumn;
166 }
167
168 inline bool operator!=(const RemarkLocation &LHS, const RemarkLocation &RHS) {
169 return !(LHS == RHS);
170 }
171
172 inline bool operator<(const RemarkLocation &LHS, const RemarkLocation &RHS) {
173 return std::make_tuple(LHS.SourceFilePath, LHS.SourceLine, LHS.SourceColumn) <
174 std::make_tuple(RHS.SourceFilePath, RHS.SourceLine, RHS.SourceColumn);
175 }
176
177 inline bool operator==(const Argument &LHS, const Argument &RHS) {
178 return LHS.Key == RHS.Key && LHS.Val == RHS.Val && LHS.Loc == RHS.Loc;
179 }
180
181 inline bool operator!=(const Argument &LHS, const Argument &RHS) {
182 return !(LHS == RHS);
183 }
184
185 inline bool operator<(const Argument &LHS, const Argument &RHS) {
186 return std::make_tuple(LHS.Key, LHS.Val, LHS.Loc) <
187 std::make_tuple(RHS.Key, RHS.Val, RHS.Loc);
188 }
189
190 inline bool operator==(const Remark &LHS, const Remark &RHS) {
191 return LHS.RemarkType == RHS.RemarkType && LHS.PassName == RHS.PassName &&
192 LHS.RemarkName == RHS.RemarkName &&
193 LHS.FunctionName == RHS.FunctionName && LHS.Loc == RHS.Loc &&
194 LHS.Hotness == RHS.Hotness && LHS.Args == RHS.Args;
195 }
196
197 inline bool operator!=(const Remark &LHS, const Remark &RHS) {
198 return !(LHS == RHS);
199 }
200
201 inline bool operator<(const Remark &LHS, const Remark &RHS) {
202 return std::make_tuple(LHS.RemarkType, LHS.PassName, LHS.RemarkName,
203 LHS.FunctionName, LHS.Loc, LHS.Hotness, LHS.Args) <
204 std::make_tuple(RHS.RemarkType, RHS.PassName, RHS.RemarkName,
205 RHS.FunctionName, RHS.Loc, RHS.Hotness, RHS.Args);
206 }
207
208 inline raw_ostream &operator<<(raw_ostream &OS, const RemarkLocation &RLoc) {
209 RLoc.print(OS);
210 return OS;
211 }
212
213 inline raw_ostream &operator<<(raw_ostream &OS, const Argument &Arg) {
214 Arg.print(OS);
215 return OS;
216 }
217
218 inline raw_ostream &operator<<(raw_ostream &OS, const Remark &Remark) {
219 Remark.print(OS);
220 return OS;
221 }
222
223 } // end namespace remarks
224 } // end namespace llvm
225
226 #endif /* LLVM_REMARKS_REMARK_H */
227