llvm.org GIT mirror llvm / d54d4f6
New PBQP solver, and updates to the PBQP graph. The previous PBQP solver was very robust but consumed a lot of memory, performed a lot of redundant computation, and contained some unnecessarily tight coupling that prevented experimentation with novel solution techniques. This new solver is an attempt to address these shortcomings. Important/interesting changes: 1) The domain-independent PBQP solver class, HeuristicSolverImpl, is gone. It is replaced by a register allocation specific solver, PBQP::RegAlloc::Solver (see RegAllocSolver.h). The optimal reduction rules and the backpropagation algorithm have been extracted into stand-alone functions (see ReductionRules.h), which can be used to build domain specific PBQP solvers. This provides many more opportunities for domain-specific knowledge to inform the PBQP solvers' decisions. In theory this should allow us to generate better solutions. In practice, we can at least test out ideas now. As a side benefit, I believe the new solver is more readable than the old one. 2) The solver type is now a template parameter of the PBQP graph. This allows the graph to notify the solver of any modifications made (e.g. by domain independent rules) without the overhead of a virtual call. It also allows the solver to supply policy information to the graph (see below). 3) Significantly reduced memory overhead. Memory management policy is now an explicit property of the PBQP graph (via the CostAllocator typedef on the graph's solver template argument). Because PBQP graphs for register allocation tend to contain many redundant instances of single values (E.g. the value representing an interference constraint between GPRs), the new RASolver class uses a uniquing scheme. This massively reduces memory consumption for large register allocation problems. For example, looking at the largest interference graph in each of the SPEC2006 benchmarks (the largest graph will always set the memory consumption high-water mark for PBQP), the average memory reduction for the PBQP costs was 400x. That's times, not percent. The highest was 1400x. Yikes. So - this is fixed. "PBQP: No longer feasting upon every last byte of your RAM". Minor details: - Fully C++11'd. Never copy-construct another vector/matrix! - Cute tricks with cost metadata: Metadata that is derived solely from cost matrices/vectors is attached directly to the cost instances themselves. That way if you unique the costs you never have to recompute the metadata. 400x less memory means 400x less cost metadata (re)computation. Special thanks to Arnaud de Grandmaison, who has been the source of much encouragement, and of many very useful test cases. This new solver forms the basis for future work, of which there's plenty to do. I will be adding TODO notes shortly. - Lang. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202551 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 6 years ago
11 changed file(s) with 1584 addition(s) and 1976 deletion(s). Raw diff Collapse all Expand all
0 //===---------- CostAllocator.h - PBQP Cost Allocator -----------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Defines classes conforming to the PBQP cost value manager concept.
10 //
11 // Cost value managers are memory managers for PBQP cost values (vectors and
12 // matrices). Since PBQP graphs can grow very large (E.g. hundreds of thousands
13 // of edges on the largest function in SPEC2006).
14 //
15 //===----------------------------------------------------------------------===//
16
17 #ifndef LLVM_COSTALLOCATOR_H
18 #define LLVM_COSTALLOCATOR_H
19
20 #include
21 #include
22
23 namespace PBQP {
24
25 template
26 typename CostKeyTComparator>
27 class CostPool {
28 public:
29
30 class PoolEntry {
31 public:
32 template
33 PoolEntry(CostPool &pool, CostKeyT cost)
34 : pool(pool), cost(std::move(cost)), refCount(0) {}
35 ~PoolEntry() { pool.removeEntry(this); }
36 void incRef() { ++refCount; }
37 bool decRef() { --refCount; return (refCount == 0); }
38 CostT& getCost() { return cost; }
39 const CostT& getCost() const { return cost; }
40 private:
41 CostPool &pool;
42 CostT cost;
43 std::size_t refCount;
44 };
45
46 class PoolRef {
47 public:
48 PoolRef(PoolEntry *entry) : entry(entry) {
49 this->entry->incRef();
50 }
51 PoolRef(const PoolRef &r) {
52 entry = r.entry;
53 entry->incRef();
54 }
55 PoolRef& operator=(const PoolRef &r) {
56 assert(entry != 0 && "entry should not be null.");
57 PoolEntry *temp = r.entry;
58 temp->incRef();
59 entry->decRef();
60 entry = temp;
61 return *this;
62 }
63
64 ~PoolRef() {
65 if (entry->decRef())
66 delete entry;
67 }
68 void reset(PoolEntry *entry) {
69 entry->incRef();
70 this->entry->decRef();
71 this->entry = entry;
72 }
73 CostT& operator*() { return entry->getCost(); }
74 const CostT& operator*() const { return entry->getCost(); }
75 CostT* operator->() { return &entry->getCost(); }
76 const CostT* operator->() const { return &entry->getCost(); }
77 private:
78 PoolEntry *entry;
79 };
80
81 private:
82 class EntryComparator {
83 public:
84 template
85 typename std::enable_if<
86 !std::is_same
87 typename std::remove_const::type>::value,
88 bool>::type
89 operator()(const PoolEntry* a, const CostKeyT &b) {
90 return compare(a->getCost(), b);
91 }
92 bool operator()(const PoolEntry* a, const PoolEntry* b) {
93 return compare(a->getCost(), b->getCost());
94 }
95 private:
96 CostKeyTComparator compare;
97 };
98
99 typedef std::set EntrySet;
100
101 EntrySet entrySet;
102
103 void removeEntry(PoolEntry *p) { entrySet.erase(p); }
104
105 public:
106
107 template
108 PoolRef getCost(CostKeyT costKey) {
109 typename EntrySet::iterator itr =
110 std::lower_bound(entrySet.begin(), entrySet.end(), costKey,
111 EntryComparator());
112
113 if (itr != entrySet.end() && costKey == (*itr)->getCost())
114 return PoolRef(*itr);
115
116 PoolEntry *p = new PoolEntry(*this, std::move(costKey));
117 entrySet.insert(itr, p);
118 return PoolRef(p);
119 }
120 };
121
122 template
123 typename MatrixT, typename MatrixTComparator>
124 class PoolCostAllocator {
125 private:
126 typedef CostPool VectorCostPool;
127 typedef CostPool MatrixCostPool;
128 public:
129 typedef VectorT Vector;
130 typedef MatrixT Matrix;
131 typedef typename VectorCostPool::PoolRef VectorPtr;
132 typedef typename MatrixCostPool::PoolRef MatrixPtr;
133
134 template
135 VectorPtr getVector(VectorKeyT v) { return vectorPool.getCost(std::move(v)); }
136
137 template
138 MatrixPtr getMatrix(MatrixKeyT m) { return matrixPool.getCost(std::move(m)); }
139 private:
140 VectorCostPool vectorPool;
141 MatrixCostPool matrixPool;
142 };
143
144 }
145
146 #endif // LLVM_COSTALLOCATOR_H
1414 #ifndef LLVM_CODEGEN_PBQP_GRAPH_H
1515 #define LLVM_CODEGEN_PBQP_GRAPH_H
1616
17 #include "Math.h"
1817 #include "llvm/ADT/ilist.h"
1918 #include "llvm/ADT/ilist_node.h"
19 #include "llvm/Support/Compiler.h"
2020 #include
2121 #include
2222 #include
2323
2424 namespace PBQP {
2525
26 class GraphBase {
27 public:
28 typedef unsigned NodeId;
29 typedef unsigned EdgeId;
30 };
31
2632 /// PBQP Graph class.
2733 /// Instances of this class describe PBQP problems.
28 class Graph {
34 ///
35 template
36 class Graph : public GraphBase {
37 private:
38 typedef typename SolverT::CostAllocator CostAllocator;
2939 public:
30
31 typedef unsigned NodeId;
32 typedef unsigned EdgeId;
40 typedef typename SolverT::RawVector RawVector;
41 typedef typename SolverT::RawMatrix RawMatrix;
42 typedef typename SolverT::Vector Vector;
43 typedef typename SolverT::Matrix Matrix;
44 typedef typename CostAllocator::VectorPtr VectorPtr;
45 typedef typename CostAllocator::MatrixPtr MatrixPtr;
46 typedef typename SolverT::NodeMetadata NodeMetadata;
47 typedef typename SolverT::EdgeMetadata EdgeMetadata;
3348
3449 private:
3550
36 typedef std::set AdjEdgeList;
37
38 public:
39
40 typedef AdjEdgeList::iterator AdjEdgeItr;
41
42 private:
43
4451 class NodeEntry {
52 public:
53 typedef std::set AdjEdgeList;
54 typedef AdjEdgeList::const_iterator AdjEdgeItr;
55 NodeEntry(VectorPtr Costs) : Costs(Costs) {}
56
57 VectorPtr Costs;
58 NodeMetadata Metadata;
59 AdjEdgeList AdjEdgeIds;
60 };
61
62 class EdgeEntry {
63 public:
64 EdgeEntry(NodeId N1Id, NodeId N2Id, MatrixPtr Costs)
65 : Costs(Costs), N1Id(N1Id), N2Id(N2Id) {}
66 void invalidate() {
67 N1Id = N2Id = Graph::invalidNodeId();
68 Costs = nullptr;
69 }
70 NodeId getN1Id() const { return N1Id; }
71 NodeId getN2Id() const { return N2Id; }
72 MatrixPtr Costs;
73 EdgeMetadata Metadata;
4574 private:
46 Vector costs;
47 AdjEdgeList adjEdges;
48 void *data;
49 NodeEntry() : costs(0, 0) {}
50 public:
51 NodeEntry(const Vector &costs) : costs(costs), data(0) {}
52 Vector& getCosts() { return costs; }
53 const Vector& getCosts() const { return costs; }
54 unsigned getDegree() const { return adjEdges.size(); }
55 AdjEdgeItr edgesBegin() { return adjEdges.begin(); }
56 AdjEdgeItr edgesEnd() { return adjEdges.end(); }
57 AdjEdgeItr addEdge(EdgeId e) {
58 return adjEdges.insert(adjEdges.end(), e);
59 }
60 void removeEdge(AdjEdgeItr ae) {
61 adjEdges.erase(ae);
62 }
63 void setData(void *data) { this->data = data; }
64 void* getData() { return data; }
65 };
66
67 class EdgeEntry {
68 private:
69 NodeId node1, node2;
70 Matrix costs;
71 AdjEdgeItr node1AEItr, node2AEItr;
72 void *data;
73 EdgeEntry() : costs(0, 0, 0), data(0) {}
74 public:
75 EdgeEntry(NodeId node1, NodeId node2, const Matrix &costs)
76 : node1(node1), node2(node2), costs(costs) {}
77 NodeId getNode1() const { return node1; }
78 NodeId getNode2() const { return node2; }
79 Matrix& getCosts() { return costs; }
80 const Matrix& getCosts() const { return costs; }
81 void setNode1AEItr(AdjEdgeItr ae) { node1AEItr = ae; }
82 AdjEdgeItr getNode1AEItr() { return node1AEItr; }
83 void setNode2AEItr(AdjEdgeItr ae) { node2AEItr = ae; }
84 AdjEdgeItr getNode2AEItr() { return node2AEItr; }
85 void setData(void *data) { this->data = data; }
86 void *getData() { return data; }
75 NodeId N1Id, N2Id;
8776 };
8877
8978 // ----- MEMBERS -----
79
80 CostAllocator CostAlloc;
81 SolverT *Solver;
9082
9183 typedef std::vector NodeVector;
9284 typedef std::vector FreeNodeVector;
93 NodeVector nodes;
94 FreeNodeVector freeNodes;
85 NodeVector Nodes;
86 FreeNodeVector FreeNodeIds;
9587
9688 typedef std::vector EdgeVector;
9789 typedef std::vector FreeEdgeVector;
98 EdgeVector edges;
99 FreeEdgeVector freeEdges;
90 EdgeVector Edges;
91 FreeEdgeVector FreeEdgeIds;
10092
10193 // ----- INTERNAL METHODS -----
10294
103 NodeEntry& getNode(NodeId nId) { return nodes[nId]; }
104 const NodeEntry& getNode(NodeId nId) const { return nodes[nId]; }
105
106 EdgeEntry& getEdge(EdgeId eId) { return edges[eId]; }
107 const EdgeEntry& getEdge(EdgeId eId) const { return edges[eId]; }
108
109 NodeId addConstructedNode(const NodeEntry &n) {
110 NodeId nodeId = 0;
111 if (!freeNodes.empty()) {
112 nodeId = freeNodes.back();
113 freeNodes.pop_back();
114 nodes[nodeId] = n;
95 NodeEntry& getNode(NodeId NId) { return Nodes[NId]; }
96 const NodeEntry& getNode(NodeId NId) const { return Nodes[NId]; }
97
98 EdgeEntry& getEdge(EdgeId EId) { return Edges[EId]; }
99 const EdgeEntry& getEdge(EdgeId EId) const { return Edges[EId]; }
100
101 NodeId addConstructedNode(const NodeEntry &N) {
102 NodeId NId = 0;
103 if (!FreeNodeIds.empty()) {
104 NId = FreeNodeIds.back();
105 FreeNodeIds.pop_back();
106 Nodes[NId] = std::move(N);
115107 } else {
116 nodeId = nodes.size();
117 nodes.push_back(n);
118 }
119 return nodeId;
120 }
121
122 EdgeId addConstructedEdge(const EdgeEntry &e) {
123 assert(findEdge(e.getNode1(), e.getNode2()) == invalidEdgeId() &&
108 NId = Nodes.size();
109 Nodes.push_back(std::move(N));
110 }
111 return NId;
112 }
113
114 EdgeId addConstructedEdge(const EdgeEntry &E) {
115 assert(findEdge(E.getN1Id(), E.getN2Id()) == invalidEdgeId() &&
124116 "Attempt to add duplicate edge.");
125 EdgeId edgeId = 0;
126 if (!freeEdges.empty()) {
127 edgeId = freeEdges.back();
128 freeEdges.pop_back();
129 edges[edgeId] = e;
117 EdgeId EId = 0;
118 if (!FreeEdgeIds.empty()) {
119 EId = FreeEdgeIds.back();
120 FreeEdgeIds.pop_back();
121 Edges[EId] = std::move(E);
130122 } else {
131 edgeId = edges.size();
132 edges.push_back(e);
133 }
134
135 EdgeEntry &ne = getEdge(edgeId);
136 NodeEntry &n1 = getNode(ne.getNode1());
137 NodeEntry &n2 = getNode(ne.getNode2());
123 EId = Edges.size();
124 Edges.push_back(std::move(E));
125 }
126
127 EdgeEntry &NE = getEdge(EId);
128 NodeEntry &N1 = getNode(NE.getN1Id());
129 NodeEntry &N2 = getNode(NE.getN2Id());
138130
139131 // Sanity check on matrix dimensions:
140 assert((n1.getCosts().getLength() == ne.getCosts().getRows()) &&
141 (n2.getCosts().getLength() == ne.getCosts().getCols()) &&
132 assert((N1.Costs->getLength() == NE.Costs->getRows()) &&
133 (N2.Costs->getLength() == NE.Costs->getCols()) &&
142134 "Edge cost dimensions do not match node costs dimensions.");
143135
144 ne.setNode1AEItr(n1.addEdge(edgeId));
145 ne.setNode2AEItr(n2.addEdge(edgeId));
146 return edgeId;
147 }
148
149 Graph(const Graph &other) {}
150 void operator=(const Graph &other) {}
136 N1.AdjEdgeIds.insert(EId);
137 N2.AdjEdgeIds.insert(EId);
138 return EId;
139 }
140
141 Graph(const Graph &Other) {}
142 void operator=(const Graph &Other) {}
151143
152144 public:
153145
146 typedef typename NodeEntry::AdjEdgeItr AdjEdgeItr;
147
154148 class NodeItr {
155149 public:
156 NodeItr(NodeId nodeId, const Graph &g)
157 : nodeId(nodeId), endNodeId(g.nodes.size()), freeNodes(g.freeNodes) {
158 this->nodeId = findNextInUse(nodeId); // Move to the first in-use nodeId
159 }
160
161 bool operator==(const NodeItr& n) const { return nodeId == n.nodeId; }
162 bool operator!=(const NodeItr& n) const { return !(*this == n); }
163 NodeItr& operator++() { nodeId = findNextInUse(++nodeId); return *this; }
164 NodeId operator*() const { return nodeId; }
150 NodeItr(NodeId CurNId, const Graph &G)
151 : CurNId(CurNId), EndNId(G.Nodes.size()), FreeNodeIds(G.FreeNodeIds) {
152 this->CurNId = findNextInUse(CurNId); // Move to first in-use node id
153 }
154
155 bool operator==(const NodeItr &O) const { return CurNId == O.CurNId; }
156 bool operator!=(const NodeItr &O) const { return !(*this == O); }
157 NodeItr& operator++() { CurNId = findNextInUse(++CurNId); return *this; }
158 NodeId operator*() const { return CurNId; }
165159
166160 private:
167 NodeId findNextInUse(NodeId n) const {
168 while (n < endNodeId &&
169 std::find(freeNodes.begin(), freeNodes.end(), n) !=
170 freeNodes.end()) {
171 ++n;
161 NodeId findNextInUse(NodeId NId) const {
162 while (NId < EndNId &&
163 std::find(FreeNodeIds.begin(), FreeNodeIds.end(), NId) !=
164 FreeNodeIds.end()) {
165 ++NId;
172166 }
173 return n;
174 }
175
176 NodeId nodeId, endNodeId;
177 const FreeNodeVector& freeNodes;
167 return NId;
168 }
169
170 NodeId CurNId, EndNId;
171 const FreeNodeVector &FreeNodeIds;
178172 };
179173
180174 class EdgeItr {
181175 public:
182 EdgeItr(EdgeId edgeId, const Graph &g)
183 : edgeId(edgeId), endEdgeId(g.edges.size()), freeEdges(g.freeEdges) {
184 this->edgeId = findNextInUse(edgeId); // Move to the first in-use edgeId
185 }
186
187 bool operator==(const EdgeItr& n) const { return edgeId == n.edgeId; }
188 bool operator!=(const EdgeItr& n) const { return !(*this == n); }
189 EdgeItr& operator++() { edgeId = findNextInUse(++edgeId); return *this; }
190 EdgeId operator*() const { return edgeId; }
176 EdgeItr(EdgeId CurEId, const Graph &G)
177 : CurEId(CurEId), EndEId(G.Edges.size()), FreeEdgeIds(G.FreeEdgeIds) {
178 this->CurEId = findNextInUse(CurEId); // Move to first in-use edge id
179 }
180
181 bool operator==(const EdgeItr &O) const { return CurEId == O.CurEId; }
182 bool operator!=(const EdgeItr &O) const { return !(*this == O); }
183 EdgeItr& operator++() { CurEId = findNextInUse(++CurEId); return *this; }
184 EdgeId operator*() const { return CurEId; }
191185
192186 private:
193 EdgeId findNextInUse(EdgeId n) const {
194 while (n < endEdgeId &&
195 std::find(freeEdges.begin(), freeEdges.end(), n) !=
196 freeEdges.end()) {
197 ++n;
187 EdgeId findNextInUse(EdgeId EId) const {
188 while (EId < EndEId &&
189 std::find(FreeEdgeIds.begin(), FreeEdgeIds.end(), EId) !=
190 FreeEdgeIds.end()) {
191 ++EId;
198192 }
199 return n;
200 }
201
202 EdgeId edgeId, endEdgeId;
203 const FreeEdgeVector& freeEdges;
193 return EId;
194 }
195
196 EdgeId CurEId, EndEId;
197 const FreeEdgeVector &FreeEdgeIds;
198 };
199
200 class NodeIdSet {
201 public:
202 NodeIdSet(const Graph &G) : G(G) { }
203 NodeItr begin() const { return NodeItr(0, G); }
204 NodeItr end() const { return NodeItr(G.Nodes.size(), G); }
205 bool empty() const { return G.Nodes.empty(); }
206 typename NodeVector::size_type size() const {
207 return G.Nodes.size() - G.FreeNodeIds.size();
208 }
209 private:
210 const Graph& G;
211 };
212
213 class EdgeIdSet {
214 public:
215 EdgeIdSet(const Graph &G) : G(G) { }
216 EdgeItr begin() const { return EdgeItr(0, G); }
217 EdgeItr end() const { return EdgeItr(G.Edges.size(), G); }
218 bool empty() const { return G.Edges.empty(); }
219 typename NodeVector::size_type size() const {
220 return G.Edges.size() - G.FreeEdgeIds.size();
221 }
222 private:
223 const Graph& G;
224 };
225
226 class AdjEdgeIdSet {
227 public:
228 AdjEdgeIdSet(const NodeEntry &NE) : NE(NE) { }
229 typename NodeEntry::AdjEdgeItr begin() const {
230 return NE.AdjEdgeIds.begin();
231 }
232 typename NodeEntry::AdjEdgeItr end() const {
233 return NE.AdjEdgeIds.end();
234 }
235 bool empty() const { return NE.AdjEdges.empty(); }
236 typename NodeEntry::AdjEdgeList::size_type size() const {
237 return NE.AdjEdgeIds.size();
238 }
239 private:
240 const NodeEntry &NE;
204241 };
205242
206243 /// \brief Construct an empty PBQP graph.
207 Graph() {}
244 Graph() : Solver(nullptr) { }
245
246 /// \brief Lock this graph to the given solver instance in preparation
247 /// for running the solver. This method will call solver.handleAddNode for
248 /// each node in the graph, and handleAddEdge for each edge, to give the
249 /// solver an opportunity to set up any requried metadata.
250 void setSolver(SolverT &S) {
251 assert(Solver == nullptr && "Solver already set. Call unsetSolver().");
252 Solver = &S;
253 for (auto NId : nodeIds())
254 Solver->handleAddNode(NId);
255 for (auto EId : edgeIds())
256 Solver->handleAddEdge(EId);
257 }
258
259 /// \brief Release from solver instance.
260 void unsetSolver() {
261 assert(Solver != nullptr && "Solver not set.");
262 Solver = nullptr;
263 }
208264
209265 /// \brief Add a node with the given costs.
210 /// @param costs Cost vector for the new node.
266 /// @param Costs Cost vector for the new node.
211267 /// @return Node iterator for the added node.
212 NodeId addNode(const Vector &costs) {
213 return addConstructedNode(NodeEntry(costs));
268 template
269 NodeId addNode(OtherVectorT Costs) {
270 // Get cost vector from the problem domain
271 VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs));
272 NodeId NId = addConstructedNode(NodeEntry(AllocatedCosts));
273 if (Solver)
274 Solver->handleAddNode(NId);
275 return NId;
214276 }
215277
216278 /// \brief Add an edge between the given nodes with the given costs.
217 /// @param n1Id First node.
218 /// @param n2Id Second node.
279 /// @param N1Id First node.
280 /// @param N2Id Second node.
219281 /// @return Edge iterator for the added edge.
220 EdgeId addEdge(NodeId n1Id, NodeId n2Id, const Matrix &costs) {
221 assert(getNodeCosts(n1Id).getLength() == costs.getRows() &&
222 getNodeCosts(n2Id).getLength() == costs.getCols() &&
282 template
283 EdgeId addEdge(NodeId N1Id, NodeId N2Id, OtherVectorT Costs) {
284 assert(getNodeCosts(N1Id).getLength() == Costs.getRows() &&
285 getNodeCosts(N2Id).getLength() == Costs.getCols() &&
223286 "Matrix dimensions mismatch.");
224 return addConstructedEdge(EdgeEntry(n1Id, n2Id, costs));
225 }
287 // Get cost matrix from the problem domain.
288 MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs));
289 EdgeId EId = addConstructedEdge(EdgeEntry(N1Id, N2Id, AllocatedCosts));
290 if (Solver)
291 Solver->handleAddEdge(EId);
292 return EId;
293 }
294
295 /// \brief Returns true if the graph is empty.
296 bool empty() const { return NodeIdSet(*this).empty(); }
297
298 NodeIdSet nodeIds() const { return NodeIdSet(*this); }
299 EdgeIdSet edgeIds() const { return EdgeIdSet(*this); }
300
301 AdjEdgeIdSet adjEdgeIds(NodeId NId) { return AdjEdgeIdSet(getNode(NId)); }
226302
227303 /// \brief Get the number of nodes in the graph.
228304 /// @return Number of nodes in the graph.
229 unsigned getNumNodes() const { return nodes.size() - freeNodes.size(); }
305 unsigned getNumNodes() const { return NodeIdSet(*this).size(); }
230306
231307 /// \brief Get the number of edges in the graph.
232308 /// @return Number of edges in the graph.
233 unsigned getNumEdges() const { return edges.size() - freeEdges.size(); }
234
235 /// \brief Get a node's cost vector.
236 /// @param nId Node id.
309 unsigned getNumEdges() const { return EdgeIdSet(*this).size(); }
310
311 /// \brief Set a node's cost vector.
312 /// @param NId Node to update.
313 /// @param Costs New costs to set.
237314 /// @return Node cost vector.
238 Vector& getNodeCosts(NodeId nId) { return getNode(nId).getCosts(); }
315 template
316 void setNodeCosts(NodeId NId, OtherVectorT Costs) {
317 VectorPtr AllocatedCosts = CostAlloc.getVector(std::move(Costs));
318 if (Solver)
319 Solver->handleSetNodeCosts(NId, *AllocatedCosts);
320 getNode(NId).Costs = AllocatedCosts;
321 }
239322
240323 /// \brief Get a node's cost vector (const version).
241 /// @param nId Node id.
324 /// @param NId Node id.
242325 /// @return Node cost vector.
243 const Vector& getNodeCosts(NodeId nId) const {
244 return getNode(nId).getCosts();
245 }
246
247 /// \brief Set a node's data pointer.
248 /// @param nId Node id.
249 /// @param data Pointer to node data.
250 ///
251 /// Typically used by a PBQP solver to attach data to aid in solution.
252 void setNodeData(NodeId nId, void *data) { getNode(nId).setData(data); }
253
254 /// \brief Get the node's data pointer.
255 /// @param nId Node id.
256 /// @return Pointer to node data.
257 void* getNodeData(NodeId nId) { return getNode(nId).getData(); }
258
259 /// \brief Get an edge's cost matrix.
260 /// @param eId Edge id.
326 const Vector& getNodeCosts(NodeId NId) const {
327 return *getNode(NId).Costs;
328 }
329
330 NodeMetadata& getNodeMetadata(NodeId NId) {
331 return getNode(NId).Metadata;
332 }
333
334 const NodeMetadata& getNodeMetadata(NodeId NId) const {
335 return getNode(NId).Metadata;
336 }
337
338 typename NodeEntry::AdjEdgeList::size_type getNodeDegree(NodeId NId) const {
339 return getNode(NId).AdjEdgeIds.size();
340 }
341
342 /// \brief Set an edge's cost matrix.
343 /// @param EId Edge id.
344 /// @param Costs New cost matrix.
345 template
346 void setEdgeCosts(EdgeId EId, OtherMatrixT Costs) {
347 MatrixPtr AllocatedCosts = CostAlloc.getMatrix(std::move(Costs));
348 if (Solver)
349 Solver->handleSetEdgeCosts(EId, *AllocatedCosts);
350 getEdge(EId).Costs = AllocatedCosts;
351 }
352
353 /// \brief Get an edge's cost matrix (const version).
354 /// @param EId Edge id.
261355 /// @return Edge cost matrix.
262 Matrix& getEdgeCosts(EdgeId eId) { return getEdge(eId).getCosts(); }
263
264 /// \brief Get an edge's cost matrix (const version).
265 /// @param eId Edge id.
266 /// @return Edge cost matrix.
267 const Matrix& getEdgeCosts(EdgeId eId) const {
268 return getEdge(eId).getCosts();
269 }
270
271 /// \brief Set an edge's data pointer.
272 /// @param eId Edge id.
273 /// @param data Pointer to edge data.
274 ///
275 /// Typically used by a PBQP solver to attach data to aid in solution.
276 void setEdgeData(EdgeId eId, void *data) { getEdge(eId).setData(data); }
277
278 /// \brief Get an edge's data pointer.
279 /// @param eId Edge id.
280 /// @return Pointer to edge data.
281 void* getEdgeData(EdgeId eId) { return getEdge(eId).getData(); }
282
283 /// \brief Get a node's degree.
284 /// @param nId Node id.
285 /// @return The degree of the node.
286 unsigned getNodeDegree(NodeId nId) const {
287 return getNode(nId).getDegree();
288 }
289
290 /// \brief Begin iterator for node set.
291 NodeItr nodesBegin() const { return NodeItr(0, *this); }
292
293 /// \brief End iterator for node set.
294 NodeItr nodesEnd() const { return NodeItr(nodes.size(), *this); }
295
296 /// \brief Begin iterator for edge set.
297 EdgeItr edgesBegin() const { return EdgeItr(0, *this); }
298
299 /// \brief End iterator for edge set.
300 EdgeItr edgesEnd() const { return EdgeItr(edges.size(), *this); }
301
302 /// \brief Get begin iterator for adjacent edge set.
303 /// @param nId Node id.
304 /// @return Begin iterator for the set of edges connected to the given node.
305 AdjEdgeItr adjEdgesBegin(NodeId nId) {
306 return getNode(nId).edgesBegin();
307 }
308
309 /// \brief Get end iterator for adjacent edge set.
310 /// @param nId Node id.
311 /// @return End iterator for the set of edges connected to the given node.
312 AdjEdgeItr adjEdgesEnd(NodeId nId) {
313 return getNode(nId).edgesEnd();
356 const Matrix& getEdgeCosts(EdgeId EId) const { return *getEdge(EId).Costs; }
357
358 EdgeMetadata& getEdgeMetadata(EdgeId NId) {
359 return getEdge(NId).Metadata;
360 }
361
362 const EdgeMetadata& getEdgeMetadata(EdgeId NId) const {
363 return getEdge(NId).Metadata;
314364 }
315365
316366 /// \brief Get the first node connected to this edge.
317 /// @param eId Edge id.
367 /// @param EId Edge id.
318368 /// @return The first node connected to the given edge.
319 NodeId getEdgeNode1(EdgeId eId) {
320 return getEdge(eId).getNode1();
369 NodeId getEdgeNode1Id(EdgeId EId) {
370 return getEdge(EId).getN1Id();
321371 }
322372
323373 /// \brief Get the second node connected to this edge.
324 /// @param eId Edge id.
374 /// @param EId Edge id.
325375 /// @return The second node connected to the given edge.
326 NodeId getEdgeNode2(EdgeId eId) {
327 return getEdge(eId).getNode2();
376 NodeId getEdgeNode2Id(EdgeId EId) {
377 return getEdge(EId).getN2Id();
328378 }
329379
330380 /// \brief Get the "other" node connected to this edge.
331 /// @param eId Edge id.
332 /// @param nId Node id for the "given" node.
381 /// @param EId Edge id.
382 /// @param NId Node id for the "given" node.
333383 /// @return The iterator for the "other" node connected to this edge.
334 NodeId getEdgeOtherNode(EdgeId eId, NodeId nId) {
335 EdgeEntry &e = getEdge(eId);
336 if (e.getNode1() == nId) {
337 return e.getNode2();
384 NodeId getEdgeOtherNodeId(EdgeId EId, NodeId NId) {
385 EdgeEntry &E = getEdge(EId);
386 if (E.getN1Id() == NId) {
387 return E.getN2Id();
338388 } // else
339 return e.getNode1();
340 }
341
342 EdgeId invalidEdgeId() const {
389 return E.getN1Id();
390 }
391
392 /// \brief Returns a value representing an invalid (non-existant) node.
393 static NodeId invalidNodeId() {
394 return std::numeric_limits::max();
395 }
396
397 /// \brief Returns a value representing an invalid (non-existant) edge.
398 static EdgeId invalidEdgeId() {
343399 return std::numeric_limits::max();
344400 }
345401
346402 /// \brief Get the edge connecting two nodes.
347 /// @param n1Id First node id.
348 /// @param n2Id Second node id.
349 /// @return An id for edge (n1Id, n2Id) if such an edge exists,
403 /// @param N1Id First node id.
404 /// @param N2Id Second node id.
405 /// @return An id for edge (N1Id, N2Id) if such an edge exists,
350406 /// otherwise returns an invalid edge id.
351 EdgeId findEdge(NodeId n1Id, NodeId n2Id) {
352 for (AdjEdgeItr aeItr = adjEdgesBegin(n1Id), aeEnd = adjEdgesEnd(n1Id);
353 aeItr != aeEnd; ++aeItr) {
354 if ((getEdgeNode1(*aeItr) == n2Id) ||
355 (getEdgeNode2(*aeItr) == n2Id)) {
356 return *aeItr;
407 EdgeId findEdge(NodeId N1Id, NodeId N2Id) {
408 for (auto AEId : adjEdgeIds(N1Id)) {
409 if ((getEdgeNode1Id(AEId) == N2Id) ||
410 (getEdgeNode2Id(AEId) == N2Id)) {
411 return AEId;
357412 }
358413 }
359414 return invalidEdgeId();
360415 }
361416
362417 /// \brief Remove a node from the graph.
363 /// @param nId Node id.
364 void removeNode(NodeId nId) {
365 NodeEntry &n = getNode(nId);
366 for (AdjEdgeItr itr = n.edgesBegin(), end = n.edgesEnd(); itr != end; ++itr) {
367 EdgeId eId = *itr;
368 removeEdge(eId);
369 }
370 freeNodes.push_back(nId);
418 /// @param NId Node id.
419 void removeNode(NodeId NId) {
420 if (Solver)
421 Solver->handleRemoveNode(NId);
422 NodeEntry &N = getNode(NId);
423 // TODO: Can this be for-each'd?
424 for (AdjEdgeItr AEItr = N.adjEdgesBegin(),
425 AEEnd = N.adjEdgesEnd();
426 AEItr != AEEnd;) {
427 EdgeId EId = *AEItr;
428 ++AEItr;
429 removeEdge(EId);
430 }
431 FreeNodeIds.push_back(NId);
432 }
433
434 /// \brief Disconnect an edge from the given node.
435 ///
436 /// Removes the given edge from the adjacency list of the given node.
437 /// This operation leaves the edge in an 'asymmetric' state: It will no
438 /// longer appear in an iteration over the given node's (NId's) edges, but
439 /// will appear in an iteration over the 'other', unnamed node's edges.
440 ///
441 /// This does not correspond to any normal graph operation, but exists to
442 /// support efficient PBQP graph-reduction based solvers. It is used to
443 /// 'effectively' remove the unnamed node from the graph while the solver
444 /// is performing the reduction. The solver will later call reconnectNode
445 /// to restore the edge in the named node's adjacency list.
446 ///
447 /// Since the degree of a node is the number of connected edges,
448 /// disconnecting an edge from a node 'u' will cause the degree of 'u' to
449 /// drop by 1.
450 ///
451 /// A disconnected edge WILL still appear in an iteration over the graph
452 /// edges.
453 ///
454 /// A disconnected edge should not be removed from the graph, it should be
455 /// reconnected first.
456 ///
457 /// A disconnected edge can be reconnected by calling the reconnectEdge
458 /// method.
459 void disconnectEdge(EdgeId EId, NodeId NId) {
460 if (Solver)
461 Solver->handleDisconnectEdge(EId, NId);
462 NodeEntry &N = getNode(NId);
463 N.AdjEdgeIds.erase(EId);
464 }
465
466 /// \brief Convenience method to disconnect all neighbours from the given
467 /// node.
468 void disconnectAllNeighborsFromNode(NodeId NId) {
469 for (auto AEId : adjEdgeIds(NId))
470 disconnectEdge(AEId, getEdgeOtherNodeId(AEId, NId));
471 }
472
473 /// \brief Re-attach an edge to its nodes.
474 ///
475 /// Adds an edge that had been previously disconnected back into the
476 /// adjacency set of the nodes that the edge connects.
477 void reconnectEdge(EdgeId EId, NodeId NId) {
478 NodeEntry &N = getNode(NId);
479 N.addAdjEdge(EId);
480 if (Solver)
481 Solver->handleReconnectEdge(EId, NId);
371482 }
372483
373484 /// \brief Remove an edge from the graph.
374 /// @param eId Edge id.
375 void removeEdge(EdgeId eId) {
376 EdgeEntry &e = getEdge(eId);
377 NodeEntry &n1 = getNode(e.getNode1());
378 NodeEntry &n2 = getNode(e.getNode2());
379 n1.removeEdge(e.getNode1AEItr());
380 n2.removeEdge(e.getNode2AEItr());
381 freeEdges.push_back(eId);
485 /// @param EId Edge id.
486 void removeEdge(EdgeId EId) {
487 if (Solver)
488 Solver->handleRemoveEdge(EId);
489 EdgeEntry &E = getEdge(EId);
490 NodeEntry &N1 = getNode(E.getNode1());
491 NodeEntry &N2 = getNode(E.getNode2());
492 N1.removeEdge(EId);
493 N2.removeEdge(EId);
494 FreeEdgeIds.push_back(EId);
495 Edges[EId].invalidate();
382496 }
383497
384498 /// \brief Remove all nodes and edges from the graph.
385499 void clear() {
386 nodes.clear();
387 freeNodes.clear();
388 edges.clear();
389 freeEdges.clear();
500 Nodes.clear();
501 FreeNodeIds.clear();
502 Edges.clear();
503 FreeEdgeIds.clear();
390504 }
391505
392506 /// \brief Dump a graph to an output stream.
393507 template
394 void dump(OStream &os) {
395 os << getNumNodes() << " " << getNumEdges() << "\n";
396
397 for (NodeItr nodeItr = nodesBegin(), nodeEnd = nodesEnd();
398 nodeItr != nodeEnd; ++nodeItr) {
399 const Vector& v = getNodeCosts(*nodeItr);
400 os << "\n" << v.getLength() << "\n";
401 assert(v.getLength() != 0 && "Empty vector in graph.");
402 os << v[0];
403 for (unsigned i = 1; i < v.getLength(); ++i) {
404 os << " " << v[i];
508 void dump(OStream &OS) {
509 OS << nodeIds().size() << " " << edgeIds().size() << "\n";
510
511 for (auto NId : nodeIds()) {
512 const Vector& V = getNodeCosts(NId);
513 OS << "\n" << V.getLength() << "\n";
514 assert(V.getLength() != 0 && "Empty vector in graph.");
515 OS << V[0];
516 for (unsigned i = 1; i < V.getLength(); ++i) {
517 OS << " " << V[i];
405518 }
406 os << "\n";
407 }
408
409 for (EdgeItr edgeItr = edgesBegin(), edgeEnd = edgesEnd();
410 edgeItr != edgeEnd; ++edgeItr) {
411 NodeId n1 = getEdgeNode1(*edgeItr);
412 NodeId n2 = getEdgeNode2(*edgeItr);
413 assert(n1 != n2 && "PBQP graphs shound not have self-edges.");
414 const Matrix& m = getEdgeCosts(*edgeItr);
415 os << "\n" << n1 << " " << n2 << "\n"
416 << m.getRows() << " " << m.getCols() << "\n";
417 assert(m.getRows() != 0 && "No rows in matrix.");
418 assert(m.getCols() != 0 && "No cols in matrix.");
419 for (unsigned i = 0; i < m.getRows(); ++i) {
420 os << m[i][0];
421 for (unsigned j = 1; j < m.getCols(); ++j) {
422 os << " " << m[i][j];
519 OS << "\n";
520 }
521
522 for (auto EId : edgeIds()) {
523 NodeId N1Id = getEdgeNode1Id(EId);
524 NodeId N2Id = getEdgeNode2Id(EId);
525 assert(N1Id != N2Id && "PBQP graphs shound not have self-edges.");
526 const Matrix& M = getEdgeCosts(EId);
527 OS << "\n" << N1Id << " " << N2Id << "\n"
528 << M.getRows() << " " << M.getCols() << "\n";
529 assert(M.getRows() != 0 && "No rows in matrix.");
530 assert(M.getCols() != 0 && "No cols in matrix.");
531 for (unsigned i = 0; i < M.getRows(); ++i) {
532 OS << M[i][0];
533 for (unsigned j = 1; j < M.getCols(); ++j) {
534 OS << " " << M[i][j];
423535 }
424 os << "\n";
536 OS << "\n";
425537 }
426538 }
427539 }
429541 /// \brief Print a representation of this graph in DOT format.
430542 /// @param os Output stream to print on.
431543 template
432 void printDot(OStream &os) {
433
434 os << "graph {\n";
435
436 for (NodeItr nodeItr = nodesBegin(), nodeEnd = nodesEnd();
437 nodeItr != nodeEnd; ++nodeItr) {
438
439 os << " node" << *nodeItr << " [ label=\""
440 << *nodeItr << ": " << getNodeCosts(*nodeItr) << "\" ]\n";
441 }
442
443 os << " edge [ len=" << getNumNodes() << " ]\n";
444
445 for (EdgeItr edgeItr = edgesBegin(), edgeEnd = edgesEnd();
446 edgeItr != edgeEnd; ++edgeItr) {
447
448 os << " node" << getEdgeNode1(*edgeItr)
449 << " -- node" << getEdgeNode2(*edgeItr)
544 void printDot(OStream &OS) {
545 OS << "graph {\n";
546 for (auto NId : nodeIds()) {
547 OS << " node" << NId << " [ label=\""
548 << NId << ": " << getNodeCosts(NId) << "\" ]\n";
549 }
550 OS << " edge [ len=" << nodeIds().size() << " ]\n";
551 for (auto EId : edgeIds()) {
552 OS << " node" << getEdgeNode1Id(EId)
553 << " -- node" << getEdgeNode2Id(EId)
450554 << " [ label=\"";
451
452 const Matrix &edgeCosts = getEdgeCosts(*edgeItr);
453
454 for (unsigned i = 0; i < edgeCosts.getRows(); ++i) {
455 os << edgeCosts.getRowAsVector(i) << "\\n";
555 const Matrix &EdgeCosts = getEdgeCosts(EId);
556 for (unsigned i = 0; i < EdgeCosts.getRows(); ++i) {
557 OS << EdgeCosts.getRowAsVector(i) << "\\n";
456558 }
457 os << "\" ]\n";
458 }
459 os << "}\n";
460 }
461
559 OS << "\" ]\n";
560 }
561 OS << "}\n";
562 }
462563 };
463564
464 // void Graph::copyFrom(const Graph &other) {
465 // std::map
466 // NodeItrComparator> nodeMap;
467
468 // for (Graph::ConstNodeItr nItr = other.nodesBegin(),
469 // nEnd = other.nodesEnd();
470 // nItr != nEnd; ++nItr) {
471 // nodeMap[nItr] = addNode(other.getNodeCosts(nItr));
472 // }
473 // }
474
475565 }
476566
477567 #endif // LLVM_CODEGEN_PBQP_GRAPH_HPP
+0
-247
include/llvm/CodeGen/PBQP/HeuristicBase.h less more
None //===-- HeuristcBase.h --- Heuristic base class for PBQP --------*- C++ -*-===//
1 //
2 // The LLVM Compiler Infrastructure
3 //
4 // This file is distributed under the University of Illinois Open Source
5 // License. See LICENSE.TXT for details.
6 //
7 //===----------------------------------------------------------------------===//
8
9 #ifndef LLVM_CODEGEN_PBQP_HEURISTICBASE_H
10 #define LLVM_CODEGEN_PBQP_HEURISTICBASE_H
11
12 #include "HeuristicSolver.h"
13
14 namespace PBQP {
15
16 /// \brief Abstract base class for heuristic implementations.
17 ///
18 /// This class provides a handy base for heuristic implementations with common
19 /// solver behaviour implemented for a number of methods.
20 ///
21 /// To implement your own heuristic using this class as a base you'll have to
22 /// implement, as a minimum, the following methods:
23 ///
24 ///
  • void addToHeuristicList(Graph::NodeItr) : Add a node to the
  • 25 /// heuristic reduction list.
    26 ///
  • void heuristicReduce() : Perform a single heuristic reduction.
  • 27 ///
  • void preUpdateEdgeCosts(Graph::EdgeItr) : Handle the (imminent)
  • 28 /// change to the cost matrix on the given edge (by R2).
    29 ///
  • void postUpdateEdgeCostts(Graph::EdgeItr) : Handle the new
  • 30 /// costs on the given edge.
    31 ///
  • void handleAddEdge(Graph::EdgeItr) : Handle the addition of a new
  • 32 /// edge into the PBQP graph (by R2).
    33 ///
  • void handleRemoveEdge(Graph::EdgeItr, Graph::NodeItr) : Handle the
  • 34 /// disconnection of the given edge from the given node.
    35 ///
  • A constructor for your derived class : to pass back a reference to
  • 36 /// the solver which is using this heuristic.
    37 ///
    38 ///
    39 /// These methods are implemented in this class for documentation purposes,
    40 /// but will assert if called.
    41 ///
    42 /// Note that this class uses the curiously recursive template idiom to
    43 /// forward calls to the derived class. These methods need not be made
    44 /// virtual, and indeed probably shouldn't for performance reasons.
    45 ///
    46 /// You'll also need to provide NodeData and EdgeData structs in your class.
    47 /// These can be used to attach data relevant to your heuristic to each
    48 /// node/edge in the PBQP graph.
    49
    50 template
    51 class HeuristicBase {
    52 private:
    53
    54 typedef std::list OptimalList;
    55
    56 HeuristicSolverImpl &s;
    57 Graph &g;
    58 OptimalList optimalList;
    59
    60 // Return a reference to the derived heuristic.
    61 HImpl& impl() { return static_cast(*this); }
    62
    63 // Add the given node to the optimal reductions list. Keep an iterator to
    64 // its location for fast removal.
    65 void addToOptimalReductionList(Graph::NodeId nId) {
    66 optimalList.insert(optimalList.end(), nId);
    67 }
    68
    69 public:
    70
    71 /// \brief Construct an instance with a reference to the given solver.
    72 /// @param solver The solver which is using this heuristic instance.
    73 HeuristicBase(HeuristicSolverImpl &solver)
    74 : s(solver), g(s.getGraph()) { }
    75
    76 /// \brief Get the solver which is using this heuristic instance.
    77 /// @return The solver which is using this heuristic instance.
    78 ///
    79 /// You can use this method to get access to the solver in your derived
    80 /// heuristic implementation.
    81 HeuristicSolverImpl& getSolver() { return s; }
    82
    83 /// \brief Get the graph representing the problem to be solved.
    84 /// @return The graph representing the problem to be solved.
    85 Graph& getGraph() { return g; }
    86
    87 /// \brief Tell the solver to simplify the graph before the reduction phase.
    88 /// @return Whether or not the solver should run a simplification phase
    89 /// prior to the main setup and reduction.
    90 ///
    91 /// HeuristicBase returns true from this method as it's a sensible default,
    92 /// however you can over-ride it in your derived class if you want different
    93 /// behaviour.
    94 bool solverRunSimplify() const { return true; }
    95
    96 /// \brief Decide whether a node should be optimally or heuristically
    97 /// reduced.
    98 /// @return Whether or not the given node should be listed for optimal
    99 /// reduction (via R0, R1 or R2).
    100 ///
    101 /// HeuristicBase returns true for any node with degree less than 3. This is
    102 /// sane and sensible for many situations, but not all. You can over-ride
    103 /// this method in your derived class if you want a different selection
    104 /// criteria. Note however that your criteria for selecting optimal nodes
    105 /// should be at least as strong as this. I.e. Nodes of degree 3 or
    106 /// higher should not be selected under any circumstances.
    107 bool shouldOptimallyReduce(Graph::NodeId nId) {
    108 if (g.getNodeDegree(nId) < 3)
    109 return true;
    110 // else
    111 return false;
    112 }
    113
    114 /// \brief Add the given node to the list of nodes to be optimally reduced.
    115 /// @param nId Node id to be added.
    116 ///
    117 /// You probably don't want to over-ride this, except perhaps to record
    118 /// statistics before calling this implementation. HeuristicBase relies on
    119 /// its behaviour.
    120 void addToOptimalReduceList(Graph::NodeId nId) {
    121 optimalList.push_back(nId);
    122 }
    123
    124 /// \brief Initialise the heuristic.
    125 ///
    126 /// HeuristicBase iterates over all nodes in the problem and adds them to
    127 /// the appropriate list using addToOptimalReduceList or
    128 /// addToHeuristicReduceList based on the result of shouldOptimallyReduce.
    129 ///
    130 /// This behaviour should be fine for most situations.
    131 void setup() {
    132 for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd();
    133 nItr != nEnd; ++nItr) {
    134 if (impl().shouldOptimallyReduce(*nItr)) {
    135 addToOptimalReduceList(*nItr);
    136 } else {
    137 impl().addToHeuristicReduceList(*nItr);
    138 }
    139 }
    140 }
    141
    142 /// \brief Optimally reduce one of the nodes in the optimal reduce list.
    143 /// @return True if a reduction takes place, false if the optimal reduce
    144 /// list is empty.
    145 ///
    146 /// Selects a node from the optimal reduce list and removes it, applying
    147 /// R0, R1 or R2 as appropriate based on the selected node's degree.
    148 bool optimalReduce() {
    149 if (optimalList.empty())
    150 return false;
    151
    152 Graph::NodeId nId = optimalList.front();
    153 optimalList.pop_front();
    154
    155 switch (s.getSolverDegree(nId)) {
    156 case 0: s.applyR0(nId); break;
    157 case 1: s.applyR1(nId); break;
    158 case 2: s.applyR2(nId); break;
    159 default: llvm_unreachable(
    160 "Optimal reductions of degree > 2 nodes is invalid.");
    161 }
    162
    163 return true;
    164 }
    165
    166 /// \brief Perform the PBQP reduction process.
    167 ///
    168 /// Reduces the problem to the empty graph by repeated application of the
    169 /// reduction rules R0, R1, R2 and RN.
    170 /// R0, R1 or R2 are always applied if possible before RN is used.
    171 void reduce() {
    172 bool finished = false;
    173
    174 while (!finished) {
    175 if (!optimalReduce()) {
    176 if (impl().heuristicReduce()) {
    177 getSolver().recordRN();
    178 } else {
    179 finished = true;
    180 }
    181 }
    182 }
    183 }
    184
    185 /// \brief Add a node to the heuristic reduce list.
    186 /// @param nId Node id to add to the heuristic reduce list.
    187 void addToHeuristicList(Graph::NodeId nId) {
    188 llvm_unreachable("Must be implemented in derived class.");
    189 }
    190
    191 /// \brief Heuristically reduce one of the nodes in the heuristic
    192 /// reduce list.
    193 /// @return True if a reduction takes place, false if the heuristic reduce
    194 /// list is empty.
    195 bool heuristicReduce() {
    196 llvm_unreachable("Must be implemented in derived class.");
    197 return false;
    198 }
    199
    200 /// \brief Prepare a change in the costs on the given edge.
    201 /// @param eId Edge id.
    202 void preUpdateEdgeCosts(Graph::EdgeId eId) {
    203 llvm_unreachable("Must be implemented in derived class.");
    204 }
    205
    206 /// \brief Handle the change in the costs on the given edge.
    207 /// @param eId Edge id.
    208 void postUpdateEdgeCostts(Graph::EdgeId eId) {
    209 llvm_unreachable("Must be implemented in derived class.");
    210 }
    211
    212 /// \brief Handle the addition of a new edge into the PBQP graph.
    213 /// @param eId Edge id for the added edge.
    214 void handleAddEdge(Graph::EdgeId eId) {
    215 llvm_unreachable("Must be implemented in derived class.");
    216 }
    217
    218 /// \brief Handle disconnection of an edge from a node.
    219 /// @param eId Edge id for edge being disconnected.
    220 /// @param nId Node id for the node being disconnected from.
    221 ///
    222 /// Edges are frequently removed due to the removal of a node. This
    223 /// method allows for the effect to be computed only for the remaining
    224 /// node in the graph.
    225 void handleRemoveEdge(Graph::EdgeId eId, Graph::NodeId nId) {
    226 llvm_unreachable("Must be implemented in derived class.");
    227 }
    228
    229 /// \brief Clean up any structures used by HeuristicBase.
    230 ///
    231 /// At present this just performs a sanity check: that the optimal reduce
    232 /// list is empty now that reduction has completed.
    233 ///
    234 /// If your derived class has more complex structures which need tearing
    235 /// down you should over-ride this method but include a call back to this
    236 /// implementation.
    237 void cleanup() {
    238 assert(optimalList.empty() && "Nodes left over in optimal reduce list?");
    239 }
    240
    241 };
    242
    243 }
    244
    245
    246 #endif // LLVM_CODEGEN_PBQP_HEURISTICBASE_H
    +0
    -618
    include/llvm/CodeGen/PBQP/HeuristicSolver.h less more
    None //===-- HeuristicSolver.h - Heuristic PBQP Solver --------------*- C++ -*-===//
    1 //
    2 // The LLVM Compiler Infrastructure
    3 //
    4 // This file is distributed under the University of Illinois Open Source
    5 // License. See LICENSE.TXT for details.
    6 //
    7 //===----------------------------------------------------------------------===//
    8 //
    9 // Heuristic PBQP solver. This solver is able to perform optimal reductions for
    10 // nodes of degree 0, 1 or 2. For nodes of degree >2 a plugable heuristic is
    11 // used to select a node for reduction.
    12 //
    13 //===----------------------------------------------------------------------===//
    14
    15 #ifndef LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H
    16 #define LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H
    17
    18 #include "Graph.h"
    19 #include "Solution.h"
    20 #include
    21 #include
    22
    23 namespace PBQP {
    24
    25 /// \brief Heuristic PBQP solver implementation.
    26 ///
    27 /// This class should usually be created (and destroyed) indirectly via a call
    28 /// to HeuristicSolver::solve(Graph&).
    29 /// See the comments for HeuristicSolver.
    30 ///
    31 /// HeuristicSolverImpl provides the R0, R1 and R2 reduction rules,
    32 /// backpropagation phase, and maintains the internal copy of the graph on
    33 /// which the reduction is carried out (the original being kept to facilitate
    34 /// backpropagation).
    35 template
    36 class HeuristicSolverImpl {
    37 private:
    38
    39 typedef typename HImpl::NodeData HeuristicNodeData;
    40 typedef typename HImpl::EdgeData HeuristicEdgeData;
    41
    42 typedef std::list SolverEdges;
    43
    44 public:
    45
    46 /// \brief Iterator type for edges in the solver graph.
    47 typedef SolverEdges::iterator SolverEdgeItr;
    48
    49 private:
    50
    51 class NodeData {
    52 public:
    53 NodeData() : solverDegree(0) {}
    54
    55 HeuristicNodeData& getHeuristicData() { return hData; }
    56
    57 SolverEdgeItr addSolverEdge(Graph::EdgeId eId) {
    58 ++solverDegree;
    59 return solverEdges.insert(solverEdges.end(), eId);
    60 }
    61
    62 void removeSolverEdge(SolverEdgeItr seItr) {
    63 --solverDegree;
    64 solverEdges.erase(seItr);
    65 }
    66
    67 SolverEdgeItr solverEdgesBegin() { return solverEdges.begin(); }
    68 SolverEdgeItr solverEdgesEnd() { return solverEdges.end(); }
    69 unsigned getSolverDegree() const { return solverDegree; }
    70 void clearSolverEdges() {
    71 solverDegree = 0;
    72 solverEdges.clear();
    73 }
    74
    75 private:
    76 HeuristicNodeData hData;
    77 unsigned solverDegree;
    78 SolverEdges solverEdges;
    79 };
    80
    81 class EdgeData {
    82 public:
    83 HeuristicEdgeData& getHeuristicData() { return hData; }
    84
    85 void setN1SolverEdgeItr(SolverEdgeItr n1SolverEdgeItr) {
    86 this->n1SolverEdgeItr = n1SolverEdgeItr;
    87 }
    88
    89 SolverEdgeItr getN1SolverEdgeItr() { return n1SolverEdgeItr; }
    90
    91 void setN2SolverEdgeItr(SolverEdgeItr n2SolverEdgeItr){
    92 this->n2SolverEdgeItr = n2SolverEdgeItr;
    93 }
    94
    95 SolverEdgeItr getN2SolverEdgeItr() { return n2SolverEdgeItr; }
    96
    97 private:
    98
    99 HeuristicEdgeData hData;
    100 SolverEdgeItr n1SolverEdgeItr, n2SolverEdgeItr;
    101 };
    102
    103 Graph &g;
    104 HImpl h;
    105 Solution s;
    106 std::vector stack;
    107
    108 typedef std::list NodeDataList;
    109 NodeDataList nodeDataList;
    110
    111 typedef std::list EdgeDataList;
    112 EdgeDataList edgeDataList;
    113
    114 public:
    115
    116 /// \brief Construct a heuristic solver implementation to solve the given
    117 /// graph.
    118 /// @param g The graph representing the problem instance to be solved.
    119 HeuristicSolverImpl(Graph &g) : g(g), h(*this) {}
    120
    121 /// \brief Get the graph being solved by this solver.
    122 /// @return The graph representing the problem instance being solved by this
    123 /// solver.
    124 Graph& getGraph() { return g; }
    125
    126 /// \brief Get the heuristic data attached to the given node.
    127 /// @param nId Node id.
    128 /// @return The heuristic data attached to the given node.
    129 HeuristicNodeData& getHeuristicNodeData(Graph::NodeId nId) {
    130 return getSolverNodeData(nId).getHeuristicData();
    131 }
    132
    133 /// \brief Get the heuristic data attached to the given edge.
    134 /// @param eId Edge id.
    135 /// @return The heuristic data attached to the given node.
    136 HeuristicEdgeData& getHeuristicEdgeData(Graph::EdgeId eId) {
    137 return getSolverEdgeData(eId).getHeuristicData();
    138 }
    139
    140 /// \brief Begin iterator for the set of edges adjacent to the given node in
    141 /// the solver graph.
    142 /// @param nId Node id.
    143 /// @return Begin iterator for the set of edges adjacent to the given node
    144 /// in the solver graph.
    145 SolverEdgeItr solverEdgesBegin(Graph::NodeId nId) {
    146 return getSolverNodeData(nId).solverEdgesBegin();
    147 }
    148
    149 /// \brief End iterator for the set of edges adjacent to the given node in
    150 /// the solver graph.
    151 /// @param nId Node id.
    152 /// @return End iterator for the set of edges adjacent to the given node in
    153 /// the solver graph.
    154 SolverEdgeItr solverEdgesEnd(Graph::NodeId nId) {
    155 return getSolverNodeData(nId).solverEdgesEnd();
    156 }
    157
    158 /// \brief Remove a node from the solver graph.
    159 /// @param eId Edge id for edge to be removed.
    160 ///
    161 /// Does not notify the heuristic of the removal. That should be
    162 /// done manually if necessary.
    163 void removeSolverEdge(Graph::EdgeId eId) {
    164 EdgeData &eData = getSolverEdgeData(eId);
    165 NodeData &n1Data = getSolverNodeData(g.getEdgeNode1(eId)),
    166 &n2Data = getSolverNodeData(g.getEdgeNode2(eId));
    167
    168 n1Data.removeSolverEdge(eData.getN1SolverEdgeItr());
    169 n2Data.removeSolverEdge(eData.getN2SolverEdgeItr());
    170 }
    171
    172 /// \brief Compute a solution to the PBQP problem instance with which this
    173 /// heuristic solver was constructed.
    174 /// @return A solution to the PBQP problem.
    175 ///
    176 /// Performs the full PBQP heuristic solver algorithm, including setup,
    177 /// calls to the heuristic (which will call back to the reduction rules in
    178 /// this class), and cleanup.
    179 Solution computeSolution() {
    180 setup();
    181 h.setup();
    182 h.reduce();
    183 backpropagate();
    184 h.cleanup();
    185 cleanup();
    186 return s;
    187 }
    188
    189 /// \brief Add to the end of the stack.
    190 /// @param nId Node id to add to the reduction stack.
    191 void pushToStack(Graph::NodeId nId) {
    192 getSolverNodeData(nId).clearSolverEdges();
    193 stack.push_back(nId);
    194 }
    195
    196 /// \brief Returns the solver degree of the given node.
    197 /// @param nId Node id for which degree is requested.
    198 /// @return Node degree in the solver graph (not the original graph).
    199 unsigned getSolverDegree(Graph::NodeId nId) {
    200 return getSolverNodeData(nId).getSolverDegree();
    201 }
    202
    203 /// \brief Set the solution of the given node.
    204 /// @param nId Node id to set solution for.
    205 /// @param selection Selection for node.
    206 void setSolution(const Graph::NodeId &nId, unsigned selection) {
    207 s.setSelection(nId, selection);
    208
    209 for (Graph::AdjEdgeItr aeItr = g.adjEdgesBegin(nId),
    210 aeEnd = g.adjEdgesEnd(nId);
    211 aeItr != aeEnd; ++aeItr) {
    212 Graph::EdgeId eId(*aeItr);
    213 Graph::NodeId anId(g.getEdgeOtherNode(eId, nId));
    214 getSolverNodeData(anId).addSolverEdge(eId);
    215 }
    216 }
    217
    218 /// \brief Apply rule R0.
    219 /// @param nId Node id for node to apply R0 to.
    220 ///
    221 /// Node will be automatically pushed to the solver stack.
    222 void applyR0(Graph::NodeId nId) {
    223 assert(getSolverNodeData(nId).getSolverDegree() == 0 &&
    224 "R0 applied to node with degree != 0.");
    225
    226 // Nothing to do. Just push the node onto the reduction stack.
    227 pushToStack(nId);
    228
    229 s.recordR0();
    230 }
    231
    232 /// \brief Apply rule R1.
    233 /// @param xnId Node id for node to apply R1 to.
    234 ///
    235 /// Node will be automatically pushed to the solver stack.
    236 void applyR1(Graph::NodeId xnId) {
    237 NodeData &nd = getSolverNodeData(xnId);
    238 assert(nd.getSolverDegree() == 1 &&
    239 "R1 applied to node with degree != 1.");
    240
    241 Graph::EdgeId eId = *nd.solverEdgesBegin();
    242
    243 const Matrix &eCosts = g.getEdgeCosts(eId);
    244 const Vector &xCosts = g.getNodeCosts(xnId);
    245
    246 // Duplicate a little to avoid transposing matrices.
    247 if (xnId == g.getEdgeNode1(eId)) {
    248 Graph::NodeId ynId = g.getEdgeNode2(eId);
    249 Vector &yCosts = g.getNodeCosts(ynId);
    250 for (unsigned j = 0; j < yCosts.getLength(); ++j) {
    251 PBQPNum min = eCosts[0][j] + xCosts[0];
    252 for (unsigned i = 1; i < xCosts.getLength(); ++i) {
    253 PBQPNum c = eCosts[i][j] + xCosts[i];
    254 if (c < min)
    255 min = c;
    256 }
    257 yCosts[j] += min;
    258 }
    259 h.handleRemoveEdge(eId, ynId);
    260 } else {
    261 Graph::NodeId ynId = g.getEdgeNode1(eId);
    262 Vector &yCosts = g.getNodeCosts(ynId);
    263 for (unsigned i = 0; i < yCosts.getLength(); ++i) {
    264 PBQPNum min = eCosts[i][0] + xCosts[0];
    265 for (unsigned j = 1; j < xCosts.getLength(); ++j) {
    266 PBQPNum c = eCosts[i][j] + xCosts[j];
    267 if (c < min)
    268 min = c;
    269 }
    270 yCosts[i] += min;
    271 }
    272 h.handleRemoveEdge(eId, ynId);
    273 }
    274 removeSolverEdge(eId);
    275 assert(nd.getSolverDegree() == 0 &&
    276 "Degree 1 with edge removed should be 0.");
    277 pushToStack(xnId);
    278 s.recordR1();
    279 }
    280
    281 /// \brief Apply rule R2.
    282 /// @param xnId Node id for node to apply R2 to.
    283 ///
    284 /// Node will be automatically pushed to the solver stack.
    285 void applyR2(Graph::NodeId xnId) {
    286 assert(getSolverNodeData(xnId).getSolverDegree() == 2 &&
    287 "R2 applied to node with degree != 2.");
    288
    289 NodeData &nd = getSolverNodeData(xnId);
    290 const Vector &xCosts = g.getNodeCosts(xnId);
    291
    292 SolverEdgeItr aeItr = nd.solverEdgesBegin();
    293 Graph::EdgeId yxeId = *aeItr,
    294 zxeId = *(++aeItr);
    295
    296 Graph::NodeId ynId = g.getEdgeOtherNode(yxeId, xnId),
    297 znId = g.getEdgeOtherNode(zxeId, xnId);
    298
    299 bool flipEdge1 = (g.getEdgeNode1(yxeId) == xnId),
    300 flipEdge2 = (g.getEdgeNode1(zxeId) == xnId);
    301
    302 const Matrix *yxeCosts = flipEdge1 ?
    303 new Matrix(g.getEdgeCosts(yxeId).transpose()) :
    304 &g.getEdgeCosts(yxeId);
    305
    306 const Matrix *zxeCosts = flipEdge2 ?
    307 new Matrix(g.getEdgeCosts(zxeId).transpose()) :
    308 &g.getEdgeCosts(zxeId);
    309
    310 unsigned xLen = xCosts.getLength(),
    311 yLen = yxeCosts->getRows(),
    312 zLen = zxeCosts->getRows();
    313
    314 Matrix delta(yLen, zLen);
    315
    316 for (unsigned i = 0; i < yLen; ++i) {
    317 for (unsigned j = 0; j < zLen; ++j) {
    318 PBQPNum min = (*yxeCosts)[i][0] + (*zxeCosts)[j][0] + xCosts[0];
    319 for (unsigned k = 1; k < xLen; ++k) {
    320 PBQPNum c = (*yxeCosts)[i][k] + (*zxeCosts)[j][k] + xCosts[k];
    321 if (c < min) {
    322 min = c;
    323 }
    324 }
    325 delta[i][j] = min;
    326 }
    327 }
    328
    329 if (flipEdge1)
    330 delete yxeCosts;
    331
    332 if (flipEdge2)
    333 delete zxeCosts;
    334
    335 Graph::EdgeId yzeId = g.findEdge(ynId, znId);
    336 bool addedEdge = false;
    337
    338 if (yzeId == g.invalidEdgeId()) {
    339 yzeId = g.addEdge(ynId, znId, delta);
    340 addedEdge = true;
    341 } else {
    342 Matrix &yzeCosts = g.getEdgeCosts(yzeId);
    343 h.preUpdateEdgeCosts(yzeId);
    344 if (ynId == g.getEdgeNode1(yzeId)) {
    345 yzeCosts += delta;
    346 } else {
    347 yzeCosts += delta.transpose();
    348 }
    349 }
    350
    351 bool nullCostEdge = tryNormaliseEdgeMatrix(yzeId);
    352
    353 if (!addedEdge) {
    354 // If we modified the edge costs let the heuristic know.
    355 h.postUpdateEdgeCosts(yzeId);
    356 }
    357
    358 if (nullCostEdge) {
    359 // If this edge ended up null remove it.
    360 if (!addedEdge) {
    361 // We didn't just add it, so we need to notify the heuristic
    362 // and remove it from the solver.
    363 h.handleRemoveEdge(yzeId, ynId);
    364 h.handleRemoveEdge(yzeId, znId);
    365 removeSolverEdge(yzeId);
    366 }
    367 g.removeEdge(yzeId);
    368 } else if (addedEdge) {
    369 // If the edge was added, and non-null, finish setting it up, add it to
    370 // the solver & notify heuristic.
    371 edgeDataList.push_back(EdgeData());
    372 g.setEdgeData(yzeId, &edgeDataList.back());
    373 addSolverEdge(yzeId);
    374 h.handleAddEdge(yzeId);
    375 }
    376
    377 h.handleRemoveEdge(yxeId, ynId);
    378 removeSolverEdge(yxeId);
    379 h.handleRemoveEdge(zxeId, znId);
    380 removeSolverEdge(zxeId);
    381
    382 pushToStack(xnId);
    383 s.recordR2();
    384 }
    385
    386 /// \brief Record an application of the RN rule.
    387 ///
    388 /// For use by the HeuristicBase.
    389 void recordRN() { s.recordRN(); }
    390
    391 private:
    392
    393 NodeData& getSolverNodeData(Graph::NodeId nId) {
    394 return *static_cast(g.getNodeData(nId));
    395 }
    396
    397 EdgeData& getSolverEdgeData(Graph::EdgeId eId) {
    398 return *static_cast(g.getEdgeData(eId));
    399 }
    400
    401 void addSolverEdge(Graph::EdgeId eId) {
    402 EdgeData &eData = getSolverEdgeData(eId);
    403 NodeData &n1Data = getSolverNodeData(g.getEdgeNode1(eId)),
    404 &n2Data = getSolverNodeData(g.getEdgeNode2(eId));
    405
    406 eData.setN1SolverEdgeItr(n1Data.addSolverEdge(eId));
    407 eData.setN2SolverEdgeItr(n2Data.addSolverEdge(eId));
    408 }
    409
    410 void setup() {
    411 if (h.solverRunSimplify()) {
    412 simplify();
    413 }
    414
    415 // Create node data objects.
    416 for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd();
    417 nItr != nEnd; ++nItr) {
    418 nodeDataList.push_back(NodeData());
    419 g.setNodeData(*nItr, &nodeDataList.back());
    420 }
    421
    422 // Create edge data objects.
    423 for (Graph::EdgeItr eItr = g.edgesBegin(), eEnd = g.edgesEnd();
    424 eItr != eEnd; ++eItr) {
    425 edgeDataList.push_back(EdgeData());
    426 g.setEdgeData(*eItr, &edgeDataList.back());
    427 addSolverEdge(*eItr);
    428 }
    429 }
    430
    431 void simplify() {
    432 disconnectTrivialNodes();
    433 eliminateIndependentEdges();
    434 }
    435
    436 // Eliminate trivial nodes.
    437 void disconnectTrivialNodes() {
    438 unsigned numDisconnected = 0;
    439
    440 for (Graph::NodeItr nItr = g.nodesBegin(), nEnd = g.nodesEnd();
    441 nItr != nEnd; ++nItr) {
    442
    443 Graph::NodeId nId = *nItr;
    444
    445 if (g.getNodeCosts(nId).getLength() == 1) {
    446
    447 std::vector edgesToRemove;
    448
    449 for (Graph::AdjEdgeItr aeItr = g.adjEdgesBegin(nId),
    450 aeEnd = g.adjEdgesEnd(nId);
    451 aeItr != aeEnd; ++aeItr) {
    452
    453 Graph::EdgeId eId = *aeItr;
    454
    455 if (g.getEdgeNode1(eId) == nId) {
    456 Graph::NodeId otherNodeId = g.getEdgeNode2(eId);
    457 g.getNodeCosts(otherNodeId) +=
    458 g.getEdgeCosts(eId).getRowAsVector(0);
    459 }
    460 else {
    461 Graph::NodeId otherNodeId = g.getEdgeNode1(eId);
    462 g.getNodeCosts(otherNodeId) +=
    463 g.getEdgeCosts(eId).getColAsVector(0);
    464 }
    465
    466 edgesToRemove.push_back(eId);
    467 }
    468
    469 if (!edgesToRemove.empty())
    470 ++numDisconnected;
    471
    472 while (!edgesToRemove.empty()) {
    473 g.removeEdge(edgesToRemove.back());
    474 edgesToRemove.pop_back();
    475 }
    476 }
    477 }
    478 }
    479
    480 void eliminateIndependentEdges() {
    481 std::vector edgesToProcess;
    482 unsigned numEliminated = 0;
    483
    484 for (Graph::EdgeItr eItr = g.edgesBegin(), eEnd = g.edgesEnd();
    485 eItr != eEnd; ++eItr) {
    486 edgesToProcess.push_back(*eItr);
    487 }
    488
    489 while (!edgesToProcess.empty()) {
    490 if (tryToEliminateEdge(edgesToProcess.back()))
    491 ++numEliminated;
    492 edgesToProcess.pop_back();
    493 }
    494 }
    495
    496 bool tryToEliminateEdge(Graph::EdgeId eId) {
    497 if (tryNormaliseEdgeMatrix(eId)) {
    498 g.removeEdge(eId);
    499 return true;
    500 }
    501 return false;
    502 }
    503
    504 bool tryNormaliseEdgeMatrix(Graph::EdgeId &eId) {
    505
    506 const PBQPNum infinity = std::numeric_limits::infinity();
    507
    508 Matrix &edgeCosts = g.getEdgeCosts(eId);
    509 Vector &uCosts = g.getNodeCosts(g.getEdgeNode1(eId)),
    510 &vCosts = g.getNodeCosts(g.getEdgeNode2(eId));
    511
    512 for (unsigned r = 0; r < edgeCosts.getRows(); ++r) {
    513 PBQPNum rowMin = infinity;
    514
    515 for (unsigned c = 0; c < edgeCosts.getCols(); ++c) {
    516 if (vCosts[c] != infinity && edgeCosts[r][c] < rowMin)
    517 rowMin = edgeCosts[r][c];
    518 }
    519
    520 uCosts[r] += rowMin;
    521
    522 if (rowMin != infinity) {
    523 edgeCosts.subFromRow(r, rowMin);
    524 }
    525 else {
    526 edgeCosts.setRow(r, 0);
    527 }
    528 }
    529
    530 for (unsigned c = 0; c < edgeCosts.getCols(); ++c) {
    531 PBQPNum colMin = infinity;
    532
    533 for (unsigned r = 0; r < edgeCosts.getRows(); ++r) {
    534 if (uCosts[r] != infinity && edgeCosts[r][c] < colMin)
    535 colMin = edgeCosts[r][c];
    536 }
    537
    538 vCosts[c] += colMin;
    539
    540 if (colMin != infinity) {
    541 edgeCosts.subFromCol(c, colMin);
    542 }
    543 else {
    544 edgeCosts.setCol(c, 0);
    545 }
    546 }
    547
    548 return edgeCosts.isZero();
    549 }
    550
    551 void backpropagate() {
    552 while (!stack.empty()) {
    553 computeSolution(stack.back());
    554 stack.pop_back();
    555 }
    556 }
    557
    558 void computeSolution(Graph::NodeId nId) {
    559
    560 NodeData &nodeData = getSolverNodeData(nId);
    561
    562 Vector v(g.getNodeCosts(nId));
    563
    564 // Solve based on existing solved edges.
    565 for (SolverEdgeItr solvedEdgeItr = nodeData.solverEdgesBegin(),
    566 solvedEdgeEnd = nodeData.solverEdgesEnd();
    567 solvedEdgeItr != solvedEdgeEnd; ++solvedEdgeItr) {
    568
    569 Graph::EdgeId eId(*solvedEdgeItr);
    570 Matrix &edgeCosts = g.getEdgeCosts(eId);
    571
    572 if (nId == g.getEdgeNode1(eId)) {
    573 Graph::NodeId adjNode(g.getEdgeNode2(eId));
    574 unsigned adjSolution = s.getSelection(adjNode);
    575 v += edgeCosts.getColAsVector(adjSolution);
    576 }
    577 else {
    578 Graph::NodeId adjNode(g.getEdgeNode1(eId));
    579 unsigned adjSolution = s.getSelection(adjNode);
    580 v += edgeCosts.getRowAsVector(adjSolution);
    581 }
    582
    583 }
    584
    585 setSolution(nId, v.minIndex());
    586 }
    587
    588 void cleanup() {
    589 h.cleanup();
    590 nodeDataList.clear();
    591 edgeDataList.clear();
    592 }
    593 };
    594
    595 /// \brief PBQP heuristic solver class.
    596 ///
    597 /// Given a PBQP Graph g representing a PBQP problem, you can find a solution
    598 /// by calling
    599 /// Solution s = HeuristicSolver::solve(g);
    600 ///
    601 /// The choice of heuristic for the H parameter will affect both the solver
    602 /// speed and solution quality. The heuristic should be chosen based on the
    603 /// nature of the problem being solved.
    604 /// Currently the only solver included with LLVM is the Briggs heuristic for
    605 /// register allocation.
    606 template
    607 class HeuristicSolver {
    608 public:
    609 static Solution solve(Graph &g) {
    610 HeuristicSolverImpl hs(g);
    611 return hs.computeSolution();
    612 }
    613 };
    614
    615 }
    616
    617 #endif // LLVM_CODEGEN_PBQP_HEURISTICSOLVER_H
    +0
    -468
    include/llvm/CodeGen/PBQP/Heuristics/Briggs.h less more
    None //===-- Briggs.h --- Briggs Heuristic for PBQP ------------------*- C++ -*-===//
    1 //
    2 // The LLVM Compiler Infrastructure
    3 //
    4 // This file is distributed under the University of Illinois Open Source
    5 // License. See LICENSE.TXT for details.
    6 //
    7 //===----------------------------------------------------------------------===//
    8 //
    9 // This class implements the Briggs test for "allocability" of nodes in a
    10 // PBQP graph representing a register allocation problem. Nodes which can be
    11 // proven allocable (by a safe and relatively accurate test) are removed from
    12 // the PBQP graph first. If no provably allocable node is present in the graph
    13 // then the node with the minimal spill-cost to degree ratio is removed.
    14 //
    15 //===----------------------------------------------------------------------===//
    16
    17 #ifndef LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H
    18 #define LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H
    19
    20 #include "../HeuristicBase.h"
    21 #include "../HeuristicSolver.h"
    22 #include
    23
    24 namespace PBQP {
    25 namespace Heuristics {
    26
    27 /// \brief PBQP Heuristic which applies an allocability test based on
    28 /// Briggs.
    29 ///
    30 /// This heuristic assumes that the elements of cost vectors in the PBQP
    31 /// problem represent storage options, with the first being the spill
    32 /// option and subsequent elements representing legal registers for the
    33 /// corresponding node. Edge cost matrices are likewise assumed to represent
    34 /// register constraints.
    35 /// If one or more nodes can be proven allocable by this heuristic (by
    36 /// inspection of their constraint matrices) then the allocable node of
    37 /// highest degree is selected for the next reduction and pushed to the
    38 /// solver stack. If no nodes can be proven allocable then the node with
    39 /// the lowest estimated spill cost is selected and push to the solver stack
    40 /// instead.
    41 ///
    42 /// This implementation is built on top of HeuristicBase.
    43 class Briggs : public HeuristicBase {
    44 private:
    45
    46 class LinkDegreeComparator {
    47 public:
    48 LinkDegreeComparator(HeuristicSolverImpl &s) : s(&s) {}
    49 bool operator()(Graph::NodeId n1Id, Graph::NodeId n2Id) const {
    50 if (s->getSolverDegree(n1Id) > s->getSolverDegree(n2Id))
    51 return true;
    52 return false;
    53 }
    54 private:
    55 HeuristicSolverImpl *s;
    56 };
    57
    58 class SpillCostComparator {
    59 public:
    60 SpillCostComparator(HeuristicSolverImpl &s)
    61 : s(&s), g(&s.getGraph()) {}
    62 bool operator()(Graph::NodeId n1Id, Graph::NodeId n2Id) const {
    63 const PBQP::Vector &cv1 = g->getNodeCosts(n1Id);
    64 const PBQP::Vector &cv2 = g->getNodeCosts(n2Id);
    65
    66 PBQPNum cost1 = cv1[0] / s->getSolverDegree(n1Id);
    67 PBQPNum cost2 = cv2[0] / s->getSolverDegree(n2Id);
    68
    69 if (cost1 < cost2)
    70 return true;
    71 return false;
    72 }
    73
    74 private:
    75 HeuristicSolverImpl *s;
    76 Graph *g;
    77 };
    78
    79 typedef std::list RNAllocableList;
    80 typedef RNAllocableList::iterator RNAllocableListItr;
    81
    82 typedef std::list RNUnallocableList;
    83 typedef RNUnallocableList::iterator RNUnallocableListItr;
    84
    85 public:
    86
    87 struct NodeData {
    88 typedef std::vector UnsafeDegreesArray;
    89 bool isHeuristic, isAllocable, isInitialized;
    90 unsigned numDenied, numSafe;
    91 UnsafeDegreesArray unsafeDegrees;
    92 RNAllocableListItr rnaItr;
    93 RNUnallocableListItr rnuItr;
    94
    95 NodeData()
    96 : isHeuristic(false), isAllocable(false), isInitialized(false),
    97 numDenied(0), numSafe(0) { }
    98 };
    99
    100 struct EdgeData {
    101 typedef std::vector UnsafeArray;
    102 unsigned worst, reverseWorst;
    103 UnsafeArray unsafe, reverseUnsafe;
    104 bool isUpToDate;
    105
    106 EdgeData() : worst(0), reverseWorst(0), isUpToDate(false) {}
    107 };
    108
    109 /// \brief Construct an instance of the Briggs heuristic.
    110 /// @param solver A reference to the solver which is using this heuristic.
    111 Briggs(HeuristicSolverImpl &solver) :
    112 HeuristicBase(solver) {}
    113
    114 /// \brief Determine whether a node should be reduced using optimal
    115 /// reduction.
    116 /// @param nId Node id to be considered.
    117 /// @return True if the given node should be optimally reduced, false
    118 /// otherwise.
    119 ///
    120 /// Selects nodes of degree 0, 1 or 2 for optimal reduction, with one
    121 /// exception. Nodes whose spill cost (element 0 of their cost vector) is
    122 /// infinite are checked for allocability first. Allocable nodes may be
    123 /// optimally reduced, but nodes whose allocability cannot be proven are
    124 /// selected for heuristic reduction instead.
    125 bool shouldOptimallyReduce(Graph::NodeId nId) {
    126 if (getSolver().getSolverDegree(nId) < 3) {
    127 return true;
    128 }
    129 // else
    130 return false;
    131 }
    132
    133 /// \brief Add a node to the heuristic reduce list.
    134 /// @param nId Node id to add to the heuristic reduce list.
    135 void addToHeuristicReduceList(Graph::NodeId nId) {
    136 NodeData &nd = getHeuristicNodeData(nId);
    137 initializeNode(nId);
    138 nd.isHeuristic = true;
    139 if (nd.isAllocable) {
    140 nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nId);
    141 } else {
    142 nd.rnuItr = rnUnallocableList.insert(rnUnallocableList.end(), nId);
    143 }
    144 }
    145
    146 /// \brief Heuristically reduce one of the nodes in the heuristic
    147 /// reduce list.
    148 /// @return True if a reduction takes place, false if the heuristic reduce
    149 /// list is empty.
    150 ///
    151 /// If the list of allocable nodes is non-empty a node is selected
    152 /// from it and pushed to the stack. Otherwise if the non-allocable list
    153 /// is non-empty a node is selected from it and pushed to the stack.
    154 /// If both lists are empty the method simply returns false with no action
    155 /// taken.
    156 bool heuristicReduce() {
    157 if (!rnAllocableList.empty()) {
    158 RNAllocableListItr rnaItr =
    159 min_element(rnAllocableList.begin(), rnAllocableList.end(),
    160 LinkDegreeComparator(getSolver()));
    161 Graph::NodeId nId = *rnaItr;
    162 rnAllocableList.erase(rnaItr);
    163 handleRemoveNode(nId);
    164 getSolver().pushToStack(nId);
    165 return true;
    166 } else if (!rnUnallocableList.empty()) {
    167 RNUnallocableListItr rnuItr =
    168 min_element(rnUnallocableList.begin(), rnUnallocableList.end(),
    169 SpillCostComparator(getSolver()));
    170 Graph::NodeId nId = *rnuItr;
    171 rnUnallocableList.erase(rnuItr);
    172 handleRemoveNode(nId);
    173 getSolver().pushToStack(nId);
    174 return true;
    175 }
    176 // else
    177 return false;
    178 }
    179
    180 /// \brief Prepare a change in the costs on the given edge.
    181 /// @param eId Edge id.
    182 void preUpdateEdgeCosts(Graph::EdgeId eId) {
    183 Graph &g = getGraph();
    184 Graph::NodeId n1Id = g.getEdgeNode1(eId),
    185 n2Id = g.getEdgeNode2(eId);
    186 NodeData &n1 = getHeuristicNodeData(n1Id),
    187 &n2 = getHeuristicNodeData(n2Id);
    188
    189 if (n1.isHeuristic)
    190 subtractEdgeContributions(eId, getGraph().getEdgeNode1(eId));
    191 if (n2.isHeuristic)
    192 subtractEdgeContributions(eId, getGraph().getEdgeNode2(eId));
    193
    194 EdgeData &ed = getHeuristicEdgeData(eId);
    195 ed.isUpToDate = false;
    196 }
    197
    198 /// \brief Handle the change in the costs on the given edge.
    199 /// @param eId Edge id.
    200 void postUpdateEdgeCosts(Graph::EdgeId eId) {
    201 // This is effectively the same as adding a new edge now, since
    202 // we've factored out the costs of the old one.
    203 handleAddEdge(eId);
    204 }
    205
    206 /// \brief Handle the addition of a new edge into the PBQP graph.
    207 /// @param eId Edge id for the added edge.
    208 ///
    209 /// Updates allocability of any nodes connected by this edge which are
    210 /// being managed by the heuristic. If allocability changes they are
    211 /// moved to the appropriate list.
    212 void handleAddEdge(Graph::EdgeId eId) {
    213 Graph &g = getGraph();
    214 Graph::NodeId n1Id = g.getEdgeNode1(eId),
    215 n2Id = g.getEdgeNode2(eId);
    216 NodeData &n1 = getHeuristicNodeData(n1Id),
    217 &n2 = getHeuristicNodeData(n2Id);
    218
    219 // If neither node is managed by the heuristic there's nothing to be
    220 // done.
    221 if (!n1.isHeuristic && !n2.isHeuristic)
    222 return;
    223
    224 // Ok - we need to update at least one node.
    225 computeEdgeContributions(eId);
    226
    227 // Update node 1 if it's managed by the heuristic.
    228 if (n1.isHeuristic) {
    229 bool n1WasAllocable = n1.isAllocable;
    230 addEdgeContributions(eId, n1Id);
    231 updateAllocability(n1Id);
    232 if (n1WasAllocable && !n1.isAllocable) {
    233 rnAllocableList.erase(n1.rnaItr);
    234 n1.rnuItr =
    235 rnUnallocableList.insert(rnUnallocableList.end(), n1Id);
    236 }
    237 }
    238
    239 // Likewise for node 2.
    240 if (n2.isHeuristic) {
    241 bool n2WasAllocable = n2.isAllocable;
    242 addEdgeContributions(eId, n2Id);
    243 updateAllocability(n2Id);
    244 if (n2WasAllocable && !n2.isAllocable) {
    245 rnAllocableList.erase(n2.rnaItr);
    246 n2.rnuItr =
    247 rnUnallocableList.insert(rnUnallocableList.end(), n2Id);
    248 }
    249 }
    250 }
    251
    252 /// \brief Handle disconnection of an edge from a node.
    253 /// @param eId Edge id for edge being disconnected.
    254 /// @param nId Node id for the node being disconnected from.
    255 ///
    256 /// Updates allocability of the given node and, if appropriate, moves the
    257 /// node to a new list.
    258 void handleRemoveEdge(Graph::EdgeId eId, Graph::NodeId nId) {
    259 NodeData &nd =getHeuristicNodeData(nId);
    260
    261 // If the node is not managed by the heuristic there's nothing to be
    262 // done.
    263 if (!nd.isHeuristic)
    264 return;
    265
    266 EdgeData &ed = getHeuristicEdgeData(eId);
    267 (void)ed;
    268 assert(ed.isUpToDate && "Edge data is not up to date.");
    269
    270 // Update node.
    271 bool ndWasAllocable = nd.isAllocable;
    272 subtractEdgeContributions(eId, nId);
    273 updateAllocability(nId);
    274
    275 // If the node has gone optimal...
    276 if (shouldOptimallyReduce(nId)) {
    277 nd.isHeuristic = false;
    278 addToOptimalReduceList(nId);
    279 if (ndWasAllocable) {
    280 rnAllocableList.erase(nd.rnaItr);
    281 } else {
    282 rnUnallocableList.erase(nd.rnuItr);
    283 }
    284 } else {
    285 // Node didn't go optimal, but we might have to move it
    286 // from "unallocable" to "allocable".
    287 if (!ndWasAllocable && nd.isAllocable) {
    288 rnUnallocableList.erase(nd.rnuItr);
    289 nd.rnaItr = rnAllocableList.insert(rnAllocableList.end(), nId);
    290 }
    291 }
    292 }
    293
    294 private:
    295
    296 NodeData& getHeuristicNodeData(Graph::NodeId nId) {
    297 return getSolver().getHeuristicNodeData(nId);
    298 }
    299
    300 EdgeData& getHeuristicEdgeData(Graph::EdgeId eId) {
    301 return getSolver().getHeuristicEdgeData(eId);
    302 }
    303
    304 // Work out what this edge will contribute to the allocability of the
    305 // nodes connected to it.
    306 void computeEdgeContributions(Graph::EdgeId eId) {
    307 EdgeData &ed = getHeuristicEdgeData(eId);
    308
    309 if (ed.isUpToDate)
    310 return; // Edge data is already up to date.
    311
    312 Matrix &eCosts = getGraph().getEdgeCosts(eId);
    313
    314 unsigned numRegs = eCosts.getRows() - 1,
    315 numReverseRegs = eCosts.getCols() - 1;
    316
    317 std::vector rowInfCounts(numRegs, 0),
    318 colInfCounts(numReverseRegs, 0);
    319
    320 ed.worst = 0;
    321 ed.reverseWorst = 0;
    322 ed.unsafe.clear();
    323 ed.unsafe.resize(numRegs, 0);
    324 ed.reverseUnsafe.clear();
    325 ed.reverseUnsafe.resize(numReverseRegs, 0);
    326
    327 for (unsigned i = 0; i < numRegs; ++i) {
    328 for (unsigned j = 0; j < numReverseRegs; ++j) {
    329 if (eCosts[i + 1][j + 1] ==
    330 std::numeric_limits::infinity()) {
    331 ed.unsafe[i] = 1;
    332 ed.reverseUnsafe[j] = 1;
    333 ++rowInfCounts[i];
    334 ++colInfCounts[j];
    335
    336 if (colInfCounts[j] > ed.worst) {
    337 ed.worst = colInfCounts[j];
    338 }
    339
    340 if (rowInfCounts[i] > ed.reverseWorst) {
    341 ed.reverseWorst = rowInfCounts[i];
    342 }
    343 }
    344 }
    345 }
    346
    347 ed.isUpToDate = true;
    348 }
    349
    350 // Add the contributions of the given edge to the given node's
    351 // numDenied and safe members. No action is taken other than to update
    352 // these member values. Once updated these numbers can be used by clients
    353 // to update the node's allocability.
    354 void addEdgeContributions(Graph::EdgeId eId, Graph::NodeId nId) {
    355 EdgeData &ed = getHeuristicEdgeData(eId);
    356
    357 assert(ed.isUpToDate && "Using out-of-date edge numbers.");
    358
    359 NodeData &nd = getHeuristicNodeData(nId);
    360 unsigned numRegs = getGraph().getNodeCosts(nId).getLength() - 1;
    361
    362 bool nIsNode1 = nId == getGraph().getEdgeNode1(eId);
    363 EdgeData::UnsafeArray &unsafe =
    364 nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
    365 nd.numDenied += nIsNode1 ? ed.worst : ed.reverseWorst;
    366
    367 for (unsigned r = 0; r < numRegs; ++r) {
    368 if (unsafe[r]) {
    369 if (nd.unsafeDegrees[r]==0) {
    370 --nd.numSafe;
    371 }
    372 ++nd.unsafeDegrees[r];
    373 }
    374 }
    375 }
    376
    377 // Subtract the contributions of the given edge to the given node's
    378 // numDenied and safe members. No action is taken other than to update
    379 // these member values. Once updated these numbers can be used by clients
    380 // to update the node's allocability.
    381 void subtractEdgeContributions(Graph::EdgeId eId, Graph::NodeId nId) {
    382 EdgeData &ed = getHeuristicEdgeData(eId);
    383
    384 assert(ed.isUpToDate && "Using out-of-date edge numbers.");
    385
    386 NodeData &nd = getHeuristicNodeData(nId);
    387 unsigned numRegs = getGraph().getNodeCosts(nId).getLength() - 1;
    388
    389 bool nIsNode1 = nId == getGraph().getEdgeNode1(eId);
    390 EdgeData::UnsafeArray &unsafe =
    391 nIsNode1 ? ed.unsafe : ed.reverseUnsafe;
    392 nd.numDenied -= nIsNode1 ? ed.worst : ed.reverseWorst;
    393
    394 for (unsigned r = 0; r < numRegs; ++r) {
    395 if (unsafe[r]) {
    396 if (nd.unsafeDegrees[r] == 1) {
    397 ++nd.numSafe;
    398 }
    399 --nd.unsafeDegrees[r];
    400 }
    401 }
    402 }
    403
    404 void updateAllocability(Graph::NodeId nId) {
    405 NodeData &nd = getHeuristicNodeData(nId);
    406 unsigned numRegs = getGraph().getNodeCosts(nId).getLength() - 1;
    407 nd.isAllocable = nd.numDenied < numRegs || nd.numSafe > 0;
    408 }
    409
    410 void initializeNode(Graph::NodeId nId) {
    411 NodeData &nd = getHeuristicNodeData(nId);
    412
    413 if (nd.isInitialized)
    414 return; // Node data is already up to date.
    415
    416 unsigned numRegs = getGraph().getNodeCosts(nId).getLength() - 1;
    417
    418 nd.numDenied = 0;
    419 const Vector& nCosts = getGraph().getNodeCosts(nId);
    420 for (unsigned i = 1; i < nCosts.getLength(); ++i) {
    421 if (nCosts[i] == std::numeric_limits::infinity())
    422 ++nd.numDenied;
    423 }
    424
    425 nd.numSafe = numRegs;
    426 nd.unsafeDegrees.resize(numRegs, 0);
    427
    428 typedef HeuristicSolverImpl::SolverEdgeItr SolverEdgeItr;
    429
    430 for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(nId),
    431 aeEnd = getSolver().solverEdgesEnd(nId);
    432 aeItr != aeEnd; ++aeItr) {
    433
    434 Graph::EdgeId eId = *aeItr;
    435 computeEdgeContributions(eId);
    436 addEdgeContributions(eId, nId);
    437 }
    438
    439 updateAllocability(nId);
    440 nd.isInitialized = true;
    441 }
    442
    443 void handleRemoveNode(Graph::NodeId xnId) {
    444 typedef HeuristicSolverImpl::SolverEdgeItr SolverEdgeItr;
    445 std::vector edgesToRemove;
    446 for (SolverEdgeItr aeItr = getSolver().solverEdgesBegin(xnId),
    447 aeEnd = getSolver().solverEdgesEnd(xnId);
    448 aeItr != aeEnd; ++aeItr) {
    449 Graph::NodeId ynId = getGraph().getEdgeOtherNode(*aeItr, xnId);
    450 handleRemoveEdge(*aeItr, ynId);
    451 edgesToRemove.push_back(*aeItr);
    452 }
    453 while (!edgesToRemove.empty()) {
    454 getSolver().removeSolverEdge(edgesToRemove.back());
    455 edgesToRemove.pop_back();
    456 }
    457 }
    458
    459 RNAllocableList rnAllocableList;
    460 RNUnallocableList rnUnallocableList;
    461 };
    462
    463 }
    464 }
    465
    466
    467 #endif // LLVM_CODEGEN_PBQP_HEURISTICS_BRIGGS_H
    1919
    2020 /// \brief PBQP Vector class.
    2121 class Vector {
    22 public:
    23
    24 /// \brief Construct a PBQP vector of the given size.
    25 explicit Vector(unsigned length) :
    26 length(length), data(new PBQPNum[length]) {
    27 }
    28
    29 /// \brief Construct a PBQP vector with initializer.
    30 Vector(unsigned length, PBQPNum initVal) :
    31 length(length), data(new PBQPNum[length]) {
    32 std::fill(data, data + length, initVal);
    33 }
    34
    35 /// \brief Copy construct a PBQP vector.
    36 Vector(const Vector &v) :
    37 length(v.length), data(new PBQPNum[length]) {
    38 std::copy(v.data, v.data + length, data);
    39 }
    40
    41 /// \brief Destroy this vector, return its memory.
    42 ~Vector() { delete[] data; }
    43
    44 /// \brief Assignment operator.
    45 Vector& operator=(const Vector &v) {
    46 delete[] data;
    47 length = v.length;
    48 data = new PBQPNum[length];
    49 std::copy(v.data, v.data + length, data);
    50 return *this;
    51 }
    52
    53 /// \brief Return the length of the vector
    54 unsigned getLength() const {
    55 return length;
    56 }
    57
    58 /// \brief Element access.
    59 PBQPNum& operator[](unsigned index) {
    60 assert(index < length && "Vector element access out of bounds.");
    61 return data[index];
    62 }
    63
    64 /// \brief Const element access.
    65 const PBQPNum& operator[](unsigned index) const {
    66 assert(index < length && "Vector element access out of bounds.");
    67 return data[index];
    68 }
    69
    70 /// \brief Add another vector to this one.
    71 Vector& operator+=(const Vector &v) {
    72 assert(length == v.length && "Vector length mismatch.");
    73 std::transform(data, data + length, v.data, data, std::plus());
    74 return *this;
    75 }
    76
    77 /// \brief Subtract another vector from this one.
    78 Vector& operator-=(const Vector &v) {
    79 assert(length == v.length && "Vector length mismatch.");
    80 std::transform(data, data + length, v.data, data, std::minus());
    81 return *this;
    82 }
    83
    84 /// \brief Returns the index of the minimum value in this vector
    85 unsigned minIndex() const {
    86 return std::min_element(data, data + length) - data;
    87 }
    88
    89 private:
    90 unsigned length;
    91 PBQPNum *data;
    22 friend class VectorComparator;
    23 public:
    24
    25 /// \brief Construct a PBQP vector of the given size.
    26 explicit Vector(unsigned Length)
    27 : Length(Length), Data(new PBQPNum[Length]) {
    28 // llvm::dbgs() << "Constructing PBQP::Vector "
    29 // << this << " (length " << Length << ")\n";
    30 }
    31
    32 /// \brief Construct a PBQP vector with initializer.
    33 Vector(unsigned Length, PBQPNum InitVal)
    34 : Length(Length), Data(new PBQPNum[Length]) {
    35 // llvm::dbgs() << "Constructing PBQP::Vector "
    36 // << this << " (length " << Length << ", fill "
    37 // << InitVal << ")\n";
    38 std::fill(Data, Data + Length, InitVal);
    39 }
    40
    41 /// \brief Copy construct a PBQP vector.
    42 Vector(const Vector &V)
    43 : Length(V.Length), Data(new PBQPNum[Length]) {
    44 // llvm::dbgs() << "Copy-constructing PBQP::Vector " << this
    45 // << " from PBQP::Vector " << &V << "\n";
    46 std::copy(V.Data, V.Data + Length, Data);
    47 }
    48
    49 /// \brief Move construct a PBQP vector.
    50 Vector(Vector &&V)
    51 : Length(V.Length), Data(V.Data) {
    52 V.Length = 0;
    53 V.Data = nullptr;
    54 }
    55
    56 /// \brief Destroy this vector, return its memory.
    57 ~Vector() {
    58 // llvm::dbgs() << "Deleting PBQP::Vector " << this << "\n";
    59 delete[] Data;
    60 }
    61
    62 /// \brief Copy-assignment operator.
    63 Vector& operator=(const Vector &V) {
    64 // llvm::dbgs() << "Assigning to PBQP::Vector " << this
    65 // << " from PBQP::Vector " << &V << "\n";
    66 delete[] Data;
    67 Length = V.Length;
    68 Data = new PBQPNum[Length];
    69 std::copy(V.Data, V.Data + Length, Data);
    70 return *this;
    71 }
    72
    73 /// \brief Move-assignment operator.
    74 Vector& operator=(Vector &&V) {
    75 delete[] Data;
    76 Length = V.Length;
    77 Data = V.Data;
    78 V.Length = 0;
    79 V.Data = nullptr;
    80 return *this;
    81 }
    82
    83 /// \brief Comparison operator.
    84 bool operator==(const Vector &V) const {
    85 assert(Length != 0 && Data != nullptr && "Invalid vector");
    86 if (Length != V.Length)
    87 return false;
    88 return std::equal(Data, Data + Length, V.Data);
    89 }
    90
    91 /// \brief Return the length of the vector
    92 unsigned getLength() const {
    93 assert(Length != 0 && Data != nullptr && "Invalid vector");
    94 return Length;
    95 }
    96
    97 /// \brief Element access.
    98 PBQPNum& operator[](unsigned Index) {
    99 assert(Length != 0 && Data != nullptr && "Invalid vector");
    100 assert(Index < Length && "Vector element access out of bounds.");
    101 return Data[Index];
    102 }
    103
    104 /// \brief Const element access.
    105 const PBQPNum& operator[](unsigned Index) const {
    106 assert(Length != 0 && Data != nullptr && "Invalid vector");
    107 assert(Index < Length && "Vector element access out of bounds.");
    108 return Data[Index];
    109 }
    110
    111 /// \brief Add another vector to this one.
    112 Vector& operator+=(const Vector &V) {
    113 assert(Length != 0 && Data != nullptr && "Invalid vector");
    114 assert(Length == V.Length && "Vector length mismatch.");
    115 std::transform(Data, Data + Length, V.Data, Data, std::plus());
    116 return *this;
    117 }
    118
    119 /// \brief Subtract another vector from this one.
    120 Vector& operator-=(const Vector &V) {
    121 assert(Length != 0 && Data != nullptr && "Invalid vector");
    122 assert(Length == V.Length && "Vector length mismatch.");
    123 std::transform(Data, Data + Length, V.Data, Data, std::minus());
    124 return *this;
    125 }
    126
    127 /// \brief Returns the index of the minimum value in this vector
    128 unsigned minIndex() const {
    129 assert(Length != 0 && Data != nullptr && "Invalid vector");
    130 return std::min_element(Data, Data + Length) - Data;
    131 }
    132
    133 private:
    134 unsigned Length;
    135 PBQPNum *Data;
    136 };
    137
    138 class VectorComparator {
    139 public:
    140 bool operator()(const Vector &A, const Vector &B) {
    141 if (A.Length < B.Length)
    142 return true;
    143 if (B.Length < A.Length)
    144 return false;
    145 char *AData = reinterpret_cast(A.Data);
    146 char *BData = reinterpret_cast(B.Data);
    147 return std::lexicographical_compare(AData,
    148 AData + A.Length * sizeof(PBQPNum),
    149 BData,
    150 BData + A.Length * sizeof(PBQPNum));
    151 }
    92152 };
    93153
    94154 /// \brief Output a textual representation of the given vector on the given
    95155 /// output stream.
    96156 template
    97 OStream& operator<<(OStream &os, const Vector &v) {
    98 assert((v.getLength() != 0) && "Zero-length vector badness.");
    99
    100 os << "[ " << v[0];
    101 for (unsigned i = 1; i < v.getLength(); ++i) {
    102 os << ", " << v[i];
    103 }
    104 os << " ]";
    105
    106 return os;
    107 }
    157 OStream& operator<<(OStream &OS, const Vector &V) {
    158 assert((V.getLength() != 0) && "Zero-length vector badness.");
    159
    160 OS << "[ " << V[0];
    161 for (unsigned i = 1; i < V.getLength(); ++i)
    162 OS << ", " << V[i];
    163 OS << " ]";
    164
    165 return OS;
    166 }
    108167
    109168
    110169 /// \brief PBQP Matrix class
    111170 class Matrix {
    112 public:
    113
    114 /// \brief Construct a PBQP Matrix with the given dimensions.
    115 Matrix(unsigned rows, unsigned cols) :
    116 rows(rows), cols(cols), data(new PBQPNum[rows * cols]) {
    117 }
    118
    119 /// \brief Construct a PBQP Matrix with the given dimensions and initial
    120 /// value.
    121 Matrix(unsigned rows, unsigned cols, PBQPNum initVal) :
    122 rows(rows), cols(cols), data(new PBQPNum[rows * cols]) {
    123 std::fill(data, data + (rows * cols), initVal);
    124 }
    125
    126 /// \brief Copy construct a PBQP matrix.
    127 Matrix(const Matrix &m) :
    128 rows(m.rows), cols(m.cols), data(new PBQPNum[rows * cols]) {
    129 std::copy(m.data, m.data + (rows * cols), data);
    130 }
    131
    132 /// \brief Destroy this matrix, return its memory.
    133 ~Matrix() { delete[] data; }
    134
    135 /// \brief Assignment operator.
    136 Matrix& operator=(const Matrix &m) {
    137 delete[] data;
    138 rows = m.rows; cols = m.cols;
    139 data = new PBQPNum[rows * cols];
    140 std::copy(m.data, m.data + (rows * cols), data);
    141 return *this;
    142 }
    143
    144 /// \brief Return the number of rows in this matrix.
    145 unsigned getRows() const { return rows; }
    146
    147 /// \brief Return the number of cols in this matrix.
    148 unsigned getCols() const { return cols; }
    149
    150 /// \brief Matrix element access.
    151 PBQPNum* operator[](unsigned r) {
    152 assert(r < rows && "Row out of bounds.");
    153 return data + (r * cols);
    154 }
    155
    156 /// \brief Matrix element access.
    157 const PBQPNum* operator[](unsigned r) const {
    158 assert(r < rows && "Row out of bounds.");
    159 return data + (r * cols);
    160 }
    161
    162 /// \brief Returns the given row as a vector.
    163 Vector getRowAsVector(unsigned r) const {
    164 Vector v(cols);
    165 for (unsigned c = 0; c < cols; ++c)
    166 v[c] = (*this)[r][c];
    167 return v;
    168 }
    169
    170 /// \brief Returns the given column as a vector.
    171 Vector getColAsVector(unsigned c) const {
    172 Vector v(rows);
    173 for (unsigned r = 0; r < rows; ++r)
    174 v[r] = (*this)[r][c];
    175 return v;
    176 }
    177
    178 /// \brief Reset the matrix to the given value.
    179 Matrix& reset(PBQPNum val = 0) {
    180 std::fill(data, data + (rows * cols), val);
    181 return *this;
    182 }
    183
    184 /// \brief Set a single row of this matrix to the given value.
    185 Matrix& setRow(unsigned r, PBQPNum val) {
    186 assert(r < rows && "Row out of bounds.");
    187 std::fill(data + (r * cols), data + ((r + 1) * cols), val);
    188 return *this;
    189 }
    190
    191 /// \brief Set a single column of this matrix to the given value.
    192 Matrix& setCol(unsigned c, PBQPNum val) {
    193 assert(c < cols && "Column out of bounds.");
    194 for (unsigned r = 0; r < rows; ++r)
    195 (*this)[r][c] = val;
    196 return *this;
    197 }
    198
    199 /// \brief Matrix transpose.
    200 Matrix transpose() const {
    201 Matrix m(cols, rows);
    202 for (unsigned r = 0; r < rows; ++r)
    203 for (unsigned c = 0; c < cols; ++c)
    204 m[c][r] = (*this)[r][c];
    205 return m;
    206 }
    207
    208 /// \brief Returns the diagonal of the matrix as a vector.
    209 ///
    210 /// Matrix must be square.
    211 Vector diagonalize() const {
    212 assert(rows == cols && "Attempt to diagonalize non-square matrix.");
    213
    214 Vector v(rows);
    215 for (unsigned r = 0; r < rows; ++r)
    216 v[r] = (*this)[r][r];
    217 return v;
    218 }
    219
    220 /// \brief Add the given matrix to this one.
    221 Matrix& operator+=(const Matrix &m) {
    222 assert(rows == m.rows && cols == m.cols &&
    223 "Matrix dimensions mismatch.");
    224 std::transform(data, data + (rows * cols), m.data, data,
    225 std::plus());
    226 return *this;
    227 }
    228
    229 /// \brief Returns the minimum of the given row
    230 PBQPNum getRowMin(unsigned r) const {
    231 assert(r < rows && "Row out of bounds");
    232 return *std::min_element(data + (r * cols), data + ((r + 1) * cols));
    233 }
    234
    235 /// \brief Returns the minimum of the given column
    236 PBQPNum getColMin(unsigned c) const {
    237 PBQPNum minElem = (*this)[0][c];
    238 for (unsigned r = 1; r < rows; ++r)
    239 if ((*this)[r][c] < minElem) minElem = (*this)[r][c];
    240 return minElem;
    241 }
    242
    243 /// \brief Subtracts the given scalar from the elements of the given row.
    244 Matrix& subFromRow(unsigned r, PBQPNum val) {
    245 assert(r < rows && "Row out of bounds");
    246 std::transform(data + (r * cols), data + ((r + 1) * cols),
    247 data + (r * cols),
    248 std::bind2nd(std::minus(), val));
    249 return *this;
    250 }
    251
    252 /// \brief Subtracts the given scalar from the elements of the given column.
    253 Matrix& subFromCol(unsigned c, PBQPNum val) {
    254 for (unsigned r = 0; r < rows; ++r)
    255 (*this)[r][c] -= val;
    256 return *this;
    257 }
    258
    259 /// \brief Returns true if this is a zero matrix.
    260 bool isZero() const {
    261 return find_if(data, data + (rows * cols),
    262 std::bind2nd(std::not_equal_to(), 0)) ==
    263 data + (rows * cols);
    264 }
    265
    266 private:
    267 unsigned rows, cols;
    268 PBQPNum *data;
    171 private:
    172 friend class MatrixComparator;
    173 public:
    174
    175 /// \brief Construct a PBQP Matrix with the given dimensions.
    176 Matrix(unsigned Rows, unsigned Cols) :
    177 Rows(Rows), Cols(Cols), Data(new PBQPNum[Rows * Cols]) {
    178 }
    179
    180 /// \brief Construct a PBQP Matrix with the given dimensions and initial
    181 /// value.
    182 Matrix(unsigned Rows, unsigned Cols, PBQPNum InitVal)
    183 : Rows(Rows), Cols(Cols), Data(new PBQPNum[Rows * Cols]) {
    184 std::fill(Data, Data + (Rows * Cols), InitVal);
    185 }
    186
    187 /// \brief Copy construct a PBQP matrix.
    188 Matrix(const Matrix &M)
    189 : Rows(M.Rows), Cols(M.Cols), Data(new PBQPNum[Rows * Cols]) {
    190 std::copy(M.Data, M.Data + (Rows * Cols), Data);
    191 }
    192
    193 /// \brief Move construct a PBQP matrix.
    194 Matrix(Matrix &&M)
    195 : Rows(M.Rows), Cols(M.Cols), Data(M.Data) {
    196 M.Rows = M.Cols = 0;
    197 M.Data = nullptr;
    198 }
    199
    200 /// \brief Destroy this matrix, return its memory.
    201 ~Matrix() { delete[] Data; }
    202
    203 /// \brief Copy-assignment operator.
    204 Matrix& operator=(const Matrix &M) {
    205 delete[] Data;
    206 Rows = M.Rows; Cols = M.Cols;
    207 Data = new PBQPNum[Rows * Cols];
    208 std::copy(M.Data, M.Data + (Rows * Cols), Data);
    209 return *this;
    210 }
    211
    212 /// \brief Move-assignment operator.
    213 Matrix& operator=(Matrix &&M) {
    214 delete[] Data;
    215 Rows = M.Rows;
    216 Cols = M.Cols;
    217 Data = M.Data;
    218 M.Rows = M.Cols = 0;
    219 M.Data = nullptr;
    220 return *this;
    221 }
    222
    223 /// \brief Comparison operator.
    224 bool operator==(const Matrix &M) const {
    225 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    226 if (Rows != M.Rows || Cols != M.Cols)
    227 return false;
    228 return std::equal(Data, Data + (Rows * Cols), M.Data);
    229 }
    230
    231 /// \brief Return the number of rows in this matrix.
    232 unsigned getRows() const {
    233 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    234 return Rows;
    235 }
    236
    237 /// \brief Return the number of cols in this matrix.
    238 unsigned getCols() const {
    239 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    240 return Cols;
    241 }
    242
    243 /// \brief Matrix element access.
    244 PBQPNum* operator[](unsigned R) {
    245 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    246 assert(R < Rows && "Row out of bounds.");
    247 return Data + (R * Cols);
    248 }
    249
    250 /// \brief Matrix element access.
    251 const PBQPNum* operator[](unsigned R) const {
    252 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    253 assert(R < Rows && "Row out of bounds.");
    254 return Data + (R * Cols);
    255 }
    256
    257 /// \brief Returns the given row as a vector.
    258 Vector getRowAsVector(unsigned R) const {
    259 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    260 Vector V(Cols);
    261 for (unsigned C = 0; C < Cols; ++C)
    262 V[C] = (*this)[R][C];
    263 return V;
    264 }
    265
    266 /// \brief Returns the given column as a vector.
    267 Vector getColAsVector(unsigned C) const {
    268 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    269 Vector V(Rows);
    270 for (unsigned R = 0; R < Rows; ++R)
    271 V[R] = (*this)[R][C];
    272 return V;
    273 }
    274
    275 /// \brief Reset the matrix to the given value.
    276 Matrix& reset(PBQPNum Val = 0) {
    277 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    278 std::fill(Data, Data + (Rows * Cols), Val);
    279 return *this;
    280 }
    281
    282 /// \brief Set a single row of this matrix to the given value.
    283 Matrix& setRow(unsigned R, PBQPNum Val) {
    284 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    285 assert(R < Rows && "Row out of bounds.");
    286 std::fill(Data + (R * Cols), Data + ((R + 1) * Cols), Val);
    287 return *this;
    288 }
    289
    290 /// \brief Set a single column of this matrix to the given value.
    291 Matrix& setCol(unsigned C, PBQPNum Val) {
    292 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    293 assert(C < Cols && "Column out of bounds.");
    294 for (unsigned R = 0; R < Rows; ++R)
    295 (*this)[R][C] = Val;
    296 return *this;
    297 }
    298
    299 /// \brief Matrix transpose.
    300 Matrix transpose() const {
    301 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    302 Matrix M(Cols, Rows);
    303 for (unsigned r = 0; r < Rows; ++r)
    304 for (unsigned c = 0; c < Cols; ++c)
    305 M[c][r] = (*this)[r][c];
    306 return M;
    307 }
    308
    309 /// \brief Returns the diagonal of the matrix as a vector.
    310 ///
    311 /// Matrix must be square.
    312 Vector diagonalize() const {
    313 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    314 assert(Rows == Cols && "Attempt to diagonalize non-square matrix.");
    315 Vector V(Rows);
    316 for (unsigned r = 0; r < Rows; ++r)
    317 V[r] = (*this)[r][r];
    318 return V;
    319 }
    320
    321 /// \brief Add the given matrix to this one.
    322 Matrix& operator+=(const Matrix &M) {
    323 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    324 assert(Rows == M.Rows && Cols == M.Cols &&
    325 "Matrix dimensions mismatch.");
    326 std::transform(Data, Data + (Rows * Cols), M.Data, Data,
    327 std::plus());
    328 return *this;
    329 }
    330
    331 Matrix operator+(const Matrix &M) {
    332 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    333 Matrix Tmp(*this);
    334 Tmp += M;
    335 return Tmp;
    336 }
    337
    338 /// \brief Returns the minimum of the given row
    339 PBQPNum getRowMin(unsigned R) const {
    340 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    341 assert(R < Rows && "Row out of bounds");
    342 return *std::min_element(Data + (R * Cols), Data + ((R + 1) * Cols));
    343 }
    344
    345 /// \brief Returns the minimum of the given column
    346 PBQPNum getColMin(unsigned C) const {
    347 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    348 PBQPNum MinElem = (*this)[0][C];
    349 for (unsigned R = 1; R < Rows; ++R)
    350 if ((*this)[R][C] < MinElem)
    351 MinElem = (*this)[R][C];
    352 return MinElem;
    353 }
    354
    355 /// \brief Subtracts the given scalar from the elements of the given row.
    356 Matrix& subFromRow(unsigned R, PBQPNum Val) {
    357 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    358 assert(R < Rows && "Row out of bounds");
    359 std::transform(Data + (R * Cols), Data + ((R + 1) * Cols),
    360 Data + (R * Cols),
    361 std::bind2nd(std::minus(), Val));
    362 return *this;
    363 }
    364
    365 /// \brief Subtracts the given scalar from the elements of the given column.
    366 Matrix& subFromCol(unsigned C, PBQPNum Val) {
    367 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    368 for (unsigned R = 0; R < Rows; ++R)
    369 (*this)[R][C] -= Val;
    370 return *this;
    371 }
    372
    373 /// \brief Returns true if this is a zero matrix.
    374 bool isZero() const {
    375 assert(Rows != 0 && Cols != 0 && Data != nullptr && "Invalid matrix");
    376 return find_if(Data, Data + (Rows * Cols),
    377 std::bind2nd(std::not_equal_to(), 0)) ==
    378 Data + (Rows * Cols);
    379 }
    380
    381 private:
    382 unsigned Rows, Cols;
    383 PBQPNum *Data;
    384 };
    385
    386 class MatrixComparator {
    387 public:
    388 bool operator()(const Matrix &A, const Matrix &B) {
    389 if (A.Rows < B.Rows)
    390 return true;
    391 if (B.Rows < A.Rows)
    392 return false;
    393 if (A.Cols < B.Cols)
    394 return true;
    395 if (B.Cols < A.Cols)
    396 return false;
    397 char *AData = reinterpret_cast(A.Data);
    398 char *BData = reinterpret_cast(B.Data);
    399 return std::lexicographical_compare(
    400 AData, AData + (A.Rows * A.Cols * sizeof(PBQPNum)),
    401 BData, BData + (A.Rows * A.Cols * sizeof(PBQPNum)));
    402 }
    269403 };
    270404
    271405 /// \brief Output a textual representation of the given matrix on the given
    272406 /// output stream.
    273407 template
    274 OStream& operator<<(OStream &os, const Matrix &m) {
    275
    276 assert((m.getRows() != 0) && "Zero-row matrix badness.");
    277
    278 for (unsigned i = 0; i < m.getRows(); ++i) {
    279 os << m.getRowAsVector(i);
    280 }
    281
    282 return os;
    408 OStream& operator<<(OStream &OS, const Matrix &M) {
    409 assert((M.getRows() != 0) && "Zero-row matrix badness.");
    410 for (unsigned i = 0; i < M.getRows(); ++i)
    411 OS << M.getRowAsVector(i);
    412 return OS;
    283413 }
    284414
    415 template
    416 class MDVector : public Vector {
    417 public:
    418 MDVector(const Vector &v) : Vector(v), md(*this) { }
    419 MDVector(Vector &&v) : Vector(std::move(v)), md(*this) { }
    420 const Metadata& getMetadata() const { return md; }
    421 private:
    422 Metadata md;
    423 };
    424
    425 template
    426 class MDMatrix : public Matrix {
    427 public:
    428 MDMatrix(const Matrix &m) : Matrix(m), md(*this) { }
    429 MDMatrix(Matrix &&m) : Matrix(std::move(m)), md(*this) { }
    430 const Metadata& getMetadata() const { return md; }
    431 private:
    432 Metadata md;
    433 };
    434
    285435 }
    286436
    287437 #endif // LLVM_CODEGEN_PBQP_MATH_H
    0 //===----------- ReductionRules.h - Reduction Rules -------------*- C++ -*-===//
    1 //
    2 // The LLVM Compiler Infrastructure
    3 //
    4 // This file is distributed under the University of Illinois Open Source
    5 // License. See LICENSE.TXT for details.
    6 //
    7 //===----------------------------------------------------------------------===//
    8 //
    9 // Reduction Rules.
    10 //
    11 //===----------------------------------------------------------------------===//
    12
    13 #ifndef LLVM_REDUCTIONRULES_H
    14 #define LLVM_REDUCTIONRULES_H
    15
    16 #include "Graph.h"
    17 #include "Math.h"
    18 #include "Solution.h"
    19
    20 namespace PBQP {
    21
    22 /// \brief Reduce a node of degree one.
    23 ///
    24 /// Propagate costs from the given node, which must be of degree one, to its
    25 /// neighbor. Notify the problem domain.
    26 template
    27 void applyR1(GraphT &G, typename GraphT::NodeId NId) {
    28 typedef typename GraphT::NodeId NodeId;
    29 typedef typename GraphT::EdgeId EdgeId;
    30 typedef typename GraphT::Vector Vector;
    31 typedef typename GraphT::Matrix Matrix;
    32 typedef typename GraphT::RawVector RawVector;
    33
    34 assert(G.getNodeDegree(NId) == 1 &&
    35 "R1 applied to node with degree != 1.");
    36
    37 EdgeId EId = *G.adjEdgeIds(NId).begin();
    38 NodeId MId = G.getEdgeOtherNodeId(EId, NId);
    39
    40 const Matrix &ECosts = G.getEdgeCosts(EId);
    41 const Vector &XCosts = G.getNodeCosts(NId);
    42 RawVector YCosts = G.getNodeCosts(MId);
    43
    44 // Duplicate a little to avoid transposing matrices.
    45 if (NId == G.getEdgeNode1Id(EId)) {
    46 for (unsigned j = 0; j < YCosts.getLength(); ++j) {
    47 PBQPNum Min = ECosts[0][j] + XCosts[0];
    48 for (unsigned i = 1; i < XCosts.getLength(); ++i) {
    49 PBQPNum C = ECosts[i][j] + XCosts[i];
    50 if (C < Min)
    51 Min = C;
    52 }
    53 YCosts[j] += Min;
    54 }
    55 } else {
    56 for (unsigned i = 0; i < YCosts.getLength(); ++i) {
    57 PBQPNum Min = ECosts[i][0] + XCosts[0];
    58 for (unsigned j = 1; j < XCosts.getLength(); ++j) {
    59 PBQPNum C = ECosts[i][j] + XCosts[j];
    60 if (C < Min)
    61 Min = C;
    62 }
    63 YCosts[i] += Min;
    64 }
    65 }
    66 G.setNodeCosts(MId, YCosts);
    67 G.disconnectEdge(EId, MId);
    68 }
    69
    70 template
    71 void applyR2(GraphT &G, typename GraphT::NodeId NId) {
    72 typedef typename GraphT::NodeId NodeId;
    73 typedef typename GraphT::EdgeId EdgeId;
    74 typedef typename GraphT::Vector Vector;
    75 typedef typename GraphT::Matrix Matrix;
    76 typedef typename GraphT::RawMatrix RawMatrix;
    77
    78 assert(G.getNodeDegree(NId) == 2 &&
    79 "R2 applied to node with degree != 2.");
    80
    81 const Vector &XCosts = G.getNodeCosts(NId);
    82
    83 typename GraphT::AdjEdgeItr AEItr = G.adjEdgeIds(NId).begin();
    84 EdgeId YXEId = *AEItr,
    85 ZXEId = *(++AEItr);
    86
    87 NodeId YNId = G.getEdgeOtherNodeId(YXEId, NId),
    88 ZNId = G.getEdgeOtherNodeId(ZXEId, NId);
    89
    90 bool FlipEdge1 = (G.getEdgeNode1Id(YXEId) == NId),
    91 FlipEdge2 = (G.getEdgeNode1Id(ZXEId) == NId);
    92
    93 const Matrix *YXECosts = FlipEdge1 ?
    94 new Matrix(G.getEdgeCosts(YXEId).transpose()) :
    95 &G.getEdgeCosts(YXEId);
    96
    97 const Matrix *ZXECosts = FlipEdge2 ?
    98 new Matrix(G.getEdgeCosts(ZXEId).transpose()) :
    99 &G.getEdgeCosts(ZXEId);
    100
    101 unsigned XLen = XCosts.getLength(),
    102 YLen = YXECosts->getRows(),
    103 ZLen = ZXECosts->getRows();
    104
    105 RawMatrix Delta(YLen, ZLen);
    106
    107 for (unsigned i = 0; i < YLen; ++i) {
    108 for (unsigned j = 0; j < ZLen; ++j) {
    109 PBQPNum Min = (*YXECosts)[i][0] + (*ZXECosts)[j][0] + XCosts[0];
    110 for (unsigned k = 1; k < XLen; ++k) {
    111 PBQPNum C = (*YXECosts)[i][k] + (*ZXECosts)[j][k] + XCosts[k];
    112 if (C < Min) {
    113 Min = C;
    114 }
    115 }
    116 Delta[i][j] = Min;
    117 }
    118 }
    119
    120 if (FlipEdge1)
    121 delete YXECosts;
    122
    123 if (FlipEdge2)
    124 delete ZXECosts;
    125
    126 EdgeId YZEId = G.findEdge(YNId, ZNId);
    127 bool AddedEdge = false;
    128
    129 if (YZEId == G.invalidEdgeId()) {
    130 YZEId = G.addEdge(YNId, ZNId, Delta);
    131 AddedEdge = true;
    132 } else {
    133 const Matrix &YZECosts = G.getEdgeCosts(YZEId);
    134 if (YNId == G.getEdgeNode1Id(YZEId)) {
    135 G.setEdgeCosts(YZEId, Delta + YZECosts);
    136 } else {
    137 G.setEdgeCosts(YZEId, Delta.transpose() + YZECosts);
    138 }
    139 }
    140
    141 G.disconnectEdge(YXEId, YNId);
    142 G.disconnectEdge(ZXEId, ZNId);
    143
    144 // TODO: Try to normalize newly added/modified edge.
    145 }
    146
    147
    148 // \brief Find a solution to a fully reduced graph by backpropagation.
    149 //
    150 // Given a graph and a reduction order, pop each node from the reduction
    151 // order and greedily compute a minimum solution based on the node costs, and
    152 // the dependent costs due to previously solved nodes.
    153 //
    154 // Note - This does not return the graph to its original (pre-reduction)
    155 // state: the existing solvers destructively alter the node and edge
    156 // costs. Given that, the backpropagate function doesn't attempt to
    157 // replace the edges either, but leaves the graph in its reduced
    158 // state.
    159 template
    160 Solution backpropagate(GraphT& G, StackT stack) {
    161 typedef GraphBase::NodeId NodeId;
    162 typedef GraphBase::EdgeId EdgeId;
    163 typedef typename GraphT::Matrix Matrix;
    164 typedef typename GraphT::RawVector RawVector;
    165
    166 Solution s;
    167
    168 while (!stack.empty()) {
    169 NodeId NId = stack.back();
    170 stack.pop_back();
    171
    172 RawVector v = G.getNodeCosts(NId);
    173
    174 for (auto EId : G.adjEdgeIds(NId)) {
    175 const Matrix& edgeCosts = G.getEdgeCosts(EId);
    176 if (NId == G.getEdgeNode1Id(EId)) {
    177 NodeId mId = G.getEdgeNode2Id(EId);
    178 v += edgeCosts.getColAsVector(s.getSelection(mId));
    179 } else {
    180 NodeId mId = G.getEdgeNode1Id(EId);
    181 v += edgeCosts.getRowAsVector(s.getSelection(mId));
    182 }
    183 }
    184
    185 s.setSelection(NId, v.minIndex());
    186 }
    187
    188 return s;
    189 }
    190
    191 }
    192
    193 #endif // LLVM_REDUCTIONRULES_H
    0 //===-- RegAllocSolver.h - Heuristic PBQP Solver for reg alloc --*- C++ -*-===//
    1 //
    2 // The LLVM Compiler Infrastructure
    3 //
    4 // This file is distributed under the University of Illinois Open Source
    5 // License. See LICENSE.TXT for details.
    6 //
    7 //===----------------------------------------------------------------------===//
    8 //
    9 // Heuristic PBQP solver for register allocation problems. This solver uses a
    10 // graph reduction approach. Nodes of degree 0, 1 and 2 are eliminated with
    11 // optimality-preserving rules (see ReductionRules.h). When no low-degree (<3)
    12 // nodes are present, a heuristic derived from Brigg's graph coloring approach
    13 // is used.
    14 //
    15 //===----------------------------------------------------------------------===//
    16
    17 #ifndef LLVM_CODEGEN_PBQP_REGALLOCSOLVER_H
    18 #define LLVM_CODEGEN_PBQP_REGALLOCSOLVER_H
    19
    20 #include "CostAllocator.h"
    21 #include "Graph.h"
    22 #include "ReductionRules.h"
    23 #include "Solution.h"
    24 #include "llvm/Support/ErrorHandling.h"
    25 #include
    26 #include
    27
    28 namespace PBQP {
    29
    30 namespace RegAlloc {
    31
    32 /// \brief Metadata to speed allocatability test.
    33 ///
    34 /// Keeps track of the number of infinities in each row and column.
    35 class MatrixMetadata {
    36 private:
    37 MatrixMetadata(const MatrixMetadata&);
    38 void operator=(const MatrixMetadata&);
    39 public:
    40 MatrixMetadata(const PBQP::Matrix& m)
    41 : worstRow(0), worstCol(0),
    42 unsafeRows(new bool[m.getRows() - 1]()),
    43 unsafeCols(new bool[m.getCols() - 1]()) {
    44
    45 unsigned* colCounts = new unsigned[m.getCols() - 1]();
    46
    47 for (unsigned i = 1; i < m.getRows(); ++i) {
    48 unsigned rowCount = 0;
    49 for (unsigned j = 1; j < m.getCols(); ++j) {
    50 if (m[i][j] == std::numeric_limits::infinity()) {
    51 ++rowCount;
    52 ++colCounts[j - 1];
    53 unsafeRows[i - 1] = true;
    54 unsafeCols[j - 1] = true;
    55 }
    56 }
    57 worstRow = std::max(worstRow, rowCount);
    58 }
    59 unsigned worstColCountForCurRow =
    60 *std::max_element(colCounts, colCounts + m.getCols() - 1);
    61 worstCol = std::max(worstCol, worstColCountForCurRow);
    62 delete[] colCounts;
    63 }
    64
    65 ~MatrixMetadata() {
    66 delete[] unsafeRows;
    67 delete[] unsafeCols;
    68 }
    69
    70 unsigned getWorstRow() const { return worstRow; }
    71 unsigned getWorstCol() const { return worstCol; }
    72 const bool* getUnsafeRows() const { return unsafeRows; }
    73 const bool* getUnsafeCols() const { return unsafeCols; }
    74
    75 private:
    76 unsigned worstRow, worstCol;
    77 bool* unsafeRows;
    78 bool* unsafeCols;
    79 };
    80
    81 class NodeMetadata {
    82 public:
    83 typedef enum { Unprocessed,
    84 OptimallyReducible,
    85 ConservativelyAllocatable,
    86 NotProvablyAllocatable } ReductionState;
    87
    88 NodeMetadata() : rs(Unprocessed), deniedOpts(0), optUnsafeEdges(0) {}
    89 ~NodeMetadata() { delete[] optUnsafeEdges; }
    90
    91 void setup(const Vector& costs) {
    92 numOpts = costs.getLength() - 1;
    93 optUnsafeEdges = new unsigned[numOpts]();
    94 }
    95
    96 ReductionState getReductionState() const { return rs; }
    97 void setReductionState(ReductionState rs) { this->rs = rs; }
    98
    99 void handleAddEdge(const MatrixMetadata& md, bool transpose) {
    100 deniedOpts += transpose ? md.getWorstCol() : md.getWorstRow();
    101 const bool* unsafeOpts =
    102 transpose ? md.getUnsafeCols() : md.getUnsafeRows();
    103 for (unsigned i = 0; i < numOpts; ++i)
    104 optUnsafeEdges[i] += unsafeOpts[i];
    105 }
    106
    107 void handleRemoveEdge(const MatrixMetadata& md, bool transpose) {
    108 deniedOpts -= transpose ? md.getWorstCol() : md.getWorstRow();
    109 const bool* unsafeOpts =
    110 transpose ? md.getUnsafeCols() : md.getUnsafeRows();
    111 for (unsigned i = 0; i < numOpts; ++i)
    112 optUnsafeEdges[i] -= unsafeOpts[i];
    113 }
    114
    115 bool isConservativelyAllocatable() const {
    116 return (deniedOpts < numOpts) ||
    117 (std::find(optUnsafeEdges, optUnsafeEdges + numOpts, 0) !=
    118 optUnsafeEdges + numOpts);
    119 }
    120
    121 private:
    122 ReductionState rs;
    123 unsigned numOpts;
    124 unsigned deniedOpts;
    125 unsigned* optUnsafeEdges;
    126 };
    127
    128 class RegAllocSolverImpl {
    129 private:
    130 typedef PBQP::MDMatrix RAMatrix;
    131 public:
    132 typedef PBQP::Vector RawVector;
    133 typedef PBQP::Matrix RawMatrix;
    134 typedef PBQP::Vector Vector;
    135 typedef RAMatrix Matrix;
    136 typedef PBQP::PoolCostAllocator<
    137 Vector, PBQP::VectorComparator,
    138 Matrix, PBQP::MatrixComparator> CostAllocator;
    139
    140 typedef PBQP::GraphBase::NodeId NodeId;
    141 typedef PBQP::GraphBase::EdgeId EdgeId;
    142
    143 typedef RegAlloc::NodeMetadata NodeMetadata;
    144
    145 struct EdgeMetadata { };
    146
    147 typedef PBQP::Graph Graph;
    148
    149 RegAllocSolverImpl(Graph &G) : G(G) {}
    150
    151 Solution solve() {
    152 G.setSolver(*this);
    153 Solution S;
    154 setup();
    155 S = backpropagate(G, reduce());
    156 G.unsetSolver();
    157 return S;
    158 }
    159
    160 void handleAddNode(NodeId NId) {
    161 G.getNodeMetadata(NId).setup(G.getNodeCosts(NId));
    162 }
    163 void handleRemoveNode(NodeId NId) {}
    164 void handleSetNodeCosts(NodeId NId, const Vector& newCosts) {}
    165
    166 void handleAddEdge(EdgeId EId) {
    167 handleReconnectEdge(EId, G.getEdgeNode1Id(EId));
    168 handleReconnectEdge(EId, G.getEdgeNode2Id(EId));
    169 }
    170
    171 void handleRemoveEdge(EdgeId EId) {
    172 handleDisconnectEdge(EId, G.getEdgeNode1Id(EId));
    173 handleDisconnectEdge(EId, G.getEdgeNode2Id(EId));
    174 }
    175
    176 void handleDisconnectEdge(EdgeId EId, NodeId NId) {
    177 NodeMetadata& nMd = G.getNodeMetadata(NId);
    178 const MatrixMetadata& mMd = G.getEdgeCosts(EId).getMetadata();
    179 nMd.handleRemoveEdge(mMd, NId == G.getEdgeNode2Id(EId));
    180 if (G.getNodeDegree(NId) == 3) {
    181 // This node is becoming optimally reducible.
    182 moveToOptimallyReducibleNodes(NId);
    183 } else if (nMd.getReductionState() ==
    184 NodeMetadata::NotProvablyAllocatable &&
    185 nMd.isConservativelyAllocatable()) {
    186 // This node just became conservatively allocatable.
    187 moveToConservativelyAllocatableNodes(NId);
    188 }
    189 }
    190
    191 void handleReconnectEdge(EdgeId EId, NodeId NId) {
    192 NodeMetadata& nMd = G.getNodeMetadata(NId);
    193 const MatrixMetadata& mMd = G.getEdgeCosts(EId).getMetadata();
    194 nMd.handleAddEdge(mMd, NId == G.getEdgeNode2Id(EId));
    195 }
    196
    197 void handleSetEdgeCosts(EdgeId EId, const Matrix& NewCosts) {
    198 handleRemoveEdge(EId);
    199
    200 NodeId n1Id = G.getEdgeNode1Id(EId);
    201 NodeId n2Id = G.getEdgeNode2Id(EId);
    202 NodeMetadata& n1Md = G.getNodeMetadata(n1Id);
    203 NodeMetadata& n2Md = G.getNodeMetadata(n2Id);
    204 const MatrixMetadata& mMd = NewCosts.getMetadata();
    205 n1Md.handleAddEdge(mMd, n1Id != G.getEdgeNode1Id(EId));
    206 n2Md.handleAddEdge(mMd, n2Id != G.getEdgeNode1Id(EId));
    207 }
    208
    209 private:
    210
    211 void removeFromCurrentSet(NodeId NId) {
    212 switch (G.getNodeMetadata(NId).getReductionState()) {
    213 case NodeMetadata::Unprocessed: break;
    214 case NodeMetadata::OptimallyReducible:
    215 assert(OptimallyReducibleNodes.find(NId) !=
    216 OptimallyReducibleNodes.end() &&
    217 "Node not in optimally reducible set.");
    218 OptimallyReducibleNodes.erase(NId);
    219 break;
    220 case NodeMetadata::ConservativelyAllocatable:
    221 assert(ConservativelyAllocatableNodes.find(NId) !=
    222 ConservativelyAllocatableNodes.end() &&
    223 "Node not in conservatively allocatable set.");
    224 ConservativelyAllocatableNodes.erase(NId);
    225 break;
    226 case NodeMetadata::NotProvablyAllocatable:
    227 assert(NotProvablyAllocatableNodes.find(NId) !=
    228 NotProvablyAllocatableNodes.end() &&
    229 "Node not in not-provably-allocatable set.");
    230 NotProvablyAllocatableNodes.erase(NId);
    231 break;
    232 }
    233 }
    234
    235 void moveToOptimallyReducibleNodes(NodeId NId) {
    236 removeFromCurrentSet(NId);
    237 OptimallyReducibleNodes.insert(NId);
    238 G.getNodeMetadata(NId).setReductionState(
    239 NodeMetadata::OptimallyReducible);
    240 }
    241
    242 void moveToConservativelyAllocatableNodes(NodeId NId) {
    243 removeFromCurrentSet(NId);
    244 ConservativelyAllocatableNodes.insert(NId);
    245 G.getNodeMetadata(NId).setReductionState(
    246 NodeMetadata::ConservativelyAllocatable);
    247 }
    248
    249 void moveToNotProvablyAllocatableNodes(NodeId NId) {
    250 removeFromCurrentSet(NId);
    251 NotProvablyAllocatableNodes.insert(NId);
    252 G.getNodeMetadata(NId).setReductionState(
    253 NodeMetadata::NotProvablyAllocatable);
    254 }
    255
    256 void setup() {
    257 // Set up worklists.
    258 for (auto NId : G.nodeIds()) {
    259 if (G.getNodeDegree(NId) < 3)
    260 moveToOptimallyReducibleNodes(NId);
    261 else if (G.getNodeMetadata(NId).isConservativelyAllocatable())
    262 moveToConservativelyAllocatableNodes(NId);
    263 else
    264 moveToNotProvablyAllocatableNodes(NId);
    265 }
    266 }
    267
    268 // Compute a reduction order for the graph by iteratively applying PBQP
    269 // reduction rules. Locally optimal rules are applied whenever possible (R0,
    270 // R1, R2). If no locally-optimal rules apply then any conservatively
    271 // allocatable node is reduced. Finally, if no conservatively allocatable
    272 // node exists then the node with the lowest spill-cost:degree ratio is
    273 // selected.
    274 std::vector reduce() {
    275 assert(!G.empty() && "Cannot reduce empty graph.");
    276
    277 typedef GraphBase::NodeId NodeId;
    278 std::vector NodeStack;
    279
    280 // Consume worklists.
    281 while (true) {
    282 if (!OptimallyReducibleNodes.empty()) {
    283 NodeSet::iterator nItr = OptimallyReducibleNodes.begin();
    284 NodeId NId = *nItr;
    285 OptimallyReducibleNodes.erase(nItr);
    286 NodeStack.push_back(NId);
    287 switch (G.getNodeDegree(NId)) {
    288 case 0:
    289 break;
    290 case 1:
    291 applyR1(G, NId);
    292 break;
    293 case 2:
    294 applyR2(G, NId);
    295 break;
    296 default: llvm_unreachable("Not an optimally reducible node.");
    297 }
    298 } else if (!ConservativelyAllocatableNodes.empty()) {
    299 // Conservatively allocatable nodes will never spill. For now just
    300 // take the first node in the set and push it on the stack. When we
    301 // start optimizing more heavily for register preferencing, it may
    302 // would be better to push nodes with lower 'expected' or worst-case
    303 // register costs first (since early nodes are the most
    304 // constrained).
    305 NodeSet::iterator nItr = ConservativelyAllocatableNodes.begin();
    306 NodeId NId = *nItr;
    307 ConservativelyAllocatableNodes.erase(nItr);
    308 NodeStack.push_back(NId);
    309 G.disconnectAllNeighborsFromNode(NId);
    310
    311 } else if (!NotProvablyAllocatableNodes.empty()) {
    312 NodeSet::iterator nItr =
    313 std::min_element(NotProvablyAllocatableNodes.begin(),
    314 NotProvablyAllocatableNodes.end(),
    315 SpillCostComparator(G));
    316 NodeId NId = *nItr;
    317 NotProvablyAllocatableNodes.erase(nItr);
    318 NodeStack.push_back(NId);
    319 G.disconnectAllNeighborsFromNode(NId);
    320 } else
    321 break;
    322 }
    323
    324 return NodeStack;
    325 }
    326
    327 class SpillCostComparator {
    328 public:
    329 SpillCostComparator(const Graph& G) : G(G) {}
    330 bool operator()(NodeId N1Id, NodeId N2Id) {
    331 PBQPNum N1SC = G.getNodeCosts(N1Id)[0] / G.getNodeDegree(N1Id);
    332 PBQPNum N2SC = G.getNodeCosts(N2Id)[0] / G.getNodeDegree(N2Id);
    333 return N1SC < N2SC;
    334 }
    335 private:
    336 const Graph& G;
    337 };
    338
    339 Graph& G;
    340 typedef std::set NodeSet;
    341 NodeSet OptimallyReducibleNodes;
    342 NodeSet ConservativelyAllocatableNodes;
    343 NodeSet NotProvablyAllocatableNodes;
    344 };
    345
    346 typedef Graph Graph;
    347
    348 Solution solve(Graph& G) {
    349 if (G.empty())
    350 return Solution();
    351 RegAllocSolverImpl RegAllocSolver(G);
    352 return RegAllocSolver.solve();
    353 }
    354
    355 }
    356 }
    357
    358 #endif // LLVM_CODEGEN_PBQP_REGALLOCSOLVER_H
    2525 class Solution {
    2626 private:
    2727
    28 typedef std::map::NodeId, unsigned> SelectionsMap;
    28