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