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 |
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: |
34 | DiagnosticInfoMIROptimization(enum DiagnosticKind Kind, const char *PassName, |
35 | StringRef , |
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 | |
48 | static bool classof(const DiagnosticInfo *DI) { |
49 | return DI->getKind() >= DK_FirstMachineRemark && |
50 | DI->getKind() <= DK_LastMachineRemark; |
51 | } |
52 | |
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 : 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. |
67 | (const char *PassName, StringRef , |
68 | const DiagnosticLocation &Loc, |
69 | const MachineBasicBlock *MBB) |
70 | : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemark, PassName, |
71 | RemarkName, Loc, MBB) {} |
72 | |
73 | static bool (const DiagnosticInfo *DI) { |
74 | return DI->getKind() == DK_MachineOptimizationRemark; |
75 | } |
76 | |
77 | /// \see DiagnosticInfoOptimizationBase::isEnabled. |
78 | bool () const override { |
79 | const Function &Fn = getFunction(); |
80 | LLVMContext &Ctx = Fn.getContext(); |
81 | return Ctx.getDiagHandlerPtr()->isPassedOptRemarkEnabled(PassName: getPassName()); |
82 | } |
83 | }; |
84 | |
85 | /// Diagnostic information for missed-optimization remarks. |
86 | class : 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. |
93 | (const char *PassName, StringRef , |
94 | const DiagnosticLocation &Loc, |
95 | const MachineBasicBlock *MBB) |
96 | : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkMissed, |
97 | PassName, RemarkName, Loc, MBB) {} |
98 | |
99 | static bool (const DiagnosticInfo *DI) { |
100 | return DI->getKind() == DK_MachineOptimizationRemarkMissed; |
101 | } |
102 | |
103 | /// \see DiagnosticInfoOptimizationBase::isEnabled. |
104 | bool () const override { |
105 | const Function &Fn = getFunction(); |
106 | LLVMContext &Ctx = Fn.getContext(); |
107 | return Ctx.getDiagHandlerPtr()->isMissedOptRemarkEnabled(PassName: getPassName()); |
108 | } |
109 | }; |
110 | |
111 | /// Diagnostic information for optimization analysis remarks. |
112 | class : 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. |
119 | (const char *PassName, StringRef , |
120 | const DiagnosticLocation &Loc, |
121 | const MachineBasicBlock *MBB) |
122 | : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis, |
123 | PassName, RemarkName, Loc, MBB) {} |
124 | |
125 | (const char *PassName, StringRef , |
126 | const MachineInstr *MI) |
127 | : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis, |
128 | PassName, RemarkName, MI->getDebugLoc(), |
129 | MI->getParent()) {} |
130 | |
131 | static bool (const DiagnosticInfo *DI) { |
132 | return DI->getKind() == DK_MachineOptimizationRemarkAnalysis; |
133 | } |
134 | |
135 | /// \see DiagnosticInfoOptimizationBase::isEnabled. |
136 | bool () const override { |
137 | const Function &Fn = getFunction(); |
138 | LLVMContext &Ctx = Fn.getContext(); |
139 | return Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(PassName: 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 { |
155 | public: |
156 | (MachineFunction &MF, |
157 | MachineBlockFrequencyInfo *MBFI) |
158 | : MF(MF), MBFI(MBFI) {} |
159 | |
160 | (MachineOptimizationRemarkEmitter &&) = |
161 | default; |
162 | |
163 | /// Handle invalidation events in the new pass manager. |
164 | LLVM_ABI bool (MachineFunction &MF, const PreservedAnalyses &PA, |
165 | MachineFunctionAnalysisManager::Invalidator &Inv); |
166 | |
167 | /// Emit an optimization remark. |
168 | LLVM_ABI void (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. |
177 | bool (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 (T , 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(OptDiag&: (DiagnosticInfoOptimizationBase &)R); |
199 | } |
200 | } |
201 | |
202 | MachineBlockFrequencyInfo *() { |
203 | return MBFI; |
204 | } |
205 | |
206 | private: |
207 | MachineFunction &; |
208 | |
209 | /// MBFI is only set if hotness is requested. |
210 | MachineBlockFrequencyInfo *; |
211 | |
212 | /// Compute hotness from IR value (currently assumed to be a block) if PGO is |
213 | /// available. |
214 | std::optional<uint64_t> (const MachineBasicBlock &MBB); |
215 | |
216 | /// Similar but use value from \p OptDiag and update hotness there. |
217 | void (DiagnosticInfoMIROptimization &); |
218 | |
219 | /// Only allow verbose messages if we know we're filtering by hotness |
220 | /// (BFI is only set in this case). |
221 | bool () { return MBFI != nullptr; } |
222 | }; |
223 | |
224 | /// The analysis pass |
225 | class |
226 | : public AnalysisInfoMixin<MachineOptimizationRemarkEmitterAnalysis> { |
227 | friend AnalysisInfoMixin<MachineOptimizationRemarkEmitterAnalysis>; |
228 | LLVM_ABI static AnalysisKey ; |
229 | |
230 | public: |
231 | using = MachineOptimizationRemarkEmitter; |
232 | LLVM_ABI Result (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 |
242 | : public MachineFunctionPass { |
243 | std::unique_ptr<MachineOptimizationRemarkEmitter> ; |
244 | |
245 | public: |
246 | (); |
247 | |
248 | bool (MachineFunction &MF) override; |
249 | |
250 | void (AnalysisUsage &AU) const override; |
251 | |
252 | MachineOptimizationRemarkEmitter &() { |
253 | assert(ORE && "pass not run yet" ); |
254 | return *ORE; |
255 | } |
256 | |
257 | static char ; |
258 | }; |
259 | } |
260 | |
261 | #endif |
262 | |