Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 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 LLVM_ANALYSIS_OPTIMIZATIONREMARKEMITTER_H |
||
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 OptimizationRemarkEmitter { |
||
34 | public: |
||
35 | OptimizationRemarkEmitter(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 | OptimizationRemarkEmitter(const Function *F); |
||
50 | |||
51 | OptimizationRemarkEmitter(OptimizationRemarkEmitter &&Arg) |
||
52 | : F(Arg.F), BFI(Arg.BFI) {} |
||
53 | |||
54 | OptimizationRemarkEmitter &operator=(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 invalidate(Function &F, const PreservedAnalyses &PA, |
||
62 | FunctionAnalysisManager::Invalidator &Inv); |
||
63 | |||
64 | /// Return true iff at least *some* remarks are enabled. |
||
65 | bool enabled() 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 emit(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 emit(T RemarkBuilder, 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((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 allowExtraAnalysis(StringRef PassName) const { |
||
99 | return OptimizationRemarkEmitter::allowExtraAnalysis(*F, PassName); |
||
100 | } |
||
101 | static bool allowExtraAnalysis(const Function &F, StringRef PassName) { |
||
102 | return allowExtraAnalysis(F.getContext(), PassName); |
||
103 | } |
||
104 | static bool allowExtraAnalysis(LLVMContext &Ctx, StringRef PassName) { |
||
105 | return Ctx.getLLVMRemarkStreamer() || |
||
106 | Ctx.getDiagHandlerPtr()->isAnyRemarkEnabled(PassName); |
||
107 | } |
||
108 | |||
109 | private: |
||
110 | const Function *F; |
||
111 | |||
112 | BlockFrequencyInfo *BFI; |
||
113 | |||
114 | /// If we generate BFI on demand, we need to free it when ORE is freed. |
||
115 | std::unique_ptr<BlockFrequencyInfo> OwnedBFI; |
||
116 | |||
117 | /// Compute hotness from IR value (currently assumed to be a block) if PGO is |
||
118 | /// available. |
||
119 | std::optional<uint64_t> computeHotness(const Value *V); |
||
120 | |||
121 | /// Similar but use value from \p OptDiag and update hotness there. |
||
122 | void computeHotness(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 shouldEmitVerbose() { return BFI != nullptr; } |
||
127 | |||
128 | OptimizationRemarkEmitter(const OptimizationRemarkEmitter &) = delete; |
||
129 | void operator=(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 setExtraArgs = 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 OptimizationRemarkEmitterWrapperPass : public FunctionPass { |
||
147 | std::unique_ptr<OptimizationRemarkEmitter> ORE; |
||
148 | |||
149 | public: |
||
150 | OptimizationRemarkEmitterWrapperPass(); |
||
151 | |||
152 | bool runOnFunction(Function &F) override; |
||
153 | |||
154 | void getAnalysisUsage(AnalysisUsage &AU) const override; |
||
155 | |||
156 | OptimizationRemarkEmitter &getORE() { |
||
157 | assert(ORE && "pass not run yet"); |
||
158 | return *ORE; |
||
159 | } |
||
160 | |||
161 | static char ID; |
||
162 | }; |
||
163 | |||
164 | class OptimizationRemarkEmitterAnalysis |
||
165 | : public AnalysisInfoMixin<OptimizationRemarkEmitterAnalysis> { |
||
166 | friend AnalysisInfoMixin<OptimizationRemarkEmitterAnalysis>; |
||
167 | static AnalysisKey Key; |
||
168 | |||
169 | public: |
||
170 | /// Provide the result typedef for this analysis pass. |
||
171 | typedef OptimizationRemarkEmitter Result; |
||
172 | |||
173 | /// Run the analysis pass over a function and produce BFI. |
||
174 | Result run(Function &F, FunctionAnalysisManager &AM); |
||
175 | }; |
||
176 | } |
||
177 | #endif // LLVM_ANALYSIS_OPTIMIZATIONREMARKEMITTER_H |