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