1 //===- PassManager.h --- Pass management for CodeGen ------------*- 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 //
9 // This header defines the pass manager interface for codegen. The codegen
10 // pipeline consists of only machine function passes. There is no container
11 // relationship between IR module/function and machine function in terms of pass
12 // manager organization. So there is no need for adaptor classes (for example
13 // ModuleToMachineFunctionAdaptor). Since invalidation could only happen among
14 // machine function passes, there is no proxy classes to handle cross-IR-unit
15 // invalidation. IR analysis results are provided for machine function passes by
16 // their respective analysis managers such as ModuleAnalysisManager and
17 // FunctionAnalysisManager.
18 //
19 // TODO: Add MachineFunctionProperties support.
20 //
21 //===----------------------------------------------------------------------===//
22 
23 #ifndef LLVM_CODEGEN_MACHINEPASSMANAGER_H
24 #define LLVM_CODEGEN_MACHINEPASSMANAGER_H
25 
26 #include "llvm/ADT/FunctionExtras.h"
27 #include "llvm/ADT/SmallVector.h"
28 #include "llvm/CodeGen/MachineFunction.h"
29 #include "llvm/IR/PassManager.h"
30 #include "llvm/IR/PassManagerInternal.h"
31 #include "llvm/Support/Error.h"
32 
33 namespace llvm {
34 class Module;
35 class Function;
36 class MachineFunction;
37 
38 extern template class AnalysisManager<MachineFunction>;
39 using MachineFunctionAnalysisManager = AnalysisManager<MachineFunction>;
40 
41 /// A CRTP mix-in that provides informational APIs needed for machine passes.
42 ///
43 /// This provides some boilerplate for types that are machine passes. It
44 /// automatically mixes in \c PassInfoMixin.
45 template <typename DerivedT>
46 struct MachinePassInfoMixin : public PassInfoMixin<DerivedT> {
47   // TODO: Add MachineFunctionProperties support.
48 };
49 
50 namespace detail {
51 struct MachinePassConcept
52     : PassConcept<MachineFunction, MachineFunctionAnalysisManager> {
53   virtual MachineFunctionProperties getRequiredProperties() const = 0;
54   virtual MachineFunctionProperties getSetProperties() const = 0;
55   virtual MachineFunctionProperties getClearedProperties() const = 0;
56 };
57 
58 template <typename PassT> struct MachinePassModel : MachinePassConcept {
MachinePassModelMachinePassModel59   explicit MachinePassModel(PassT Pass) : Pass(std::move(Pass)) {}
60   // We have to explicitly define all the special member functions because MSVC
61   // refuses to generate them.
MachinePassModelMachinePassModel62   MachinePassModel(const MachinePassModel &Arg) : Pass(Arg.Pass) {}
MachinePassModelMachinePassModel63   MachinePassModel(MachinePassModel &&Arg) : Pass(std::move(Arg.Pass)) {}
64 
swapMachinePassModel65   friend void swap(MachinePassModel &LHS, MachinePassModel &RHS) {
66     using std::swap;
67     swap(LHS.Pass, RHS.Pass);
68   }
69 
70   MachinePassModel &operator=(MachinePassModel RHS) {
71     swap(*this, RHS);
72     return *this;
73   }
74 
runMachinePassModel75   PreservedAnalyses run(MachineFunction &IR,
76                         MachineFunctionAnalysisManager &AM) override {
77     return Pass.run(IR, AM);
78   }
79 
printPipelineMachinePassModel80   void printPipeline(
81       raw_ostream &OS,
82       function_ref<StringRef(StringRef)> MapClassName2PassName) override {
83     Pass.printPipeline(OS, MapClassName2PassName);
84   }
85 
nameMachinePassModel86   StringRef name() const override { return PassT::name(); }
87 
88   template <typename T>
89   using has_required_t = decltype(std::declval<T &>().isRequired());
90   template <typename T>
91   static std::enable_if_t<is_detected<has_required_t, T>::value, bool>
passIsRequiredImplMachinePassModel92   passIsRequiredImpl() {
93     return T::isRequired();
94   }
95   template <typename T>
96   static std::enable_if_t<!is_detected<has_required_t, T>::value, bool>
passIsRequiredImplMachinePassModel97   passIsRequiredImpl() {
98     return false;
99   }
isRequiredMachinePassModel100   bool isRequired() const override { return passIsRequiredImpl<PassT>(); }
101 
102   template <typename T>
103   using has_get_required_properties_t =
104       decltype(std::declval<T &>().getRequiredProperties());
105   template <typename T>
106   static std::enable_if_t<is_detected<has_get_required_properties_t, T>::value,
107                           MachineFunctionProperties>
getRequiredPropertiesImplMachinePassModel108   getRequiredPropertiesImpl() {
109     return PassT::getRequiredProperties();
110   }
111   template <typename T>
112   static std::enable_if_t<!is_detected<has_get_required_properties_t, T>::value,
113                           MachineFunctionProperties>
getRequiredPropertiesImplMachinePassModel114   getRequiredPropertiesImpl() {
115     return MachineFunctionProperties();
116   }
getRequiredPropertiesMachinePassModel117   MachineFunctionProperties getRequiredProperties() const override {
118     return getRequiredPropertiesImpl<PassT>();
119   }
120 
121   template <typename T>
122   using has_get_set_properties_t =
123       decltype(std::declval<T &>().getSetProperties());
124   template <typename T>
125   static std::enable_if_t<is_detected<has_get_set_properties_t, T>::value,
126                           MachineFunctionProperties>
getSetPropertiesImplMachinePassModel127   getSetPropertiesImpl() {
128     return PassT::getSetProperties();
129   }
130   template <typename T>
131   static std::enable_if_t<!is_detected<has_get_set_properties_t, T>::value,
132                           MachineFunctionProperties>
getSetPropertiesImplMachinePassModel133   getSetPropertiesImpl() {
134     return MachineFunctionProperties();
135   }
getSetPropertiesMachinePassModel136   MachineFunctionProperties getSetProperties() const override {
137     return getSetPropertiesImpl<PassT>();
138   }
139 
140   template <typename T>
141   using has_get_cleared_properties_t =
142       decltype(std::declval<T &>().getClearedProperties());
143   template <typename T>
144   static std::enable_if_t<is_detected<has_get_cleared_properties_t, T>::value,
145                           MachineFunctionProperties>
getClearedPropertiesImplMachinePassModel146   getClearedPropertiesImpl() {
147     return PassT::getClearedProperties();
148   }
149   template <typename T>
150   static std::enable_if_t<!is_detected<has_get_cleared_properties_t, T>::value,
151                           MachineFunctionProperties>
getClearedPropertiesImplMachinePassModel152   getClearedPropertiesImpl() {
153     return MachineFunctionProperties();
154   }
getClearedPropertiesMachinePassModel155   MachineFunctionProperties getClearedProperties() const override {
156     return getClearedPropertiesImpl<PassT>();
157   }
158 
159   PassT Pass;
160 };
161 } // namespace detail
162 
163 using MachineFunctionAnalysisManagerModuleProxy =
164     InnerAnalysisManagerProxy<MachineFunctionAnalysisManager, Module>;
165 
166 template <>
167 bool MachineFunctionAnalysisManagerModuleProxy::Result::invalidate(
168     Module &M, const PreservedAnalyses &PA,
169     ModuleAnalysisManager::Invalidator &Inv);
170 extern template class InnerAnalysisManagerProxy<MachineFunctionAnalysisManager,
171                                                 Module>;
172 
173 extern template class OuterAnalysisManagerProxy<ModuleAnalysisManager,
174                                                 MachineFunction>;
175 /// Provide the \c ModuleAnalysisManager to \c Function proxy.
176 using ModuleAnalysisManagerMachineFunctionProxy =
177     OuterAnalysisManagerProxy<ModuleAnalysisManager, MachineFunction>;
178 
179 class FunctionAnalysisManagerMachineFunctionProxy
180     : public AnalysisInfoMixin<FunctionAnalysisManagerMachineFunctionProxy> {
181 public:
182   class Result {
183   public:
Result(FunctionAnalysisManager & FAM)184     explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {}
185 
Result(Result && Arg)186     Result(Result &&Arg) : FAM(std::move(Arg.FAM)) {
187       // We have to null out the analysis manager in the moved-from state
188       // because we are taking ownership of the responsibilty to clear the
189       // analysis state.
190       Arg.FAM = nullptr;
191     }
192 
~Result()193     ~Result() {
194       // FAM is cleared in a moved from state where there is nothing to do.
195       if (!FAM)
196         return;
197 
198       // Clear out the analysis manager if we're being destroyed -- it means we
199       // didn't even see an invalidate call when we got invalidated.
200       FAM->clear();
201     }
202 
203     Result &operator=(Result &&RHS) {
204       FAM = RHS.FAM;
205       // We have to null out the analysis manager in the moved-from state
206       // because we are taking ownership of the responsibilty to clear the
207       // analysis state.
208       RHS.FAM = nullptr;
209       return *this;
210     }
211 
212     /// Accessor for the analysis manager.
getManager()213     FunctionAnalysisManager &getManager() { return *FAM; }
214 
215     /// Handler for invalidation of the outer IR unit, \c IRUnitT.
216     ///
217     /// If the proxy analysis itself is not preserved, we assume that the set of
218     /// inner IR objects contained in IRUnit may have changed.  In this case,
219     /// we have to call \c clear() on the inner analysis manager, as it may now
220     /// have stale pointers to its inner IR objects.
221     ///
222     /// Regardless of whether the proxy analysis is marked as preserved, all of
223     /// the analyses in the inner analysis manager are potentially invalidated
224     /// based on the set of preserved analyses.
225     bool invalidate(MachineFunction &IR, const PreservedAnalyses &PA,
226                     MachineFunctionAnalysisManager::Invalidator &Inv);
227 
228   private:
229     FunctionAnalysisManager *FAM;
230   };
231 
FunctionAnalysisManagerMachineFunctionProxy(FunctionAnalysisManager & FAM)232   explicit FunctionAnalysisManagerMachineFunctionProxy(
233       FunctionAnalysisManager &FAM)
234       : FAM(&FAM) {}
235 
236   /// Run the analysis pass and create our proxy result object.
237   ///
238   /// This doesn't do any interesting work; it is primarily used to insert our
239   /// proxy result object into the outer analysis cache so that we can proxy
240   /// invalidation to the inner analysis manager.
run(MachineFunction &,MachineFunctionAnalysisManager &)241   Result run(MachineFunction &, MachineFunctionAnalysisManager &) {
242     return Result(*FAM);
243   }
244 
245   static AnalysisKey Key;
246 
247 private:
248   FunctionAnalysisManager *FAM;
249 };
250 
251 class ModuleToMachineFunctionPassAdaptor
252     : public PassInfoMixin<ModuleToMachineFunctionPassAdaptor> {
253   using MachinePassConcept = detail::MachinePassConcept;
254 
255 public:
ModuleToMachineFunctionPassAdaptor(std::unique_ptr<MachinePassConcept> Pass)256   explicit ModuleToMachineFunctionPassAdaptor(
257       std::unique_ptr<MachinePassConcept> Pass)
258       : Pass(std::move(Pass)) {}
259 
260   /// Runs the function pass across every function in the module.
261   PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM);
262   void printPipeline(raw_ostream &OS,
263                      function_ref<StringRef(StringRef)> MapClassName2PassName);
264 
isRequired()265   static bool isRequired() { return true; }
266 
267 private:
268   std::unique_ptr<MachinePassConcept> Pass;
269 };
270 
271 template <typename MachineFunctionPassT>
272 ModuleToMachineFunctionPassAdaptor
createModuleToMachineFunctionPassAdaptor(MachineFunctionPassT && Pass)273 createModuleToMachineFunctionPassAdaptor(MachineFunctionPassT &&Pass) {
274   using PassModelT = detail::MachinePassModel<MachineFunctionPassT>;
275   // Do not use make_unique, it causes too many template instantiations,
276   // causing terrible compile times.
277   return ModuleToMachineFunctionPassAdaptor(
278       std::unique_ptr<detail::MachinePassConcept>(
279           new PassModelT(std::forward<MachineFunctionPassT>(Pass))));
280 }
281 
282 template <>
283 PreservedAnalyses
284 PassManager<MachineFunction>::run(MachineFunction &,
285                                   AnalysisManager<MachineFunction> &);
286 extern template class PassManager<MachineFunction>;
287 
288 /// Convenience typedef for a pass manager over functions.
289 using MachineFunctionPassManager = PassManager<MachineFunction>;
290 
291 } // end namespace llvm
292 
293 #endif // LLVM_CODEGEN_MACHINEPASSMANAGER_H
294