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 |