10b57cec5SDimitry Andric //===- OptimizationRemarkEmitter.h - Optimization Diagnostic ----*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // Optimization diagnostic interfaces.  It's packaged as an analysis pass so
100b57cec5SDimitry Andric // that by using this service passes become dependent on BFI as well.  BFI is
110b57cec5SDimitry Andric // used to compute the "hotness" of the diagnostic message.
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
14fe6060f1SDimitry Andric #ifndef LLVM_ANALYSIS_OPTIMIZATIONREMARKEMITTER_H
15fe6060f1SDimitry Andric #define LLVM_ANALYSIS_OPTIMIZATIONREMARKEMITTER_H
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "llvm/Analysis/BlockFrequencyInfo.h"
180b57cec5SDimitry Andric #include "llvm/IR/DiagnosticInfo.h"
190b57cec5SDimitry Andric #include "llvm/IR/PassManager.h"
200b57cec5SDimitry Andric #include "llvm/Pass.h"
21bdd1243dSDimitry Andric #include <optional>
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric namespace llvm {
245ffd83dbSDimitry Andric class Function;
250b57cec5SDimitry Andric class Value;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric /// The optimization diagnostic interface.
280b57cec5SDimitry Andric ///
290b57cec5SDimitry Andric /// It allows reporting when optimizations are performed and when they are not
300b57cec5SDimitry Andric /// along with the reasons for it.  Hotness information of the corresponding
310b57cec5SDimitry Andric /// code region can be included in the remark if DiagnosticsHotnessRequested is
320b57cec5SDimitry Andric /// enabled in the LLVM context.
330b57cec5SDimitry Andric class OptimizationRemarkEmitter {
340b57cec5SDimitry Andric public:
OptimizationRemarkEmitter(const Function * F,BlockFrequencyInfo * BFI)350b57cec5SDimitry Andric   OptimizationRemarkEmitter(const Function *F, BlockFrequencyInfo *BFI)
360b57cec5SDimitry Andric       : F(F), BFI(BFI) {}
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric   /// This variant can be used to generate ORE on demand (without the
390b57cec5SDimitry Andric   /// analysis pass).
400b57cec5SDimitry Andric   ///
410b57cec5SDimitry Andric   /// Note that this ctor has a very different cost depending on whether
420b57cec5SDimitry Andric   /// F->getContext().getDiagnosticsHotnessRequested() is on or not.  If it's off
430b57cec5SDimitry Andric   /// the operation is free.
440b57cec5SDimitry Andric   ///
450b57cec5SDimitry Andric   /// Whereas if DiagnosticsHotnessRequested is on, it is fairly expensive
460b57cec5SDimitry Andric   /// operation since BFI and all its required analyses are computed.  This is
470b57cec5SDimitry Andric   /// for example useful for CGSCC passes that can't use function analyses
480b57cec5SDimitry Andric   /// passes in the old PM.
490b57cec5SDimitry Andric   OptimizationRemarkEmitter(const Function *F);
500b57cec5SDimitry Andric 
OptimizationRemarkEmitter(OptimizationRemarkEmitter && Arg)510b57cec5SDimitry Andric   OptimizationRemarkEmitter(OptimizationRemarkEmitter &&Arg)
520b57cec5SDimitry Andric       : F(Arg.F), BFI(Arg.BFI) {}
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   OptimizationRemarkEmitter &operator=(OptimizationRemarkEmitter &&RHS) {
550b57cec5SDimitry Andric     F = RHS.F;
560b57cec5SDimitry Andric     BFI = RHS.BFI;
570b57cec5SDimitry Andric     return *this;
580b57cec5SDimitry Andric   }
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric   /// Handle invalidation events in the new pass manager.
610b57cec5SDimitry Andric   bool invalidate(Function &F, const PreservedAnalyses &PA,
620b57cec5SDimitry Andric                   FunctionAnalysisManager::Invalidator &Inv);
630b57cec5SDimitry Andric 
64fe6060f1SDimitry Andric   /// Return true iff at least *some* remarks are enabled.
enabled()65fe6060f1SDimitry Andric   bool enabled() const {
66fe6060f1SDimitry Andric     return F->getContext().getLLVMRemarkStreamer() ||
67fe6060f1SDimitry Andric            F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled();
68fe6060f1SDimitry Andric   }
69fe6060f1SDimitry Andric 
700b57cec5SDimitry Andric   /// Output the remark via the diagnostic handler and to the
710b57cec5SDimitry Andric   /// optimization record file.
720b57cec5SDimitry Andric   void emit(DiagnosticInfoOptimizationBase &OptDiag);
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   /// Take a lambda that returns a remark which will be emitted.  Second
750b57cec5SDimitry Andric   /// argument is only used to restrict this to functions.
760b57cec5SDimitry Andric   template <typename T>
770b57cec5SDimitry Andric   void emit(T RemarkBuilder, decltype(RemarkBuilder()) * = nullptr) {
780b57cec5SDimitry Andric     // Avoid building the remark unless we know there are at least *some*
790b57cec5SDimitry Andric     // remarks enabled. We can't currently check whether remarks are requested
800b57cec5SDimitry Andric     // for the calling pass since that requires actually building the remark.
810b57cec5SDimitry Andric 
82fe6060f1SDimitry Andric     if (enabled()) {
830b57cec5SDimitry Andric       auto R = RemarkBuilder();
84fe6060f1SDimitry Andric       static_assert(
85fe6060f1SDimitry Andric           std::is_base_of<DiagnosticInfoOptimizationBase, decltype(R)>::value,
86fe6060f1SDimitry Andric           "the lambda passed to emit() must return a remark");
870b57cec5SDimitry Andric       emit((DiagnosticInfoOptimizationBase &)R);
880b57cec5SDimitry Andric     }
890b57cec5SDimitry Andric   }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric   /// Whether we allow for extra compile-time budget to perform more
920b57cec5SDimitry Andric   /// analysis to produce fewer false positives.
930b57cec5SDimitry Andric   ///
940b57cec5SDimitry Andric   /// This is useful when reporting missed optimizations.  In this case we can
950b57cec5SDimitry Andric   /// use the extra analysis (1) to filter trivial false positives or (2) to
960b57cec5SDimitry Andric   /// provide more context so that non-trivial false positives can be quickly
970b57cec5SDimitry Andric   /// detected by the user.
allowExtraAnalysis(StringRef PassName)980b57cec5SDimitry Andric   bool allowExtraAnalysis(StringRef PassName) const {
99e8d8bef9SDimitry Andric     return OptimizationRemarkEmitter::allowExtraAnalysis(*F, PassName);
100e8d8bef9SDimitry Andric   }
allowExtraAnalysis(const Function & F,StringRef PassName)101e8d8bef9SDimitry Andric   static bool allowExtraAnalysis(const Function &F, StringRef PassName) {
102e8d8bef9SDimitry Andric     return allowExtraAnalysis(F.getContext(), PassName);
103e8d8bef9SDimitry Andric   }
allowExtraAnalysis(LLVMContext & Ctx,StringRef PassName)104e8d8bef9SDimitry Andric   static bool allowExtraAnalysis(LLVMContext &Ctx, StringRef PassName) {
105e8d8bef9SDimitry Andric     return Ctx.getLLVMRemarkStreamer() ||
106e8d8bef9SDimitry Andric            Ctx.getDiagHandlerPtr()->isAnyRemarkEnabled(PassName);
1070b57cec5SDimitry Andric   }
1080b57cec5SDimitry Andric 
1090b57cec5SDimitry Andric private:
1100b57cec5SDimitry Andric   const Function *F;
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric   BlockFrequencyInfo *BFI;
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   /// If we generate BFI on demand, we need to free it when ORE is freed.
1150b57cec5SDimitry Andric   std::unique_ptr<BlockFrequencyInfo> OwnedBFI;
1160b57cec5SDimitry Andric 
1170b57cec5SDimitry Andric   /// Compute hotness from IR value (currently assumed to be a block) if PGO is
1180b57cec5SDimitry Andric   /// available.
119bdd1243dSDimitry Andric   std::optional<uint64_t> computeHotness(const Value *V);
1200b57cec5SDimitry Andric 
1210b57cec5SDimitry Andric   /// Similar but use value from \p OptDiag and update hotness there.
1220b57cec5SDimitry Andric   void computeHotness(DiagnosticInfoIROptimization &OptDiag);
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric   /// Only allow verbose messages if we know we're filtering by hotness
1250b57cec5SDimitry Andric   /// (BFI is only set in this case).
shouldEmitVerbose()1260b57cec5SDimitry Andric   bool shouldEmitVerbose() { return BFI != nullptr; }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric   OptimizationRemarkEmitter(const OptimizationRemarkEmitter &) = delete;
1290b57cec5SDimitry Andric   void operator=(const OptimizationRemarkEmitter &) = delete;
1300b57cec5SDimitry Andric };
1310b57cec5SDimitry Andric 
1320b57cec5SDimitry Andric /// Add a small namespace to avoid name clashes with the classes used in
1330b57cec5SDimitry Andric /// the streaming interface.  We want these to be short for better
1340b57cec5SDimitry Andric /// write/readability.
1350b57cec5SDimitry Andric namespace ore {
1360b57cec5SDimitry Andric using NV = DiagnosticInfoOptimizationBase::Argument;
1370b57cec5SDimitry Andric using setIsVerbose = DiagnosticInfoOptimizationBase::setIsVerbose;
1380b57cec5SDimitry Andric using setExtraArgs = DiagnosticInfoOptimizationBase::setExtraArgs;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric /// OptimizationRemarkEmitter legacy analysis pass
1420b57cec5SDimitry Andric ///
1430b57cec5SDimitry Andric /// Note that this pass shouldn't generally be marked as preserved by other
1440b57cec5SDimitry Andric /// passes.  It's holding onto BFI, so if the pass does not preserve BFI, BFI
1450b57cec5SDimitry Andric /// could be freed.
1460b57cec5SDimitry Andric class OptimizationRemarkEmitterWrapperPass : public FunctionPass {
1470b57cec5SDimitry Andric   std::unique_ptr<OptimizationRemarkEmitter> ORE;
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric public:
1500b57cec5SDimitry Andric   OptimizationRemarkEmitterWrapperPass();
1510b57cec5SDimitry Andric 
1520b57cec5SDimitry Andric   bool runOnFunction(Function &F) override;
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   void getAnalysisUsage(AnalysisUsage &AU) const override;
1550b57cec5SDimitry Andric 
getORE()1560b57cec5SDimitry Andric   OptimizationRemarkEmitter &getORE() {
1570b57cec5SDimitry Andric     assert(ORE && "pass not run yet");
1580b57cec5SDimitry Andric     return *ORE;
1590b57cec5SDimitry Andric   }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric   static char ID;
1620b57cec5SDimitry Andric };
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric class OptimizationRemarkEmitterAnalysis
1650b57cec5SDimitry Andric     : public AnalysisInfoMixin<OptimizationRemarkEmitterAnalysis> {
1660b57cec5SDimitry Andric   friend AnalysisInfoMixin<OptimizationRemarkEmitterAnalysis>;
1670b57cec5SDimitry Andric   static AnalysisKey Key;
1680b57cec5SDimitry Andric 
1690b57cec5SDimitry Andric public:
1700b57cec5SDimitry Andric   /// Provide the result typedef for this analysis pass.
1710b57cec5SDimitry Andric   typedef OptimizationRemarkEmitter Result;
1720b57cec5SDimitry Andric 
1730b57cec5SDimitry Andric   /// Run the analysis pass over a function and produce BFI.
1740b57cec5SDimitry Andric   Result run(Function &F, FunctionAnalysisManager &AM);
1750b57cec5SDimitry Andric };
1760b57cec5SDimitry Andric }
177fe6060f1SDimitry Andric #endif // LLVM_ANALYSIS_OPTIMIZATIONREMARKEMITTER_H
178