a859e5899f063cf3a8f8dd24ac938d6c666934d4
[oota-llvm.git] / include / llvm / CodeGen / PBQP / Heuristics / Briggs.h
1 //===-- Briggs.h --- Briggs Heuristic for PBQP ------------------*- 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 class implements the Briggs test for "allocability" of nodes in a
11 // PBQP graph representing a register allocation problem. Nodes which can be
12 // proven allocable (by a safe and relatively accurate test) are removed from
13 // the PBQP graph first. If no provably allocable node is present in the graph
14 // then the node with the minimal spill-cost to degree ratio is removed.
15 //
16 //===----------------------------------------------------------------------===//
17
18 #ifndef LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H
19 #define LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H
20
21 #include "../HeuristicSolver.h"
22 #include "../HeuristicBase.h"
23
24 #include <limits>
25
26 namespace PBQP {
27   namespace Heuristics {
28
29     /// \brief PBQP Heuristic which applies an allocability test based on
30     ///        Briggs.
31     /// 
32     /// This heuristic assumes that the elements of cost vectors in the PBQP
33     /// problem represent storage options, with the first being the spill
34     /// option and subsequent elements representing legal registers for the
35     /// corresponding node. Edge cost matrices are likewise assumed to represent
36     /// register constraints.
37     /// If one or more nodes can be proven allocable by this heuristic (by
38     /// inspection of their constraint matrices) then the allocable node of
39     /// highest degree is selected for the next reduction and pushed to the
40     /// solver stack. If no nodes can be proven allocable then the node with
41     /// the lowest estimated spill cost is selected and push to the solver stack
42     /// instead.
43     /// 
44     /// This implementation is built on top of HeuristicBase.       
45     class Briggs : public HeuristicBase<Briggs> {
46     private:
47
48       class LinkDegreeComparator {
49       public:
50         LinkDegreeComparator(HeuristicSolverImpl<Briggs> &s) : s(&s) {}
51         bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const {
52           if (s->getSolverDegree(n1Itr) > s->getSolverDegree(n2Itr))
53             return true;
54           return false;
55         }
56       private:
57         HeuristicSolverImpl<Briggs> *s;
58       };
59
60       class SpillCostComparator {
61       public:
62         SpillCostComparator(HeuristicSolverImpl<Briggs> &s)
63           : s(&s), g(&s.getGraph()) {}
64         bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const {
65           const PBQP::Vector &cv1 = g->getNodeCosts(n1Itr);
66           const PBQP::Vector &cv2 = g->getNodeCosts(n2Itr);
67
68           PBQPNum cost1 = cv1[0] / s->getSolverDegree(n1Itr);
69           PBQPNum cost2 = cv2[0] / s->getSolverDegree(n2Itr);
70
71           if (cost1 < cost2)
72             return true;
73           return false;
74         }
75
76       private:
77         HeuristicSolverImpl<Briggs> *s;
78         Graph *g;
79       };
80
81       typedef std::list<Graph::NodeItr> RNAllocableList;
82       typedef RNAllocableList::iterator RNAllocableListItr;
83
84       typedef std::list<Graph::NodeItr> RNUnallocableList;  
85       typedef RNUnallocableList::iterator RNUnallocableListItr;
86
87     public:
88
89       struct NodeData {
90         typedef std::vector<unsigned> UnsafeDegreesArray;
91         bool isHeuristic, isAllocable, isInitialized;
92         unsigned numDenied, numSafe;
93         UnsafeDegreesArray unsafeDegrees;
94         RNAllocableListItr rnaItr;
95         RNUnallocableListItr rnuItr;
96
97         NodeData()
98           : isHeuristic(false), isAllocable(false), isInitialized(false),
99             numDenied(0), numSafe(0) { }
100       };
101
102       struct EdgeData {
103         typedef std::vector<unsigned> UnsafeArray;
104         unsigned worst, reverseWorst;
105         UnsafeArray unsafe, reverseUnsafe;
106         bool isUpToDate;
107
108         EdgeData() : worst(0), reverseWorst(0), isUpToDate(false) {}
109       };
110
111       /// \brief Construct an instance of the Briggs heuristic.
112       /// @param solver A reference to the solver which is using this heuristic.
113       Briggs(HeuristicSolverImpl<Briggs> &solver) :
114         HeuristicBase<Briggs>(solver) {}
115
116       /// \brief Determine whether a node should be reduced using optimal
117       ///        reduction.
118       /// @param nItr Node iterator to be considered.
119       /// @return True if the given node should be optimally reduced, false
120       ///         otherwise.
121       ///
122       /// Selects nodes of degree 0, 1 or 2 for optimal reduction, with one
123       /// exception. Nodes whose spill cost (element 0 of their cost vector) is
124       /// infinite are checked for allocability first. Allocable nodes may be
125       /// optimally reduced, but nodes whose allocability cannot be proven are
126       /// selected for heuristic reduction instead.
127       bool shouldOptimallyReduce(Graph::NodeItr nItr) {
128         if (getSolver().getSolverDegree(nItr) < 3) {
129           return true;
130         }
131         // else
132         return false;
133       }
134
135       /// \brief Add a node to the heuristic reduce list.
136       /// @param nItr Node iterator to add to the heuristic reduce list.
137       void addToHeuristicReduceList(Graph::NodeItr nItr) {
138         NodeData &nd = getHeuristicNodeData(nItr);
139         initializeNode(nItr);
140         nd.isHeuristic = true;
141         if (nd.isAllocable) {
142           nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr);
143         } else {
144           nd.rnuItr = rnUnallocableList.insert(rnUnallocableList.end(), nItr);
145         }
146       }
147
148       /// \brief Heuristically reduce one of the nodes in the heuristic
149       ///        reduce list.
150       /// @return True if a reduction takes place, false if the heuristic reduce
151       ///         list is empty.
152       ///
153       /// If the list of allocable nodes is non-empty a node is selected
154       /// from it and pushed to the stack. Otherwise if the non-allocable list
155       /// is non-empty a node is selected from it and pushed to the stack.
156       /// If both lists are empty the method simply returns false with no action
157       /// taken.
158       bool heuristicReduce() {
159         if (!rnAllocableList.empty()) {
160           RNAllocableListItr rnaItr =
161             min_element(rnAllocableList.begin(), rnAllocableList.end(),
162                         LinkDegreeComparator(getSolver()));
163           Graph::NodeItr nItr = *rnaItr;
164           rnAllocableList.erase(rnaItr);
165           handleRemoveNode(nItr);
166           getSolver().pushToStack(nItr);
167           return true;
168         } else if (!rnUnallocableList.empty()) {
169           RNUnallocableListItr rnuItr =
170             min_element(rnUnallocableList.begin(), rnUnallocableList.end(),
171                         SpillCostComparator(getSolver()));
172           Graph::NodeItr nItr = *rnuItr;
173           rnUnallocableList.erase(rnuItr);
174           handleRemoveNode(nItr);
175           getSolver().pushToStack(nItr);
176           return true;
177         }
178         // else
179         return false;
180       }
181
182       /// \brief Prepare a change in the costs on the given edge.
183       /// @param eItr Edge iterator.    
184       void preUpdateEdgeCosts(Graph::EdgeItr eItr) {
185         Graph &g = getGraph();
186         Graph::NodeItr n1Itr = g.getEdgeNode1(eItr),
187                        n2Itr = g.getEdgeNode2(eItr);
188         NodeData &n1 = getHeuristicNodeData(n1Itr),
189                  &n2 = getHeuristicNodeData(n2Itr);
190
191         if (n1.isHeuristic)
192           subtractEdgeContributions(eItr, getGraph().getEdgeNode1(eItr));
193         if (n2.isHeuristic)
194           subtractEdgeContributions(eItr, getGraph().getEdgeNode2(eItr));
195
196         EdgeData &ed = getHeuristicEdgeData(eItr);
197         ed.isUpToDate = false;
198       }
199
200       /// \brief Handle the change in the costs on the given edge.
201       /// @param eItr Edge iterator.
202       void postUpdateEdgeCosts(Graph::EdgeItr eItr) {
203         // This is effectively the same as adding a new edge now, since
204         // we've factored out the costs of the old one.
205         handleAddEdge(eItr);
206       }
207
208       /// \brief Handle the addition of a new edge into the PBQP graph.
209       /// @param eItr Edge iterator for the added edge.
210       ///
211       /// Updates allocability of any nodes connected by this edge which are
212       /// being managed by the heuristic. If allocability changes they are
213       /// moved to the appropriate list.
214       void handleAddEdge(Graph::EdgeItr eItr) {
215         Graph &g = getGraph();
216         Graph::NodeItr n1Itr = g.getEdgeNode1(eItr),
217                        n2Itr = g.getEdgeNode2(eItr);
218         NodeData &n1 = getHeuristicNodeData(n1Itr),
219                  &n2 = getHeuristicNodeData(n2Itr);
220
221         // If neither node is managed by the heuristic there's nothing to be
222         // done.
223         if (!n1.isHeuristic && !n2.isHeuristic)
224           return;
225
226         // Ok - we need to update at least one node.
227         computeEdgeContributions(eItr);
228
229         // Update node 1 if it's managed by the heuristic.
230         if (n1.isHeuristic) {
231           bool n1WasAllocable = n1.isAllocable;
232           addEdgeContributions(eItr, n1Itr);
233           updateAllocability(n1Itr);
234           if (n1WasAllocable && !n1.isAllocable) {
235             rnAllocableList.erase(n1.rnaItr);
236             n1.rnuItr =
237               rnUnallocableList.insert(rnUnallocableList.end(), n1Itr);
238           }
239         }
240
241         // Likewise for node 2.
242         if (n2.isHeuristic) {
243           bool n2WasAllocable = n2.isAllocable;
244           addEdgeContributions(eItr, n2Itr);
245           updateAllocability(n2Itr);
246           if (n2WasAllocable && !n2.isAllocable) {
247             rnAllocableList.erase(n2.rnaItr);
248             n2.rnuItr =
249               rnUnallocableList.insert(rnUnallocableList.end(), n2Itr);
250           }
251         }
252       }
253
254       /// \brief Handle disconnection of an edge from a node.
255       /// @param eItr Edge iterator for edge being disconnected.
256       /// @param nItr Node iterator for the node being disconnected from.
257       ///
258       /// Updates allocability of the given node and, if appropriate, moves the
259       /// node to a new list.
260       void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
261         NodeData &nd = getHeuristicNodeData(nItr);
262
263         // If the node is not managed by the heuristic there's nothing to be
264         // done.
265         if (!nd.isHeuristic)
266           return;
267
268         EdgeData &ed = getHeuristicEdgeData(eItr);
269         (void)ed;
270         assert(ed.isUpToDate && "Edge data is not up to date.");
271
272         // Update node.
273         bool ndWasAllocable = nd.isAllocable;
274         subtractEdgeContributions(eItr, nItr);
275         updateAllocability(nItr);
276
277         // If the node has gone optimal...
278         if (shouldOptimallyReduce(nItr)) {
279           nd.isHeuristic = false;
280           addToOptimalReduceList(nItr);
281           if (ndWasAllocable) {
282             rnAllocableList.erase(nd.rnaItr);
283           } else {
284             rnUnallocableList.erase(nd.rnuItr);
285           }
286         } else {
287           // Node didn't go optimal, but we might have to move it
288           // from "unallocable" to "allocable".
289           if (!ndWasAllocable && nd.isAllocable) {
290             rnUnallocableList.erase(nd.rnuItr);
291             nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr);
292           }
293         }
294       }
295
296     private:
297
298       NodeData& getHeuristicNodeData(Graph::NodeItr nItr) {
299         return getSolver().getHeuristicNodeData(nItr);
300       }
301
302       EdgeData& getHeuristicEdgeData(Graph::EdgeItr eItr) {
303         return getSolver().getHeuristicEdgeData(eItr);
304       }
305
306       // Work out what this edge will contribute to the allocability of the
307       // nodes connected to it.
308       void computeEdgeContributions(Graph::EdgeItr eItr) {
309         EdgeData &ed = getHeuristicEdgeData(eItr);
310
311         if (ed.isUpToDate)
312           return; // Edge data is already up to date.
313
314         Matrix &eCosts = getGraph().getEdgeCosts(eItr);
315
316         unsigned numRegs = eCosts.getRows() - 1,
317                  numReverseRegs = eCosts.getCols() - 1;
318
319         std::vector<unsigned> rowInfCounts(numRegs, 0),
320                               colInfCounts(numReverseRegs, 0);        
321
322         ed.worst = 0;
323         ed.reverseWorst = 0;
324         ed.unsafe.clear();
325         ed.unsafe.resize(numRegs, 0);
326         ed.reverseUnsafe.clear();
327         ed.reverseUnsafe.resize(numReverseRegs, 0);
328
329         for (unsigned i = 0; i < numRegs; ++i) {
330           for (unsigned j = 0; j < numReverseRegs; ++j) {
331             if (eCosts[i + 1][j + 1] ==
332                   std::numeric_limits<PBQPNum>::infinity()) {
333               ed.unsafe[i] = 1;
334               ed.reverseUnsafe[j] = 1;
335               ++rowInfCounts[i];
336               ++colInfCounts[j];
337
338               if (colInfCounts[j] > ed.worst) {
339                 ed.worst = colInfCounts[j];
340               }
341
342               if (rowInfCounts[i] > ed.reverseWorst) {
343                 ed.reverseWorst = rowInfCounts[i];
344               }
345             }
346           }
347         }
348
349         ed.isUpToDate = true;
350       }
351
352       // Add the contributions of the given edge to the given node's 
353       // numDenied and safe members. No action is taken other than to update
354       // these member values. Once updated these numbers can be used by clients
355       // to update the node's allocability.
356       void addEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
357         EdgeData &ed = getHeuristicEdgeData(eItr);
358
359         assert(ed.isUpToDate && "Using out-of-date edge numbers.");
360
361         NodeData &nd = getHeuristicNodeData(nItr);
362         unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
363         
364         bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr);
365         EdgeData::UnsafeArray &unsafe =
366           nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
367         nd.numDenied += nIsNode1 ? ed.worst : ed.reverseWorst;
368
369         for (unsigned r = 0; r < numRegs; ++r) {
370           if (unsafe[r]) {
371             if (nd.unsafeDegrees[r]==0) {
372               --nd.numSafe;
373             }
374             ++nd.unsafeDegrees[r];
375           }
376         }
377       }
378
379       // Subtract the contributions of the given edge to the given node's 
380       // numDenied and safe members. No action is taken other than to update
381       // these member values. Once updated these numbers can be used by clients
382       // to update the node's allocability.
383       void subtractEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
384         EdgeData &ed = getHeuristicEdgeData(eItr);
385
386         assert(ed.isUpToDate && "Using out-of-date edge numbers.");
387
388         NodeData &nd = getHeuristicNodeData(nItr);
389         unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
390         
391         bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr);
392         EdgeData::UnsafeArray &unsafe =
393           nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
394         nd.numDenied -= nIsNode1 ? ed.worst : ed.reverseWorst;
395
396         for (unsigned r = 0; r < numRegs; ++r) {
397           if (unsafe[r]) { 
398             if (nd.unsafeDegrees[r] == 1) {
399               ++nd.numSafe;
400             }
401             --nd.unsafeDegrees[r];
402           }
403         }
404       }
405
406       void updateAllocability(Graph::NodeItr nItr) {
407         NodeData &nd = getHeuristicNodeData(nItr);
408         unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
409         nd.isAllocable = nd.numDenied < numRegs || nd.numSafe > 0;
410       }
411
412       void initializeNode(Graph::NodeItr nItr) {
413         NodeData &nd = getHeuristicNodeData(nItr);
414
415         if (nd.isInitialized)
416           return; // Node data is already up to date.
417
418         unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
419
420         nd.numDenied = 0;
421         const Vector& nCosts = getGraph().getNodeCosts(nItr);
422         for (unsigned i = 1; i < nCosts.getLength(); ++i) {
423           if (nCosts[i] == std::numeric_limits<PBQPNum>::infinity())
424             ++nd.numDenied;
425         }
426
427         nd.numSafe = numRegs;
428         nd.unsafeDegrees.resize(numRegs, 0);
429
430         typedef HeuristicSolverImpl<Briggs>::SolverEdgeItr SolverEdgeItr;
431
432         for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(nItr),
433                            aeEnd = getSolver().solverEdgesEnd(nItr);
434              aeItr != aeEnd; ++aeItr) {
435           
436           Graph::EdgeItr eItr = *aeItr;
437           computeEdgeContributions(eItr);
438           addEdgeContributions(eItr, nItr);
439         }
440
441         updateAllocability(nItr);
442         nd.isInitialized = true;
443       }
444
445       void handleRemoveNode(Graph::NodeItr xnItr) {
446         typedef HeuristicSolverImpl<Briggs>::SolverEdgeItr SolverEdgeItr;
447         std::vector<Graph::EdgeItr> edgesToRemove;
448         for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(xnItr),
449                            aeEnd = getSolver().solverEdgesEnd(xnItr);
450              aeItr != aeEnd; ++aeItr) {
451           Graph::NodeItr ynItr = getGraph().getEdgeOtherNode(*aeItr, xnItr);
452           handleRemoveEdge(*aeItr, ynItr);
453           edgesToRemove.push_back(*aeItr);
454         }
455         while (!edgesToRemove.empty()) {
456           getSolver().removeSolverEdge(edgesToRemove.back());
457           edgesToRemove.pop_back();
458         }
459       }
460
461       RNAllocableList rnAllocableList;
462       RNUnallocableList rnUnallocableList;
463     };
464
465   }
466 }
467
468
469 #endif // LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H