Home | History | Annotate | Line # | Download | only in CodeGen
      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 
     21 namespace llvm {
     22 class MachineBasicBlock;
     23 class MachineBlockFrequencyInfo;
     24 class MachineInstr;
     25 
     26 /// Common features for diagnostics dealing with optimization remarks
     27 /// that are used by machine passes.
     28 class DiagnosticInfoMIROptimization : public DiagnosticInfoOptimizationBase {
     29 public:
     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 
     51 private:
     52   const MachineBasicBlock *MBB;
     53 };
     54 
     55 /// Diagnostic information for applied optimization remarks.
     56 class MachineOptimizationRemark : public DiagnosticInfoMIROptimization {
     57 public:
     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.
     82 class MachineOptimizationRemarkMissed : public DiagnosticInfoMIROptimization {
     83 public:
     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.
    108 class MachineOptimizationRemarkAnalysis : public DiagnosticInfoMIROptimization {
    109 public:
    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.
    134 namespace ore {
    135 using 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.
    144 class MachineOptimizationRemarkEmitter {
    145 public:
    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().getLLVMRemarkStreamer() ||
    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().getLLVMRemarkStreamer() ||
    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 
    189 private:
    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.
    212 class MachineOptimizationRemarkEmitterPass : public MachineFunctionPass {
    213   std::unique_ptr<MachineOptimizationRemarkEmitter> ORE;
    214 
    215 public:
    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