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