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