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
23namespace llvm {
24class MachineBasicBlock;
25class MachineBlockFrequencyInfo;
26class MachineInstr;
27
28/// Common features for diagnostics dealing with optimization remarks
29/// that are used by machine passes.
30class DiagnosticInfoMIROptimization : public DiagnosticInfoOptimizationBase {
31public:
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
53private:
54 const MachineBasicBlock *MBB;
55};
56
57/// Diagnostic information for applied optimization remarks.
58class MachineOptimizationRemark : public DiagnosticInfoMIROptimization {
59public:
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(PassName: getPassName());
80 }
81};
82
83/// Diagnostic information for missed-optimization remarks.
84class MachineOptimizationRemarkMissed : public DiagnosticInfoMIROptimization {
85public:
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(PassName: getPassName());
106 }
107};
108
109/// Diagnostic information for optimization analysis remarks.
110class MachineOptimizationRemarkAnalysis : public DiagnosticInfoMIROptimization {
111public:
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(PassName: getPassName());
138 }
139};
140
141/// Extend llvm::ore:: with MI-specific helper names.
142namespace ore {
143using 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.
152class MachineOptimizationRemarkEmitter {
153public:
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(OptDiag&: (DiagnosticInfoOptimizationBase &)R);
190 }
191 }
192
193 MachineBlockFrequencyInfo *getBFI() {
194 return MBFI;
195 }
196
197private:
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.
220class MachineOptimizationRemarkEmitterPass : public MachineFunctionPass {
221 std::unique_ptr<MachineOptimizationRemarkEmitter> ORE;
222
223public:
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
240

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