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
63namespace llvm {
64
65class PreservedAnalyses;
66
67/// This class manages callbacks registration, as well as provides a way for
68/// PassInstrumentation to pass control to the registered callbacks.
69class PassInstrumentationCallbacks {
70public:
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
85public:
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
115private:
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.
130class PassInstrumentation {
131 PassInstrumentationCallbacks *Callbacks;
132
133public:
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