Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

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