1 | //===- OptimizationRemarkEmitter.h - Optimization Diagnostic ----*- 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 | // |
9 | // Optimization diagnostic interfaces. It's packaged as an analysis pass so |
10 | // that by using this service passes become dependent on BFI as well. BFI is |
11 | // used to compute the "hotness" of the diagnostic message. |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_ANALYSIS_OPTIMIZATIONREMARKEMITTER_H |
15 | #define |
16 | |
17 | #include "llvm/Analysis/BlockFrequencyInfo.h" |
18 | #include "llvm/IR/DiagnosticInfo.h" |
19 | #include "llvm/IR/PassManager.h" |
20 | #include "llvm/Pass.h" |
21 | #include <optional> |
22 | |
23 | namespace llvm { |
24 | class Function; |
25 | class Value; |
26 | |
27 | /// The optimization diagnostic interface. |
28 | /// |
29 | /// It allows reporting when optimizations are performed and when they are not |
30 | /// along with the reasons for it. Hotness information of the corresponding |
31 | /// code region can be included in the remark if DiagnosticsHotnessRequested is |
32 | /// enabled in the LLVM context. |
33 | class { |
34 | public: |
35 | (const Function *F, BlockFrequencyInfo *BFI) |
36 | : F(F), BFI(BFI) {} |
37 | |
38 | /// This variant can be used to generate ORE on demand (without the |
39 | /// analysis pass). |
40 | /// |
41 | /// Note that this ctor has a very different cost depending on whether |
42 | /// F->getContext().getDiagnosticsHotnessRequested() is on or not. If it's off |
43 | /// the operation is free. |
44 | /// |
45 | /// Whereas if DiagnosticsHotnessRequested is on, it is fairly expensive |
46 | /// operation since BFI and all its required analyses are computed. This is |
47 | /// for example useful for CGSCC passes that can't use function analyses |
48 | /// passes in the old PM. |
49 | (const Function *F); |
50 | |
51 | (OptimizationRemarkEmitter &&Arg) |
52 | : F(Arg.F), BFI(Arg.BFI) {} |
53 | |
54 | OptimizationRemarkEmitter &(OptimizationRemarkEmitter &&RHS) { |
55 | F = RHS.F; |
56 | BFI = RHS.BFI; |
57 | return *this; |
58 | } |
59 | |
60 | /// Handle invalidation events in the new pass manager. |
61 | bool (Function &F, const PreservedAnalyses &PA, |
62 | FunctionAnalysisManager::Invalidator &Inv); |
63 | |
64 | /// Return true iff at least *some* remarks are enabled. |
65 | bool () const { |
66 | return F->getContext().getLLVMRemarkStreamer() || |
67 | F->getContext().getDiagHandlerPtr()->isAnyRemarkEnabled(); |
68 | } |
69 | |
70 | /// Output the remark via the diagnostic handler and to the |
71 | /// optimization record file. |
72 | void (DiagnosticInfoOptimizationBase &OptDiag); |
73 | |
74 | /// Take a lambda that returns a remark which will be emitted. Second |
75 | /// argument is only used to restrict this to functions. |
76 | template <typename T> |
77 | void (T , decltype(RemarkBuilder()) * = nullptr) { |
78 | // Avoid building the remark unless we know there are at least *some* |
79 | // remarks enabled. We can't currently check whether remarks are requested |
80 | // for the calling pass since that requires actually building the remark. |
81 | |
82 | if (enabled()) { |
83 | auto R = RemarkBuilder(); |
84 | static_assert( |
85 | std::is_base_of<DiagnosticInfoOptimizationBase, decltype(R)>::value, |
86 | "the lambda passed to emit() must return a remark" ); |
87 | emit(OptDiag&: (DiagnosticInfoOptimizationBase &)R); |
88 | } |
89 | } |
90 | |
91 | /// Whether we allow for extra compile-time budget to perform more |
92 | /// analysis to produce fewer false positives. |
93 | /// |
94 | /// This is useful when reporting missed optimizations. In this case we can |
95 | /// use the extra analysis (1) to filter trivial false positives or (2) to |
96 | /// provide more context so that non-trivial false positives can be quickly |
97 | /// detected by the user. |
98 | bool (StringRef PassName) const { |
99 | return OptimizationRemarkEmitter::allowExtraAnalysis(F: *F, PassName); |
100 | } |
101 | static bool (const Function &F, StringRef PassName) { |
102 | return allowExtraAnalysis(Ctx&: F.getContext(), PassName); |
103 | } |
104 | static bool (LLVMContext &Ctx, StringRef PassName) { |
105 | return Ctx.getLLVMRemarkStreamer() || |
106 | Ctx.getDiagHandlerPtr()->isAnyRemarkEnabled(PassName); |
107 | } |
108 | |
109 | private: |
110 | const Function *; |
111 | |
112 | BlockFrequencyInfo *; |
113 | |
114 | /// If we generate BFI on demand, we need to free it when ORE is freed. |
115 | std::unique_ptr<BlockFrequencyInfo> ; |
116 | |
117 | /// Compute hotness from IR value (currently assumed to be a block) if PGO is |
118 | /// available. |
119 | std::optional<uint64_t> (const Value *V); |
120 | |
121 | /// Similar but use value from \p OptDiag and update hotness there. |
122 | void (DiagnosticInfoIROptimization &OptDiag); |
123 | |
124 | /// Only allow verbose messages if we know we're filtering by hotness |
125 | /// (BFI is only set in this case). |
126 | bool () { return BFI != nullptr; } |
127 | |
128 | (const OptimizationRemarkEmitter &) = delete; |
129 | void (const OptimizationRemarkEmitter &) = delete; |
130 | }; |
131 | |
132 | /// Add a small namespace to avoid name clashes with the classes used in |
133 | /// the streaming interface. We want these to be short for better |
134 | /// write/readability. |
135 | namespace ore { |
136 | using NV = DiagnosticInfoOptimizationBase::Argument; |
137 | using setIsVerbose = DiagnosticInfoOptimizationBase::setIsVerbose; |
138 | using = DiagnosticInfoOptimizationBase::setExtraArgs; |
139 | } |
140 | |
141 | /// OptimizationRemarkEmitter legacy analysis pass |
142 | /// |
143 | /// Note that this pass shouldn't generally be marked as preserved by other |
144 | /// passes. It's holding onto BFI, so if the pass does not preserve BFI, BFI |
145 | /// could be freed. |
146 | class : public FunctionPass { |
147 | std::unique_ptr<OptimizationRemarkEmitter> ; |
148 | |
149 | public: |
150 | (); |
151 | |
152 | bool (Function &F) override; |
153 | |
154 | void (AnalysisUsage &AU) const override; |
155 | |
156 | OptimizationRemarkEmitter &() { |
157 | assert(ORE && "pass not run yet" ); |
158 | return *ORE; |
159 | } |
160 | |
161 | static char ; |
162 | }; |
163 | |
164 | class |
165 | : public AnalysisInfoMixin<OptimizationRemarkEmitterAnalysis> { |
166 | friend AnalysisInfoMixin<OptimizationRemarkEmitterAnalysis>; |
167 | static AnalysisKey ; |
168 | |
169 | public: |
170 | /// Provide the result typedef for this analysis pass. |
171 | typedef OptimizationRemarkEmitter ; |
172 | |
173 | /// Run the analysis pass over a function and produce BFI. |
174 | Result (Function &F, FunctionAnalysisManager &AM); |
175 | }; |
176 | } |
177 | #endif // LLVM_ANALYSIS_OPTIMIZATIONREMARKEMITTER_H |
178 | |