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