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