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