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 "llvm/Support/TypeName.h" 60 #include <type_traits> 61 62 namespace llvm { 63 64 class PreservedAnalyses; 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