1 //===-- Briggs.h --- Briggs Heuristic for PBQP ------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
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.
16 //===----------------------------------------------------------------------===//
18 #ifndef LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H
19 #define LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H
21 #include "../HeuristicSolver.h"
22 #include "../HeuristicBase.h"
28 namespace Heuristics {
30 /// \brief PBQP Heuristic which applies an allocability test based on
33 /// This heuristic assumes that the elements of cost vectors in the PBQP
34 /// problem represent storage options, with the first being the spill
35 /// option and subsequent elements representing legal registers for the
36 /// corresponding node. Edge cost matrices are likewise assumed to represent
37 /// register constraints.
38 /// If one or more nodes can be proven allocable by this heuristic (by
39 /// inspection of their constraint matrices) then the allocable node of
40 /// highest degree is selected for the next reduction and pushed to the
41 /// solver stack. If no nodes can be proven allocable then the node with
42 /// the lowest estimated spill cost is selected and push to the solver stack
45 /// This implementation is built on top of HeuristicBase.
46 class Briggs : public HeuristicBase<Briggs> {
49 class LinkDegreeComparator {
51 LinkDegreeComparator(HeuristicSolverImpl<Briggs> &s) : s(&s) {}
52 bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const {
53 if (s->getSolverDegree(n1Itr) > s->getSolverDegree(n2Itr))
58 HeuristicSolverImpl<Briggs> *s;
61 class SpillCostComparator {
63 SpillCostComparator(HeuristicSolverImpl<Briggs> &s)
64 : s(&s), g(&s.getGraph()) {}
65 bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const {
66 PBQPNum cost1 = g->getNodeCosts(n1Itr)[0] / s->getSolverDegree(n1Itr),
67 cost2 = g->getNodeCosts(n2Itr)[0] / s->getSolverDegree(n2Itr);
74 HeuristicSolverImpl<Briggs> *s;
78 typedef std::list<Graph::NodeItr> RNAllocableList;
79 typedef RNAllocableList::iterator RNAllocableListItr;
81 typedef std::list<Graph::NodeItr> RNUnallocableList;
82 typedef RNUnallocableList::iterator RNUnallocableListItr;
87 typedef std::vector<unsigned> UnsafeDegreesArray;
88 bool isHeuristic, isAllocable, isInitialized;
89 unsigned numDenied, numSafe;
90 UnsafeDegreesArray unsafeDegrees;
91 RNAllocableListItr rnaItr;
92 RNUnallocableListItr rnuItr;
95 : isHeuristic(false), isAllocable(false), isInitialized(false),
96 numDenied(0), numSafe(0) { }
100 typedef std::vector<unsigned> UnsafeArray;
101 unsigned worst, reverseWorst;
102 UnsafeArray unsafe, reverseUnsafe;
105 EdgeData() : worst(0), reverseWorst(0), isUpToDate(false) {}
108 /// \brief Construct an instance of the Briggs heuristic.
109 /// @param solver A reference to the solver which is using this heuristic.
110 Briggs(HeuristicSolverImpl<Briggs> &solver) :
111 HeuristicBase<Briggs>(solver) {}
113 /// \brief Determine whether a node should be reduced using optimal
115 /// @param nItr Node iterator to be considered.
116 /// @return True if the given node should be optimally reduced, false
119 /// Selects nodes of degree 0, 1 or 2 for optimal reduction, with one
120 /// exception. Nodes whose spill cost (element 0 of their cost vector) is
121 /// infinite are checked for allocability first. Allocable nodes may be
122 /// optimally reduced, but nodes whose allocability cannot be proven are
123 /// selected for heuristic reduction instead.
124 bool shouldOptimallyReduce(Graph::NodeItr nItr) {
125 if (getSolver().getSolverDegree(nItr) < 3) {
132 /// \brief Add a node to the heuristic reduce list.
133 /// @param nItr Node iterator to add to the heuristic reduce list.
134 void addToHeuristicReduceList(Graph::NodeItr nItr) {
135 NodeData &nd = getHeuristicNodeData(nItr);
136 initializeNode(nItr);
137 nd.isHeuristic = true;
138 if (nd.isAllocable) {
139 nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr);
141 nd.rnuItr = rnUnallocableList.insert(rnUnallocableList.end(), nItr);
145 /// \brief Heuristically reduce one of the nodes in the heuristic
147 /// @return True if a reduction takes place, false if the heuristic reduce
150 /// If the list of allocable nodes is non-empty a node is selected
151 /// from it and pushed to the stack. Otherwise if the non-allocable list
152 /// is non-empty a node is selected from it and pushed to the stack.
153 /// If both lists are empty the method simply returns false with no action
155 bool heuristicReduce() {
156 if (!rnAllocableList.empty()) {
157 RNAllocableListItr rnaItr =
158 min_element(rnAllocableList.begin(), rnAllocableList.end(),
159 LinkDegreeComparator(getSolver()));
160 Graph::NodeItr nItr = *rnaItr;
161 rnAllocableList.erase(rnaItr);
162 handleRemoveNode(nItr);
163 getSolver().pushToStack(nItr);
165 } else if (!rnUnallocableList.empty()) {
166 RNUnallocableListItr rnuItr =
167 min_element(rnUnallocableList.begin(), rnUnallocableList.end(),
168 SpillCostComparator(getSolver()));
169 Graph::NodeItr nItr = *rnuItr;
170 rnUnallocableList.erase(rnuItr);
171 handleRemoveNode(nItr);
172 getSolver().pushToStack(nItr);
179 /// \brief Prepare a change in the costs on the given edge.
180 /// @param eItr Edge iterator.
181 void preUpdateEdgeCosts(Graph::EdgeItr eItr) {
182 Graph &g = getGraph();
183 Graph::NodeItr n1Itr = g.getEdgeNode1(eItr),
184 n2Itr = g.getEdgeNode2(eItr);
185 NodeData &n1 = getHeuristicNodeData(n1Itr),
186 &n2 = getHeuristicNodeData(n2Itr);
189 subtractEdgeContributions(eItr, getGraph().getEdgeNode1(eItr));
191 subtractEdgeContributions(eItr, getGraph().getEdgeNode2(eItr));
193 EdgeData &ed = getHeuristicEdgeData(eItr);
194 ed.isUpToDate = false;
197 /// \brief Handle the change in the costs on the given edge.
198 /// @param eItr Edge iterator.
199 void postUpdateEdgeCosts(Graph::EdgeItr eItr) {
200 // This is effectively the same as adding a new edge now, since
201 // we've factored out the costs of the old one.
205 /// \brief Handle the addition of a new edge into the PBQP graph.
206 /// @param eItr Edge iterator for the added edge.
208 /// Updates allocability of any nodes connected by this edge which are
209 /// being managed by the heuristic. If allocability changes they are
210 /// moved to the appropriate list.
211 void handleAddEdge(Graph::EdgeItr eItr) {
212 Graph &g = getGraph();
213 Graph::NodeItr n1Itr = g.getEdgeNode1(eItr),
214 n2Itr = g.getEdgeNode2(eItr);
215 NodeData &n1 = getHeuristicNodeData(n1Itr),
216 &n2 = getHeuristicNodeData(n2Itr);
218 // If neither node is managed by the heuristic there's nothing to be
220 if (!n1.isHeuristic && !n2.isHeuristic)
223 // Ok - we need to update at least one node.
224 computeEdgeContributions(eItr);
226 // Update node 1 if it's managed by the heuristic.
227 if (n1.isHeuristic) {
228 bool n1WasAllocable = n1.isAllocable;
229 addEdgeContributions(eItr, n1Itr);
230 updateAllocability(n1Itr);
231 if (n1WasAllocable && !n1.isAllocable) {
232 rnAllocableList.erase(n1.rnaItr);
234 rnUnallocableList.insert(rnUnallocableList.end(), n1Itr);
238 // Likewise for node 2.
239 if (n2.isHeuristic) {
240 bool n2WasAllocable = n2.isAllocable;
241 addEdgeContributions(eItr, n2Itr);
242 updateAllocability(n2Itr);
243 if (n2WasAllocable && !n2.isAllocable) {
244 rnAllocableList.erase(n2.rnaItr);
246 rnUnallocableList.insert(rnUnallocableList.end(), n2Itr);
251 /// \brief Handle disconnection of an edge from a node.
252 /// @param eItr Edge iterator for edge being disconnected.
253 /// @param nItr Node iterator for the node being disconnected from.
255 /// Updates allocability of the given node and, if appropriate, moves the
256 /// node to a new list.
257 void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
258 NodeData &nd = getHeuristicNodeData(nItr);
260 // If the node is not managed by the heuristic there's nothing to be
265 EdgeData &ed = getHeuristicEdgeData(eItr);
267 assert(ed.isUpToDate && "Edge data is not up to date.");
270 bool ndWasAllocable = nd.isAllocable;
271 subtractEdgeContributions(eItr, nItr);
272 updateAllocability(nItr);
274 // If the node has gone optimal...
275 if (shouldOptimallyReduce(nItr)) {
276 nd.isHeuristic = false;
277 addToOptimalReduceList(nItr);
278 if (ndWasAllocable) {
279 rnAllocableList.erase(nd.rnaItr);
281 rnUnallocableList.erase(nd.rnuItr);
284 // Node didn't go optimal, but we might have to move it
285 // from "unallocable" to "allocable".
286 if (!ndWasAllocable && nd.isAllocable) {
287 rnUnallocableList.erase(nd.rnuItr);
288 nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr);
295 NodeData& getHeuristicNodeData(Graph::NodeItr nItr) {
296 return getSolver().getHeuristicNodeData(nItr);
299 EdgeData& getHeuristicEdgeData(Graph::EdgeItr eItr) {
300 return getSolver().getHeuristicEdgeData(eItr);
303 // Work out what this edge will contribute to the allocability of the
304 // nodes connected to it.
305 void computeEdgeContributions(Graph::EdgeItr eItr) {
306 EdgeData &ed = getHeuristicEdgeData(eItr);
309 return; // Edge data is already up to date.
311 Matrix &eCosts = getGraph().getEdgeCosts(eItr);
313 unsigned numRegs = eCosts.getRows() - 1,
314 numReverseRegs = eCosts.getCols() - 1;
316 std::vector<unsigned> rowInfCounts(numRegs, 0),
317 colInfCounts(numReverseRegs, 0);
322 ed.unsafe.resize(numRegs, 0);
323 ed.reverseUnsafe.clear();
324 ed.reverseUnsafe.resize(numReverseRegs, 0);
326 for (unsigned i = 0; i < numRegs; ++i) {
327 for (unsigned j = 0; j < numReverseRegs; ++j) {
328 if (eCosts[i + 1][j + 1] ==
329 std::numeric_limits<PBQPNum>::infinity()) {
331 ed.reverseUnsafe[j] = 1;
335 if (colInfCounts[j] > ed.worst) {
336 ed.worst = colInfCounts[j];
339 if (rowInfCounts[i] > ed.reverseWorst) {
340 ed.reverseWorst = rowInfCounts[i];
346 ed.isUpToDate = true;
349 // Add the contributions of the given edge to the given node's
350 // numDenied and safe members. No action is taken other than to update
351 // these member values. Once updated these numbers can be used by clients
352 // to update the node's allocability.
353 void addEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
354 EdgeData &ed = getHeuristicEdgeData(eItr);
356 assert(ed.isUpToDate && "Using out-of-date edge numbers.");
358 NodeData &nd = getHeuristicNodeData(nItr);
359 unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
361 bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr);
362 EdgeData::UnsafeArray &unsafe =
363 nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
364 nd.numDenied += nIsNode1 ? ed.worst : ed.reverseWorst;
366 for (unsigned r = 0; r < numRegs; ++r) {
368 if (nd.unsafeDegrees[r]==0) {
371 ++nd.unsafeDegrees[r];
376 // Subtract the contributions of the given edge to the given node's
377 // numDenied and safe members. No action is taken other than to update
378 // these member values. Once updated these numbers can be used by clients
379 // to update the node's allocability.
380 void subtractEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
381 EdgeData &ed = getHeuristicEdgeData(eItr);
383 assert(ed.isUpToDate && "Using out-of-date edge numbers.");
385 NodeData &nd = getHeuristicNodeData(nItr);
386 unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
388 bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr);
389 EdgeData::UnsafeArray &unsafe =
390 nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
391 nd.numDenied -= nIsNode1 ? ed.worst : ed.reverseWorst;
393 for (unsigned r = 0; r < numRegs; ++r) {
395 if (nd.unsafeDegrees[r] == 1) {
398 --nd.unsafeDegrees[r];
403 void updateAllocability(Graph::NodeItr nItr) {
404 NodeData &nd = getHeuristicNodeData(nItr);
405 unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
406 nd.isAllocable = nd.numDenied < numRegs || nd.numSafe > 0;
409 void initializeNode(Graph::NodeItr nItr) {
410 NodeData &nd = getHeuristicNodeData(nItr);
412 if (nd.isInitialized)
413 return; // Node data is already up to date.
415 unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
418 nd.numSafe = numRegs;
419 nd.unsafeDegrees.resize(numRegs, 0);
421 typedef HeuristicSolverImpl<Briggs>::SolverEdgeItr SolverEdgeItr;
423 for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(nItr),
424 aeEnd = getSolver().solverEdgesEnd(nItr);
425 aeItr != aeEnd; ++aeItr) {
427 Graph::EdgeItr eItr = *aeItr;
428 computeEdgeContributions(eItr);
429 addEdgeContributions(eItr, nItr);
432 updateAllocability(nItr);
433 nd.isInitialized = true;
436 void handleRemoveNode(Graph::NodeItr xnItr) {
437 typedef HeuristicSolverImpl<Briggs>::SolverEdgeItr SolverEdgeItr;
438 std::vector<Graph::EdgeItr> edgesToRemove;
439 for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(xnItr),
440 aeEnd = getSolver().solverEdgesEnd(xnItr);
441 aeItr != aeEnd; ++aeItr) {
442 Graph::NodeItr ynItr = getGraph().getEdgeOtherNode(*aeItr, xnItr);
443 handleRemoveEdge(*aeItr, ynItr);
444 edgesToRemove.push_back(*aeItr);
446 while (!edgesToRemove.empty()) {
447 getSolver().removeSolverEdge(edgesToRemove.back());
448 edgesToRemove.pop_back();
452 RNAllocableList rnAllocableList;
453 RNUnallocableList rnUnallocableList;
460 #endif // LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H