LLVM API Documentation

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