RegAllocPBQP.h 17 KB

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