LLVM  8.0.1
GCNMinRegStrategy.cpp
Go to the documentation of this file.
1 //===- GCNMinRegStrategy.cpp ----------------------------------------------===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "llvm/ADT/ArrayRef.h"
11 #include "llvm/ADT/SmallPtrSet.h"
12 #include "llvm/ADT/SmallVector.h"
13 #include "llvm/ADT/ilist_node.h"
14 #include "llvm/ADT/simple_ilist.h"
16 #include "llvm/Support/Allocator.h"
17 #include "llvm/Support/Debug.h"
19 #include <cassert>
20 #include <cstdint>
21 #include <limits>
22 #include <vector>
23 
24 using namespace llvm;
25 
26 #define DEBUG_TYPE "machine-scheduler"
27 
28 namespace {
29 
30 class GCNMinRegScheduler {
31  struct Candidate : ilist_node<Candidate> {
32  const SUnit *SU;
33  int Priority;
34 
35  Candidate(const SUnit *SU_, int Priority_ = 0)
36  : SU(SU_), Priority(Priority_) {}
37  };
38 
40  using Queue = simple_ilist<Candidate>;
41  Queue RQ; // Ready queue
42 
43  std::vector<unsigned> NumPreds;
44 
45  bool isScheduled(const SUnit *SU) const {
46  assert(!SU->isBoundaryNode());
47  return NumPreds[SU->NodeNum] == std::numeric_limits<unsigned>::max();
48  }
49 
50  void setIsScheduled(const SUnit *SU) {
51  assert(!SU->isBoundaryNode());
53  }
54 
55  unsigned getNumPreds(const SUnit *SU) const {
56  assert(!SU->isBoundaryNode());
58  return NumPreds[SU->NodeNum];
59  }
60 
61  unsigned decNumPreds(const SUnit *SU) {
62  assert(!SU->isBoundaryNode());
64  return --NumPreds[SU->NodeNum];
65  }
66 
67  void initNumPreds(const decltype(ScheduleDAG::SUnits) &SUnits);
68 
69  int getReadySuccessors(const SUnit *SU) const;
70  int getNotReadySuccessors(const SUnit *SU) const;
71 
72  template <typename Calc>
73  unsigned findMax(unsigned Num, Calc C);
74 
75  Candidate* pickCandidate();
76 
77  void bumpPredsPriority(const SUnit *SchedSU, int Priority);
78  void releaseSuccessors(const SUnit* SU, int Priority);
79 
80 public:
81  std::vector<const SUnit*> schedule(ArrayRef<const SUnit*> TopRoots,
82  const ScheduleDAG &DAG);
83 };
84 
85 } // end anonymous namespace
86 
87 void GCNMinRegScheduler::initNumPreds(const decltype(ScheduleDAG::SUnits) &SUnits) {
88  NumPreds.resize(SUnits.size());
89  for (unsigned I = 0; I < SUnits.size(); ++I)
90  NumPreds[I] = SUnits[I].NumPredsLeft;
91 }
92 
93 int GCNMinRegScheduler::getReadySuccessors(const SUnit *SU) const {
94  unsigned NumSchedSuccs = 0;
95  for (auto SDep : SU->Succs) {
96  bool wouldBeScheduled = true;
97  for (auto PDep : SDep.getSUnit()->Preds) {
98  auto PSU = PDep.getSUnit();
99  assert(!PSU->isBoundaryNode());
100  if (PSU != SU && !isScheduled(PSU)) {
101  wouldBeScheduled = false;
102  break;
103  }
104  }
105  NumSchedSuccs += wouldBeScheduled ? 1 : 0;
106  }
107  return NumSchedSuccs;
108 }
109 
110 int GCNMinRegScheduler::getNotReadySuccessors(const SUnit *SU) const {
111  return SU->Succs.size() - getReadySuccessors(SU);
112 }
113 
114 template <typename Calc>
115 unsigned GCNMinRegScheduler::findMax(unsigned Num, Calc C) {
116  assert(!RQ.empty() && Num <= RQ.size());
117 
118  using T = decltype(C(*RQ.begin())) ;
119 
120  T Max = std::numeric_limits<T>::min();
121  unsigned NumMax = 0;
122  for (auto I = RQ.begin(); Num; --Num) {
123  T Cur = C(*I);
124  if (Cur >= Max) {
125  if (Cur > Max) {
126  Max = Cur;
127  NumMax = 1;
128  } else
129  ++NumMax;
130  auto &Cand = *I++;
131  RQ.remove(Cand);
132  RQ.push_front(Cand);
133  continue;
134  }
135  ++I;
136  }
137  return NumMax;
138 }
139 
140 GCNMinRegScheduler::Candidate* GCNMinRegScheduler::pickCandidate() {
141  do {
142  unsigned Num = RQ.size();
143  if (Num == 1) break;
144 
145  LLVM_DEBUG(dbgs() << "\nSelecting max priority candidates among " << Num
146  << '\n');
147  Num = findMax(Num, [=](const Candidate &C) { return C.Priority; });
148  if (Num == 1) break;
149 
150  LLVM_DEBUG(dbgs() << "\nSelecting min non-ready producing candidate among "
151  << Num << '\n');
152  Num = findMax(Num, [=](const Candidate &C) {
153  auto SU = C.SU;
154  int Res = getNotReadySuccessors(SU);
155  LLVM_DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would left non-ready "
156  << Res << " successors, metric = " << -Res << '\n');
157  return -Res;
158  });
159  if (Num == 1) break;
160 
161  LLVM_DEBUG(dbgs() << "\nSelecting most producing candidate among " << Num
162  << '\n');
163  Num = findMax(Num, [=](const Candidate &C) {
164  auto SU = C.SU;
165  auto Res = getReadySuccessors(SU);
166  LLVM_DEBUG(dbgs() << "SU(" << SU->NodeNum << ") would make ready " << Res
167  << " successors, metric = " << Res << '\n');
168  return Res;
169  });
170  if (Num == 1) break;
171 
172  Num = Num ? Num : RQ.size();
173  LLVM_DEBUG(
174  dbgs()
175  << "\nCan't find best candidate, selecting in program order among "
176  << Num << '\n');
177  Num = findMax(Num, [=](const Candidate &C) { return -(int64_t)C.SU->NodeNum; });
178  assert(Num == 1);
179  } while (false);
180 
181  return &RQ.front();
182 }
183 
184 void GCNMinRegScheduler::bumpPredsPriority(const SUnit *SchedSU, int Priority) {
186  for (const auto &S : SchedSU->Succs) {
187  if (S.getSUnit()->isBoundaryNode() || isScheduled(S.getSUnit()) ||
188  S.getKind() != SDep::Data)
189  continue;
190  for (const auto &P : S.getSUnit()->Preds) {
191  auto PSU = P.getSUnit();
192  assert(!PSU->isBoundaryNode());
193  if (PSU != SchedSU && !isScheduled(PSU)) {
194  Set.insert(PSU);
195  }
196  }
197  }
198  SmallVector<const SUnit*, 32> Worklist(Set.begin(), Set.end());
199  while (!Worklist.empty()) {
200  auto SU = Worklist.pop_back_val();
201  assert(!SU->isBoundaryNode());
202  for (const auto &P : SU->Preds) {
203  if (!P.getSUnit()->isBoundaryNode() && !isScheduled(P.getSUnit()) &&
204  Set.insert(P.getSUnit()).second)
205  Worklist.push_back(P.getSUnit());
206  }
207  }
208  LLVM_DEBUG(dbgs() << "Make the predecessors of SU(" << SchedSU->NodeNum
209  << ")'s non-ready successors of " << Priority
210  << " priority in ready queue: ");
211  const auto SetEnd = Set.end();
212  for (auto &C : RQ) {
213  if (Set.find(C.SU) != SetEnd) {
214  C.Priority = Priority;
215  LLVM_DEBUG(dbgs() << " SU(" << C.SU->NodeNum << ')');
216  }
217  }
218  LLVM_DEBUG(dbgs() << '\n');
219 }
220 
221 void GCNMinRegScheduler::releaseSuccessors(const SUnit* SU, int Priority) {
222  for (const auto &S : SU->Succs) {
223  auto SuccSU = S.getSUnit();
224  if (S.isWeak())
225  continue;
226  assert(SuccSU->isBoundaryNode() || getNumPreds(SuccSU) > 0);
227  if (!SuccSU->isBoundaryNode() && decNumPreds(SuccSU) == 0)
228  RQ.push_front(*new (Alloc.Allocate()) Candidate(SuccSU, Priority));
229  }
230 }
231 
232 std::vector<const SUnit*>
233 GCNMinRegScheduler::schedule(ArrayRef<const SUnit*> TopRoots,
234  const ScheduleDAG &DAG) {
235  const auto &SUnits = DAG.SUnits;
236  std::vector<const SUnit*> Schedule;
237  Schedule.reserve(SUnits.size());
238 
239  initNumPreds(SUnits);
240 
241  int StepNo = 0;
242 
243  for (auto SU : TopRoots) {
244  RQ.push_back(*new (Alloc.Allocate()) Candidate(SU, StepNo));
245  }
246  releaseSuccessors(&DAG.EntrySU, StepNo);
247 
248  while (!RQ.empty()) {
249  LLVM_DEBUG(dbgs() << "\n=== Picking candidate, Step = " << StepNo
250  << "\n"
251  "Ready queue:";
252  for (auto &C
253  : RQ) dbgs()
254  << ' ' << C.SU->NodeNum << "(P" << C.Priority << ')';
255  dbgs() << '\n';);
256 
257  auto C = pickCandidate();
258  assert(C);
259  RQ.remove(*C);
260  auto SU = C->SU;
261  LLVM_DEBUG(dbgs() << "Selected "; DAG.dumpNode(*SU));
262 
263  releaseSuccessors(SU, StepNo);
264  Schedule.push_back(SU);
265  setIsScheduled(SU);
266 
267  if (getReadySuccessors(SU) == 0)
268  bumpPredsPriority(SU, StepNo);
269 
270  ++StepNo;
271  }
272  assert(SUnits.size() == Schedule.size());
273 
274  return Schedule;
275 }
276 
277 namespace llvm {
278 
279 std::vector<const SUnit*> makeMinRegSchedule(ArrayRef<const SUnit*> TopRoots,
280  const ScheduleDAG &DAG) {
281  GCNMinRegScheduler S;
282  return S.schedule(TopRoots, DAG);
283 }
284 
285 } // end namespace llvm
uint64_t CallInst * C
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
This class represents lattice values for constants.
Definition: AllocatorList.h:24
virtual void dumpNode(const SUnit &SU) const =0
unsigned second
SmallVector< SDep, 4 > Preds
All sunit predecessors.
Definition: ScheduleDAG.h:260
This file defines the MallocAllocator and BumpPtrAllocator interfaces.
iterator find(ConstPtrType Ptr) const
Definition: SmallPtrSet.h:383
Regular data dependence (aka true-dependence).
Definition: ScheduleDAG.h:54
A simple intrusive list implementation.
Definition: simple_ilist.h:79
std::vector< const SUnit * > makeMinRegSchedule(ArrayRef< const SUnit *> TopRoots, const ScheduleDAG &DAG)
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory)...
Definition: APInt.h:33
SUnit * getSUnit() const
Definition: ScheduleDAG.h:484
bool isBoundaryNode() const
Boundary nodes are placeholders for the boundary of the scheduling region.
Definition: ScheduleDAG.h:348
Scheduling dependency.
Definition: ScheduleDAG.h:50
#define P(N)
LLVM_ATTRIBUTE_RETURNS_NONNULL LLVM_ATTRIBUTE_RETURNS_NOALIAS void * Allocate(size_t Size, size_t Alignment)
Allocate space at the specified alignment.
Definition: Allocator.h:215
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
Definition: SmallPtrSet.h:371
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
Definition: SmallPtrSet.h:418
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:847
A BumpPtrAllocator that allows only elements of a specific type to be allocated.
Definition: Allocator.h:442
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:133
SUnit EntrySU
Special node for the region entry.
Definition: ScheduleDAG.h:567
iterator begin() const
Definition: SmallPtrSet.h:397
#define I(x, y, z)
Definition: MD5.cpp:58
iterator end() const
Definition: SmallPtrSet.h:402
unsigned NodeNum
Entry # of node in the node vector.
Definition: ScheduleDAG.h:268
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
SmallVector< SDep, 4 > Succs
All sunit successors.
Definition: ScheduleDAG.h:261
std::vector< SUnit > SUnits
The scheduling units.
Definition: ScheduleDAG.h:566
#define LLVM_DEBUG(X)
Definition: Debug.h:123
Scheduling unit. This is a node in the scheduling DAG.
Definition: ScheduleDAG.h:246