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 "llvm/Support/Compiler.h"
22
#include "../HeuristicSolver.h"
23
#include "../HeuristicBase.h"
29
namespace Heuristics {
31
/// \brief PBQP Heuristic which applies an allocability test based on
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
46
/// This implementation is built on top of HeuristicBase.
47
class Briggs : public HeuristicBase<Briggs> {
50
class LinkDegreeComparator {
52
LinkDegreeComparator(HeuristicSolverImpl<Briggs> &s) : s(&s) {}
53
bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const {
54
if (s->getSolverDegree(n1Itr) > s->getSolverDegree(n2Itr))
56
if (s->getSolverDegree(n1Itr) < s->getSolverDegree(n2Itr))
58
return (&*n1Itr < &*n2Itr);
61
HeuristicSolverImpl<Briggs> *s;
64
class SpillCostComparator {
66
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);
75
return (&*n1Itr < &*n2Itr);
79
HeuristicSolverImpl<Briggs> *s;
83
typedef std::list<Graph::NodeItr> RNAllocableList;
84
typedef RNAllocableList::iterator RNAllocableListItr;
86
typedef std::list<Graph::NodeItr> RNUnallocableList;
87
typedef RNUnallocableList::iterator RNUnallocableListItr;
92
typedef std::vector<unsigned> UnsafeDegreesArray;
93
bool isHeuristic, isAllocable, isInitialized;
94
unsigned numDenied, numSafe;
95
UnsafeDegreesArray unsafeDegrees;
96
RNAllocableListItr rnaItr;
97
RNUnallocableListItr rnuItr;
100
: isHeuristic(false), isAllocable(false), isInitialized(false),
101
numDenied(0), numSafe(0) { }
105
typedef std::vector<unsigned> UnsafeArray;
106
unsigned worst, reverseWorst;
107
UnsafeArray unsafe, reverseUnsafe;
110
EdgeData() : worst(0), reverseWorst(0), isUpToDate(false) {}
113
/// \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) {}
118
/// \brief Determine whether a node should be reduced using optimal
120
/// @param nItr Node iterator to be considered.
121
/// @return True if the given node should be optimally reduced, false
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) {
137
/// \brief Add a node to the heuristic reduce list.
138
/// @param nItr Node iterator to add to the heuristic reduce list.
139
void addToHeuristicReduceList(Graph::NodeItr nItr) {
140
NodeData &nd = getHeuristicNodeData(nItr);
141
initializeNode(nItr);
142
nd.isHeuristic = true;
143
if (nd.isAllocable) {
144
nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr);
146
nd.rnuItr = rnUnallocableList.insert(rnUnallocableList.end(), nItr);
150
/// \brief Heuristically reduce one of the nodes in the heuristic
152
/// @return True if a reduction takes place, false if the heuristic reduce
155
/// If the list of allocable nodes is non-empty a node is selected
156
/// from it and pushed to the stack. Otherwise if the non-allocable list
157
/// is non-empty a node is selected from it and pushed to the stack.
158
/// If both lists are empty the method simply returns false with no action
160
bool heuristicReduce() {
161
if (!rnAllocableList.empty()) {
162
RNAllocableListItr rnaItr =
163
min_element(rnAllocableList.begin(), rnAllocableList.end(),
164
LinkDegreeComparator(getSolver()));
165
Graph::NodeItr nItr = *rnaItr;
166
rnAllocableList.erase(rnaItr);
167
handleRemoveNode(nItr);
168
getSolver().pushToStack(nItr);
170
} else if (!rnUnallocableList.empty()) {
171
RNUnallocableListItr rnuItr =
172
min_element(rnUnallocableList.begin(), rnUnallocableList.end(),
173
SpillCostComparator(getSolver()));
174
Graph::NodeItr nItr = *rnuItr;
175
rnUnallocableList.erase(rnuItr);
176
handleRemoveNode(nItr);
177
getSolver().pushToStack(nItr);
184
/// \brief Prepare a change in the costs on the given edge.
185
/// @param eItr Edge iterator.
186
void preUpdateEdgeCosts(Graph::EdgeItr eItr) {
187
Graph &g = getGraph();
188
Graph::NodeItr n1Itr = g.getEdgeNode1(eItr),
189
n2Itr = g.getEdgeNode2(eItr);
190
NodeData &n1 = getHeuristicNodeData(n1Itr),
191
&n2 = getHeuristicNodeData(n2Itr);
194
subtractEdgeContributions(eItr, getGraph().getEdgeNode1(eItr));
196
subtractEdgeContributions(eItr, getGraph().getEdgeNode2(eItr));
198
EdgeData &ed = getHeuristicEdgeData(eItr);
199
ed.isUpToDate = false;
202
/// \brief Handle the change in the costs on the given edge.
203
/// @param eItr Edge iterator.
204
void postUpdateEdgeCosts(Graph::EdgeItr eItr) {
205
// This is effectively the same as adding a new edge now, since
206
// we've factored out the costs of the old one.
210
/// \brief Handle the addition of a new edge into the PBQP graph.
211
/// @param eItr Edge iterator for the added edge.
213
/// Updates allocability of any nodes connected by this edge which are
214
/// being managed by the heuristic. If allocability changes they are
215
/// moved to the appropriate list.
216
void handleAddEdge(Graph::EdgeItr eItr) {
217
Graph &g = getGraph();
218
Graph::NodeItr n1Itr = g.getEdgeNode1(eItr),
219
n2Itr = g.getEdgeNode2(eItr);
220
NodeData &n1 = getHeuristicNodeData(n1Itr),
221
&n2 = getHeuristicNodeData(n2Itr);
223
// If neither node is managed by the heuristic there's nothing to be
225
if (!n1.isHeuristic && !n2.isHeuristic)
228
// Ok - we need to update at least one node.
229
computeEdgeContributions(eItr);
231
// Update node 1 if it's managed by the heuristic.
232
if (n1.isHeuristic) {
233
bool n1WasAllocable = n1.isAllocable;
234
addEdgeContributions(eItr, n1Itr);
235
updateAllocability(n1Itr);
236
if (n1WasAllocable && !n1.isAllocable) {
237
rnAllocableList.erase(n1.rnaItr);
239
rnUnallocableList.insert(rnUnallocableList.end(), n1Itr);
243
// Likewise for node 2.
244
if (n2.isHeuristic) {
245
bool n2WasAllocable = n2.isAllocable;
246
addEdgeContributions(eItr, n2Itr);
247
updateAllocability(n2Itr);
248
if (n2WasAllocable && !n2.isAllocable) {
249
rnAllocableList.erase(n2.rnaItr);
251
rnUnallocableList.insert(rnUnallocableList.end(), n2Itr);
256
/// \brief Handle disconnection of an edge from a node.
257
/// @param eItr Edge iterator for edge being disconnected.
258
/// @param nItr Node iterator for the node being disconnected from.
260
/// Updates allocability of the given node and, if appropriate, moves the
261
/// node to a new list.
262
void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
263
NodeData &nd = getHeuristicNodeData(nItr);
265
// If the node is not managed by the heuristic there's nothing to be
270
EdgeData &ed ATTRIBUTE_UNUSED = getHeuristicEdgeData(eItr);
272
assert(ed.isUpToDate && "Edge data is not up to date.");
275
bool ndWasAllocable = nd.isAllocable;
276
subtractEdgeContributions(eItr, nItr);
277
updateAllocability(nItr);
279
// If the node has gone optimal...
280
if (shouldOptimallyReduce(nItr)) {
281
nd.isHeuristic = false;
282
addToOptimalReduceList(nItr);
283
if (ndWasAllocable) {
284
rnAllocableList.erase(nd.rnaItr);
286
rnUnallocableList.erase(nd.rnuItr);
289
// Node didn't go optimal, but we might have to move it
290
// from "unallocable" to "allocable".
291
if (!ndWasAllocable && nd.isAllocable) {
292
rnUnallocableList.erase(nd.rnuItr);
293
nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr);
300
NodeData& getHeuristicNodeData(Graph::NodeItr nItr) {
301
return getSolver().getHeuristicNodeData(nItr);
304
EdgeData& getHeuristicEdgeData(Graph::EdgeItr eItr) {
305
return getSolver().getHeuristicEdgeData(eItr);
308
// Work out what this edge will contribute to the allocability of the
309
// nodes connected to it.
310
void computeEdgeContributions(Graph::EdgeItr eItr) {
311
EdgeData &ed = getHeuristicEdgeData(eItr);
314
return; // Edge data is already up to date.
316
Matrix &eCosts = getGraph().getEdgeCosts(eItr);
318
unsigned numRegs = eCosts.getRows() - 1,
319
numReverseRegs = eCosts.getCols() - 1;
321
std::vector<unsigned> rowInfCounts(numRegs, 0),
322
colInfCounts(numReverseRegs, 0);
327
ed.unsafe.resize(numRegs, 0);
328
ed.reverseUnsafe.clear();
329
ed.reverseUnsafe.resize(numReverseRegs, 0);
331
for (unsigned i = 0; i < numRegs; ++i) {
332
for (unsigned j = 0; j < numReverseRegs; ++j) {
333
if (eCosts[i + 1][j + 1] ==
334
std::numeric_limits<PBQPNum>::infinity()) {
336
ed.reverseUnsafe[j] = 1;
340
if (colInfCounts[j] > ed.worst) {
341
ed.worst = colInfCounts[j];
344
if (rowInfCounts[i] > ed.reverseWorst) {
345
ed.reverseWorst = rowInfCounts[i];
351
ed.isUpToDate = true;
354
// Add the contributions of the given edge to the given node's
355
// numDenied and safe members. No action is taken other than to update
356
// these member values. Once updated these numbers can be used by clients
357
// to update the node's allocability.
358
void addEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
359
EdgeData &ed = getHeuristicEdgeData(eItr);
361
assert(ed.isUpToDate && "Using out-of-date edge numbers.");
363
NodeData &nd = getHeuristicNodeData(nItr);
364
unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
366
bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr);
367
EdgeData::UnsafeArray &unsafe =
368
nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
369
nd.numDenied += nIsNode1 ? ed.worst : ed.reverseWorst;
371
for (unsigned r = 0; r < numRegs; ++r) {
373
if (nd.unsafeDegrees[r]==0) {
376
++nd.unsafeDegrees[r];
381
// Subtract the contributions of the given edge to the given node's
382
// numDenied and safe members. No action is taken other than to update
383
// these member values. Once updated these numbers can be used by clients
384
// to update the node's allocability.
385
void subtractEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
386
EdgeData &ed = getHeuristicEdgeData(eItr);
388
assert(ed.isUpToDate && "Using out-of-date edge numbers.");
390
NodeData &nd = getHeuristicNodeData(nItr);
391
unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
393
bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr);
394
EdgeData::UnsafeArray &unsafe =
395
nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
396
nd.numDenied -= nIsNode1 ? ed.worst : ed.reverseWorst;
398
for (unsigned r = 0; r < numRegs; ++r) {
400
if (nd.unsafeDegrees[r] == 1) {
403
--nd.unsafeDegrees[r];
408
void updateAllocability(Graph::NodeItr nItr) {
409
NodeData &nd = getHeuristicNodeData(nItr);
410
unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
411
nd.isAllocable = nd.numDenied < numRegs || nd.numSafe > 0;
414
void initializeNode(Graph::NodeItr nItr) {
415
NodeData &nd = getHeuristicNodeData(nItr);
417
if (nd.isInitialized)
418
return; // Node data is already up to date.
420
unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
423
nd.numSafe = numRegs;
424
nd.unsafeDegrees.resize(numRegs, 0);
426
typedef HeuristicSolverImpl<Briggs>::SolverEdgeItr SolverEdgeItr;
428
for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(nItr),
429
aeEnd = getSolver().solverEdgesEnd(nItr);
430
aeItr != aeEnd; ++aeItr) {
432
Graph::EdgeItr eItr = *aeItr;
433
computeEdgeContributions(eItr);
434
addEdgeContributions(eItr, nItr);
437
updateAllocability(nItr);
438
nd.isInitialized = true;
441
void handleRemoveNode(Graph::NodeItr xnItr) {
442
typedef HeuristicSolverImpl<Briggs>::SolverEdgeItr SolverEdgeItr;
443
std::vector<Graph::EdgeItr> edgesToRemove;
444
for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(xnItr),
445
aeEnd = getSolver().solverEdgesEnd(xnItr);
446
aeItr != aeEnd; ++aeItr) {
447
Graph::NodeItr ynItr = getGraph().getEdgeOtherNode(*aeItr, xnItr);
448
handleRemoveEdge(*aeItr, ynItr);
449
edgesToRemove.push_back(*aeItr);
451
while (!edgesToRemove.empty()) {
452
getSolver().removeSolverEdge(edgesToRemove.back());
453
edgesToRemove.pop_back();
457
RNAllocableList rnAllocableList;
458
RNUnallocableList rnUnallocableList;
465
#endif // LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H