1 ///===- MachineOptimizationRemarkEmitter.h - Opt Diagnostics -*- 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 /// \file 9 /// Optimization diagnostic interfaces for machine passes. It's packaged as an 10 /// analysis pass so that by using this service passes become dependent on MBFI 11 /// as well. MBFI is used to compute the "hotness" of the diagnostic message. 12 /// 13 ///===---------------------------------------------------------------------===// 14 15 #ifndef LLVM_CODEGEN_MACHINEOPTIMIZATIONREMARKEMITTER_H 16 #define LLVM_CODEGEN_MACHINEOPTIMIZATIONREMARKEMITTER_H 17 18 #include "llvm/CodeGen/MachineFunctionPass.h" 19 #include "llvm/IR/DiagnosticInfo.h" 20 #include "llvm/IR/Function.h" 21 22 namespace llvm { 23 class MachineBasicBlock; 24 class MachineBlockFrequencyInfo; 25 class MachineInstr; 26 27 /// Common features for diagnostics dealing with optimization remarks 28 /// that are used by machine passes. 29 class DiagnosticInfoMIROptimization : public DiagnosticInfoOptimizationBase { 30 public: 31 DiagnosticInfoMIROptimization(enum DiagnosticKind Kind, const char *PassName, 32 StringRef RemarkName, 33 const DiagnosticLocation &Loc, 34 const MachineBasicBlock *MBB) 35 : DiagnosticInfoOptimizationBase(Kind, DS_Remark, PassName, RemarkName, 36 MBB->getParent()->getFunction(), Loc), 37 MBB(MBB) {} 38 39 /// MI-specific kinds of diagnostic Arguments. 40 struct MachineArgument : public DiagnosticInfoOptimizationBase::Argument { 41 /// Print an entire MachineInstr. 42 MachineArgument(StringRef Key, const MachineInstr &MI); 43 }; 44 45 static bool classof(const DiagnosticInfo *DI) { 46 return DI->getKind() >= DK_FirstMachineRemark && 47 DI->getKind() <= DK_LastMachineRemark; 48 } 49 50 const MachineBasicBlock *getBlock() const { return MBB; } 51 52 private: 53 const MachineBasicBlock *MBB; 54 }; 55 56 /// Diagnostic information for applied optimization remarks. 57 class MachineOptimizationRemark : public DiagnosticInfoMIROptimization { 58 public: 59 /// \p PassName is the name of the pass emitting this diagnostic. If this name 60 /// matches the regular expression given in -Rpass=, then the diagnostic will 61 /// be emitted. \p RemarkName is a textual identifier for the remark. \p 62 /// Loc is the debug location and \p MBB is the block that the optimization 63 /// operates in. 64 MachineOptimizationRemark(const char *PassName, StringRef RemarkName, 65 const DiagnosticLocation &Loc, 66 const MachineBasicBlock *MBB) 67 : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemark, PassName, 68 RemarkName, Loc, MBB) {} 69 70 static bool classof(const DiagnosticInfo *DI) { 71 return DI->getKind() == DK_MachineOptimizationRemark; 72 } 73 74 /// \see DiagnosticInfoOptimizationBase::isEnabled. 75 bool isEnabled() const override { 76 const Function &Fn = getFunction(); 77 LLVMContext &Ctx = Fn.getContext(); 78 return Ctx.getDiagHandlerPtr()->isPassedOptRemarkEnabled(getPassName()); 79 } 80 }; 81 82 /// Diagnostic information for missed-optimization remarks. 83 class MachineOptimizationRemarkMissed : public DiagnosticInfoMIROptimization { 84 public: 85 /// \p PassName is the name of the pass emitting this diagnostic. If this name 86 /// matches the regular expression given in -Rpass-missed=, then the 87 /// diagnostic will be emitted. \p RemarkName is a textual identifier for the 88 /// remark. \p Loc is the debug location and \p MBB is the block that the 89 /// optimization operates in. 90 MachineOptimizationRemarkMissed(const char *PassName, StringRef RemarkName, 91 const DiagnosticLocation &Loc, 92 const MachineBasicBlock *MBB) 93 : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkMissed, 94 PassName, RemarkName, Loc, MBB) {} 95 96 static bool classof(const DiagnosticInfo *DI) { 97 return DI->getKind() == DK_MachineOptimizationRemarkMissed; 98 } 99 100 /// \see DiagnosticInfoOptimizationBase::isEnabled. 101 bool isEnabled() const override { 102 const Function &Fn = getFunction(); 103 LLVMContext &Ctx = Fn.getContext(); 104 return Ctx.getDiagHandlerPtr()->isMissedOptRemarkEnabled(getPassName()); 105 } 106 }; 107 108 /// Diagnostic information for optimization analysis remarks. 109 class MachineOptimizationRemarkAnalysis : public DiagnosticInfoMIROptimization { 110 public: 111 /// \p PassName is the name of the pass emitting this diagnostic. If this name 112 /// matches the regular expression given in -Rpass-analysis=, then the 113 /// diagnostic will be emitted. \p RemarkName is a textual identifier for the 114 /// remark. \p Loc is the debug location and \p MBB is the block that the 115 /// optimization operates in. 116 MachineOptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, 117 const DiagnosticLocation &Loc, 118 const MachineBasicBlock *MBB) 119 : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis, 120 PassName, RemarkName, Loc, MBB) {} 121 122 MachineOptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName, 123 const MachineInstr *MI) 124 : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis, 125 PassName, RemarkName, MI->getDebugLoc(), 126 MI->getParent()) {} 127 128 static bool classof(const DiagnosticInfo *DI) { 129 return DI->getKind() == DK_MachineOptimizationRemarkAnalysis; 130 } 131 132 /// \see DiagnosticInfoOptimizationBase::isEnabled. 133 bool isEnabled() const override { 134 const Function &Fn = getFunction(); 135 LLVMContext &Ctx = Fn.getContext(); 136 return Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(getPassName()); 137 } 138 }; 139 140 /// Extend llvm::ore:: with MI-specific helper names. 141 namespace ore { 142 using MNV = DiagnosticInfoMIROptimization::MachineArgument; 143 } 144 145 /// The optimization diagnostic interface. 146 /// 147 /// It allows reporting when optimizations are performed and when they are not 148 /// along with the reasons for it. Hotness information of the corresponding 149 /// code region can be included in the remark if DiagnosticsHotnessRequested is 150 /// enabled in the LLVM context. 151 class MachineOptimizationRemarkEmitter { 152 public: 153 MachineOptimizationRemarkEmitter(MachineFunction &MF, 154 MachineBlockFrequencyInfo *MBFI) 155 : MF(MF), MBFI(MBFI) {} 156 157 /// Emit an optimization remark. 158 void emit(DiagnosticInfoOptimizationBase &OptDiag); 159 160 /// Whether we allow for extra compile-time budget to perform more 161 /// analysis to be more informative. 162 /// 163 /// This is useful to enable additional missed optimizations to be reported 164 /// that are normally too noisy. In this mode, we can use the extra analysis 165 /// (1) to filter trivial false positives or (2) to provide more context so 166 /// that non-trivial false positives can be quickly detected by the user. 167 bool allowExtraAnalysis(StringRef PassName) const { 168 return ( 169 MF.getFunction().getContext().getLLVMRemarkStreamer() || 170 MF.getFunction().getContext().getDiagHandlerPtr()->isAnyRemarkEnabled( 171 PassName)); 172 } 173 174 /// Take a lambda that returns a remark which will be emitted. Second 175 /// argument is only used to restrict this to functions. 176 template <typename T> 177 void emit(T RemarkBuilder, decltype(RemarkBuilder()) * = nullptr) { 178 // Avoid building the remark unless we know there are at least *some* 179 // remarks enabled. We can't currently check whether remarks are requested 180 // for the calling pass since that requires actually building the remark. 181 182 if (MF.getFunction().getContext().getLLVMRemarkStreamer() || 183 MF.getFunction() 184 .getContext() 185 .getDiagHandlerPtr() 186 ->isAnyRemarkEnabled()) { 187 auto R = RemarkBuilder(); 188 emit((DiagnosticInfoOptimizationBase &)R); 189 } 190 } 191 192 MachineBlockFrequencyInfo *getBFI() { 193 return MBFI; 194 } 195 196 private: 197 MachineFunction &MF; 198 199 /// MBFI is only set if hotness is requested. 200 MachineBlockFrequencyInfo *MBFI; 201 202 /// Compute hotness from IR value (currently assumed to be a block) if PGO is 203 /// available. 204 Optional<uint64_t> computeHotness(const MachineBasicBlock &MBB); 205 206 /// Similar but use value from \p OptDiag and update hotness there. 207 void computeHotness(DiagnosticInfoMIROptimization &Remark); 208 209 /// Only allow verbose messages if we know we're filtering by hotness 210 /// (BFI is only set in this case). 211 bool shouldEmitVerbose() { return MBFI != nullptr; } 212 }; 213 214 /// The analysis pass 215 /// 216 /// Note that this pass shouldn't generally be marked as preserved by other 217 /// passes. It's holding onto BFI, so if the pass does not preserve BFI, BFI 218 /// could be freed. 219 class MachineOptimizationRemarkEmitterPass : public MachineFunctionPass { 220 std::unique_ptr<MachineOptimizationRemarkEmitter> ORE; 221 222 public: 223 MachineOptimizationRemarkEmitterPass(); 224 225 bool runOnMachineFunction(MachineFunction &MF) override; 226 227 void getAnalysisUsage(AnalysisUsage &AU) const override; 228 229 MachineOptimizationRemarkEmitter &getORE() { 230 assert(ORE && "pass not run yet"); 231 return *ORE; 232 } 233 234 static char ID; 235 }; 236 } 237 238 #endif 239