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