xref: /freebsd/contrib/llvm-project/llvm/include/llvm/CodeGen/MachineOptimizationRemarkEmitter.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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 <optional>
23 
24 namespace llvm {
25 class MachineBasicBlock;
26 class MachineBlockFrequencyInfo;
27 class MachineInstr;
28 
29 /// Common features for diagnostics dealing with optimization remarks
30 /// that are used by machine passes.
31 class DiagnosticInfoMIROptimization : public DiagnosticInfoOptimizationBase {
32 public:
DiagnosticInfoMIROptimization(enum DiagnosticKind Kind,const char * PassName,StringRef RemarkName,const DiagnosticLocation & Loc,const MachineBasicBlock * MBB)33   DiagnosticInfoMIROptimization(enum DiagnosticKind Kind, const char *PassName,
34                                 StringRef RemarkName,
35                                 const DiagnosticLocation &Loc,
36                                 const MachineBasicBlock *MBB)
37       : DiagnosticInfoOptimizationBase(Kind, DS_Remark, PassName, RemarkName,
38                                        MBB->getParent()->getFunction(), Loc),
39         MBB(MBB) {}
40 
41   /// MI-specific kinds of diagnostic Arguments.
42   struct MachineArgument : public DiagnosticInfoOptimizationBase::Argument {
43     /// Print an entire MachineInstr.
44     MachineArgument(StringRef Key, const MachineInstr &MI);
45   };
46 
classof(const DiagnosticInfo * DI)47   static bool classof(const DiagnosticInfo *DI) {
48     return DI->getKind() >= DK_FirstMachineRemark &&
49            DI->getKind() <= DK_LastMachineRemark;
50   }
51 
getBlock()52   const MachineBasicBlock *getBlock() const { return MBB; }
53 
54 private:
55   const MachineBasicBlock *MBB;
56 };
57 
58 /// Diagnostic information for applied optimization remarks.
59 class MachineOptimizationRemark : public DiagnosticInfoMIROptimization {
60 public:
61   /// \p PassName is the name of the pass emitting this diagnostic. If this name
62   /// matches the regular expression given in -Rpass=, then the diagnostic will
63   /// be emitted.  \p RemarkName is a textual identifier for the remark.  \p
64   /// Loc is the debug location and \p MBB is the block that the optimization
65   /// operates in.
MachineOptimizationRemark(const char * PassName,StringRef RemarkName,const DiagnosticLocation & Loc,const MachineBasicBlock * MBB)66   MachineOptimizationRemark(const char *PassName, StringRef RemarkName,
67                             const DiagnosticLocation &Loc,
68                             const MachineBasicBlock *MBB)
69       : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemark, PassName,
70                                       RemarkName, Loc, MBB) {}
71 
classof(const DiagnosticInfo * DI)72   static bool classof(const DiagnosticInfo *DI) {
73     return DI->getKind() == DK_MachineOptimizationRemark;
74   }
75 
76   /// \see DiagnosticInfoOptimizationBase::isEnabled.
isEnabled()77   bool isEnabled() const override {
78     const Function &Fn = getFunction();
79     LLVMContext &Ctx = Fn.getContext();
80     return Ctx.getDiagHandlerPtr()->isPassedOptRemarkEnabled(getPassName());
81   }
82 };
83 
84 /// Diagnostic information for missed-optimization remarks.
85 class MachineOptimizationRemarkMissed : public DiagnosticInfoMIROptimization {
86 public:
87   /// \p PassName is the name of the pass emitting this diagnostic. If this name
88   /// matches the regular expression given in -Rpass-missed=, then the
89   /// diagnostic will be emitted.  \p RemarkName is a textual identifier for the
90   /// remark.  \p Loc is the debug location and \p MBB is the block that the
91   /// optimization operates in.
MachineOptimizationRemarkMissed(const char * PassName,StringRef RemarkName,const DiagnosticLocation & Loc,const MachineBasicBlock * MBB)92   MachineOptimizationRemarkMissed(const char *PassName, StringRef RemarkName,
93                                   const DiagnosticLocation &Loc,
94                                   const MachineBasicBlock *MBB)
95       : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkMissed,
96                                       PassName, RemarkName, Loc, MBB) {}
97 
classof(const DiagnosticInfo * DI)98   static bool classof(const DiagnosticInfo *DI) {
99     return DI->getKind() == DK_MachineOptimizationRemarkMissed;
100   }
101 
102   /// \see DiagnosticInfoOptimizationBase::isEnabled.
isEnabled()103   bool isEnabled() const override {
104     const Function &Fn = getFunction();
105     LLVMContext &Ctx = Fn.getContext();
106     return Ctx.getDiagHandlerPtr()->isMissedOptRemarkEnabled(getPassName());
107   }
108 };
109 
110 /// Diagnostic information for optimization analysis remarks.
111 class MachineOptimizationRemarkAnalysis : public DiagnosticInfoMIROptimization {
112 public:
113   /// \p PassName is the name of the pass emitting this diagnostic. If this name
114   /// matches the regular expression given in -Rpass-analysis=, then the
115   /// diagnostic will be emitted.  \p RemarkName is a textual identifier for the
116   /// remark.  \p Loc is the debug location and \p MBB is the block that the
117   /// optimization operates in.
MachineOptimizationRemarkAnalysis(const char * PassName,StringRef RemarkName,const DiagnosticLocation & Loc,const MachineBasicBlock * MBB)118   MachineOptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName,
119                                     const DiagnosticLocation &Loc,
120                                     const MachineBasicBlock *MBB)
121       : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis,
122                                       PassName, RemarkName, Loc, MBB) {}
123 
MachineOptimizationRemarkAnalysis(const char * PassName,StringRef RemarkName,const MachineInstr * MI)124   MachineOptimizationRemarkAnalysis(const char *PassName, StringRef RemarkName,
125                                     const MachineInstr *MI)
126       : DiagnosticInfoMIROptimization(DK_MachineOptimizationRemarkAnalysis,
127                                       PassName, RemarkName, MI->getDebugLoc(),
128                                       MI->getParent()) {}
129 
classof(const DiagnosticInfo * DI)130   static bool classof(const DiagnosticInfo *DI) {
131     return DI->getKind() == DK_MachineOptimizationRemarkAnalysis;
132   }
133 
134   /// \see DiagnosticInfoOptimizationBase::isEnabled.
isEnabled()135   bool isEnabled() const override {
136     const Function &Fn = getFunction();
137     LLVMContext &Ctx = Fn.getContext();
138     return Ctx.getDiagHandlerPtr()->isAnalysisRemarkEnabled(getPassName());
139   }
140 };
141 
142 /// Extend llvm::ore:: with MI-specific helper names.
143 namespace ore {
144 using MNV = DiagnosticInfoMIROptimization::MachineArgument;
145 }
146 
147 /// The optimization diagnostic interface.
148 ///
149 /// It allows reporting when optimizations are performed and when they are not
150 /// along with the reasons for it.  Hotness information of the corresponding
151 /// code region can be included in the remark if DiagnosticsHotnessRequested is
152 /// enabled in the LLVM context.
153 class MachineOptimizationRemarkEmitter {
154 public:
MachineOptimizationRemarkEmitter(MachineFunction & MF,MachineBlockFrequencyInfo * MBFI)155   MachineOptimizationRemarkEmitter(MachineFunction &MF,
156                                    MachineBlockFrequencyInfo *MBFI)
157       : MF(MF), MBFI(MBFI) {}
158 
159   MachineOptimizationRemarkEmitter(MachineOptimizationRemarkEmitter &&) =
160       default;
161 
162   /// Handle invalidation events in the new pass manager.
163   bool invalidate(MachineFunction &MF, const PreservedAnalyses &PA,
164                   MachineFunctionAnalysisManager::Invalidator &Inv);
165 
166   /// Emit an optimization remark.
167   void emit(DiagnosticInfoOptimizationBase &OptDiag);
168 
169   /// Whether we allow for extra compile-time budget to perform more
170   /// analysis to be more informative.
171   ///
172   /// This is useful to enable additional missed optimizations to be reported
173   /// that are normally too noisy.  In this mode, we can use the extra analysis
174   /// (1) to filter trivial false positives or (2) to provide more context so
175   /// that non-trivial false positives can be quickly detected by the user.
allowExtraAnalysis(StringRef PassName)176   bool allowExtraAnalysis(StringRef PassName) const {
177     return (
178         MF.getFunction().getContext().getLLVMRemarkStreamer() ||
179         MF.getFunction().getContext().getDiagHandlerPtr()->isAnyRemarkEnabled(
180             PassName));
181   }
182 
183   /// Take a lambda that returns a remark which will be emitted.  Second
184   /// argument is only used to restrict this to functions.
185   template <typename T>
186   void emit(T RemarkBuilder, decltype(RemarkBuilder()) * = nullptr) {
187     // Avoid building the remark unless we know there are at least *some*
188     // remarks enabled. We can't currently check whether remarks are requested
189     // for the calling pass since that requires actually building the remark.
190 
191     if (MF.getFunction().getContext().getLLVMRemarkStreamer() ||
192         MF.getFunction()
193             .getContext()
194             .getDiagHandlerPtr()
195             ->isAnyRemarkEnabled()) {
196       auto R = RemarkBuilder();
197       emit((DiagnosticInfoOptimizationBase &)R);
198     }
199   }
200 
getBFI()201   MachineBlockFrequencyInfo *getBFI() {
202     return MBFI;
203   }
204 
205 private:
206   MachineFunction &MF;
207 
208   /// MBFI is only set if hotness is requested.
209   MachineBlockFrequencyInfo *MBFI;
210 
211   /// Compute hotness from IR value (currently assumed to be a block) if PGO is
212   /// available.
213   std::optional<uint64_t> computeHotness(const MachineBasicBlock &MBB);
214 
215   /// Similar but use value from \p OptDiag and update hotness there.
216   void computeHotness(DiagnosticInfoMIROptimization &Remark);
217 
218   /// Only allow verbose messages if we know we're filtering by hotness
219   /// (BFI is only set in this case).
shouldEmitVerbose()220   bool shouldEmitVerbose() { return MBFI != nullptr; }
221 };
222 
223 /// The analysis pass
224 class MachineOptimizationRemarkEmitterAnalysis
225     : public AnalysisInfoMixin<MachineOptimizationRemarkEmitterAnalysis> {
226   friend AnalysisInfoMixin<MachineOptimizationRemarkEmitterAnalysis>;
227   static AnalysisKey Key;
228 
229 public:
230   using Result = MachineOptimizationRemarkEmitter;
231   Result run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM);
232 };
233 
234 /// The analysis pass
235 ///
236 /// Note that this pass shouldn't generally be marked as preserved by other
237 /// passes.  It's holding onto BFI, so if the pass does not preserve BFI, BFI
238 /// could be freed.
239 class MachineOptimizationRemarkEmitterPass : public MachineFunctionPass {
240   std::unique_ptr<MachineOptimizationRemarkEmitter> ORE;
241 
242 public:
243   MachineOptimizationRemarkEmitterPass();
244 
245   bool runOnMachineFunction(MachineFunction &MF) override;
246 
247   void getAnalysisUsage(AnalysisUsage &AU) const override;
248 
getORE()249   MachineOptimizationRemarkEmitter &getORE() {
250     assert(ORE && "pass not run yet");
251     return *ORE;
252   }
253 
254   static char ID;
255 };
256 }
257 
258 #endif
259