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