[PBQP] Explicitly define copy/move operations for NodeMetadata to keep VS happy.
[oota-llvm.git] / include / llvm / CodeGen / RegAllocPBQP.h
1 //===-- RegAllocPBQP.h ------------------------------------------*- 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 //
10 // This file defines the PBQPBuilder interface, for classes which build PBQP
11 // instances to represent register allocation problems, and the RegAllocPBQP
12 // interface.
13 //
14 //===----------------------------------------------------------------------===//
15
16 #ifndef LLVM_CODEGEN_REGALLOCPBQP_H
17 #define LLVM_CODEGEN_REGALLOCPBQP_H
18
19 #include "llvm/CodeGen/MachineFunctionPass.h"
20 #include "llvm/CodeGen/PBQPRAConstraint.h"
21 #include "llvm/CodeGen/PBQP/CostAllocator.h"
22 #include "llvm/CodeGen/PBQP/ReductionRules.h"
23 #include "llvm/Support/ErrorHandling.h"
24
25 namespace llvm {
26 namespace PBQP {
27 namespace RegAlloc {
28
29 /// @brief Spill option index.
30 inline unsigned getSpillOptionIdx() { return 0; }
31
32 /// \brief Metadata to speed allocatability test.
33 ///
34 /// Keeps track of the number of infinities in each row and column.
35 class MatrixMetadata {
36 private:
37   MatrixMetadata(const MatrixMetadata&);
38   void operator=(const MatrixMetadata&);
39 public:
40   MatrixMetadata(const Matrix& M)
41     : WorstRow(0), WorstCol(0),
42       UnsafeRows(new bool[M.getRows() - 1]()),
43       UnsafeCols(new bool[M.getCols() - 1]()) {
44
45     unsigned* ColCounts = new unsigned[M.getCols() - 1]();
46
47     for (unsigned i = 1; i < M.getRows(); ++i) {
48       unsigned RowCount = 0;
49       for (unsigned j = 1; j < M.getCols(); ++j) {
50         if (M[i][j] == std::numeric_limits<PBQPNum>::infinity()) {
51           ++RowCount;
52           ++ColCounts[j - 1];
53           UnsafeRows[i - 1] = true;
54           UnsafeCols[j - 1] = true;
55         }
56       }
57       WorstRow = std::max(WorstRow, RowCount);
58     }
59     unsigned WorstColCountForCurRow =
60       *std::max_element(ColCounts, ColCounts + M.getCols() - 1);
61     WorstCol = std::max(WorstCol, WorstColCountForCurRow);
62     delete[] ColCounts;
63   }
64
65   unsigned getWorstRow() const { return WorstRow; }
66   unsigned getWorstCol() const { return WorstCol; }
67   const bool* getUnsafeRows() const { return UnsafeRows.get(); }
68   const bool* getUnsafeCols() const { return UnsafeCols.get(); }
69
70 private:
71   unsigned WorstRow, WorstCol;
72   std::unique_ptr<bool[]> UnsafeRows;
73   std::unique_ptr<bool[]> UnsafeCols;
74 };
75
76 class NodeMetadata {
77 public:
78   typedef std::vector<unsigned> OptionToRegMap;
79
80   typedef enum { Unprocessed,
81                  OptimallyReducible,
82                  ConservativelyAllocatable,
83                  NotProvablyAllocatable } ReductionState;
84
85   NodeMetadata()
86     : RS(Unprocessed), NumOpts(0), DeniedOpts(0), OptUnsafeEdges(nullptr),
87       VReg(0) {}
88
89   // FIXME: Re-implementing default behavior to work around MSVC. Remove once
90   // MSVC synthesizes move constructors properly.
91   NodeMetadata(const NodeMetadata &Other)
92     : RS(Other.RS), NumOpts(Other.NumOpts), DeniedOpts(Other.DeniedOpts),
93       OptUnsafeEdges(new unsigned[NumOpts]), VReg(Other.VReg),
94       OptionRegs(Other.OptionRegs) {
95     std::copy(&Other.OptUnsafeEdges[0], &Other.OptUnsafeEdges[NumOpts],
96               &OptUnsafeEdges[0]);
97   }
98
99   // FIXME: Re-implementing default behavior to work around MSVC. Remove once
100   // MSVC synthesizes move constructors properly.
101   NodeMetadata(NodeMetadata &&Other)
102     : RS(Other.RS), NumOpts(Other.NumOpts), DeniedOpts(Other.DeniedOpts),
103       OptUnsafeEdges(std::move(Other.OptUnsafeEdges)), VReg(Other.VReg),
104       OptionRegs(std::move(Other.OptionRegs)) {}
105
106   // FIXME: Re-implementing default behavior to work around MSVC. Remove once
107   // MSVC synthesizes move constructors properly.
108   NodeMetadata& operator=(const NodeMetadata &Other) {
109     RS = Other.RS;
110     NumOpts = Other.NumOpts;
111     DeniedOpts = Other.DeniedOpts;
112     OptUnsafeEdges = std::unique_ptr<unsigned[]>(new unsigned[NumOpts]);
113     std::copy(&Other.OptUnsafeEdges[0], &Other.OptUnsafeEdges[NumOpts],
114               &OptUnsafeEdges[0]);
115     VReg = Other.VReg;
116     OptionRegs = Other.OptionRegs;
117     return *this;
118   }
119
120   // FIXME: Re-implementing default behavior to work around MSVC. Remove once
121   // MSVC synthesizes move constructors properly.
122   NodeMetadata& operator=(NodeMetadata &&Other) {
123     RS = Other.RS;
124     NumOpts = Other.NumOpts;
125     DeniedOpts = Other.DeniedOpts;
126     OptUnsafeEdges = std::move(Other.OptUnsafeEdges);
127     VReg = Other.VReg;
128     OptionRegs = std::move(Other.OptionRegs);
129     return *this;
130   }
131
132   void setVReg(unsigned VReg) { this->VReg = VReg; }
133   unsigned getVReg() const { return VReg; }
134
135   void setOptionRegs(OptionToRegMap OptionRegs) {
136     this->OptionRegs = std::move(OptionRegs);
137   }
138   const OptionToRegMap& getOptionRegs() const { return OptionRegs; }
139
140   void setup(const Vector& Costs) {
141     NumOpts = Costs.getLength() - 1;
142     OptUnsafeEdges = std::unique_ptr<unsigned[]>(new unsigned[NumOpts]());
143   }
144
145   ReductionState getReductionState() const { return RS; }
146   void setReductionState(ReductionState RS) { this->RS = RS; }
147
148   void handleAddEdge(const MatrixMetadata& MD, bool Transpose) {
149     DeniedOpts += Transpose ? MD.getWorstCol() : MD.getWorstRow();
150     const bool* UnsafeOpts =
151       Transpose ? MD.getUnsafeCols() : MD.getUnsafeRows();
152     for (unsigned i = 0; i < NumOpts; ++i)
153       OptUnsafeEdges[i] += UnsafeOpts[i];
154   }
155
156   void handleRemoveEdge(const MatrixMetadata& MD, bool Transpose) {
157     DeniedOpts -= Transpose ? MD.getWorstCol() : MD.getWorstRow();
158     const bool* UnsafeOpts =
159       Transpose ? MD.getUnsafeCols() : MD.getUnsafeRows();
160     for (unsigned i = 0; i < NumOpts; ++i)
161       OptUnsafeEdges[i] -= UnsafeOpts[i];
162   }
163
164   bool isConservativelyAllocatable() const {
165     return (DeniedOpts < NumOpts) ||
166       (std::find(&OptUnsafeEdges[0], &OptUnsafeEdges[NumOpts], 0) !=
167        &OptUnsafeEdges[NumOpts]);
168   }
169
170 private:
171   ReductionState RS;
172   unsigned NumOpts;
173   unsigned DeniedOpts;
174   std::unique_ptr<unsigned[]> OptUnsafeEdges;
175   unsigned VReg;
176   OptionToRegMap OptionRegs;
177 };
178
179 class RegAllocSolverImpl {
180 private:
181   typedef MDMatrix<MatrixMetadata> RAMatrix;
182 public:
183   typedef PBQP::Vector RawVector;
184   typedef PBQP::Matrix RawMatrix;
185   typedef PBQP::Vector Vector;
186   typedef RAMatrix     Matrix;
187   typedef PBQP::PoolCostAllocator<Vector, Matrix> CostAllocator;
188
189   typedef GraphBase::NodeId NodeId;
190   typedef GraphBase::EdgeId EdgeId;
191
192   typedef RegAlloc::NodeMetadata NodeMetadata;
193
194   struct EdgeMetadata { };
195
196   class GraphMetadata {
197   public:
198     GraphMetadata(MachineFunction &MF,
199                   LiveIntervals &LIS,
200                   MachineBlockFrequencyInfo &MBFI)
201       : MF(MF), LIS(LIS), MBFI(MBFI) {}
202
203     MachineFunction &MF;
204     LiveIntervals &LIS;
205     MachineBlockFrequencyInfo &MBFI;
206
207     void setNodeIdForVReg(unsigned VReg, GraphBase::NodeId NId) {
208       VRegToNodeId[VReg] = NId;
209     }
210
211     GraphBase::NodeId getNodeIdForVReg(unsigned VReg) const {
212       auto VRegItr = VRegToNodeId.find(VReg);
213       if (VRegItr == VRegToNodeId.end())
214         return GraphBase::invalidNodeId();
215       return VRegItr->second;
216     }
217
218     void eraseNodeIdForVReg(unsigned VReg) {
219       VRegToNodeId.erase(VReg);
220     }
221
222   private:
223     DenseMap<unsigned, NodeId> VRegToNodeId;
224   };
225
226   typedef PBQP::Graph<RegAllocSolverImpl> Graph;
227
228   RegAllocSolverImpl(Graph &G) : G(G) {}
229
230   Solution solve() {
231     G.setSolver(*this);
232     Solution S;
233     setup();
234     S = backpropagate(G, reduce());
235     G.unsetSolver();
236     return S;
237   }
238
239   void handleAddNode(NodeId NId) {
240     G.getNodeMetadata(NId).setup(G.getNodeCosts(NId));
241   }
242   void handleRemoveNode(NodeId NId) {}
243   void handleSetNodeCosts(NodeId NId, const Vector& newCosts) {}
244
245   void handleAddEdge(EdgeId EId) {
246     handleReconnectEdge(EId, G.getEdgeNode1Id(EId));
247     handleReconnectEdge(EId, G.getEdgeNode2Id(EId));
248   }
249
250   void handleRemoveEdge(EdgeId EId) {
251     handleDisconnectEdge(EId, G.getEdgeNode1Id(EId));
252     handleDisconnectEdge(EId, G.getEdgeNode2Id(EId));
253   }
254
255   void handleDisconnectEdge(EdgeId EId, NodeId NId) {
256     NodeMetadata& NMd = G.getNodeMetadata(NId);
257     const MatrixMetadata& MMd = G.getEdgeCosts(EId).getMetadata();
258     NMd.handleRemoveEdge(MMd, NId == G.getEdgeNode2Id(EId));
259     if (G.getNodeDegree(NId) == 3) {
260       // This node is becoming optimally reducible.
261       moveToOptimallyReducibleNodes(NId);
262     } else if (NMd.getReductionState() ==
263                NodeMetadata::NotProvablyAllocatable &&
264                NMd.isConservativelyAllocatable()) {
265       // This node just became conservatively allocatable.
266       moveToConservativelyAllocatableNodes(NId);
267     }
268   }
269
270   void handleReconnectEdge(EdgeId EId, NodeId NId) {
271     NodeMetadata& NMd = G.getNodeMetadata(NId);
272     const MatrixMetadata& MMd = G.getEdgeCosts(EId).getMetadata();
273     NMd.handleAddEdge(MMd, NId == G.getEdgeNode2Id(EId));
274   }
275
276   void handleSetEdgeCosts(EdgeId EId, const Matrix& NewCosts) {
277     handleRemoveEdge(EId);
278
279     NodeId N1Id = G.getEdgeNode1Id(EId);
280     NodeId N2Id = G.getEdgeNode2Id(EId);
281     NodeMetadata& N1Md = G.getNodeMetadata(N1Id);
282     NodeMetadata& N2Md = G.getNodeMetadata(N2Id);
283     const MatrixMetadata& MMd = NewCosts.getMetadata();
284     N1Md.handleAddEdge(MMd, N1Id != G.getEdgeNode1Id(EId));
285     N2Md.handleAddEdge(MMd, N2Id != G.getEdgeNode1Id(EId));
286   }
287
288 private:
289
290   void removeFromCurrentSet(NodeId NId) {
291     switch (G.getNodeMetadata(NId).getReductionState()) {
292     case NodeMetadata::Unprocessed: break;
293     case NodeMetadata::OptimallyReducible:
294       assert(OptimallyReducibleNodes.find(NId) !=
295              OptimallyReducibleNodes.end() &&
296              "Node not in optimally reducible set.");
297       OptimallyReducibleNodes.erase(NId);
298       break;
299     case NodeMetadata::ConservativelyAllocatable:
300       assert(ConservativelyAllocatableNodes.find(NId) !=
301              ConservativelyAllocatableNodes.end() &&
302              "Node not in conservatively allocatable set.");
303       ConservativelyAllocatableNodes.erase(NId);
304       break;
305     case NodeMetadata::NotProvablyAllocatable:
306       assert(NotProvablyAllocatableNodes.find(NId) !=
307              NotProvablyAllocatableNodes.end() &&
308              "Node not in not-provably-allocatable set.");
309       NotProvablyAllocatableNodes.erase(NId);
310       break;
311     }
312   }
313
314   void moveToOptimallyReducibleNodes(NodeId NId) {
315     removeFromCurrentSet(NId);
316     OptimallyReducibleNodes.insert(NId);
317     G.getNodeMetadata(NId).setReductionState(
318       NodeMetadata::OptimallyReducible);
319   }
320
321   void moveToConservativelyAllocatableNodes(NodeId NId) {
322     removeFromCurrentSet(NId);
323     ConservativelyAllocatableNodes.insert(NId);
324     G.getNodeMetadata(NId).setReductionState(
325       NodeMetadata::ConservativelyAllocatable);
326   }
327
328   void moveToNotProvablyAllocatableNodes(NodeId NId) {
329     removeFromCurrentSet(NId);
330     NotProvablyAllocatableNodes.insert(NId);
331     G.getNodeMetadata(NId).setReductionState(
332       NodeMetadata::NotProvablyAllocatable);
333   }
334
335   void setup() {
336     // Set up worklists.
337     for (auto NId : G.nodeIds()) {
338       if (G.getNodeDegree(NId) < 3)
339         moveToOptimallyReducibleNodes(NId);
340       else if (G.getNodeMetadata(NId).isConservativelyAllocatable())
341         moveToConservativelyAllocatableNodes(NId);
342       else
343         moveToNotProvablyAllocatableNodes(NId);
344     }
345   }
346
347   // Compute a reduction order for the graph by iteratively applying PBQP
348   // reduction rules. Locally optimal rules are applied whenever possible (R0,
349   // R1, R2). If no locally-optimal rules apply then any conservatively
350   // allocatable node is reduced. Finally, if no conservatively allocatable
351   // node exists then the node with the lowest spill-cost:degree ratio is
352   // selected.
353   std::vector<GraphBase::NodeId> reduce() {
354     assert(!G.empty() && "Cannot reduce empty graph.");
355
356     typedef GraphBase::NodeId NodeId;
357     std::vector<NodeId> NodeStack;
358
359     // Consume worklists.
360     while (true) {
361       if (!OptimallyReducibleNodes.empty()) {
362         NodeSet::iterator NItr = OptimallyReducibleNodes.begin();
363         NodeId NId = *NItr;
364         OptimallyReducibleNodes.erase(NItr);
365         NodeStack.push_back(NId);
366         switch (G.getNodeDegree(NId)) {
367         case 0:
368           break;
369         case 1:
370           applyR1(G, NId);
371           break;
372         case 2:
373           applyR2(G, NId);
374           break;
375         default: llvm_unreachable("Not an optimally reducible node.");
376         }
377       } else if (!ConservativelyAllocatableNodes.empty()) {
378         // Conservatively allocatable nodes will never spill. For now just
379         // take the first node in the set and push it on the stack. When we
380         // start optimizing more heavily for register preferencing, it may
381         // would be better to push nodes with lower 'expected' or worst-case
382         // register costs first (since early nodes are the most
383         // constrained).
384         NodeSet::iterator NItr = ConservativelyAllocatableNodes.begin();
385         NodeId NId = *NItr;
386         ConservativelyAllocatableNodes.erase(NItr);
387         NodeStack.push_back(NId);
388         G.disconnectAllNeighborsFromNode(NId);
389
390       } else if (!NotProvablyAllocatableNodes.empty()) {
391         NodeSet::iterator NItr =
392           std::min_element(NotProvablyAllocatableNodes.begin(),
393                            NotProvablyAllocatableNodes.end(),
394                            SpillCostComparator(G));
395         NodeId NId = *NItr;
396         NotProvablyAllocatableNodes.erase(NItr);
397         NodeStack.push_back(NId);
398         G.disconnectAllNeighborsFromNode(NId);
399       } else
400         break;
401     }
402
403     return NodeStack;
404   }
405
406   class SpillCostComparator {
407   public:
408     SpillCostComparator(const Graph& G) : G(G) {}
409     bool operator()(NodeId N1Id, NodeId N2Id) {
410       PBQPNum N1SC = G.getNodeCosts(N1Id)[0] / G.getNodeDegree(N1Id);
411       PBQPNum N2SC = G.getNodeCosts(N2Id)[0] / G.getNodeDegree(N2Id);
412       return N1SC < N2SC;
413     }
414   private:
415     const Graph& G;
416   };
417
418   Graph& G;
419   typedef std::set<NodeId> NodeSet;
420   NodeSet OptimallyReducibleNodes;
421   NodeSet ConservativelyAllocatableNodes;
422   NodeSet NotProvablyAllocatableNodes;
423 };
424
425 class PBQPRAGraph : public PBQP::Graph<RegAllocSolverImpl> {
426 private:
427   typedef PBQP::Graph<RegAllocSolverImpl> BaseT;
428 public:
429   PBQPRAGraph(GraphMetadata Metadata) : BaseT(Metadata) {}
430 };
431
432 inline Solution solve(PBQPRAGraph& G) {
433   if (G.empty())
434     return Solution();
435   RegAllocSolverImpl RegAllocSolver(G);
436   return RegAllocSolver.solve();
437 }
438
439 } // namespace RegAlloc
440 } // namespace PBQP
441
442 /// @brief Create a PBQP register allocator instance.
443 FunctionPass *
444 createPBQPRegisterAllocator(char *customPassID = nullptr);
445
446 } // namespace llvm
447
448 #endif /* LLVM_CODEGEN_REGALLOCPBQP_H */