1 | //===- llvm/IR/PassInstrumentation.h ----------------------*- C++ -*-===// |
2 | // |
3 | // The LLVM Compiler Infrastructure |
4 | // |
5 | // This file is distributed under the University of Illinois Open Source |
6 | // License. See LICENSE.TXT for details. |
7 | // |
8 | //===----------------------------------------------------------------------===// |
9 | /// \file |
10 | /// |
11 | /// This file defines the Pass Instrumentation classes that provide |
12 | /// instrumentation points into the pass execution by PassManager. |
13 | /// |
14 | /// There are two main classes: |
15 | /// - PassInstrumentation provides a set of instrumentation points for |
16 | /// pass managers to call on. |
17 | /// |
18 | /// - PassInstrumentationCallbacks registers callbacks and provides access |
19 | /// to them for PassInstrumentation. |
20 | /// |
21 | /// PassInstrumentation object is being used as a result of |
22 | /// PassInstrumentationAnalysis (so it is intended to be easily copyable). |
23 | /// |
24 | /// Intended scheme of use for Pass Instrumentation is as follows: |
25 | /// - register instrumentation callbacks in PassInstrumentationCallbacks |
26 | /// instance. PassBuilder provides helper for that. |
27 | /// |
28 | /// - register PassInstrumentationAnalysis with all the PassManagers. |
29 | /// PassBuilder handles that automatically when registering analyses. |
30 | /// |
31 | /// - Pass Manager requests PassInstrumentationAnalysis from analysis manager |
32 | /// and gets PassInstrumentation as its result. |
33 | /// |
34 | /// - Pass Manager invokes PassInstrumentation entry points appropriately, |
35 | /// passing StringRef identification ("name") of the pass currently being |
36 | /// executed and IRUnit it works on. There can be different schemes of |
37 | /// providing names in future, currently it is just a name() of the pass. |
38 | /// |
39 | /// - PassInstrumentation wraps address of IRUnit into llvm::Any and passes |
40 | /// control to all the registered callbacks. Note that we specifically wrap |
41 | /// 'const IRUnitT*' so as to avoid any accidental changes to IR in |
42 | /// instrumenting callbacks. |
43 | /// |
44 | /// - Some instrumentation points (BeforePass) allow to control execution |
45 | /// of a pass. For those callbacks returning false means pass will not be |
46 | /// executed. |
47 | /// |
48 | /// TODO: currently there is no way for a pass to opt-out of execution control |
49 | /// (e.g. become unskippable). PassManager is the only entity that determines |
50 | /// how pass instrumentation affects pass execution. |
51 | /// |
52 | //===----------------------------------------------------------------------===// |
53 | |
54 | #ifndef LLVM_IR_PASSINSTRUMENTATION_H |
55 | #define LLVM_IR_PASSINSTRUMENTATION_H |
56 | |
57 | #include "llvm/ADT/Any.h" |
58 | #include "llvm/ADT/FunctionExtras.h" |
59 | #include "llvm/ADT/SmallVector.h" |
60 | #include "llvm/Support/TypeName.h" |
61 | #include <type_traits> |
62 | |
63 | namespace llvm { |
64 | |
65 | class PreservedAnalyses; |
66 | |
67 | /// This class manages callbacks registration, as well as provides a way for |
68 | /// PassInstrumentation to pass control to the registered callbacks. |
69 | class PassInstrumentationCallbacks { |
70 | public: |
71 | // Before/After callbacks accept IRUnits whenever appropriate, so they need |
72 | // to take them as constant pointers, wrapped with llvm::Any. |
73 | // For the case when IRUnit has been invalidated there is a different |
74 | // callback to use - AfterPassInvalidated. |
75 | // TODO: currently AfterPassInvalidated does not accept IRUnit, since passing |
76 | // already invalidated IRUnit is unsafe. There are ways to handle invalidated IRUnits |
77 | // in a safe way, and we might pursue that as soon as there is a useful instrumentation |
78 | // that needs it. |
79 | using BeforePassFunc = bool(StringRef, Any); |
80 | using AfterPassFunc = void(StringRef, Any); |
81 | using AfterPassInvalidatedFunc = void(StringRef); |
82 | using BeforeAnalysisFunc = void(StringRef, Any); |
83 | using AfterAnalysisFunc = void(StringRef, Any); |
84 | |
85 | public: |
86 | PassInstrumentationCallbacks() {} |
87 | |
88 | /// Copying PassInstrumentationCallbacks is not intended. |
89 | PassInstrumentationCallbacks(const PassInstrumentationCallbacks &) = delete; |
90 | void operator=(const PassInstrumentationCallbacks &) = delete; |
91 | |
92 | template <typename CallableT> void registerBeforePassCallback(CallableT C) { |
93 | BeforePassCallbacks.emplace_back(std::move(C)); |
94 | } |
95 | |
96 | template <typename CallableT> void registerAfterPassCallback(CallableT C) { |
97 | AfterPassCallbacks.emplace_back(std::move(C)); |
98 | } |
99 | |
100 | template <typename CallableT> |
101 | void registerAfterPassInvalidatedCallback(CallableT C) { |
102 | AfterPassInvalidatedCallbacks.emplace_back(std::move(C)); |
103 | } |
104 | |
105 | template <typename CallableT> |
106 | void registerBeforeAnalysisCallback(CallableT C) { |
107 | BeforeAnalysisCallbacks.emplace_back(std::move(C)); |
108 | } |
109 | |
110 | template <typename CallableT> |
111 | void registerAfterAnalysisCallback(CallableT C) { |
112 | AfterAnalysisCallbacks.emplace_back(std::move(C)); |
113 | } |
114 | |
115 | private: |
116 | friend class PassInstrumentation; |
117 | |
118 | SmallVector<llvm::unique_function<BeforePassFunc>, 4> BeforePassCallbacks; |
119 | SmallVector<llvm::unique_function<AfterPassFunc>, 4> AfterPassCallbacks; |
120 | SmallVector<llvm::unique_function<AfterPassInvalidatedFunc>, 4> |
121 | AfterPassInvalidatedCallbacks; |
122 | SmallVector<llvm::unique_function<BeforeAnalysisFunc>, 4> |
123 | BeforeAnalysisCallbacks; |
124 | SmallVector<llvm::unique_function<AfterAnalysisFunc>, 4> |
125 | AfterAnalysisCallbacks; |
126 | }; |
127 | |
128 | /// This class provides instrumentation entry points for the Pass Manager, |
129 | /// doing calls to callbacks registered in PassInstrumentationCallbacks. |
130 | class PassInstrumentation { |
131 | PassInstrumentationCallbacks *Callbacks; |
132 | |
133 | public: |
134 | /// Callbacks object is not owned by PassInstrumentation, its life-time |
135 | /// should at least match the life-time of corresponding |
136 | /// PassInstrumentationAnalysis (which usually is till the end of current |
137 | /// compilation). |
138 | PassInstrumentation(PassInstrumentationCallbacks *CB = nullptr) |
139 | : Callbacks(CB) {} |
140 | |
141 | /// BeforePass instrumentation point - takes \p Pass instance to be executed |
142 | /// and constant reference to IR it operates on. \Returns true if pass is |
143 | /// allowed to be executed. |
144 | template <typename IRUnitT, typename PassT> |
145 | bool runBeforePass(const PassT &Pass, const IRUnitT &IR) const { |
146 | if (!Callbacks) |
147 | return true; |
148 | |
149 | bool ShouldRun = true; |
150 | for (auto &C : Callbacks->BeforePassCallbacks) |
151 | ShouldRun &= C(Pass.name(), llvm::Any(&IR)); |
152 | return ShouldRun; |
153 | } |
154 | |
155 | /// AfterPass instrumentation point - takes \p Pass instance that has |
156 | /// just been executed and constant reference to \p IR it operates on. |
157 | /// \p IR is guaranteed to be valid at this point. |
158 | template <typename IRUnitT, typename PassT> |
159 | void runAfterPass(const PassT &Pass, const IRUnitT &IR) const { |
160 | if (Callbacks) |
161 | for (auto &C : Callbacks->AfterPassCallbacks) |
162 | C(Pass.name(), llvm::Any(&IR)); |
163 | } |
164 | |
165 | /// AfterPassInvalidated instrumentation point - takes \p Pass instance |
166 | /// that has just been executed. For use when IR has been invalidated |
167 | /// by \p Pass execution. |
168 | template <typename IRUnitT, typename PassT> |
169 | void runAfterPassInvalidated(const PassT &Pass) const { |
170 | if (Callbacks) |
171 | for (auto &C : Callbacks->AfterPassInvalidatedCallbacks) |
172 | C(Pass.name()); |
173 | } |
174 | |
175 | /// BeforeAnalysis instrumentation point - takes \p Analysis instance |
176 | /// to be executed and constant reference to IR it operates on. |
177 | template <typename IRUnitT, typename PassT> |
178 | void runBeforeAnalysis(const PassT &Analysis, const IRUnitT &IR) const { |
179 | if (Callbacks) |
180 | for (auto &C : Callbacks->BeforeAnalysisCallbacks) |
181 | C(Analysis.name(), llvm::Any(&IR)); |
182 | } |
183 | |
184 | /// AfterAnalysis instrumentation point - takes \p Analysis instance |
185 | /// that has just been executed and constant reference to IR it operated on. |
186 | template <typename IRUnitT, typename PassT> |
187 | void runAfterAnalysis(const PassT &Analysis, const IRUnitT &IR) const { |
188 | if (Callbacks) |
189 | for (auto &C : Callbacks->AfterAnalysisCallbacks) |
190 | C(Analysis.name(), llvm::Any(&IR)); |
191 | } |
192 | |
193 | /// Handle invalidation from the pass manager when PassInstrumentation |
194 | /// is used as the result of PassInstrumentationAnalysis. |
195 | /// |
196 | /// On attempt to invalidate just return false. There is nothing to become |
197 | /// invalid here. |
198 | template <typename IRUnitT, typename... ExtraArgsT> |
199 | bool invalidate(IRUnitT &, const class llvm::PreservedAnalyses &, |
200 | ExtraArgsT...) { |
201 | return false; |
202 | } |
203 | }; |
204 | |
205 | } // namespace llvm |
206 | |
207 | #endif |
208 | |