Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
14 | pmbaty | 1 | //===- RegAllocPBQP.h -------------------------------------------*- C++ -*-===// |
2 | // |
||
3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
4 | // See https://llvm.org/LICENSE.txt for license information. |
||
5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
6 | // |
||
7 | //===----------------------------------------------------------------------===// |
||
8 | // |
||
9 | // This file defines the PBQPBuilder interface, for classes which build PBQP |
||
10 | // instances to represent register allocation problems, and the RegAllocPBQP |
||
11 | // interface. |
||
12 | // |
||
13 | //===----------------------------------------------------------------------===// |
||
14 | |||
15 | #ifndef LLVM_CODEGEN_REGALLOCPBQP_H |
||
16 | #define LLVM_CODEGEN_REGALLOCPBQP_H |
||
17 | |||
18 | #include "llvm/ADT/DenseMap.h" |
||
19 | #include "llvm/ADT/Hashing.h" |
||
20 | #include "llvm/CodeGen/PBQP/CostAllocator.h" |
||
21 | #include "llvm/CodeGen/PBQP/Graph.h" |
||
22 | #include "llvm/CodeGen/PBQP/Math.h" |
||
23 | #include "llvm/CodeGen/PBQP/ReductionRules.h" |
||
24 | #include "llvm/CodeGen/PBQP/Solution.h" |
||
25 | #include "llvm/CodeGen/Register.h" |
||
26 | #include "llvm/MC/MCRegister.h" |
||
27 | #include "llvm/Support/ErrorHandling.h" |
||
28 | #include <algorithm> |
||
29 | #include <cassert> |
||
30 | #include <cstddef> |
||
31 | #include <limits> |
||
32 | #include <memory> |
||
33 | #include <set> |
||
34 | #include <vector> |
||
35 | |||
36 | namespace llvm { |
||
37 | |||
38 | class FunctionPass; |
||
39 | class LiveIntervals; |
||
40 | class MachineBlockFrequencyInfo; |
||
41 | class MachineFunction; |
||
42 | class raw_ostream; |
||
43 | |||
44 | namespace PBQP { |
||
45 | namespace RegAlloc { |
||
46 | |||
47 | /// Spill option index. |
||
48 | inline unsigned getSpillOptionIdx() { return 0; } |
||
49 | |||
50 | /// Metadata to speed allocatability test. |
||
51 | /// |
||
52 | /// Keeps track of the number of infinities in each row and column. |
||
53 | class MatrixMetadata { |
||
54 | public: |
||
55 | MatrixMetadata(const Matrix& M) |
||
56 | : UnsafeRows(new bool[M.getRows() - 1]()), |
||
57 | UnsafeCols(new bool[M.getCols() - 1]()) { |
||
58 | unsigned* ColCounts = new unsigned[M.getCols() - 1](); |
||
59 | |||
60 | for (unsigned i = 1; i < M.getRows(); ++i) { |
||
61 | unsigned RowCount = 0; |
||
62 | for (unsigned j = 1; j < M.getCols(); ++j) { |
||
63 | if (M[i][j] == std::numeric_limits<PBQPNum>::infinity()) { |
||
64 | ++RowCount; |
||
65 | ++ColCounts[j - 1]; |
||
66 | UnsafeRows[i - 1] = true; |
||
67 | UnsafeCols[j - 1] = true; |
||
68 | } |
||
69 | } |
||
70 | WorstRow = std::max(WorstRow, RowCount); |
||
71 | } |
||
72 | unsigned WorstColCountForCurRow = |
||
73 | *std::max_element(ColCounts, ColCounts + M.getCols() - 1); |
||
74 | WorstCol = std::max(WorstCol, WorstColCountForCurRow); |
||
75 | delete[] ColCounts; |
||
76 | } |
||
77 | |||
78 | MatrixMetadata(const MatrixMetadata &) = delete; |
||
79 | MatrixMetadata &operator=(const MatrixMetadata &) = delete; |
||
80 | |||
81 | unsigned getWorstRow() const { return WorstRow; } |
||
82 | unsigned getWorstCol() const { return WorstCol; } |
||
83 | const bool* getUnsafeRows() const { return UnsafeRows.get(); } |
||
84 | const bool* getUnsafeCols() const { return UnsafeCols.get(); } |
||
85 | |||
86 | private: |
||
87 | unsigned WorstRow = 0; |
||
88 | unsigned WorstCol = 0; |
||
89 | std::unique_ptr<bool[]> UnsafeRows; |
||
90 | std::unique_ptr<bool[]> UnsafeCols; |
||
91 | }; |
||
92 | |||
93 | /// Holds a vector of the allowed physical regs for a vreg. |
||
94 | class AllowedRegVector { |
||
95 | friend hash_code hash_value(const AllowedRegVector &); |
||
96 | |||
97 | public: |
||
98 | AllowedRegVector() = default; |
||
99 | AllowedRegVector(AllowedRegVector &&) = default; |
||
100 | |||
101 | AllowedRegVector(const std::vector<MCRegister> &OptVec) |
||
102 | : NumOpts(OptVec.size()), Opts(new MCRegister[NumOpts]) { |
||
103 | std::copy(OptVec.begin(), OptVec.end(), Opts.get()); |
||
104 | } |
||
105 | |||
106 | unsigned size() const { return NumOpts; } |
||
107 | MCRegister operator[](size_t I) const { return Opts[I]; } |
||
108 | |||
109 | bool operator==(const AllowedRegVector &Other) const { |
||
110 | if (NumOpts != Other.NumOpts) |
||
111 | return false; |
||
112 | return std::equal(Opts.get(), Opts.get() + NumOpts, Other.Opts.get()); |
||
113 | } |
||
114 | |||
115 | bool operator!=(const AllowedRegVector &Other) const { |
||
116 | return !(*this == Other); |
||
117 | } |
||
118 | |||
119 | private: |
||
120 | unsigned NumOpts = 0; |
||
121 | std::unique_ptr<MCRegister[]> Opts; |
||
122 | }; |
||
123 | |||
124 | inline hash_code hash_value(const AllowedRegVector &OptRegs) { |
||
125 | MCRegister *OStart = OptRegs.Opts.get(); |
||
126 | MCRegister *OEnd = OptRegs.Opts.get() + OptRegs.NumOpts; |
||
127 | return hash_combine(OptRegs.NumOpts, |
||
128 | hash_combine_range(OStart, OEnd)); |
||
129 | } |
||
130 | |||
131 | /// Holds graph-level metadata relevant to PBQP RA problems. |
||
132 | class GraphMetadata { |
||
133 | private: |
||
134 | using AllowedRegVecPool = ValuePool<AllowedRegVector>; |
||
135 | |||
136 | public: |
||
137 | using AllowedRegVecRef = AllowedRegVecPool::PoolRef; |
||
138 | |||
139 | GraphMetadata(MachineFunction &MF, |
||
140 | LiveIntervals &LIS, |
||
141 | MachineBlockFrequencyInfo &MBFI) |
||
142 | : MF(MF), LIS(LIS), MBFI(MBFI) {} |
||
143 | |||
144 | MachineFunction &MF; |
||
145 | LiveIntervals &LIS; |
||
146 | MachineBlockFrequencyInfo &MBFI; |
||
147 | |||
148 | void setNodeIdForVReg(Register VReg, GraphBase::NodeId NId) { |
||
149 | VRegToNodeId[VReg.id()] = NId; |
||
150 | } |
||
151 | |||
152 | GraphBase::NodeId getNodeIdForVReg(Register VReg) const { |
||
153 | auto VRegItr = VRegToNodeId.find(VReg); |
||
154 | if (VRegItr == VRegToNodeId.end()) |
||
155 | return GraphBase::invalidNodeId(); |
||
156 | return VRegItr->second; |
||
157 | } |
||
158 | |||
159 | AllowedRegVecRef getAllowedRegs(AllowedRegVector Allowed) { |
||
160 | return AllowedRegVecs.getValue(std::move(Allowed)); |
||
161 | } |
||
162 | |||
163 | private: |
||
164 | DenseMap<Register, GraphBase::NodeId> VRegToNodeId; |
||
165 | AllowedRegVecPool AllowedRegVecs; |
||
166 | }; |
||
167 | |||
168 | /// Holds solver state and other metadata relevant to each PBQP RA node. |
||
169 | class NodeMetadata { |
||
170 | public: |
||
171 | using AllowedRegVector = RegAlloc::AllowedRegVector; |
||
172 | |||
173 | // The node's reduction state. The order in this enum is important, |
||
174 | // as it is assumed nodes can only progress up (i.e. towards being |
||
175 | // optimally reducible) when reducing the graph. |
||
176 | using ReductionState = enum { |
||
177 | Unprocessed, |
||
178 | NotProvablyAllocatable, |
||
179 | ConservativelyAllocatable, |
||
180 | OptimallyReducible |
||
181 | }; |
||
182 | |||
183 | NodeMetadata() = default; |
||
184 | |||
185 | NodeMetadata(const NodeMetadata &Other) |
||
186 | : RS(Other.RS), NumOpts(Other.NumOpts), DeniedOpts(Other.DeniedOpts), |
||
187 | OptUnsafeEdges(new unsigned[NumOpts]), VReg(Other.VReg), |
||
188 | AllowedRegs(Other.AllowedRegs) |
||
189 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
||
190 | , |
||
191 | everConservativelyAllocatable(Other.everConservativelyAllocatable) |
||
192 | #endif |
||
193 | { |
||
194 | if (NumOpts > 0) { |
||
195 | std::copy(&Other.OptUnsafeEdges[0], &Other.OptUnsafeEdges[NumOpts], |
||
196 | &OptUnsafeEdges[0]); |
||
197 | } |
||
198 | } |
||
199 | |||
200 | NodeMetadata(NodeMetadata &&) = default; |
||
201 | NodeMetadata& operator=(NodeMetadata &&) = default; |
||
202 | |||
203 | void setVReg(Register VReg) { this->VReg = VReg; } |
||
204 | Register getVReg() const { return VReg; } |
||
205 | |||
206 | void setAllowedRegs(GraphMetadata::AllowedRegVecRef AllowedRegs) { |
||
207 | this->AllowedRegs = std::move(AllowedRegs); |
||
208 | } |
||
209 | const AllowedRegVector& getAllowedRegs() const { return *AllowedRegs; } |
||
210 | |||
211 | void setup(const Vector& Costs) { |
||
212 | NumOpts = Costs.getLength() - 1; |
||
213 | OptUnsafeEdges = std::unique_ptr<unsigned[]>(new unsigned[NumOpts]()); |
||
214 | } |
||
215 | |||
216 | ReductionState getReductionState() const { return RS; } |
||
217 | void setReductionState(ReductionState RS) { |
||
218 | assert(RS >= this->RS && "A node's reduction state can not be downgraded"); |
||
219 | this->RS = RS; |
||
220 | |||
221 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
||
222 | // Remember this state to assert later that a non-infinite register |
||
223 | // option was available. |
||
224 | if (RS == ConservativelyAllocatable) |
||
225 | everConservativelyAllocatable = true; |
||
226 | #endif |
||
227 | } |
||
228 | |||
229 | void handleAddEdge(const MatrixMetadata& MD, bool Transpose) { |
||
230 | DeniedOpts += Transpose ? MD.getWorstRow() : MD.getWorstCol(); |
||
231 | const bool* UnsafeOpts = |
||
232 | Transpose ? MD.getUnsafeCols() : MD.getUnsafeRows(); |
||
233 | for (unsigned i = 0; i < NumOpts; ++i) |
||
234 | OptUnsafeEdges[i] += UnsafeOpts[i]; |
||
235 | } |
||
236 | |||
237 | void handleRemoveEdge(const MatrixMetadata& MD, bool Transpose) { |
||
238 | DeniedOpts -= Transpose ? MD.getWorstRow() : MD.getWorstCol(); |
||
239 | const bool* UnsafeOpts = |
||
240 | Transpose ? MD.getUnsafeCols() : MD.getUnsafeRows(); |
||
241 | for (unsigned i = 0; i < NumOpts; ++i) |
||
242 | OptUnsafeEdges[i] -= UnsafeOpts[i]; |
||
243 | } |
||
244 | |||
245 | bool isConservativelyAllocatable() const { |
||
246 | return (DeniedOpts < NumOpts) || |
||
247 | (std::find(&OptUnsafeEdges[0], &OptUnsafeEdges[NumOpts], 0) != |
||
248 | &OptUnsafeEdges[NumOpts]); |
||
249 | } |
||
250 | |||
251 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
||
252 | bool wasConservativelyAllocatable() const { |
||
253 | return everConservativelyAllocatable; |
||
254 | } |
||
255 | #endif |
||
256 | |||
257 | private: |
||
258 | ReductionState RS = Unprocessed; |
||
259 | unsigned NumOpts = 0; |
||
260 | unsigned DeniedOpts = 0; |
||
261 | std::unique_ptr<unsigned[]> OptUnsafeEdges; |
||
262 | Register VReg; |
||
263 | GraphMetadata::AllowedRegVecRef AllowedRegs; |
||
264 | |||
265 | #if LLVM_ENABLE_ABI_BREAKING_CHECKS |
||
266 | bool everConservativelyAllocatable = false; |
||
267 | #endif |
||
268 | }; |
||
269 | |||
270 | class RegAllocSolverImpl { |
||
271 | private: |
||
272 | using RAMatrix = MDMatrix<MatrixMetadata>; |
||
273 | |||
274 | public: |
||
275 | using RawVector = PBQP::Vector; |
||
276 | using RawMatrix = PBQP::Matrix; |
||
277 | using Vector = PBQP::Vector; |
||
278 | using Matrix = RAMatrix; |
||
279 | using CostAllocator = PBQP::PoolCostAllocator<Vector, Matrix>; |
||
280 | |||
281 | using NodeId = GraphBase::NodeId; |
||
282 | using EdgeId = GraphBase::EdgeId; |
||
283 | |||
284 | using NodeMetadata = RegAlloc::NodeMetadata; |
||
285 | struct EdgeMetadata {}; |
||
286 | using GraphMetadata = RegAlloc::GraphMetadata; |
||
287 | |||
288 | using Graph = PBQP::Graph<RegAllocSolverImpl>; |
||
289 | |||
290 | RegAllocSolverImpl(Graph &G) : G(G) {} |
||
291 | |||
292 | Solution solve() { |
||
293 | G.setSolver(*this); |
||
294 | Solution S; |
||
295 | setup(); |
||
296 | S = backpropagate(G, reduce()); |
||
297 | G.unsetSolver(); |
||
298 | return S; |
||
299 | } |
||
300 | |||
301 | void handleAddNode(NodeId NId) { |
||
302 | assert(G.getNodeCosts(NId).getLength() > 1 && |
||
303 | "PBQP Graph should not contain single or zero-option nodes"); |
||
304 | G.getNodeMetadata(NId).setup(G.getNodeCosts(NId)); |
||
305 | } |
||
306 | |||
307 | void handleRemoveNode(NodeId NId) {} |
||
308 | void handleSetNodeCosts(NodeId NId, const Vector& newCosts) {} |
||
309 | |||
310 | void handleAddEdge(EdgeId EId) { |
||
311 | handleReconnectEdge(EId, G.getEdgeNode1Id(EId)); |
||
312 | handleReconnectEdge(EId, G.getEdgeNode2Id(EId)); |
||
313 | } |
||
314 | |||
315 | void handleDisconnectEdge(EdgeId EId, NodeId NId) { |
||
316 | NodeMetadata& NMd = G.getNodeMetadata(NId); |
||
317 | const MatrixMetadata& MMd = G.getEdgeCosts(EId).getMetadata(); |
||
318 | NMd.handleRemoveEdge(MMd, NId == G.getEdgeNode2Id(EId)); |
||
319 | promote(NId, NMd); |
||
320 | } |
||
321 | |||
322 | void handleReconnectEdge(EdgeId EId, NodeId NId) { |
||
323 | NodeMetadata& NMd = G.getNodeMetadata(NId); |
||
324 | const MatrixMetadata& MMd = G.getEdgeCosts(EId).getMetadata(); |
||
325 | NMd.handleAddEdge(MMd, NId == G.getEdgeNode2Id(EId)); |
||
326 | } |
||
327 | |||
328 | void handleUpdateCosts(EdgeId EId, const Matrix& NewCosts) { |
||
329 | NodeId N1Id = G.getEdgeNode1Id(EId); |
||
330 | NodeId N2Id = G.getEdgeNode2Id(EId); |
||
331 | NodeMetadata& N1Md = G.getNodeMetadata(N1Id); |
||
332 | NodeMetadata& N2Md = G.getNodeMetadata(N2Id); |
||
333 | bool Transpose = N1Id != G.getEdgeNode1Id(EId); |
||
334 | |||
335 | // Metadata are computed incrementally. First, update them |
||
336 | // by removing the old cost. |
||
337 | const MatrixMetadata& OldMMd = G.getEdgeCosts(EId).getMetadata(); |
||
338 | N1Md.handleRemoveEdge(OldMMd, Transpose); |
||
339 | N2Md.handleRemoveEdge(OldMMd, !Transpose); |
||
340 | |||
341 | // And update now the metadata with the new cost. |
||
342 | const MatrixMetadata& MMd = NewCosts.getMetadata(); |
||
343 | N1Md.handleAddEdge(MMd, Transpose); |
||
344 | N2Md.handleAddEdge(MMd, !Transpose); |
||
345 | |||
346 | // As the metadata may have changed with the update, the nodes may have |
||
347 | // become ConservativelyAllocatable or OptimallyReducible. |
||
348 | promote(N1Id, N1Md); |
||
349 | promote(N2Id, N2Md); |
||
350 | } |
||
351 | |||
352 | private: |
||
353 | void promote(NodeId NId, NodeMetadata& NMd) { |
||
354 | if (G.getNodeDegree(NId) == 3) { |
||
355 | // This node is becoming optimally reducible. |
||
356 | moveToOptimallyReducibleNodes(NId); |
||
357 | } else if (NMd.getReductionState() == |
||
358 | NodeMetadata::NotProvablyAllocatable && |
||
359 | NMd.isConservativelyAllocatable()) { |
||
360 | // This node just became conservatively allocatable. |
||
361 | moveToConservativelyAllocatableNodes(NId); |
||
362 | } |
||
363 | } |
||
364 | |||
365 | void removeFromCurrentSet(NodeId NId) { |
||
366 | switch (G.getNodeMetadata(NId).getReductionState()) { |
||
367 | case NodeMetadata::Unprocessed: break; |
||
368 | case NodeMetadata::OptimallyReducible: |
||
369 | assert(OptimallyReducibleNodes.find(NId) != |
||
370 | OptimallyReducibleNodes.end() && |
||
371 | "Node not in optimally reducible set."); |
||
372 | OptimallyReducibleNodes.erase(NId); |
||
373 | break; |
||
374 | case NodeMetadata::ConservativelyAllocatable: |
||
375 | assert(ConservativelyAllocatableNodes.find(NId) != |
||
376 | ConservativelyAllocatableNodes.end() && |
||
377 | "Node not in conservatively allocatable set."); |
||
378 | ConservativelyAllocatableNodes.erase(NId); |
||
379 | break; |
||
380 | case NodeMetadata::NotProvablyAllocatable: |
||
381 | assert(NotProvablyAllocatableNodes.find(NId) != |
||
382 | NotProvablyAllocatableNodes.end() && |
||
383 | "Node not in not-provably-allocatable set."); |
||
384 | NotProvablyAllocatableNodes.erase(NId); |
||
385 | break; |
||
386 | } |
||
387 | } |
||
388 | |||
389 | void moveToOptimallyReducibleNodes(NodeId NId) { |
||
390 | removeFromCurrentSet(NId); |
||
391 | OptimallyReducibleNodes.insert(NId); |
||
392 | G.getNodeMetadata(NId).setReductionState( |
||
393 | NodeMetadata::OptimallyReducible); |
||
394 | } |
||
395 | |||
396 | void moveToConservativelyAllocatableNodes(NodeId NId) { |
||
397 | removeFromCurrentSet(NId); |
||
398 | ConservativelyAllocatableNodes.insert(NId); |
||
399 | G.getNodeMetadata(NId).setReductionState( |
||
400 | NodeMetadata::ConservativelyAllocatable); |
||
401 | } |
||
402 | |||
403 | void moveToNotProvablyAllocatableNodes(NodeId NId) { |
||
404 | removeFromCurrentSet(NId); |
||
405 | NotProvablyAllocatableNodes.insert(NId); |
||
406 | G.getNodeMetadata(NId).setReductionState( |
||
407 | NodeMetadata::NotProvablyAllocatable); |
||
408 | } |
||
409 | |||
410 | void setup() { |
||
411 | // Set up worklists. |
||
412 | for (auto NId : G.nodeIds()) { |
||
413 | if (G.getNodeDegree(NId) < 3) |
||
414 | moveToOptimallyReducibleNodes(NId); |
||
415 | else if (G.getNodeMetadata(NId).isConservativelyAllocatable()) |
||
416 | moveToConservativelyAllocatableNodes(NId); |
||
417 | else |
||
418 | moveToNotProvablyAllocatableNodes(NId); |
||
419 | } |
||
420 | } |
||
421 | |||
422 | // Compute a reduction order for the graph by iteratively applying PBQP |
||
423 | // reduction rules. Locally optimal rules are applied whenever possible (R0, |
||
424 | // R1, R2). If no locally-optimal rules apply then any conservatively |
||
425 | // allocatable node is reduced. Finally, if no conservatively allocatable |
||
426 | // node exists then the node with the lowest spill-cost:degree ratio is |
||
427 | // selected. |
||
428 | std::vector<GraphBase::NodeId> reduce() { |
||
429 | assert(!G.empty() && "Cannot reduce empty graph."); |
||
430 | |||
431 | using NodeId = GraphBase::NodeId; |
||
432 | std::vector<NodeId> NodeStack; |
||
433 | |||
434 | // Consume worklists. |
||
435 | while (true) { |
||
436 | if (!OptimallyReducibleNodes.empty()) { |
||
437 | NodeSet::iterator NItr = OptimallyReducibleNodes.begin(); |
||
438 | NodeId NId = *NItr; |
||
439 | OptimallyReducibleNodes.erase(NItr); |
||
440 | NodeStack.push_back(NId); |
||
441 | switch (G.getNodeDegree(NId)) { |
||
442 | case 0: |
||
443 | break; |
||
444 | case 1: |
||
445 | applyR1(G, NId); |
||
446 | break; |
||
447 | case 2: |
||
448 | applyR2(G, NId); |
||
449 | break; |
||
450 | default: llvm_unreachable("Not an optimally reducible node."); |
||
451 | } |
||
452 | } else if (!ConservativelyAllocatableNodes.empty()) { |
||
453 | // Conservatively allocatable nodes will never spill. For now just |
||
454 | // take the first node in the set and push it on the stack. When we |
||
455 | // start optimizing more heavily for register preferencing, it may |
||
456 | // would be better to push nodes with lower 'expected' or worst-case |
||
457 | // register costs first (since early nodes are the most |
||
458 | // constrained). |
||
459 | NodeSet::iterator NItr = ConservativelyAllocatableNodes.begin(); |
||
460 | NodeId NId = *NItr; |
||
461 | ConservativelyAllocatableNodes.erase(NItr); |
||
462 | NodeStack.push_back(NId); |
||
463 | G.disconnectAllNeighborsFromNode(NId); |
||
464 | } else if (!NotProvablyAllocatableNodes.empty()) { |
||
465 | NodeSet::iterator NItr = |
||
466 | std::min_element(NotProvablyAllocatableNodes.begin(), |
||
467 | NotProvablyAllocatableNodes.end(), |
||
468 | SpillCostComparator(G)); |
||
469 | NodeId NId = *NItr; |
||
470 | NotProvablyAllocatableNodes.erase(NItr); |
||
471 | NodeStack.push_back(NId); |
||
472 | G.disconnectAllNeighborsFromNode(NId); |
||
473 | } else |
||
474 | break; |
||
475 | } |
||
476 | |||
477 | return NodeStack; |
||
478 | } |
||
479 | |||
480 | class SpillCostComparator { |
||
481 | public: |
||
482 | SpillCostComparator(const Graph& G) : G(G) {} |
||
483 | |||
484 | bool operator()(NodeId N1Id, NodeId N2Id) { |
||
485 | PBQPNum N1SC = G.getNodeCosts(N1Id)[0]; |
||
486 | PBQPNum N2SC = G.getNodeCosts(N2Id)[0]; |
||
487 | if (N1SC == N2SC) |
||
488 | return G.getNodeDegree(N1Id) < G.getNodeDegree(N2Id); |
||
489 | return N1SC < N2SC; |
||
490 | } |
||
491 | |||
492 | private: |
||
493 | const Graph& G; |
||
494 | }; |
||
495 | |||
496 | Graph& G; |
||
497 | using NodeSet = std::set<NodeId>; |
||
498 | NodeSet OptimallyReducibleNodes; |
||
499 | NodeSet ConservativelyAllocatableNodes; |
||
500 | NodeSet NotProvablyAllocatableNodes; |
||
501 | }; |
||
502 | |||
503 | class PBQPRAGraph : public PBQP::Graph<RegAllocSolverImpl> { |
||
504 | private: |
||
505 | using BaseT = PBQP::Graph<RegAllocSolverImpl>; |
||
506 | |||
507 | public: |
||
508 | PBQPRAGraph(GraphMetadata Metadata) : BaseT(std::move(Metadata)) {} |
||
509 | |||
510 | /// Dump this graph to dbgs(). |
||
511 | void dump() const; |
||
512 | |||
513 | /// Dump this graph to an output stream. |
||
514 | /// @param OS Output stream to print on. |
||
515 | void dump(raw_ostream &OS) const; |
||
516 | |||
517 | /// Print a representation of this graph in DOT format. |
||
518 | /// @param OS Output stream to print on. |
||
519 | void printDot(raw_ostream &OS) const; |
||
520 | }; |
||
521 | |||
522 | inline Solution solve(PBQPRAGraph& G) { |
||
523 | if (G.empty()) |
||
524 | return Solution(); |
||
525 | RegAllocSolverImpl RegAllocSolver(G); |
||
526 | return RegAllocSolver.solve(); |
||
527 | } |
||
528 | |||
529 | } // end namespace RegAlloc |
||
530 | } // end namespace PBQP |
||
531 | |||
532 | /// Create a PBQP register allocator instance. |
||
533 | FunctionPass * |
||
534 | createPBQPRegisterAllocator(char *customPassID = nullptr); |
||
535 | |||
536 | } // end namespace llvm |
||
537 | |||
538 | #endif // LLVM_CODEGEN_REGALLOCPBQP_H |