PassInstrumentation.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- llvm/IR/PassInstrumentation.h ----------------------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. /// \file
  14. ///
  15. /// This file defines the Pass Instrumentation classes that provide
  16. /// instrumentation points into the pass execution by PassManager.
  17. ///
  18. /// There are two main classes:
  19. /// - PassInstrumentation provides a set of instrumentation points for
  20. /// pass managers to call on.
  21. ///
  22. /// - PassInstrumentationCallbacks registers callbacks and provides access
  23. /// to them for PassInstrumentation.
  24. ///
  25. /// PassInstrumentation object is being used as a result of
  26. /// PassInstrumentationAnalysis (so it is intended to be easily copyable).
  27. ///
  28. /// Intended scheme of use for Pass Instrumentation is as follows:
  29. /// - register instrumentation callbacks in PassInstrumentationCallbacks
  30. /// instance. PassBuilder provides helper for that.
  31. ///
  32. /// - register PassInstrumentationAnalysis with all the PassManagers.
  33. /// PassBuilder handles that automatically when registering analyses.
  34. ///
  35. /// - Pass Manager requests PassInstrumentationAnalysis from analysis manager
  36. /// and gets PassInstrumentation as its result.
  37. ///
  38. /// - Pass Manager invokes PassInstrumentation entry points appropriately,
  39. /// passing StringRef identification ("name") of the pass currently being
  40. /// executed and IRUnit it works on. There can be different schemes of
  41. /// providing names in future, currently it is just a name() of the pass.
  42. ///
  43. /// - PassInstrumentation wraps address of IRUnit into llvm::Any and passes
  44. /// control to all the registered callbacks. Note that we specifically wrap
  45. /// 'const IRUnitT*' so as to avoid any accidental changes to IR in
  46. /// instrumenting callbacks.
  47. ///
  48. /// - Some instrumentation points (BeforePass) allow to control execution
  49. /// of a pass. For those callbacks returning false means pass will not be
  50. /// executed.
  51. ///
  52. //===----------------------------------------------------------------------===//
  53. #ifndef LLVM_IR_PASSINSTRUMENTATION_H
  54. #define LLVM_IR_PASSINSTRUMENTATION_H
  55. #include "llvm/ADT/Any.h"
  56. #include "llvm/ADT/FunctionExtras.h"
  57. #include "llvm/ADT/SmallVector.h"
  58. #include "llvm/ADT/StringMap.h"
  59. #include <type_traits>
  60. namespace llvm {
  61. class PreservedAnalyses;
  62. class StringRef;
  63. /// This class manages callbacks registration, as well as provides a way for
  64. /// PassInstrumentation to pass control to the registered callbacks.
  65. class PassInstrumentationCallbacks {
  66. public:
  67. // Before/After callbacks accept IRUnits whenever appropriate, so they need
  68. // to take them as constant pointers, wrapped with llvm::Any.
  69. // For the case when IRUnit has been invalidated there is a different
  70. // callback to use - AfterPassInvalidated.
  71. // We call all BeforePassFuncs to determine if a pass should run or not.
  72. // BeforeNonSkippedPassFuncs are called only if the pass should run.
  73. // TODO: currently AfterPassInvalidated does not accept IRUnit, since passing
  74. // already invalidated IRUnit is unsafe. There are ways to handle invalidated
  75. // IRUnits in a safe way, and we might pursue that as soon as there is a
  76. // useful instrumentation that needs it.
  77. using BeforePassFunc = bool(StringRef, Any);
  78. using BeforeSkippedPassFunc = void(StringRef, Any);
  79. using BeforeNonSkippedPassFunc = void(StringRef, Any);
  80. using AfterPassFunc = void(StringRef, Any, const PreservedAnalyses &);
  81. using AfterPassInvalidatedFunc = void(StringRef, const PreservedAnalyses &);
  82. using BeforeAnalysisFunc = void(StringRef, Any);
  83. using AfterAnalysisFunc = void(StringRef, Any);
  84. public:
  85. PassInstrumentationCallbacks() {}
  86. /// Copying PassInstrumentationCallbacks is not intended.
  87. PassInstrumentationCallbacks(const PassInstrumentationCallbacks &) = delete;
  88. void operator=(const PassInstrumentationCallbacks &) = delete;
  89. template <typename CallableT>
  90. void registerShouldRunOptionalPassCallback(CallableT C) {
  91. ShouldRunOptionalPassCallbacks.emplace_back(std::move(C));
  92. }
  93. template <typename CallableT>
  94. void registerBeforeSkippedPassCallback(CallableT C) {
  95. BeforeSkippedPassCallbacks.emplace_back(std::move(C));
  96. }
  97. template <typename CallableT>
  98. void registerBeforeNonSkippedPassCallback(CallableT C) {
  99. BeforeNonSkippedPassCallbacks.emplace_back(std::move(C));
  100. }
  101. template <typename CallableT> void registerAfterPassCallback(CallableT C) {
  102. AfterPassCallbacks.emplace_back(std::move(C));
  103. }
  104. template <typename CallableT>
  105. void registerAfterPassInvalidatedCallback(CallableT C) {
  106. AfterPassInvalidatedCallbacks.emplace_back(std::move(C));
  107. }
  108. template <typename CallableT>
  109. void registerBeforeAnalysisCallback(CallableT C) {
  110. BeforeAnalysisCallbacks.emplace_back(std::move(C));
  111. }
  112. template <typename CallableT>
  113. void registerAfterAnalysisCallback(CallableT C) {
  114. AfterAnalysisCallbacks.emplace_back(std::move(C));
  115. }
  116. /// Add a class name to pass name mapping for use by pass instrumentation.
  117. void addClassToPassName(StringRef ClassName, StringRef PassName);
  118. /// Get the pass name for a given pass class name.
  119. StringRef getPassNameForClassName(StringRef ClassName);
  120. private:
  121. friend class PassInstrumentation;
  122. /// These are only run on passes that are not required. They return false when
  123. /// an optional pass should be skipped.
  124. SmallVector<llvm::unique_function<BeforePassFunc>, 4>
  125. ShouldRunOptionalPassCallbacks;
  126. /// These are run on passes that are skipped.
  127. SmallVector<llvm::unique_function<BeforeSkippedPassFunc>, 4>
  128. BeforeSkippedPassCallbacks;
  129. /// These are run on passes that are about to be run.
  130. SmallVector<llvm::unique_function<BeforeNonSkippedPassFunc>, 4>
  131. BeforeNonSkippedPassCallbacks;
  132. /// These are run on passes that have just run.
  133. SmallVector<llvm::unique_function<AfterPassFunc>, 4> AfterPassCallbacks;
  134. /// These are run passes that have just run on invalidated IR.
  135. SmallVector<llvm::unique_function<AfterPassInvalidatedFunc>, 4>
  136. AfterPassInvalidatedCallbacks;
  137. /// These are run on analyses that are about to be run.
  138. SmallVector<llvm::unique_function<BeforeAnalysisFunc>, 4>
  139. BeforeAnalysisCallbacks;
  140. /// These are run on analyses that have been run.
  141. SmallVector<llvm::unique_function<AfterAnalysisFunc>, 4>
  142. AfterAnalysisCallbacks;
  143. StringMap<std::string> ClassToPassName;
  144. };
  145. /// This class provides instrumentation entry points for the Pass Manager,
  146. /// doing calls to callbacks registered in PassInstrumentationCallbacks.
  147. class PassInstrumentation {
  148. PassInstrumentationCallbacks *Callbacks;
  149. // Template argument PassT of PassInstrumentation::runBeforePass could be two
  150. // kinds: (1) a regular pass inherited from PassInfoMixin (happen when
  151. // creating a adaptor pass for a regular pass); (2) a type-erased PassConcept
  152. // created from (1). Here we want to make case (1) skippable unconditionally
  153. // since they are regular passes. We call PassConcept::isRequired to decide
  154. // for case (2).
  155. template <typename PassT>
  156. using has_required_t = decltype(std::declval<PassT &>().isRequired());
  157. template <typename PassT>
  158. static std::enable_if_t<is_detected<has_required_t, PassT>::value, bool>
  159. isRequired(const PassT &Pass) {
  160. return Pass.isRequired();
  161. }
  162. template <typename PassT>
  163. static std::enable_if_t<!is_detected<has_required_t, PassT>::value, bool>
  164. isRequired(const PassT &Pass) {
  165. return false;
  166. }
  167. public:
  168. /// Callbacks object is not owned by PassInstrumentation, its life-time
  169. /// should at least match the life-time of corresponding
  170. /// PassInstrumentationAnalysis (which usually is till the end of current
  171. /// compilation).
  172. PassInstrumentation(PassInstrumentationCallbacks *CB = nullptr)
  173. : Callbacks(CB) {}
  174. /// BeforePass instrumentation point - takes \p Pass instance to be executed
  175. /// and constant reference to IR it operates on. \Returns true if pass is
  176. /// allowed to be executed. These are only run on optional pass since required
  177. /// passes must always be run. This allows these callbacks to print info when
  178. /// they want to skip a pass.
  179. template <typename IRUnitT, typename PassT>
  180. bool runBeforePass(const PassT &Pass, const IRUnitT &IR) const {
  181. if (!Callbacks)
  182. return true;
  183. bool ShouldRun = true;
  184. if (!isRequired(Pass)) {
  185. for (auto &C : Callbacks->ShouldRunOptionalPassCallbacks)
  186. ShouldRun &= C(Pass.name(), llvm::Any(&IR));
  187. }
  188. if (ShouldRun) {
  189. for (auto &C : Callbacks->BeforeNonSkippedPassCallbacks)
  190. C(Pass.name(), llvm::Any(&IR));
  191. } else {
  192. for (auto &C : Callbacks->BeforeSkippedPassCallbacks)
  193. C(Pass.name(), llvm::Any(&IR));
  194. }
  195. return ShouldRun;
  196. }
  197. /// AfterPass instrumentation point - takes \p Pass instance that has
  198. /// just been executed and constant reference to \p IR it operates on.
  199. /// \p IR is guaranteed to be valid at this point.
  200. template <typename IRUnitT, typename PassT>
  201. void runAfterPass(const PassT &Pass, const IRUnitT &IR,
  202. const PreservedAnalyses &PA) const {
  203. if (Callbacks)
  204. for (auto &C : Callbacks->AfterPassCallbacks)
  205. C(Pass.name(), llvm::Any(&IR), PA);
  206. }
  207. /// AfterPassInvalidated instrumentation point - takes \p Pass instance
  208. /// that has just been executed. For use when IR has been invalidated
  209. /// by \p Pass execution.
  210. template <typename IRUnitT, typename PassT>
  211. void runAfterPassInvalidated(const PassT &Pass,
  212. const PreservedAnalyses &PA) const {
  213. if (Callbacks)
  214. for (auto &C : Callbacks->AfterPassInvalidatedCallbacks)
  215. C(Pass.name(), PA);
  216. }
  217. /// BeforeAnalysis instrumentation point - takes \p Analysis instance
  218. /// to be executed and constant reference to IR it operates on.
  219. template <typename IRUnitT, typename PassT>
  220. void runBeforeAnalysis(const PassT &Analysis, const IRUnitT &IR) const {
  221. if (Callbacks)
  222. for (auto &C : Callbacks->BeforeAnalysisCallbacks)
  223. C(Analysis.name(), llvm::Any(&IR));
  224. }
  225. /// AfterAnalysis instrumentation point - takes \p Analysis instance
  226. /// that has just been executed and constant reference to IR it operated on.
  227. template <typename IRUnitT, typename PassT>
  228. void runAfterAnalysis(const PassT &Analysis, const IRUnitT &IR) const {
  229. if (Callbacks)
  230. for (auto &C : Callbacks->AfterAnalysisCallbacks)
  231. C(Analysis.name(), llvm::Any(&IR));
  232. }
  233. /// Handle invalidation from the pass manager when PassInstrumentation
  234. /// is used as the result of PassInstrumentationAnalysis.
  235. ///
  236. /// On attempt to invalidate just return false. There is nothing to become
  237. /// invalid here.
  238. template <typename IRUnitT, typename... ExtraArgsT>
  239. bool invalidate(IRUnitT &, const class llvm::PreservedAnalyses &,
  240. ExtraArgsT...) {
  241. return false;
  242. }
  243. template <typename CallableT>
  244. void pushBeforeNonSkippedPassCallback(CallableT C) {
  245. if (Callbacks)
  246. Callbacks->BeforeNonSkippedPassCallbacks.emplace_back(std::move(C));
  247. }
  248. void popBeforeNonSkippedPassCallback() {
  249. if (Callbacks)
  250. Callbacks->BeforeNonSkippedPassCallbacks.pop_back();
  251. }
  252. };
  253. bool isSpecialPass(StringRef PassID, const std::vector<StringRef> &Specials);
  254. } // namespace llvm
  255. #endif
  256. #ifdef __GNUC__
  257. #pragma GCC diagnostic pop
  258. #endif