• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===- CGSCCPassManager.h - Call graph pass management ----------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 /// \file
10 ///
11 /// This header provides classes for managing passes over SCCs of the call
12 /// graph. These passes form an important component of LLVM's interprocedural
13 /// optimizations. Because they operate on the SCCs of the call graph, and they
14 /// traverse the graph in post order, they can effectively do pair-wise
15 /// interprocedural optimizations for all call edges in the program. At each
16 /// call site edge, the callee has already been optimized as much as is
17 /// possible. This in turn allows very accurate analysis of it for IPO.
18 ///
19 //===----------------------------------------------------------------------===//
20 
21 #ifndef LLVM_ANALYSIS_CGSCCPASSMANAGER_H
22 #define LLVM_ANALYSIS_CGSCCPASSMANAGER_H
23 
24 #include "llvm/Analysis/LazyCallGraph.h"
25 #include "llvm/IR/PassManager.h"
26 
27 namespace llvm {
28 
29 extern template class PassManager<LazyCallGraph::SCC>;
30 /// \brief The CGSCC pass manager.
31 ///
32 /// See the documentation for the PassManager template for details. It runs
33 /// a sequency of SCC passes over each SCC that the manager is run over. This
34 /// typedef serves as a convenient way to refer to this construct.
35 typedef PassManager<LazyCallGraph::SCC> CGSCCPassManager;
36 
37 extern template class AnalysisManager<LazyCallGraph::SCC>;
38 /// \brief The CGSCC analysis manager.
39 ///
40 /// See the documentation for the AnalysisManager template for detail
41 /// documentation. This typedef serves as a convenient way to refer to this
42 /// construct in the adaptors and proxies used to integrate this into the larger
43 /// pass manager infrastructure.
44 typedef AnalysisManager<LazyCallGraph::SCC> CGSCCAnalysisManager;
45 
46 extern template class InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>;
47 /// A proxy from a \c CGSCCAnalysisManager to a \c Module.
48 typedef InnerAnalysisManagerProxy<CGSCCAnalysisManager, Module>
49     CGSCCAnalysisManagerModuleProxy;
50 
51 extern template class OuterAnalysisManagerProxy<ModuleAnalysisManager,
52                                                 LazyCallGraph::SCC>;
53 /// A proxy from a \c ModuleAnalysisManager to an \c SCC.
54 typedef OuterAnalysisManagerProxy<ModuleAnalysisManager, LazyCallGraph::SCC>
55     ModuleAnalysisManagerCGSCCProxy;
56 
57 /// \brief The core module pass which does a post-order walk of the SCCs and
58 /// runs a CGSCC pass over each one.
59 ///
60 /// Designed to allow composition of a CGSCCPass(Manager) and
61 /// a ModulePassManager. Note that this pass must be run with a module analysis
62 /// manager as it uses the LazyCallGraph analysis. It will also run the
63 /// \c CGSCCAnalysisManagerModuleProxy analysis prior to running the CGSCC
64 /// pass over the module to enable a \c FunctionAnalysisManager to be used
65 /// within this run safely.
66 template <typename CGSCCPassT>
67 class ModuleToPostOrderCGSCCPassAdaptor
68     : public PassInfoMixin<ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>> {
69 public:
70   explicit ModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false)
Pass(std::move (Pass))71       : Pass(std::move(Pass)), DebugLogging(DebugLogging) {}
72   // We have to explicitly define all the special member functions because MSVC
73   // refuses to generate them.
ModuleToPostOrderCGSCCPassAdaptor(const ModuleToPostOrderCGSCCPassAdaptor & Arg)74   ModuleToPostOrderCGSCCPassAdaptor(
75       const ModuleToPostOrderCGSCCPassAdaptor &Arg)
76       : Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {}
ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor && Arg)77   ModuleToPostOrderCGSCCPassAdaptor(ModuleToPostOrderCGSCCPassAdaptor &&Arg)
78       : Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {}
swap(ModuleToPostOrderCGSCCPassAdaptor & LHS,ModuleToPostOrderCGSCCPassAdaptor & RHS)79   friend void swap(ModuleToPostOrderCGSCCPassAdaptor &LHS,
80                    ModuleToPostOrderCGSCCPassAdaptor &RHS) {
81     using std::swap;
82     swap(LHS.Pass, RHS.Pass);
83     swap(LHS.DebugLogging, RHS.DebugLogging);
84   }
85   ModuleToPostOrderCGSCCPassAdaptor &
86   operator=(ModuleToPostOrderCGSCCPassAdaptor RHS) {
87     swap(*this, RHS);
88     return *this;
89   }
90 
91   /// \brief Runs the CGSCC pass across every SCC in the module.
run(Module & M,ModuleAnalysisManager & AM)92   PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM) {
93     // Setup the CGSCC analysis manager from its proxy.
94     CGSCCAnalysisManager &CGAM =
95         AM.getResult<CGSCCAnalysisManagerModuleProxy>(M).getManager();
96 
97     // Get the call graph for this module.
98     LazyCallGraph &CG = AM.getResult<LazyCallGraphAnalysis>(M);
99 
100     PreservedAnalyses PA = PreservedAnalyses::all();
101     for (LazyCallGraph::RefSCC &RC : CG.postorder_ref_sccs()) {
102       if (DebugLogging)
103         dbgs() << "Running an SCC pass across the RefSCC: " << RC << "\n";
104 
105       for (LazyCallGraph::SCC &C : RC) {
106         PreservedAnalyses PassPA = Pass.run(C, CGAM);
107 
108         // We know that the CGSCC pass couldn't have invalidated any other
109         // SCC's analyses (that's the contract of a CGSCC pass), so
110         // directly handle the CGSCC analysis manager's invalidation here. We
111         // also update the preserved set of analyses to reflect that invalidated
112         // analyses are now safe to preserve.
113         // FIXME: This isn't quite correct. We need to handle the case where the
114         // pass updated the CG, particularly some child of the current SCC, and
115         // invalidate its analyses.
116         PassPA = CGAM.invalidate(C, std::move(PassPA));
117 
118         // Then intersect the preserved set so that invalidation of module
119         // analyses will eventually occur when the module pass completes.
120         PA.intersect(std::move(PassPA));
121       }
122     }
123 
124     // By definition we preserve the proxy. This precludes *any* invalidation
125     // of CGSCC analyses by the proxy, but that's OK because we've taken
126     // care to invalidate analyses in the CGSCC analysis manager
127     // incrementally above.
128     PA.preserve<CGSCCAnalysisManagerModuleProxy>();
129     return PA;
130   }
131 
132 private:
133   CGSCCPassT Pass;
134   bool DebugLogging;
135 };
136 
137 /// \brief A function to deduce a function pass type and wrap it in the
138 /// templated adaptor.
139 template <typename CGSCCPassT>
140 ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>
141 createModuleToPostOrderCGSCCPassAdaptor(CGSCCPassT Pass, bool DebugLogging = false) {
142   return ModuleToPostOrderCGSCCPassAdaptor<CGSCCPassT>(std::move(Pass), DebugLogging);
143 }
144 
145 extern template class InnerAnalysisManagerProxy<FunctionAnalysisManager,
146                                                 LazyCallGraph::SCC>;
147 /// A proxy from a \c FunctionAnalysisManager to an \c SCC.
148 typedef InnerAnalysisManagerProxy<FunctionAnalysisManager, LazyCallGraph::SCC>
149     FunctionAnalysisManagerCGSCCProxy;
150 
151 extern template class OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>;
152 /// A proxy from a \c CGSCCAnalysisManager to a \c Function.
153 typedef OuterAnalysisManagerProxy<CGSCCAnalysisManager, Function>
154     CGSCCAnalysisManagerFunctionProxy;
155 
156 /// \brief Adaptor that maps from a SCC to its functions.
157 ///
158 /// Designed to allow composition of a FunctionPass(Manager) and
159 /// a CGSCCPassManager. Note that if this pass is constructed with a pointer
160 /// to a \c CGSCCAnalysisManager it will run the
161 /// \c FunctionAnalysisManagerCGSCCProxy analysis prior to running the function
162 /// pass over the SCC to enable a \c FunctionAnalysisManager to be used
163 /// within this run safely.
164 template <typename FunctionPassT>
165 class CGSCCToFunctionPassAdaptor
166     : public PassInfoMixin<CGSCCToFunctionPassAdaptor<FunctionPassT>> {
167 public:
168   explicit CGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false)
Pass(std::move (Pass))169       : Pass(std::move(Pass)), DebugLogging(DebugLogging) {}
170   // We have to explicitly define all the special member functions because MSVC
171   // refuses to generate them.
CGSCCToFunctionPassAdaptor(const CGSCCToFunctionPassAdaptor & Arg)172   CGSCCToFunctionPassAdaptor(const CGSCCToFunctionPassAdaptor &Arg)
173       : Pass(Arg.Pass), DebugLogging(Arg.DebugLogging) {}
CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor && Arg)174   CGSCCToFunctionPassAdaptor(CGSCCToFunctionPassAdaptor &&Arg)
175       : Pass(std::move(Arg.Pass)), DebugLogging(Arg.DebugLogging) {}
swap(CGSCCToFunctionPassAdaptor & LHS,CGSCCToFunctionPassAdaptor & RHS)176   friend void swap(CGSCCToFunctionPassAdaptor &LHS,
177                    CGSCCToFunctionPassAdaptor &RHS) {
178     using std::swap;
179     swap(LHS.Pass, RHS.Pass);
180     swap(LHS.DebugLogging, RHS.DebugLogging);
181   }
182   CGSCCToFunctionPassAdaptor &operator=(CGSCCToFunctionPassAdaptor RHS) {
183     swap(*this, RHS);
184     return *this;
185   }
186 
187   /// \brief Runs the function pass across every function in the module.
run(LazyCallGraph::SCC & C,CGSCCAnalysisManager & AM)188   PreservedAnalyses run(LazyCallGraph::SCC &C, CGSCCAnalysisManager &AM) {
189     // Setup the function analysis manager from its proxy.
190     FunctionAnalysisManager &FAM =
191         AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C).getManager();
192 
193     if (DebugLogging)
194       dbgs() << "Running function passes across an SCC: " << C << "\n";
195 
196     PreservedAnalyses PA = PreservedAnalyses::all();
197     for (LazyCallGraph::Node &N : C) {
198       PreservedAnalyses PassPA = Pass.run(N.getFunction(), FAM);
199 
200       // We know that the function pass couldn't have invalidated any other
201       // function's analyses (that's the contract of a function pass), so
202       // directly handle the function analysis manager's invalidation here.
203       // Also, update the preserved analyses to reflect that once invalidated
204       // these can again be preserved.
205       PassPA = FAM.invalidate(N.getFunction(), std::move(PassPA));
206 
207       // Then intersect the preserved set so that invalidation of module
208       // analyses will eventually occur when the module pass completes.
209       PA.intersect(std::move(PassPA));
210     }
211 
212     // By definition we preserve the proxy. This precludes *any* invalidation
213     // of function analyses by the proxy, but that's OK because we've taken
214     // care to invalidate analyses in the function analysis manager
215     // incrementally above.
216     // FIXME: We need to update the call graph here to account for any deleted
217     // edges!
218     PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
219     return PA;
220   }
221 
222 private:
223   FunctionPassT Pass;
224   bool DebugLogging;
225 };
226 
227 /// \brief A function to deduce a function pass type and wrap it in the
228 /// templated adaptor.
229 template <typename FunctionPassT>
230 CGSCCToFunctionPassAdaptor<FunctionPassT>
231 createCGSCCToFunctionPassAdaptor(FunctionPassT Pass, bool DebugLogging = false) {
232   return CGSCCToFunctionPassAdaptor<FunctionPassT>(std::move(Pass),
233                                                    DebugLogging);
234 }
235 }
236 
237 #endif
238