#ifndef LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H
#define LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H
#include "llvm/Support/Compiler.h"
#include "../HeuristicSolver.h"
#include "../HeuristicBase.h"
#include <set>
#include <limits>
namespace PBQP {
namespace Heuristics {
class Briggs : public HeuristicBase<Briggs> {
private:
class LinkDegreeComparator {
public:
LinkDegreeComparator(HeuristicSolverImpl<Briggs> &s) : s(&s) {}
bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const {
if (s->getSolverDegree(n1Itr) > s->getSolverDegree(n2Itr))
return true;
if (s->getSolverDegree(n1Itr) < s->getSolverDegree(n2Itr))
return false;
return (&*n1Itr < &*n2Itr);
}
private:
HeuristicSolverImpl<Briggs> *s;
};
class SpillCostComparator {
public:
SpillCostComparator(HeuristicSolverImpl<Briggs> &s)
: s(&s), g(&s.getGraph()) {}
bool operator()(Graph::NodeItr n1Itr, Graph::NodeItr n2Itr) const {
PBQPNum cost1 = g->getNodeCosts(n1Itr)[0] / s->getSolverDegree(n1Itr),
cost2 = g->getNodeCosts(n2Itr)[0] / s->getSolverDegree(n2Itr);
if (cost1 < cost2)
return true;
if (cost1 > cost2)
return false;
return (&*n1Itr < &*n2Itr);
}
private:
HeuristicSolverImpl<Briggs> *s;
Graph *g;
};
typedef std::list<Graph::NodeItr> RNAllocableList;
typedef RNAllocableList::iterator RNAllocableListItr;
typedef std::list<Graph::NodeItr> RNUnallocableList;
typedef RNUnallocableList::iterator RNUnallocableListItr;
public:
struct NodeData {
typedef std::vector<unsigned> UnsafeDegreesArray;
bool isHeuristic, isAllocable, isInitialized;
unsigned numDenied, numSafe;
UnsafeDegreesArray unsafeDegrees;
RNAllocableListItr rnaItr;
RNUnallocableListItr rnuItr;
NodeData()
: isHeuristic(false), isAllocable(false), isInitialized(false),
numDenied(0), numSafe(0) { }
};
struct EdgeData {
typedef std::vector<unsigned> UnsafeArray;
unsigned worst, reverseWorst;
UnsafeArray unsafe, reverseUnsafe;
bool isUpToDate;
EdgeData() : worst(0), reverseWorst(0), isUpToDate(false) {}
};
Briggs(HeuristicSolverImpl<Briggs> &solver) :
HeuristicBase<Briggs>(solver) {}
bool shouldOptimallyReduce(Graph::NodeItr nItr) {
if (getSolver().getSolverDegree(nItr) < 3) {
return true;
}
return false;
}
void addToHeuristicReduceList(Graph::NodeItr nItr) {
NodeData &nd = getHeuristicNodeData(nItr);
initializeNode(nItr);
nd.isHeuristic = true;
if (nd.isAllocable) {
nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr);
} else {
nd.rnuItr = rnUnallocableList.insert(rnUnallocableList.end(), nItr);
}
}
bool heuristicReduce() {
if (!rnAllocableList.empty()) {
RNAllocableListItr rnaItr =
min_element(rnAllocableList.begin(), rnAllocableList.end(),
LinkDegreeComparator(getSolver()));
Graph::NodeItr nItr = *rnaItr;
rnAllocableList.erase(rnaItr);
handleRemoveNode(nItr);
getSolver().pushToStack(nItr);
return true;
} else if (!rnUnallocableList.empty()) {
RNUnallocableListItr rnuItr =
min_element(rnUnallocableList.begin(), rnUnallocableList.end(),
SpillCostComparator(getSolver()));
Graph::NodeItr nItr = *rnuItr;
rnUnallocableList.erase(rnuItr);
handleRemoveNode(nItr);
getSolver().pushToStack(nItr);
return true;
}
return false;
}
void preUpdateEdgeCosts(Graph::EdgeItr eItr) {
Graph &g = getGraph();
Graph::NodeItr n1Itr = g.getEdgeNode1(eItr),
n2Itr = g.getEdgeNode2(eItr);
NodeData &n1 = getHeuristicNodeData(n1Itr),
&n2 = getHeuristicNodeData(n2Itr);
if (n1.isHeuristic)
subtractEdgeContributions(eItr, getGraph().getEdgeNode1(eItr));
if (n2.isHeuristic)
subtractEdgeContributions(eItr, getGraph().getEdgeNode2(eItr));
EdgeData &ed = getHeuristicEdgeData(eItr);
ed.isUpToDate = false;
}
void postUpdateEdgeCosts(Graph::EdgeItr eItr) {
handleAddEdge(eItr);
}
void handleAddEdge(Graph::EdgeItr eItr) {
Graph &g = getGraph();
Graph::NodeItr n1Itr = g.getEdgeNode1(eItr),
n2Itr = g.getEdgeNode2(eItr);
NodeData &n1 = getHeuristicNodeData(n1Itr),
&n2 = getHeuristicNodeData(n2Itr);
if (!n1.isHeuristic && !n2.isHeuristic)
return;
computeEdgeContributions(eItr);
if (n1.isHeuristic) {
bool n1WasAllocable = n1.isAllocable;
addEdgeContributions(eItr, n1Itr);
updateAllocability(n1Itr);
if (n1WasAllocable && !n1.isAllocable) {
rnAllocableList.erase(n1.rnaItr);
n1.rnuItr =
rnUnallocableList.insert(rnUnallocableList.end(), n1Itr);
}
}
if (n2.isHeuristic) {
bool n2WasAllocable = n2.isAllocable;
addEdgeContributions(eItr, n2Itr);
updateAllocability(n2Itr);
if (n2WasAllocable && !n2.isAllocable) {
rnAllocableList.erase(n2.rnaItr);
n2.rnuItr =
rnUnallocableList.insert(rnUnallocableList.end(), n2Itr);
}
}
}
void handleRemoveEdge(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
NodeData &nd = getHeuristicNodeData(nItr);
if (!nd.isHeuristic)
return;
EdgeData &ed ATTRIBUTE_UNUSED = getHeuristicEdgeData(eItr);
assert(ed.isUpToDate && "Edge data is not up to date.");
bool ndWasAllocable = nd.isAllocable;
subtractEdgeContributions(eItr, nItr);
updateAllocability(nItr);
if (shouldOptimallyReduce(nItr)) {
nd.isHeuristic = false;
addToOptimalReduceList(nItr);
if (ndWasAllocable) {
rnAllocableList.erase(nd.rnaItr);
} else {
rnUnallocableList.erase(nd.rnuItr);
}
} else {
if (!ndWasAllocable && nd.isAllocable) {
rnUnallocableList.erase(nd.rnuItr);
nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nItr);
}
}
}
private:
NodeData& getHeuristicNodeData(Graph::NodeItr nItr) {
return getSolver().getHeuristicNodeData(nItr);
}
EdgeData& getHeuristicEdgeData(Graph::EdgeItr eItr) {
return getSolver().getHeuristicEdgeData(eItr);
}
void computeEdgeContributions(Graph::EdgeItr eItr) {
EdgeData &ed = getHeuristicEdgeData(eItr);
if (ed.isUpToDate)
return;
Matrix &eCosts = getGraph().getEdgeCosts(eItr);
unsigned numRegs = eCosts.getRows() - 1,
numReverseRegs = eCosts.getCols() - 1;
std::vector<unsigned> rowInfCounts(numRegs, 0),
colInfCounts(numReverseRegs, 0);
ed.worst = 0;
ed.reverseWorst = 0;
ed.unsafe.clear();
ed.unsafe.resize(numRegs, 0);
ed.reverseUnsafe.clear();
ed.reverseUnsafe.resize(numReverseRegs, 0);
for (unsigned i = 0; i < numRegs; ++i) {
for (unsigned j = 0; j < numReverseRegs; ++j) {
if (eCosts[i + 1][j + 1] ==
std::numeric_limits<PBQPNum>::infinity()) {
ed.unsafe[i] = 1;
ed.reverseUnsafe[j] = 1;
++rowInfCounts[i];
++colInfCounts[j];
if (colInfCounts[j] > ed.worst) {
ed.worst = colInfCounts[j];
}
if (rowInfCounts[i] > ed.reverseWorst) {
ed.reverseWorst = rowInfCounts[i];
}
}
}
}
ed.isUpToDate = true;
}
void addEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
EdgeData &ed = getHeuristicEdgeData(eItr);
assert(ed.isUpToDate && "Using out-of-date edge numbers.");
NodeData &nd = getHeuristicNodeData(nItr);
unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr);
EdgeData::UnsafeArray &unsafe =
nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
nd.numDenied += nIsNode1 ? ed.worst : ed.reverseWorst;
for (unsigned r = 0; r < numRegs; ++r) {
if (unsafe[r]) {
if (nd.unsafeDegrees[r]==0) {
--nd.numSafe;
}
++nd.unsafeDegrees[r];
}
}
}
void subtractEdgeContributions(Graph::EdgeItr eItr, Graph::NodeItr nItr) {
EdgeData &ed = getHeuristicEdgeData(eItr);
assert(ed.isUpToDate && "Using out-of-date edge numbers.");
NodeData &nd = getHeuristicNodeData(nItr);
unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
bool nIsNode1 = nItr == getGraph().getEdgeNode1(eItr);
EdgeData::UnsafeArray &unsafe =
nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
nd.numDenied -= nIsNode1 ? ed.worst : ed.reverseWorst;
for (unsigned r = 0; r < numRegs; ++r) {
if (unsafe[r]) {
if (nd.unsafeDegrees[r] == 1) {
++nd.numSafe;
}
--nd.unsafeDegrees[r];
}
}
}
void updateAllocability(Graph::NodeItr nItr) {
NodeData &nd = getHeuristicNodeData(nItr);
unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
nd.isAllocable = nd.numDenied < numRegs || nd.numSafe > 0;
}
void initializeNode(Graph::NodeItr nItr) {
NodeData &nd = getHeuristicNodeData(nItr);
if (nd.isInitialized)
return;
unsigned numRegs = getGraph().getNodeCosts(nItr).getLength() - 1;
nd.numDenied = 0;
nd.numSafe = numRegs;
nd.unsafeDegrees.resize(numRegs, 0);
typedef HeuristicSolverImpl<Briggs>::SolverEdgeItr SolverEdgeItr;
for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(nItr),
aeEnd = getSolver().solverEdgesEnd(nItr);
aeItr != aeEnd; ++aeItr) {
Graph::EdgeItr eItr = *aeItr;
computeEdgeContributions(eItr);
addEdgeContributions(eItr, nItr);
}
updateAllocability(nItr);
nd.isInitialized = true;
}
void handleRemoveNode(Graph::NodeItr xnItr) {
typedef HeuristicSolverImpl<Briggs>::SolverEdgeItr SolverEdgeItr;
std::vector<Graph::EdgeItr> edgesToRemove;
for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(xnItr),
aeEnd = getSolver().solverEdgesEnd(xnItr);
aeItr != aeEnd; ++aeItr) {
Graph::NodeItr ynItr = getGraph().getEdgeOtherNode(*aeItr, xnItr);
handleRemoveEdge(*aeItr, ynItr);
edgesToRemove.push_back(*aeItr);
}
while (!edgesToRemove.empty()) {
getSolver().removeSolverEdge(edgesToRemove.back());
edgesToRemove.pop_back();
}
}
RNAllocableList rnAllocableList;
RNUnallocableList rnUnallocableList;
};
}
}
#endif // LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H