blob: 65f22cbc04357ff7d06fbe6f62ce154890ab8fda [file] [log] [blame]
Lang Hames98e6e6d2010-01-06 08:53:34 +00001//===-- Briggs.h --- Briggs Heuristic for PBQP ------------------*- C++ -*-===//
Lang Hames25e96512009-08-07 00:25:12 +00002//
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
Lang Hames3ca9a5b2009-08-06 23:32:48 +000018#ifndef LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H
19#define LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H
20
21#include "../HeuristicSolver.h"
Lang Hames408dcd32010-01-26 04:49:58 +000022#include "../HeuristicBase.h"
Lang Hames3ca9a5b2009-08-06 23:32:48 +000023
24#include <set>
Lang Hames408dcd32010-01-26 04:49:58 +000025#include <limits>
Lang Hames3ca9a5b2009-08-06 23:32:48 +000026
27namespace PBQP {
Lang Hames408dcd32010-01-26 04:49:58 +000028 namespace Heuristics {
Lang Hames3ca9a5b2009-08-06 23:32:48 +000029
Lang Hames408dcd32010-01-26 04:49:58 +000030 /// \brief PBQP Heuristic which applies an allocability test based on
31 /// Briggs.
32 ///
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
43 /// instead.
44 ///
45 /// This implementation is built on top of HeuristicBase.
46 class Briggs : public HeuristicBase<Briggs> {
47 private:
Lang Hames3ca9a5b2009-08-06 23:32:48 +000048
Lang Hames408dcd32010-01-26 04:49:58 +000049 class LinkDegreeComparator {
Lang Hames3ca9a5b2009-08-06 23:32:48 +000050 public:
Lang Hames408dcd32010-01-26 04:49:58 +000051 LinkDegreeComparator(HeuristicSolverImpl<Briggs> &s) : s(&s) {}
52 bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const {
53 if (s->getSolverDegree(n1Itr) > s->getSolverDegree(n2Itr))
Lang Hames3ca9a5b2009-08-06 23:32:48 +000054 return true;
Lang Hames408dcd32010-01-26 04:49:58 +000055 if (s->getSolverDegree(n1Itr) < s->getSolverDegree(n2Itr))
Lang Hames3ca9a5b2009-08-06 23:32:48 +000056 return false;
Lang Hames408dcd32010-01-26 04:49:58 +000057 return (&*n1Itr < &*n2Itr);
Lang Hames3ca9a5b2009-08-06 23:32:48 +000058 }
Lang Hames3ca9a5b2009-08-06 23:32:48 +000059 private:
Lang Hames408dcd32010-01-26 04:49:58 +000060 HeuristicSolverImpl<Briggs> *s;
61 };
Lang Hames3ca9a5b2009-08-06 23:32:48 +000062
Lang Hames408dcd32010-01-26 04:49:58 +000063 class SpillCostComparator {
Lang Hames3ca9a5b2009-08-06 23:32:48 +000064 public:
Lang Hames408dcd32010-01-26 04:49:58 +000065 SpillCostComparator(HeuristicSolverImpl<Briggs> &s)
66 : s(&s), g(&s.getGraph()) {}
67 bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const {
68 PBQPNum cost1 = g->getNodeCosts(n1Itr)[0] / s->getSolverDegree(n1Itr),
69 cost2 = g->getNodeCosts(n2Itr)[0] / s->getSolverDegree(n2Itr);
70 if (cost1 < cost2)
Lang Hames3ca9a5b2009-08-06 23:32:48 +000071 return true;
Lang Hames408dcd32010-01-26 04:49:58 +000072 if (cost1 > cost2)
Lang Hames3ca9a5b2009-08-06 23:32:48 +000073 return false;
Lang Hames408dcd32010-01-26 04:49:58 +000074 return (&*n1Itr < &*n2Itr);
Lang Hames3ca9a5b2009-08-06 23:32:48 +000075 }
76
77 private:
Lang Hames408dcd32010-01-26 04:49:58 +000078 HeuristicSolverImpl<Briggs> *s;
79 Graph *g;
80 };
Lang Hames3ca9a5b2009-08-06 23:32:48 +000081
Lang Hames408dcd32010-01-26 04:49:58 +000082 typedef std::list<Graph::NodeItr> RNAllocableList;
83 typedef RNAllocableList::iterator RNAllocableListItr;
Lang Hames3ca9a5b2009-08-06 23:32:48 +000084
Lang Hames408dcd32010-01-26 04:49:58 +000085 typedef std::list<Graph::NodeItr> RNUnallocableList;
86 typedef RNUnallocableList::iterator RNUnallocableListItr;
Lang Hames3ca9a5b2009-08-06 23:32:48 +000087
Lang Hames408dcd32010-01-26 04:49:58 +000088 public:
Lang Hames3ca9a5b2009-08-06 23:32:48 +000089
Lang Hames408dcd32010-01-26 04:49:58 +000090 struct NodeData {
91 typedef std::vector<unsigned> UnsafeDegreesArray;
92 bool isHeuristic, isAllocable, isInitialized;
93 unsigned numDenied, numSafe;
94 UnsafeDegreesArray unsafeDegrees;
95 RNAllocableListItr rnaItr;
96 RNUnallocableListItr rnuItr;
Lang Hames3ca9a5b2009-08-06 23:32:48 +000097
Lang Hames408dcd32010-01-26 04:49:58 +000098 NodeData()
99 : isHeuristic(false), isAllocable(false), isInitialized(false),
100 numDenied(0), numSafe(0) { }
101 };
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000102
Lang Hames408dcd32010-01-26 04:49:58 +0000103 struct EdgeData {
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000104 typedef std::vector<unsigned> UnsafeArray;
Lang Hames408dcd32010-01-26 04:49:58 +0000105 unsigned worst, reverseWorst;
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000106 UnsafeArray unsafe, reverseUnsafe;
Lang Hames408dcd32010-01-26 04:49:58 +0000107 bool isUpToDate;
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000108
Lang Hames408dcd32010-01-26 04:49:58 +0000109 EdgeData() : worst(0), reverseWorst(0), isUpToDate(false) {}
110 };
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000111
Lang Hames408dcd32010-01-26 04:49:58 +0000112 /// \brief Construct an instance of the Briggs heuristic.
113 /// @param solver A reference to the solver which is using this heuristic.
114 Briggs(HeuristicSolverImpl<Briggs> &solver) :
115 HeuristicBase<Briggs>(solver) {}
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000116
Lang Hames408dcd32010-01-26 04:49:58 +0000117 /// \brief Determine whether a node should be reduced using optimal
118 /// reduction.
119 /// @param nItr Node iterator to be considered.
120 /// @return True if the given node should be optimally reduced, false
121 /// otherwise.
122 ///
123 /// Selects nodes of degree 0, 1 or 2 for optimal reduction, with one
124 /// exception. Nodes whose spill cost (element 0 of their cost vector) is
125 /// infinite are checked for allocability first. Allocable nodes may be
126 /// optimally reduced, but nodes whose allocability cannot be proven are
127 /// selected for heuristic reduction instead.
128 bool shouldOptimallyReduce(Graph::NodeItr nItr) {
129 if (getSolver().getSolverDegree(nItr) < 3) {
130 if (getGraph().getNodeCosts(nItr)[0] !=
131 std::numeric_limits<PBQPNum>::infinity()) {
132 return true;
133 }
134 // Otherwise we have an infinite spill cost node.
135 initializeNode(nItr);
136 NodeData &nd = getHeuristicNodeData(nItr);
137 return nd.isAllocable;
138 }
139 // else
140 return false;
141 }
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000142
Lang Hames408dcd32010-01-26 04:49:58 +0000143 /// \brief Add a node to the heuristic reduce list.
144 /// @param nItr Node iterator to add to the heuristic reduce list.
145 void addToHeuristicReduceList(Graph::NodeItr nItr) {
146 NodeData &nd = getHeuristicNodeData(nItr);
147 initializeNode(nItr);
148 nd.isHeuristic = true;
149 if (nd.isAllocable) {
150 nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr);
151 } else {
152 nd.rnuItr = rnUnallocableList.insert(rnUnallocableList.end(), nItr);
153 }
154 }
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000155
Lang Hames408dcd32010-01-26 04:49:58 +0000156 /// \brief Heuristically reduce one of the nodes in the heuristic
157 /// reduce list.
158 /// @return True if a reduction takes place, false if the heuristic reduce
159 /// list is empty.
160 ///
161 /// If the list of allocable nodes is non-empty a node is selected
162 /// from it and pushed to the stack. Otherwise if the non-allocable list
163 /// is non-empty a node is selected from it and pushed to the stack.
164 /// If both lists are empty the method simply returns false with no action
165 /// taken.
166 bool heuristicReduce() {
167 if (!rnAllocableList.empty()) {
168 RNAllocableListItr rnaItr =
169 min_element(rnAllocableList.begin(), rnAllocableList.end(),
170 LinkDegreeComparator(getSolver()));
171 Graph::NodeItr nItr = *rnaItr;
172 rnAllocableList.erase(rnaItr);
173 handleRemoveNode(nItr);
174 getSolver().pushToStack(nItr);
175 return true;
176 } else if (!rnUnallocableList.empty()) {
177 RNUnallocableListItr rnuItr =
178 min_element(rnUnallocableList.begin(), rnUnallocableList.end(),
179 SpillCostComparator(getSolver()));
180 Graph::NodeItr nItr = *rnuItr;
181 rnUnallocableList.erase(rnuItr);
182 handleRemoveNode(nItr);
183 getSolver().pushToStack(nItr);
184 return true;
185 }
186 // else
187 return false;
188 }
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000189
Lang Hames408dcd32010-01-26 04:49:58 +0000190 /// \brief Prepare a change in the costs on the given edge.
191 /// @param eItr Edge iterator.
192 void preUpdateEdgeCosts(Graph::EdgeItr eItr) {
193 Graph &g = getGraph();
194 Graph::NodeItr n1Itr = g.getEdgeNode1(eItr),
195 n2Itr = g.getEdgeNode2(eItr);
196 NodeData &n1 = getHeuristicNodeData(n1Itr),
197 &n2 = getHeuristicNodeData(n2Itr);
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000198
Lang Hames408dcd32010-01-26 04:49:58 +0000199 if (n1.isHeuristic)
200 subtractEdgeContributions(eItr, getGraph().getEdgeNode1(eItr));
201 if (n2.isHeuristic)
202 subtractEdgeContributions(eItr, getGraph().getEdgeNode2(eItr));
203
204 EdgeData &ed = getHeuristicEdgeData(eItr);
205 ed.isUpToDate = false;
206 }
207
208 /// \brief Handle the change in the costs on the given edge.
209 /// @param eItr Edge iterator.
210 void postUpdateEdgeCosts(Graph::EdgeItr eItr) {
211 // This is effectively the same as adding a new edge now, since
212 // we've factored out the costs of the old one.
213 handleAddEdge(eItr);
214 }
215
216 /// \brief Handle the addition of a new edge into the PBQP graph.
217 /// @param eItr Edge iterator for the added edge.
218 ///
219 /// Updates allocability of any nodes connected by this edge which are
220 /// being managed by the heuristic. If allocability changes they are
221 /// moved to the appropriate list.
222 void handleAddEdge(Graph::EdgeItr eItr) {
223 Graph &g = getGraph();
224 Graph::NodeItr n1Itr = g.getEdgeNode1(eItr),
225 n2Itr = g.getEdgeNode2(eItr);
226 NodeData &n1 = getHeuristicNodeData(n1Itr),
227 &n2 = getHeuristicNodeData(n2Itr);
228
229 // If neither node is managed by the heuristic there's nothing to be
230 // done.
231 if (!n1.isHeuristic && !n2.isHeuristic)
232 return;
233
234 // Ok - we need to update at least one node.
235 computeEdgeContributions(eItr);
236
237 // Update node 1 if it's managed by the heuristic.
238 if (n1.isHeuristic) {
239 bool n1WasAllocable = n1.isAllocable;
240 addEdgeContributions(eItr, n1Itr);
241 updateAllocability(n1Itr);
242 if (n1WasAllocable && !n1.isAllocable) {
243 rnAllocableList.erase(n1.rnaItr);
244 n1.rnuItr =
245 rnUnallocableList.insert(rnUnallocableList.end(), n1Itr);
246 }
247 }
248
249 // Likewise for node 2.
250 if (n2.isHeuristic) {
251 bool n2WasAllocable = n2.isAllocable;
252 addEdgeContributions(eItr, n2Itr);
253 updateAllocability(n2Itr);
254 if (n2WasAllocable && !n2.isAllocable) {
255 rnAllocableList.erase(n2.rnaItr);
256 n2.rnuItr =
257 rnUnallocableList.insert(rnUnallocableList.end(), n2Itr);
258 }
259 }
260 }
261
262 /// \brief Handle disconnection of an edge from a node.
263 /// @param eItr Edge iterator for edge being disconnected.
264 /// @param nItr Node iterator for the node being disconnected from.
265 ///
266 /// Updates allocability of the given node and, if appropriate, moves the
267 /// node to a new list.
268 void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
269 NodeData &nd = getHeuristicNodeData(nItr);
270
271 // If the node is not managed by the heuristic there's nothing to be
272 // done.
273 if (!nd.isHeuristic)
274 return;
275
276 EdgeData &ed = getHeuristicEdgeData(eItr);
277
278 assert(ed.isUpToDate && "Edge data is not up to date.");
279
280 // Update node.
281 bool ndWasAllocable = nd.isAllocable;
282 subtractEdgeContributions(eItr, nItr);
283 updateAllocability(nItr);
284
285 // If the node has gone optimal...
286 if (shouldOptimallyReduce(nItr)) {
287 nd.isHeuristic = false;
288 addToOptimalReduceList(nItr);
289 if (ndWasAllocable) {
290 rnAllocableList.erase(nd.rnaItr);
291 } else {
292 rnUnallocableList.erase(nd.rnuItr);
293 }
294 } else {
295 // Node didn't go optimal, but we might have to move it
296 // from "unallocable" to "allocable".
297 if (!ndWasAllocable && nd.isAllocable) {
298 rnUnallocableList.erase(nd.rnuItr);
299 nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr);
300 }
301 }
302 }
303
304 private:
305
306 NodeData& getHeuristicNodeData(Graph::NodeItr nItr) {
307 return getSolver().getHeuristicNodeData(nItr);
308 }
309
310 EdgeData& getHeuristicEdgeData(Graph::EdgeItr eItr) {
311 return getSolver().getHeuristicEdgeData(eItr);
312 }
313
314 // Work out what this edge will contribute to the allocability of the
315 // nodes connected to it.
316 void computeEdgeContributions(Graph::EdgeItr eItr) {
317 EdgeData &ed = getHeuristicEdgeData(eItr);
318
319 if (ed.isUpToDate)
320 return; // Edge data is already up to date.
321
322 Matrix &eCosts = getGraph().getEdgeCosts(eItr);
323
324 unsigned numRegs = eCosts.getRows() - 1,
325 numReverseRegs = eCosts.getCols() - 1;
326
327 std::vector<unsigned> rowInfCounts(numRegs, 0),
328 colInfCounts(numReverseRegs, 0);
329
330 ed.worst = 0;
331 ed.reverseWorst = 0;
332 ed.unsafe.clear();
333 ed.unsafe.resize(numRegs, 0);
334 ed.reverseUnsafe.clear();
335 ed.reverseUnsafe.resize(numReverseRegs, 0);
336
337 for (unsigned i = 0; i < numRegs; ++i) {
338 for (unsigned j = 0; j < numReverseRegs; ++j) {
339 if (eCosts[i + 1][j + 1] ==
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000340 std::numeric_limits<PBQPNum>::infinity()) {
Lang Hames408dcd32010-01-26 04:49:58 +0000341 ed.unsafe[i] = 1;
342 ed.reverseUnsafe[j] = 1;
343 ++rowInfCounts[i];
344 ++colInfCounts[j];
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000345
Lang Hames408dcd32010-01-26 04:49:58 +0000346 if (colInfCounts[j] > ed.worst) {
347 ed.worst = colInfCounts[j];
348 }
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000349
Lang Hames408dcd32010-01-26 04:49:58 +0000350 if (rowInfCounts[i] > ed.reverseWorst) {
351 ed.reverseWorst = rowInfCounts[i];
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000352 }
353 }
354 }
355 }
356
Lang Hames408dcd32010-01-26 04:49:58 +0000357 ed.isUpToDate = true;
358 }
359
360 // Add the contributions of the given edge to the given node's
361 // numDenied and safe members. No action is taken other than to update
362 // these member values. Once updated these numbers can be used by clients
363 // to update the node's allocability.
364 void addEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
365 EdgeData &ed = getHeuristicEdgeData(eItr);
366
367 assert(ed.isUpToDate && "Using out-of-date edge numbers.");
368
369 NodeData &nd = getHeuristicNodeData(nItr);
370 unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
371
372 bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr);
373 EdgeData::UnsafeArray &unsafe =
374 nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
375 nd.numDenied += nIsNode1 ? ed.worst : ed.reverseWorst;
376
377 for (unsigned r = 0; r < numRegs; ++r) {
378 if (unsafe[r]) {
379 if (nd.unsafeDegrees[r]==0) {
380 --nd.numSafe;
381 }
382 ++nd.unsafeDegrees[r];
383 }
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000384 }
Lang Hames408dcd32010-01-26 04:49:58 +0000385 }
386
387 // Subtract the contributions of the given edge to the given node's
388 // numDenied and safe members. No action is taken other than to update
389 // these member values. Once updated these numbers can be used by clients
390 // to update the node's allocability.
391 void subtractEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
392 EdgeData &ed = getHeuristicEdgeData(eItr);
393
394 assert(ed.isUpToDate && "Using out-of-date edge numbers.");
395
396 NodeData &nd = getHeuristicNodeData(nItr);
397 unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
398
399 bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr);
400 EdgeData::UnsafeArray &unsafe =
401 nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
402 nd.numDenied -= nIsNode1 ? ed.worst : ed.reverseWorst;
403
404 for (unsigned r = 0; r < numRegs; ++r) {
405 if (unsafe[r]) {
406 if (nd.unsafeDegrees[r] == 1) {
407 ++nd.numSafe;
408 }
409 --nd.unsafeDegrees[r];
410 }
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000411 }
Lang Hames408dcd32010-01-26 04:49:58 +0000412 }
413
414 void updateAllocability(Graph::NodeItr nItr) {
415 NodeData &nd = getHeuristicNodeData(nItr);
416 unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
417 nd.isAllocable = nd.numDenied < numRegs || nd.numSafe > 0;
418 }
419
420 void initializeNode(Graph::NodeItr nItr) {
421 NodeData &nd = getHeuristicNodeData(nItr);
422
423 if (nd.isInitialized)
424 return; // Node data is already up to date.
425
426 unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
427
428 nd.numDenied = 0;
429 nd.numSafe = numRegs;
430 nd.unsafeDegrees.resize(numRegs, 0);
431
432 typedef HeuristicSolverImpl<Briggs>::SolverEdgeItr SolverEdgeItr;
433
434 for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(nItr),
435 aeEnd = getSolver().solverEdgesEnd(nItr);
436 aeItr != aeEnd; ++aeItr) {
437
438 Graph::EdgeItr eItr = *aeItr;
439 computeEdgeContributions(eItr);
440 addEdgeContributions(eItr, nItr);
441 }
442
443 updateAllocability(nItr);
444 nd.isInitialized = true;
445 }
446
447 void handleRemoveNode(Graph::NodeItr xnItr) {
448 typedef HeuristicSolverImpl<Briggs>::SolverEdgeItr SolverEdgeItr;
449 std::vector<Graph::EdgeItr> edgesToRemove;
450 for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(xnItr),
451 aeEnd = getSolver().solverEdgesEnd(xnItr);
452 aeItr != aeEnd; ++aeItr) {
453 Graph::NodeItr ynItr = getGraph().getEdgeOtherNode(*aeItr, xnItr);
454 handleRemoveEdge(*aeItr, ynItr);
455 edgesToRemove.push_back(*aeItr);
456 }
457 while (!edgesToRemove.empty()) {
458 getSolver().removeSolverEdge(edgesToRemove.back());
459 edgesToRemove.pop_back();
460 }
461 }
462
463 RNAllocableList rnAllocableList;
464 RNUnallocableList rnUnallocableList;
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000465 };
466
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000467 }
Lang Hames3ca9a5b2009-08-06 23:32:48 +0000468}
469
470
471#endif // LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H