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