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
25namespace llvm {
26class MachineBasicBlock;
27class MachineBlockFrequencyInfo;
28class MachineInstr;
29
30/// Common features for diagnostics dealing with optimization remarks
31/// that are used by machine passes.
32class DiagnosticInfoMIROptimization : public DiagnosticInfoOptimizationBase {
33public:
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
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
55private:
56 const MachineBasicBlock *MBB;
57};
58
59/// Diagnostic information for applied optimization remarks.
60class MachineOptimizationRemark : public DiagnosticInfoMIROptimization {
61public:
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 MachineOptimizationRemark(const char *PassName, StringRef RemarkName,
68 const DiagnosticLocation &Loc,
69 const MachineBasicBlock *MBB)
70 : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemark, PassName,
71 RemarkName, Loc, MBB) {}
72
73 static bool classof(const DiagnosticInfo *DI) {
74 return DI->getKind() == DK_MachineOptimizationRemark;
75 }
76
77 /// \see DiagnosticInfoOptimizationBase::isEnabled.
78 bool isEnabled() 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.
86class MachineOptimizationRemarkMissed : public DiagnosticInfoMIROptimization {
87public:
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 MachineOptimizationRemarkMissed(const char *PassName, StringRef RemarkName,
94 const DiagnosticLocation &Loc,
95 const MachineBasicBlock *MBB)
96 : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkMissed,
97 PassName, RemarkName, Loc, MBB) {}
98
99 static bool classof(const DiagnosticInfo *DI) {
100 return DI->getKind() == DK_MachineOptimizationRemarkMissed;
101 }
102
103 /// \see DiagnosticInfoOptimizationBase::isEnabled.
104 bool isEnabled() 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.
112class MachineOptimizationRemarkAnalysis : public DiagnosticInfoMIROptimization {
113public:
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 MachineOptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName,
120 const DiagnosticLocation &Loc,
121 const MachineBasicBlock *MBB)
122 : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis,
123 PassName, RemarkName, Loc, MBB) {}
124
125 MachineOptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName,
126 const MachineInstr *MI)
127 : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis,
128 PassName, RemarkName, MI->getDebugLoc(),
129 MI->getParent()) {}
130
131 static bool classof(const DiagnosticInfo *DI) {
132 return DI->getKind() == DK_MachineOptimizationRemarkAnalysis;
133 }
134
135 /// \see DiagnosticInfoOptimizationBase::isEnabled.
136 bool isEnabled() 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.
144namespace ore {
145using 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.
154class MachineOptimizationRemarkEmitter {
155public:
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.
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(OptDiag&: (DiagnosticInfoOptimizationBase &)R);
199 }
200 }
201
202 MachineBlockFrequencyInfo *getBFI() {
203 return MBFI;
204 }
205
206private:
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).
221 bool shouldEmitVerbose() { return MBFI != nullptr; }
222};
223
224/// The analysis pass
225class MachineOptimizationRemarkEmitterAnalysis
226 : public AnalysisInfoMixin<MachineOptimizationRemarkEmitterAnalysis> {
227 friend AnalysisInfoMixin<MachineOptimizationRemarkEmitterAnalysis>;
228 LLVM_ABI static AnalysisKey Key;
229
230public:
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.
241class LLVM_ABI MachineOptimizationRemarkEmitterPass
242 : public MachineFunctionPass {
243 std::unique_ptr<MachineOptimizationRemarkEmitter> ORE;
244
245public:
246 MachineOptimizationRemarkEmitterPass();
247
248 bool runOnMachineFunction(MachineFunction &MF) override;
249
250 void getAnalysisUsage(AnalysisUsage &AU) const override;
251
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

source code of llvm/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h