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