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 | //===----------------------------------------------------------------------===// |
20 | |
21 | #ifndef LLVM_CODEGEN_MACHINEPASSMANAGER_H |
22 | #define LLVM_CODEGEN_MACHINEPASSMANAGER_H |
23 | |
24 | #include "llvm/ADT/FunctionExtras.h" |
25 | #include "llvm/ADT/SmallVector.h" |
26 | #include "llvm/CodeGen/MachineFunction.h" |
27 | #include "llvm/IR/PassManager.h" |
28 | #include "llvm/IR/PassManagerInternal.h" |
29 | #include "llvm/Support/Error.h" |
30 | |
31 | namespace llvm { |
32 | class Module; |
33 | class Function; |
34 | class MachineFunction; |
35 | |
36 | extern template class AnalysisManager<MachineFunction>; |
37 | using MachineFunctionAnalysisManager = AnalysisManager<MachineFunction>; |
38 | |
39 | namespace detail { |
40 | |
41 | template <typename PassT> |
42 | struct MachinePassModel |
43 | : PassModel<MachineFunction, PassT, MachineFunctionAnalysisManager> { |
44 | explicit MachinePassModel(PassT &&Pass) |
45 | : PassModel<MachineFunction, PassT, MachineFunctionAnalysisManager>( |
46 | std::move(Pass)) {} |
47 | |
48 | friend void swap(MachinePassModel &LHS, MachinePassModel &RHS) { |
49 | using std::swap; |
50 | swap(LHS.Pass, RHS.Pass); |
51 | } |
52 | |
53 | MachinePassModel &operator=(MachinePassModel RHS) { |
54 | swap(*this, RHS); |
55 | return *this; |
56 | } |
57 | |
58 | MachinePassModel &operator=(const MachinePassModel &) = delete; |
59 | PreservedAnalyses run(MachineFunction &IR, |
60 | MachineFunctionAnalysisManager &AM) override { |
61 | #ifndef NDEBUG |
62 | if constexpr (is_detected<has_get_required_properties_t, PassT>::value) { |
63 | auto &MFProps = IR.getProperties(); |
64 | auto RequiredProperties = PassT::getRequiredProperties(); |
65 | if (!MFProps.verifyRequiredProperties(V: RequiredProperties)) { |
66 | errs() << "MachineFunctionProperties required by " << PassT::name() |
67 | << " pass are not met by function " << IR.getName() << ".\n" |
68 | << "Required properties: " ; |
69 | RequiredProperties.print(errs()); |
70 | errs() << "\nCurrent properties: " ; |
71 | MFProps.print(OS&: errs()); |
72 | errs() << '\n'; |
73 | report_fatal_error(reason: "MachineFunctionProperties check failed" ); |
74 | } |
75 | } |
76 | #endif |
77 | |
78 | auto PA = this->Pass.run(IR, AM); |
79 | |
80 | if constexpr (is_detected<has_get_set_properties_t, PassT>::value) |
81 | IR.getProperties().set(PassT::getSetProperties()); |
82 | if constexpr (is_detected<has_get_cleared_properties_t, PassT>::value) |
83 | IR.getProperties().reset(PassT::getClearedProperties()); |
84 | return PA; |
85 | } |
86 | |
87 | private: |
88 | template <typename T> |
89 | using has_get_required_properties_t = |
90 | decltype(std::declval<T &>().getRequiredProperties()); |
91 | |
92 | template <typename T> |
93 | using has_get_set_properties_t = |
94 | decltype(std::declval<T &>().getSetProperties()); |
95 | |
96 | template <typename T> |
97 | using has_get_cleared_properties_t = |
98 | decltype(std::declval<T &>().getClearedProperties()); |
99 | }; |
100 | } // namespace detail |
101 | |
102 | using MachineFunctionAnalysisManagerModuleProxy = |
103 | InnerAnalysisManagerProxy<MachineFunctionAnalysisManager, Module>; |
104 | |
105 | template <> |
106 | bool MachineFunctionAnalysisManagerModuleProxy::Result::invalidate( |
107 | Module &M, const PreservedAnalyses &PA, |
108 | ModuleAnalysisManager::Invalidator &Inv); |
109 | extern template class InnerAnalysisManagerProxy<MachineFunctionAnalysisManager, |
110 | Module>; |
111 | |
112 | extern template class OuterAnalysisManagerProxy<ModuleAnalysisManager, |
113 | MachineFunction>; |
114 | /// Provide the \c ModuleAnalysisManager to \c Function proxy. |
115 | using ModuleAnalysisManagerMachineFunctionProxy = |
116 | OuterAnalysisManagerProxy<ModuleAnalysisManager, MachineFunction>; |
117 | |
118 | class FunctionAnalysisManagerMachineFunctionProxy |
119 | : public AnalysisInfoMixin<FunctionAnalysisManagerMachineFunctionProxy> { |
120 | public: |
121 | class Result { |
122 | public: |
123 | explicit Result(FunctionAnalysisManager &FAM) : FAM(&FAM) {} |
124 | |
125 | Result(Result &&Arg) : FAM(std::move(Arg.FAM)) { |
126 | // We have to null out the analysis manager in the moved-from state |
127 | // because we are taking ownership of the responsibilty to clear the |
128 | // analysis state. |
129 | Arg.FAM = nullptr; |
130 | } |
131 | |
132 | ~Result() { |
133 | // FAM is cleared in a moved from state where there is nothing to do. |
134 | if (!FAM) |
135 | return; |
136 | |
137 | // Clear out the analysis manager if we're being destroyed -- it means we |
138 | // didn't even see an invalidate call when we got invalidated. |
139 | FAM->clear(); |
140 | } |
141 | |
142 | Result &operator=(Result &&RHS) { |
143 | FAM = RHS.FAM; |
144 | // We have to null out the analysis manager in the moved-from state |
145 | // because we are taking ownership of the responsibilty to clear the |
146 | // analysis state. |
147 | RHS.FAM = nullptr; |
148 | return *this; |
149 | } |
150 | |
151 | /// Accessor for the analysis manager. |
152 | FunctionAnalysisManager &getManager() { return *FAM; } |
153 | |
154 | /// Handler for invalidation of the outer IR unit, \c IRUnitT. |
155 | /// |
156 | /// If the proxy analysis itself is not preserved, we assume that the set of |
157 | /// inner IR objects contained in IRUnit may have changed. In this case, |
158 | /// we have to call \c clear() on the inner analysis manager, as it may now |
159 | /// have stale pointers to its inner IR objects. |
160 | /// |
161 | /// Regardless of whether the proxy analysis is marked as preserved, all of |
162 | /// the analyses in the inner analysis manager are potentially invalidated |
163 | /// based on the set of preserved analyses. |
164 | bool invalidate(MachineFunction &IR, const PreservedAnalyses &PA, |
165 | MachineFunctionAnalysisManager::Invalidator &Inv); |
166 | |
167 | private: |
168 | FunctionAnalysisManager *FAM; |
169 | }; |
170 | |
171 | explicit FunctionAnalysisManagerMachineFunctionProxy( |
172 | FunctionAnalysisManager &FAM) |
173 | : FAM(&FAM) {} |
174 | |
175 | /// Run the analysis pass and create our proxy result object. |
176 | /// |
177 | /// This doesn't do any interesting work; it is primarily used to insert our |
178 | /// proxy result object into the outer analysis cache so that we can proxy |
179 | /// invalidation to the inner analysis manager. |
180 | Result run(MachineFunction &, MachineFunctionAnalysisManager &) { |
181 | return Result(*FAM); |
182 | } |
183 | |
184 | static AnalysisKey Key; |
185 | |
186 | private: |
187 | FunctionAnalysisManager *FAM; |
188 | }; |
189 | |
190 | class ModuleToMachineFunctionPassAdaptor |
191 | : public PassInfoMixin<ModuleToMachineFunctionPassAdaptor> { |
192 | public: |
193 | using PassConceptT = |
194 | detail::PassConcept<MachineFunction, MachineFunctionAnalysisManager>; |
195 | |
196 | explicit ModuleToMachineFunctionPassAdaptor( |
197 | std::unique_ptr<PassConceptT> Pass) |
198 | : Pass(std::move(Pass)) {} |
199 | |
200 | /// Runs the function pass across every function in the module. |
201 | PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM); |
202 | void printPipeline(raw_ostream &OS, |
203 | function_ref<StringRef(StringRef)> MapClassName2PassName); |
204 | |
205 | static bool isRequired() { return true; } |
206 | |
207 | private: |
208 | std::unique_ptr<PassConceptT> Pass; |
209 | }; |
210 | |
211 | template <typename MachineFunctionPassT> |
212 | ModuleToMachineFunctionPassAdaptor |
213 | createModuleToMachineFunctionPassAdaptor(MachineFunctionPassT &&Pass) { |
214 | using PassModelT = detail::PassModel<MachineFunction, MachineFunctionPassT, |
215 | MachineFunctionAnalysisManager>; |
216 | // Do not use make_unique, it causes too many template instantiations, |
217 | // causing terrible compile times. |
218 | return ModuleToMachineFunctionPassAdaptor( |
219 | std::unique_ptr<ModuleToMachineFunctionPassAdaptor::PassConceptT>( |
220 | new PassModelT(std::forward<MachineFunctionPassT>(Pass)))); |
221 | } |
222 | |
223 | template <> |
224 | template <typename PassT> |
225 | void PassManager<MachineFunction>::addPass(PassT &&Pass) { |
226 | using MachinePassModelT = detail::MachinePassModel<PassT>; |
227 | // Do not use make_unique or emplace_back, they cause too many template |
228 | // instantiations, causing terrible compile times. |
229 | if constexpr (std::is_same_v<PassT, PassManager<MachineFunction>>) { |
230 | for (auto &P : Pass.Passes) |
231 | Passes.push_back(std::move(P)); |
232 | } else { |
233 | Passes.push_back(std::unique_ptr<MachinePassModelT>( |
234 | new MachinePassModelT(std::forward<PassT>(Pass)))); |
235 | } |
236 | } |
237 | |
238 | template <> |
239 | PreservedAnalyses |
240 | PassManager<MachineFunction>::run(MachineFunction &, |
241 | AnalysisManager<MachineFunction> &); |
242 | extern template class PassManager<MachineFunction>; |
243 | |
244 | /// Convenience typedef for a pass manager over functions. |
245 | using MachineFunctionPassManager = PassManager<MachineFunction>; |
246 | |
247 | } // end namespace llvm |
248 | |
249 | #endif // LLVM_CODEGEN_MACHINEPASSMANAGER_H |
250 | |