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