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/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: |
32 | DiagnosticInfoMIROptimization(enum DiagnosticKind Kind, const char *PassName, |
33 | StringRef , |
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 | |
46 | static bool classof(const DiagnosticInfo *DI) { |
47 | return DI->getKind() >= DK_FirstMachineRemark && |
48 | DI->getKind() <= DK_LastMachineRemark; |
49 | } |
50 | |
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 : 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. |
65 | (const char *PassName, StringRef , |
66 | const DiagnosticLocation &Loc, |
67 | const MachineBasicBlock *MBB) |
68 | : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemark, PassName, |
69 | RemarkName, Loc, MBB) {} |
70 | |
71 | static bool (const DiagnosticInfo *DI) { |
72 | return DI->getKind() == DK_MachineOptimizationRemark; |
73 | } |
74 | |
75 | /// \see DiagnosticInfoOptimizationBase::isEnabled. |
76 | bool () const override { |
77 | const Function &Fn = getFunction(); |
78 | LLVMContext &Ctx = Fn.getContext(); |
79 | return Ctx.getDiagHandlerPtr()->isPassedOptRemarkEnabled(PassName: getPassName()); |
80 | } |
81 | }; |
82 | |
83 | /// Diagnostic information for missed-optimization remarks. |
84 | class : 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. |
91 | (const char *PassName, StringRef , |
92 | const DiagnosticLocation &Loc, |
93 | const MachineBasicBlock *MBB) |
94 | : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkMissed, |
95 | PassName, RemarkName, Loc, MBB) {} |
96 | |
97 | static bool (const DiagnosticInfo *DI) { |
98 | return DI->getKind() == DK_MachineOptimizationRemarkMissed; |
99 | } |
100 | |
101 | /// \see DiagnosticInfoOptimizationBase::isEnabled. |
102 | bool () const override { |
103 | const Function &Fn = getFunction(); |
104 | LLVMContext &Ctx = Fn.getContext(); |
105 | return Ctx.getDiagHandlerPtr()->isMissedOptRemarkEnabled(PassName: getPassName()); |
106 | } |
107 | }; |
108 | |
109 | /// Diagnostic information for optimization analysis remarks. |
110 | class : 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. |
117 | (const char *PassName, StringRef , |
118 | const DiagnosticLocation &Loc, |
119 | const MachineBasicBlock *MBB) |
120 | : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis, |
121 | PassName, RemarkName, Loc, MBB) {} |
122 | |
123 | (const char *PassName, StringRef , |
124 | const MachineInstr *MI) |
125 | : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis, |
126 | PassName, RemarkName, MI->getDebugLoc(), |
127 | MI->getParent()) {} |
128 | |
129 | static bool (const DiagnosticInfo *DI) { |
130 | return DI->getKind() == DK_MachineOptimizationRemarkAnalysis; |
131 | } |
132 | |
133 | /// \see DiagnosticInfoOptimizationBase::isEnabled. |
134 | bool () const override { |
135 | const Function &Fn = getFunction(); |
136 | LLVMContext &Ctx = Fn.getContext(); |
137 | return Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(PassName: 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 { |
153 | public: |
154 | (MachineFunction &MF, |
155 | MachineBlockFrequencyInfo *MBFI) |
156 | : MF(MF), MBFI(MBFI) {} |
157 | |
158 | /// Emit an optimization remark. |
159 | void (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. |
168 | bool (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 (T , 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(OptDiag&: (DiagnosticInfoOptimizationBase &)R); |
190 | } |
191 | } |
192 | |
193 | MachineBlockFrequencyInfo *() { |
194 | return MBFI; |
195 | } |
196 | |
197 | private: |
198 | MachineFunction &; |
199 | |
200 | /// MBFI is only set if hotness is requested. |
201 | MachineBlockFrequencyInfo *; |
202 | |
203 | /// Compute hotness from IR value (currently assumed to be a block) if PGO is |
204 | /// available. |
205 | std::optional<uint64_t> (const MachineBasicBlock &MBB); |
206 | |
207 | /// Similar but use value from \p OptDiag and update hotness there. |
208 | void (DiagnosticInfoMIROptimization &); |
209 | |
210 | /// Only allow verbose messages if we know we're filtering by hotness |
211 | /// (BFI is only set in this case). |
212 | bool () { 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 : public MachineFunctionPass { |
221 | std::unique_ptr<MachineOptimizationRemarkEmitter> ; |
222 | |
223 | public: |
224 | (); |
225 | |
226 | bool (MachineFunction &MF) override; |
227 | |
228 | void (AnalysisUsage &AU) const override; |
229 | |
230 | MachineOptimizationRemarkEmitter &() { |
231 | assert(ORE && "pass not run yet" ); |
232 | return *ORE; |
233 | } |
234 | |
235 | static char ; |
236 | }; |
237 | } |
238 | |
239 | #endif |
240 | |