llvm.org GIT mirror llvm / ba34beb
Jumped the gun with r202551 and broke some bots that weren't yet C++11ified. Reverting until the C++11 switch is complete. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@202554 91177308-0d34-0410-b5e6-96231b3b80d8 Lang Hames 6 years ago
11 changed file(s) with 1972 addition(s) and 1580 deletion(s). Raw diff Collapse all Expand all
+0
-147
include/llvm/CodeGen/PBQP/CostAllocator.h less more
None //===---------- 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"
1718 #include "llvm/ADT/ilist.h"
1819 #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 {
26 /// PBQP Graph class.
27 /// Instances of this class describe PBQP problems.
28 class Graph {
2729 public:
30
2831 typedef unsigned NodeId;
2932 typedef unsigned EdgeId;
30 };
31
32 /// PBQP Graph class.
33 /// Instances of this class describe PBQP problems.
34 ///
35 template
36 class Graph : public GraphBase {
33
3734 private:
38 typedef typename SolverT::CostAllocator CostAllocator;
35
36 typedef std::set AdjEdgeList;
37
3938 public:
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;
39
40 typedef AdjEdgeList::iterator AdjEdgeItr;
4841
4942 private:
5043
5144 class NodeEntry {
45 private:
46 Vector costs;
47 AdjEdgeList adjEdges;
48 void *data;
49 NodeEntry() : costs(0, 0) {}
5250 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;
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; }
6065 };
6166
6267 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) {}
6374 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;
74 private:
75 NodeId N1Id, N2Id;
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; }
7687 };
7788
7889 // ----- MEMBERS -----
79
80 CostAllocator CostAlloc;
81 SolverT *Solver;
8290
8391 typedef std::vector NodeVector;
8492 typedef std::vector FreeNodeVector;
85 NodeVector Nodes;
86 FreeNodeVector FreeNodeIds;
93 NodeVector nodes;
94 FreeNodeVector freeNodes;
8795
8896 typedef std::vector EdgeVector;
8997 typedef std::vector FreeEdgeVector;
90 EdgeVector Edges;
91 FreeEdgeVector FreeEdgeIds;
98 EdgeVector edges;
99 FreeEdgeVector freeEdges;
92100
93101 // ----- INTERNAL METHODS -----
94102
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);
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;
107115 } else {
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() &&
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() &&
116124 "Attempt to add duplicate edge.");
117 EdgeId EId = 0;
118 if (!FreeEdgeIds.empty()) {
119 EId = FreeEdgeIds.back();
120 FreeEdgeIds.pop_back();
121 Edges[EId] = std::move(E);
125 EdgeId edgeId = 0;
126 if (!freeEdges.empty()) {
127 edgeId = freeEdges.back();
128 freeEdges.pop_back();
129 edges[edgeId] = e;
122130 } else {
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());
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());
130138
131139 // Sanity check on matrix dimensions:
132 assert((N1.Costs->getLength() == NE.Costs->getRows()) &&
133 (N2.Costs->getLength() == NE.Costs->getCols()) &&
140 assert((n1.getCosts().getLength() == ne.getCosts().getRows()) &&
141 (n2.getCosts().getLength() == ne.getCosts().getCols()) &&
134142 "Edge cost dimensions do not match node costs dimensions.");
135143
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) {}
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) {}
143151
144152 public:
145
146 typedef typename NodeEntry::AdjEdgeItr AdjEdgeItr;
147153
148154 class NodeItr {
149155 public:
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; }
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; }
159165
160166 private:
161 NodeId findNextInUse(NodeId NId) const {
162 while (NId < EndNId &&
163 std::find(FreeNodeIds.begin(), FreeNodeIds.end(), NId) !=
164 FreeNodeIds.end()) {
165 ++NId;
166 }
167 return NId;
168 }
169
170 NodeId CurNId, EndNId;
171 const FreeNodeVector &FreeNodeIds;
167 NodeId findNextInUse(NodeId n) const {
168 while (n < endNodeId &&
169 std::find(freeNodes.begin(), freeNodes.end(), n) !=
170 freeNodes.end()) {
171 ++n;
172 }
173 return n;
174 }
175
176 NodeId nodeId, endNodeId;
177 const FreeNodeVector& freeNodes;
172178 };
173179
174180 class EdgeItr {
175181 public:
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; }
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; }
185191
186192 private:
187 EdgeId findNextInUse(EdgeId EId) const {
188 while (EId < EndEId &&
189 std::find(FreeEdgeIds.begin(), FreeEdgeIds.end(), EId) !=
190 FreeEdgeIds.end()) {
191 ++EId;
192 }
193 return EId;
194 }
195
196 EdgeId CurEId, EndEId;
197 const FreeEdgeVector &FreeEdgeIds;
193 EdgeId findNextInUse(EdgeId n) const {
194 while (n < endEdgeId &&
195 std::find(freeEdges.begin(), freeEdges.end(), n) !=
196 freeEdges.end()) {
197 ++n;
198 }
199 return n;
200 }
201
202 EdgeId edgeId, endEdgeId;
203 const FreeEdgeVector& freeEdges;
198204 };
199205
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;
241 };
242
243206 /// \brief Construct an empty PBQP 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 }
207 Graph() {}
264208
265209 /// \brief Add a node with the given costs.
266 /// @param Costs Cost vector for the new node.
210 /// @param costs Cost vector for the new node.
267211 /// @return Node iterator for the added node.
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;
212 NodeId addNode(const Vector &costs) {
213 return addConstructedNode(NodeEntry(costs));
276214 }
277215
278216 /// \brief Add an edge between the given nodes with the given costs.
279 /// @param N1Id First node.
280 /// @param N2Id Second node.
217 /// @param n1Id First node.
218 /// @param n2Id Second node.
281219 /// @return Edge iterator for the added edge.
282 template
283 EdgeId addEdge(NodeId N1Id, NodeId N2Id, OtherVectorT Costs) {
284 assert(getNodeCosts(N1Id).getLength() == Costs.getRows() &&
285 getNodeCosts(N2Id).getLength() == Costs.getCols() &&
220 EdgeId addEdge(NodeId n1Id, NodeId n2Id, const Matrix &costs) {
221 assert(getNodeCosts(n1Id).getLength() == costs.getRows() &&
222 getNodeCosts(n2Id).getLength() == costs.getCols() &&
286223 "Matrix dimensions mismatch.");
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)); }
224 return addConstructedEdge(EdgeEntry(n1Id, n2Id, costs));
225 }
302226
303227 /// \brief Get the number of nodes in the graph.
304228 /// @return Number of nodes in the graph.
305 unsigned getNumNodes() const { return NodeIdSet(*this).size(); }
229 unsigned getNumNodes() const { return nodes.size() - freeNodes.size(); }
306230
307231 /// \brief Get the number of edges in the graph.
308232 /// @return Number of edges in the graph.
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.
233 unsigned getNumEdges() const { return edges.size() - freeEdges.size(); }
234
235 /// \brief Get a node's cost vector.
236 /// @param nId Node id.
314237 /// @return Node cost vector.
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 }
238 Vector& getNodeCosts(NodeId nId) { return getNode(nId).getCosts(); }
322239
323240 /// \brief Get a node's cost vector (const version).
324 /// @param NId Node id.
241 /// @param nId Node id.
325242 /// @return Node cost vector.
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 }
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.
261 /// @return Edge cost matrix.
262 Matrix& getEdgeCosts(EdgeId eId) { return getEdge(eId).getCosts(); }
352263
353264 /// \brief Get an edge's cost matrix (const version).
354 /// @param EId Edge id.
265 /// @param eId Edge id.
355266 /// @return Edge cost matrix.
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;
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();
364314 }
365315
366316 /// \brief Get the first node connected to this edge.
367 /// @param EId Edge id.
317 /// @param eId Edge id.
368318 /// @return The first node connected to the given edge.
369 NodeId getEdgeNode1Id(EdgeId EId) {
370 return getEdge(EId).getN1Id();
319 NodeId getEdgeNode1(EdgeId eId) {
320 return getEdge(eId).getNode1();
371321 }
372322
373323 /// \brief Get the second node connected to this edge.
374 /// @param EId Edge id.
324 /// @param eId Edge id.
375325 /// @return The second node connected to the given edge.
376 NodeId getEdgeNode2Id(EdgeId EId) {
377 return getEdge(EId).getN2Id();
326 NodeId getEdgeNode2(EdgeId eId) {
327 return getEdge(eId).getNode2();
378328 }
379329
380330 /// \brief Get the "other" node connected to this edge.
381 /// @param EId Edge id.
382 /// @param NId Node id for the "given" node.
331 /// @param eId Edge id.
332 /// @param nId Node id for the "given" node.
383333 /// @return The iterator for the "other" node connected to this edge.
384 NodeId getEdgeOtherNodeId(EdgeId EId, NodeId NId) {
385 EdgeEntry &E = getEdge(EId);
386 if (E.getN1Id() == NId) {
387 return E.getN2Id();
334 NodeId getEdgeOtherNode(EdgeId eId, NodeId nId) {
335 EdgeEntry &e = getEdge(eId);
336 if (e.getNode1() == nId) {
337 return e.getNode2();
388338 } // else
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() {
339 return e.getNode1();
340 }
341
342 EdgeId invalidEdgeId() const {
399343 return std::numeric_limits::max();
400344 }
401345
402346 /// \brief Get the edge connecting two nodes.
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,
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,
406350 /// otherwise returns an invalid edge id.
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;
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;
412357 }
413358 }
414359 return invalidEdgeId();
415360 }
416361
417362 /// \brief Remove a node from the graph.
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);
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);
482371 }
483372
484373 /// \brief Remove an edge from the graph.
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();
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);
496382 }
497383
498384 /// \brief Remove all nodes and edges from the graph.
499385 void clear() {
500 Nodes.clear();
501 FreeNodeIds.clear();
502 Edges.clear();
503 FreeEdgeIds.clear();
386 nodes.clear();
387 freeNodes.clear();
388 edges.clear();
389 freeEdges.clear();
504390 }
505391
506392 /// \brief Dump a graph to an output stream.
507393 template
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];
518 }
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];
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];
405 }
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];
535423 }
536 OS << "\n";
424 os << "\n";
537425 }
538426 }
539427 }
541429 /// \brief Print a representation of this graph in DOT format.
542430 /// @param os Output stream to print on.
543431 template
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)
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)
554450 << " [ label=\"";
555 const Matrix &EdgeCosts = getEdgeCosts(EId);
556 for (unsigned i = 0; i < EdgeCosts.getRows(); ++i) {
557 OS << EdgeCosts.getRowAsVector(i) << "\\n";
558 }
559 OS << "\" ]\n";
560 }
561 OS << "}\n";
562 }
451
452 const Matrix &edgeCosts = getEdgeCosts(*edgeItr);
453
454 for (unsigned i = 0; i < edgeCosts.getRows(); ++i) {
455 os << edgeCosts.getRowAsVector(i) << "\\n";
456 }
457 os << "\" ]\n";
458 }
459 os << "}\n";
460 }
461
563462 };
564463
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
565475 }
566476
567477 #endif // LLVM_CODEGEN_PBQP_GRAPH_HPP
0 //===-- 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 //===-- 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 //===-- 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 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 }
    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;
    15292 };
    15393
    15494 /// \brief Output a textual representation of the given vector on the given
    15595 /// output stream.
    15696 template
    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 }
    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 }
    167108
    168109
    169110 /// \brief PBQP Matrix class
    170111 class Matrix {
    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 }
    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;
    403269 };
    404270
    405271 /// \brief Output a textual representation of the given matrix on the given
    406272 /// output stream.
    407273 template
    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;
    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;
    413283 }
    414284
    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
    435285 }
    436286
    437287 #endif // LLVM_CODEGEN_PBQP_MATH_H
    +0
    -194
    include/llvm/CodeGen/PBQP/ReductionRules.h less more
    None //===----------- 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
    -359
    include/llvm/CodeGen/PBQP/RegAllocSolver.h less more
    <
    None //===-- 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