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