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