xref: /freebsd/contrib/llvm-project/llvm/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
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:
DiagnosticInfoMIROptimization(enum DiagnosticKind Kind,const char * PassName,StringRef RemarkName,const DiagnosticLocation & Loc,const MachineBasicBlock * MBB)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 
classof(const DiagnosticInfo * DI)48   static bool classof(const DiagnosticInfo *DI) {
49     return DI->getKind() >= DK_FirstMachineRemark &&
50            DI->getKind() <= DK_LastMachineRemark;
51   }
52 
getBlock()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 MachineOptimizationRemark : 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.
MachineOptimizationRemark(const char * PassName,StringRef RemarkName,const DiagnosticLocation & Loc,const MachineBasicBlock * MBB)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 
classof(const DiagnosticInfo * DI)73   static bool classof(const DiagnosticInfo *DI) {
74     return DI->getKind() == DK_MachineOptimizationRemark;
75   }
76 
77   /// \see DiagnosticInfoOptimizationBase::isEnabled.
isEnabled()78   bool isEnabled() const override {
79     const Function &Fn = getFunction();
80     LLVMContext &Ctx = Fn.getContext();
81     return Ctx.getDiagHandlerPtr()->isPassedOptRemarkEnabled(getPassName());
82   }
83 };
84 
85 /// Diagnostic information for missed-optimization remarks.
86 class MachineOptimizationRemarkMissed : 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.
MachineOptimizationRemarkMissed(const char * PassName,StringRef RemarkName,const DiagnosticLocation & Loc,const MachineBasicBlock * MBB)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 
classof(const DiagnosticInfo * DI)99   static bool classof(const DiagnosticInfo *DI) {
100     return DI->getKind() == DK_MachineOptimizationRemarkMissed;
101   }
102 
103   /// \see DiagnosticInfoOptimizationBase::isEnabled.
isEnabled()104   bool isEnabled() const override {
105     const Function &Fn = getFunction();
106     LLVMContext &Ctx = Fn.getContext();
107     return Ctx.getDiagHandlerPtr()->isMissedOptRemarkEnabled(getPassName());
108   }
109 };
110 
111 /// Diagnostic information for optimization analysis remarks.
112 class MachineOptimizationRemarkAnalysis : 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.
MachineOptimizationRemarkAnalysis(const char * PassName,StringRef RemarkName,const DiagnosticLocation & Loc,const MachineBasicBlock * MBB)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 
MachineOptimizationRemarkAnalysis(const char * PassName,StringRef RemarkName,const MachineInstr * MI)125   MachineOptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName,
126                                     const MachineInstr *MI)
127       : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis,
128                                       PassName, RemarkName, MI->getDebugLoc(),
129                                       MI->getParent()) {}
130 
classof(const DiagnosticInfo * DI)131   static bool classof(const DiagnosticInfo *DI) {
132     return DI->getKind() == DK_MachineOptimizationRemarkAnalysis;
133   }
134 
135   /// \see DiagnosticInfoOptimizationBase::isEnabled.
isEnabled()136   bool isEnabled() const override {
137     const Function &Fn = getFunction();
138     LLVMContext &Ctx = Fn.getContext();
139     return Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(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 MachineOptimizationRemarkEmitter {
155 public:
MachineOptimizationRemarkEmitter(MachineFunction & MF,MachineBlockFrequencyInfo * MBFI)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.
allowExtraAnalysis(StringRef PassName)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((DiagnosticInfoOptimizationBase &)R);
199     }
200   }
201 
getBFI()202   MachineBlockFrequencyInfo *getBFI() {
203     return MBFI;
204   }
205 
206 private:
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).
shouldEmitVerbose()221   bool shouldEmitVerbose() { return MBFI != nullptr; }
222 };
223 
224 /// The analysis pass
225 class MachineOptimizationRemarkEmitterAnalysis
226     : public AnalysisInfoMixin<MachineOptimizationRemarkEmitterAnalysis> {
227   friend AnalysisInfoMixin<MachineOptimizationRemarkEmitterAnalysis>;
228   LLVM_ABI static AnalysisKey Key;
229 
230 public:
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.
241 class LLVM_ABI MachineOptimizationRemarkEmitterPass
242     : public MachineFunctionPass {
243   std::unique_ptr<MachineOptimizationRemarkEmitter> ORE;
244 
245 public:
246   MachineOptimizationRemarkEmitterPass();
247 
248   bool runOnMachineFunction(MachineFunction &MF) override;
249 
250   void getAnalysisUsage(AnalysisUsage &AU) const override;
251 
getORE()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