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