1d88c1a5aSDimitry Andric //===-- GCNSchedStrategy.cpp - GCN Scheduler Strategy ---------------------===//
2d88c1a5aSDimitry Andric //
3d88c1a5aSDimitry Andric //                     The LLVM Compiler Infrastructure
4d88c1a5aSDimitry Andric //
5d88c1a5aSDimitry Andric // This file is distributed under the University of Illinois Open Source
6d88c1a5aSDimitry Andric // License. See LICENSE.TXT for details.
7d88c1a5aSDimitry Andric //
8d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
9d88c1a5aSDimitry Andric //
10d88c1a5aSDimitry Andric /// \file
11d88c1a5aSDimitry Andric /// This contains a MachineSchedStrategy implementation for maximizing wave
12d88c1a5aSDimitry Andric /// occupancy on GCN hardware.
13d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
14d88c1a5aSDimitry Andric 
15d88c1a5aSDimitry Andric #include "GCNSchedStrategy.h"
16d88c1a5aSDimitry Andric #include "AMDGPUSubtarget.h"
17d88c1a5aSDimitry Andric #include "SIInstrInfo.h"
18d88c1a5aSDimitry Andric #include "SIMachineFunctionInfo.h"
19d88c1a5aSDimitry Andric #include "SIRegisterInfo.h"
20d88c1a5aSDimitry Andric #include "llvm/CodeGen/RegisterClassInfo.h"
21d88c1a5aSDimitry Andric 
22d88c1a5aSDimitry Andric #define DEBUG_TYPE "misched"
23d88c1a5aSDimitry Andric 
24d88c1a5aSDimitry Andric using namespace llvm;
25d88c1a5aSDimitry Andric 
26d88c1a5aSDimitry Andric GCNMaxOccupancySchedStrategy::GCNMaxOccupancySchedStrategy(
27d88c1a5aSDimitry Andric     const MachineSchedContext *C) :
28d88c1a5aSDimitry Andric     GenericScheduler(C) { }
29d88c1a5aSDimitry Andric 
30d88c1a5aSDimitry Andric static unsigned getMaxWaves(unsigned SGPRs, unsigned VGPRs,
31d88c1a5aSDimitry Andric                             const MachineFunction &MF) {
32d88c1a5aSDimitry Andric 
33d88c1a5aSDimitry Andric   const SISubtarget &ST = MF.getSubtarget<SISubtarget>();
34d88c1a5aSDimitry Andric   const SIMachineFunctionInfo *MFI = MF.getInfo<SIMachineFunctionInfo>();
35d88c1a5aSDimitry Andric   unsigned MinRegOccupancy = std::min(ST.getOccupancyWithNumSGPRs(SGPRs),
36d88c1a5aSDimitry Andric                                       ST.getOccupancyWithNumVGPRs(VGPRs));
37d88c1a5aSDimitry Andric   return std::min(MinRegOccupancy,
38d88c1a5aSDimitry Andric                   ST.getOccupancyWithLocalMemSize(MFI->getLDSSize()));
39d88c1a5aSDimitry Andric }
40d88c1a5aSDimitry Andric 
41d88c1a5aSDimitry Andric void GCNMaxOccupancySchedStrategy::initCandidate(SchedCandidate &Cand, SUnit *SU,
42d88c1a5aSDimitry Andric                                      bool AtTop, const RegPressureTracker &RPTracker,
43d88c1a5aSDimitry Andric                                      const SIRegisterInfo *SRI,
44d88c1a5aSDimitry Andric                                      int SGPRPressure,
45d88c1a5aSDimitry Andric                                      int VGPRPressure,
46d88c1a5aSDimitry Andric                                      int SGPRExcessLimit,
47d88c1a5aSDimitry Andric                                      int VGPRExcessLimit,
48d88c1a5aSDimitry Andric                                      int SGPRCriticalLimit,
49d88c1a5aSDimitry Andric                                      int VGPRCriticalLimit) {
50d88c1a5aSDimitry Andric 
51d88c1a5aSDimitry Andric   Cand.SU = SU;
52d88c1a5aSDimitry Andric   Cand.AtTop = AtTop;
53d88c1a5aSDimitry Andric 
54d88c1a5aSDimitry Andric   // getDownwardPressure() and getUpwardPressure() make temporary changes to
55d88c1a5aSDimitry Andric   // the the tracker, so we need to pass those function a non-const copy.
56d88c1a5aSDimitry Andric   RegPressureTracker &TempTracker = const_cast<RegPressureTracker&>(RPTracker);
57d88c1a5aSDimitry Andric 
58d88c1a5aSDimitry Andric   std::vector<unsigned> Pressure;
59d88c1a5aSDimitry Andric   std::vector<unsigned> MaxPressure;
60d88c1a5aSDimitry Andric 
61d88c1a5aSDimitry Andric   if (AtTop)
62d88c1a5aSDimitry Andric     TempTracker.getDownwardPressure(SU->getInstr(), Pressure, MaxPressure);
63d88c1a5aSDimitry Andric   else {
64d88c1a5aSDimitry Andric     // FIXME: I think for bottom up scheduling, the register pressure is cached
65d88c1a5aSDimitry Andric     // and can be retrieved by DAG->getPressureDif(SU).
66d88c1a5aSDimitry Andric     TempTracker.getUpwardPressure(SU->getInstr(), Pressure, MaxPressure);
67d88c1a5aSDimitry Andric   }
68d88c1a5aSDimitry Andric 
69d88c1a5aSDimitry Andric   int NewSGPRPressure = Pressure[SRI->getSGPRPressureSet()];
70d88c1a5aSDimitry Andric   int NewVGPRPressure = Pressure[SRI->getVGPRPressureSet()];
71d88c1a5aSDimitry Andric 
72d88c1a5aSDimitry Andric   // If two instructions increase the pressure of different register sets
73d88c1a5aSDimitry Andric   // by the same amount, the generic scheduler will prefer to schedule the
74d88c1a5aSDimitry Andric   // instruction that increases the set with the least amount of registers,
75d88c1a5aSDimitry Andric   // which in our case would be SGPRs.  This is rarely what we want, so
76d88c1a5aSDimitry Andric   // when we report excess/critical register pressure, we do it either
77d88c1a5aSDimitry Andric   // only for VGPRs or only for SGPRs.
78d88c1a5aSDimitry Andric 
79d88c1a5aSDimitry Andric   // FIXME: Better heuristics to determine whether to prefer SGPRs or VGPRs.
80d88c1a5aSDimitry Andric   const int MaxVGPRPressureInc = 16;
81d88c1a5aSDimitry Andric   bool ShouldTrackVGPRs = VGPRPressure + MaxVGPRPressureInc >= VGPRExcessLimit;
82d88c1a5aSDimitry Andric   bool ShouldTrackSGPRs = !ShouldTrackVGPRs && SGPRPressure >= SGPRExcessLimit;
83d88c1a5aSDimitry Andric 
84d88c1a5aSDimitry Andric 
85d88c1a5aSDimitry Andric   // FIXME: We have to enter REG-EXCESS before we reach the actual threshold
86d88c1a5aSDimitry Andric   // to increase the likelihood we don't go over the limits.  We should improve
87d88c1a5aSDimitry Andric   // the analysis to look through dependencies to find the path with the least
88d88c1a5aSDimitry Andric   // register pressure.
89d88c1a5aSDimitry Andric   // FIXME: This is also necessary, because some passes that run after
90d88c1a5aSDimitry Andric   // scheduling and before regalloc increase register pressure.
91d88c1a5aSDimitry Andric   const int ErrorMargin = 3;
92d88c1a5aSDimitry Andric   VGPRExcessLimit -= ErrorMargin;
93d88c1a5aSDimitry Andric   SGPRExcessLimit -= ErrorMargin;
94d88c1a5aSDimitry Andric 
95d88c1a5aSDimitry Andric   // We only need to update the RPDelata for instructions that increase
96d88c1a5aSDimitry Andric   // register pressure.  Instructions that decrease or keep reg pressure
97d88c1a5aSDimitry Andric   // the same will be marked as RegExcess in tryCandidate() when they
98d88c1a5aSDimitry Andric   // are compared with instructions that increase the register pressure.
99d88c1a5aSDimitry Andric   if (ShouldTrackVGPRs && NewVGPRPressure >= VGPRExcessLimit) {
100d88c1a5aSDimitry Andric     Cand.RPDelta.Excess = PressureChange(SRI->getVGPRPressureSet());
101d88c1a5aSDimitry Andric     Cand.RPDelta.Excess.setUnitInc(NewVGPRPressure - VGPRExcessLimit);
102d88c1a5aSDimitry Andric   }
103d88c1a5aSDimitry Andric 
104d88c1a5aSDimitry Andric   if (ShouldTrackSGPRs && NewSGPRPressure >= SGPRExcessLimit) {
105d88c1a5aSDimitry Andric     Cand.RPDelta.Excess = PressureChange(SRI->getSGPRPressureSet());
106d88c1a5aSDimitry Andric     Cand.RPDelta.Excess.setUnitInc(NewSGPRPressure = SGPRExcessLimit);
107d88c1a5aSDimitry Andric   }
108d88c1a5aSDimitry Andric 
109d88c1a5aSDimitry Andric   // Register pressure is considered 'CRITICAL' if it is approaching a value
110d88c1a5aSDimitry Andric   // that would reduce the wave occupancy for the execution unit.  When
111d88c1a5aSDimitry Andric   // register pressure is 'CRITICAL', increading SGPR and VGPR pressure both
112d88c1a5aSDimitry Andric   // has the same cost, so we don't need to prefer one over the other.
113d88c1a5aSDimitry Andric 
114d88c1a5aSDimitry Andric   VGPRCriticalLimit -= ErrorMargin;
115d88c1a5aSDimitry Andric   SGPRCriticalLimit -= ErrorMargin;
116d88c1a5aSDimitry Andric 
117d88c1a5aSDimitry Andric   int SGPRDelta = NewSGPRPressure - SGPRCriticalLimit;
118d88c1a5aSDimitry Andric   int VGPRDelta = NewVGPRPressure - VGPRCriticalLimit;
119d88c1a5aSDimitry Andric 
120d88c1a5aSDimitry Andric   if (SGPRDelta >= 0 || VGPRDelta >= 0) {
121d88c1a5aSDimitry Andric     if (SGPRDelta > VGPRDelta) {
122d88c1a5aSDimitry Andric       Cand.RPDelta.CriticalMax = PressureChange(SRI->getSGPRPressureSet());
123d88c1a5aSDimitry Andric       Cand.RPDelta.CriticalMax.setUnitInc(SGPRDelta);
124d88c1a5aSDimitry Andric     } else {
125d88c1a5aSDimitry Andric       Cand.RPDelta.CriticalMax = PressureChange(SRI->getVGPRPressureSet());
126d88c1a5aSDimitry Andric       Cand.RPDelta.CriticalMax.setUnitInc(VGPRDelta);
127d88c1a5aSDimitry Andric     }
128d88c1a5aSDimitry Andric   }
129d88c1a5aSDimitry Andric }
130d88c1a5aSDimitry Andric 
131d88c1a5aSDimitry Andric // This function is mostly cut and pasted from
132d88c1a5aSDimitry Andric // GenericScheduler::pickNodeFromQueue()
133d88c1a5aSDimitry Andric void GCNMaxOccupancySchedStrategy::pickNodeFromQueue(SchedBoundary &Zone,
134d88c1a5aSDimitry Andric                                          const CandPolicy &ZonePolicy,
135d88c1a5aSDimitry Andric                                          const RegPressureTracker &RPTracker,
136d88c1a5aSDimitry Andric                                          SchedCandidate &Cand) {
137d88c1a5aSDimitry Andric   const SISubtarget &ST = DAG->MF.getSubtarget<SISubtarget>();
138d88c1a5aSDimitry Andric   const SIRegisterInfo *SRI = static_cast<const SIRegisterInfo*>(TRI);
139d88c1a5aSDimitry Andric   ArrayRef<unsigned> Pressure = RPTracker.getRegSetPressureAtPos();
140d88c1a5aSDimitry Andric   unsigned SGPRPressure = Pressure[SRI->getSGPRPressureSet()];
141d88c1a5aSDimitry Andric   unsigned VGPRPressure = Pressure[SRI->getVGPRPressureSet()];
142d88c1a5aSDimitry Andric   unsigned SGPRExcessLimit =
143d88c1a5aSDimitry Andric       Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::SGPR_32RegClass);
144d88c1a5aSDimitry Andric   unsigned VGPRExcessLimit =
145d88c1a5aSDimitry Andric       Context->RegClassInfo->getNumAllocatableRegs(&AMDGPU::VGPR_32RegClass);
146d88c1a5aSDimitry Andric   unsigned MaxWaves = getMaxWaves(SGPRPressure, VGPRPressure, DAG->MF);
147d88c1a5aSDimitry Andric   unsigned SGPRCriticalLimit = SRI->getMaxNumSGPRs(ST, MaxWaves, true);
148d88c1a5aSDimitry Andric   unsigned VGPRCriticalLimit = SRI->getMaxNumVGPRs(MaxWaves);
149d88c1a5aSDimitry Andric 
150d88c1a5aSDimitry Andric   ReadyQueue &Q = Zone.Available;
151d88c1a5aSDimitry Andric   for (SUnit *SU : Q) {
152d88c1a5aSDimitry Andric 
153d88c1a5aSDimitry Andric     SchedCandidate TryCand(ZonePolicy);
154d88c1a5aSDimitry Andric     initCandidate(TryCand, SU, Zone.isTop(), RPTracker, SRI,
155d88c1a5aSDimitry Andric                   SGPRPressure, VGPRPressure,
156d88c1a5aSDimitry Andric                   SGPRExcessLimit, VGPRExcessLimit,
157d88c1a5aSDimitry Andric                   SGPRCriticalLimit, VGPRCriticalLimit);
158d88c1a5aSDimitry Andric     // Pass SchedBoundary only when comparing nodes from the same boundary.
159d88c1a5aSDimitry Andric     SchedBoundary *ZoneArg = Cand.AtTop == TryCand.AtTop ? &Zone : nullptr;
160d88c1a5aSDimitry Andric     GenericScheduler::tryCandidate(Cand, TryCand, ZoneArg);
161d88c1a5aSDimitry Andric     if (TryCand.Reason != NoCand) {
162d88c1a5aSDimitry Andric       // Initialize resource delta if needed in case future heuristics query it.
163d88c1a5aSDimitry Andric       if (TryCand.ResDelta == SchedResourceDelta())
164d88c1a5aSDimitry Andric         TryCand.initResourceDelta(Zone.DAG, SchedModel);
165d88c1a5aSDimitry Andric       Cand.setBest(TryCand);
166d88c1a5aSDimitry Andric     }
167d88c1a5aSDimitry Andric   }
168d88c1a5aSDimitry Andric }
169d88c1a5aSDimitry Andric 
170d88c1a5aSDimitry Andric static int getBidirectionalReasonRank(GenericSchedulerBase::CandReason Reason) {
171d88c1a5aSDimitry Andric   switch (Reason) {
172d88c1a5aSDimitry Andric   default:
173d88c1a5aSDimitry Andric     return Reason;
174d88c1a5aSDimitry Andric   case GenericSchedulerBase::RegCritical:
175d88c1a5aSDimitry Andric   case GenericSchedulerBase::RegExcess:
176d88c1a5aSDimitry Andric     return -Reason;
177d88c1a5aSDimitry Andric  }
178d88c1a5aSDimitry Andric }
179d88c1a5aSDimitry Andric 
180d88c1a5aSDimitry Andric // This function is mostly cut and pasted from
181d88c1a5aSDimitry Andric // GenericScheduler::pickNodeBidirectional()
182d88c1a5aSDimitry Andric SUnit *GCNMaxOccupancySchedStrategy::pickNodeBidirectional(bool &IsTopNode) {
183d88c1a5aSDimitry Andric   // Schedule as far as possible in the direction of no choice. This is most
184d88c1a5aSDimitry Andric   // efficient, but also provides the best heuristics for CriticalPSets.
185d88c1a5aSDimitry Andric   if (SUnit *SU = Bot.pickOnlyChoice()) {
186d88c1a5aSDimitry Andric     IsTopNode = false;
187d88c1a5aSDimitry Andric     return SU;
188d88c1a5aSDimitry Andric   }
189d88c1a5aSDimitry Andric   if (SUnit *SU = Top.pickOnlyChoice()) {
190d88c1a5aSDimitry Andric     IsTopNode = true;
191d88c1a5aSDimitry Andric     return SU;
192d88c1a5aSDimitry Andric   }
193d88c1a5aSDimitry Andric   // Set the bottom-up policy based on the state of the current bottom zone and
194d88c1a5aSDimitry Andric   // the instructions outside the zone, including the top zone.
195d88c1a5aSDimitry Andric   CandPolicy BotPolicy;
196d88c1a5aSDimitry Andric   setPolicy(BotPolicy, /*IsPostRA=*/false, Bot, &Top);
197d88c1a5aSDimitry Andric   // Set the top-down policy based on the state of the current top zone and
198d88c1a5aSDimitry Andric   // the instructions outside the zone, including the bottom zone.
199d88c1a5aSDimitry Andric   CandPolicy TopPolicy;
200d88c1a5aSDimitry Andric   setPolicy(TopPolicy, /*IsPostRA=*/false, Top, &Bot);
201d88c1a5aSDimitry Andric 
202d88c1a5aSDimitry Andric   // See if BotCand is still valid (because we previously scheduled from Top).
203d88c1a5aSDimitry Andric   DEBUG(dbgs() << "Picking from Bot:\n");
204d88c1a5aSDimitry Andric   if (!BotCand.isValid() || BotCand.SU->isScheduled ||
205d88c1a5aSDimitry Andric       BotCand.Policy != BotPolicy) {
206d88c1a5aSDimitry Andric     BotCand.reset(CandPolicy());
207d88c1a5aSDimitry Andric     pickNodeFromQueue(Bot, BotPolicy, DAG->getBotRPTracker(), BotCand);
208d88c1a5aSDimitry Andric     assert(BotCand.Reason != NoCand && "failed to find the first candidate");
209d88c1a5aSDimitry Andric   } else {
210d88c1a5aSDimitry Andric     DEBUG(traceCandidate(BotCand));
211d88c1a5aSDimitry Andric   }
212d88c1a5aSDimitry Andric 
213d88c1a5aSDimitry Andric   // Check if the top Q has a better candidate.
214d88c1a5aSDimitry Andric   DEBUG(dbgs() << "Picking from Top:\n");
215d88c1a5aSDimitry Andric   if (!TopCand.isValid() || TopCand.SU->isScheduled ||
216d88c1a5aSDimitry Andric       TopCand.Policy != TopPolicy) {
217d88c1a5aSDimitry Andric     TopCand.reset(CandPolicy());
218d88c1a5aSDimitry Andric     pickNodeFromQueue(Top, TopPolicy, DAG->getTopRPTracker(), TopCand);
219d88c1a5aSDimitry Andric     assert(TopCand.Reason != NoCand && "failed to find the first candidate");
220d88c1a5aSDimitry Andric   } else {
221d88c1a5aSDimitry Andric     DEBUG(traceCandidate(TopCand));
222d88c1a5aSDimitry Andric   }
223d88c1a5aSDimitry Andric 
224d88c1a5aSDimitry Andric   // Pick best from BotCand and TopCand.
225d88c1a5aSDimitry Andric   DEBUG(
226d88c1a5aSDimitry Andric     dbgs() << "Top Cand: ";
227d88c1a5aSDimitry Andric     traceCandidate(BotCand);
228d88c1a5aSDimitry Andric     dbgs() << "Bot Cand: ";
229d88c1a5aSDimitry Andric     traceCandidate(TopCand);
230d88c1a5aSDimitry Andric   );
231d88c1a5aSDimitry Andric   SchedCandidate Cand;
232d88c1a5aSDimitry Andric   if (TopCand.Reason == BotCand.Reason) {
233d88c1a5aSDimitry Andric     Cand = BotCand;
234d88c1a5aSDimitry Andric     GenericSchedulerBase::CandReason TopReason = TopCand.Reason;
235d88c1a5aSDimitry Andric     TopCand.Reason = NoCand;
236d88c1a5aSDimitry Andric     GenericScheduler::tryCandidate(Cand, TopCand, nullptr);
237d88c1a5aSDimitry Andric     if (TopCand.Reason != NoCand) {
238d88c1a5aSDimitry Andric       Cand.setBest(TopCand);
239d88c1a5aSDimitry Andric     } else {
240d88c1a5aSDimitry Andric       TopCand.Reason = TopReason;
241d88c1a5aSDimitry Andric     }
242d88c1a5aSDimitry Andric   } else {
243d88c1a5aSDimitry Andric     if (TopCand.Reason == RegExcess && TopCand.RPDelta.Excess.getUnitInc() <= 0) {
244d88c1a5aSDimitry Andric       Cand = TopCand;
245d88c1a5aSDimitry Andric     } else if (BotCand.Reason == RegExcess && BotCand.RPDelta.Excess.getUnitInc() <= 0) {
246d88c1a5aSDimitry Andric       Cand = BotCand;
247d88c1a5aSDimitry Andric     } else if (TopCand.Reason == RegCritical && TopCand.RPDelta.CriticalMax.getUnitInc() <= 0) {
248d88c1a5aSDimitry Andric       Cand = TopCand;
249d88c1a5aSDimitry Andric     } else if (BotCand.Reason == RegCritical && BotCand.RPDelta.CriticalMax.getUnitInc() <= 0) {
250d88c1a5aSDimitry Andric       Cand = BotCand;
251d88c1a5aSDimitry Andric     } else {
252d88c1a5aSDimitry Andric       int TopRank = getBidirectionalReasonRank(TopCand.Reason);
253d88c1a5aSDimitry Andric       int BotRank = getBidirectionalReasonRank(BotCand.Reason);
254d88c1a5aSDimitry Andric       if (TopRank > BotRank) {
255d88c1a5aSDimitry Andric         Cand = TopCand;
256d88c1a5aSDimitry Andric       } else {
257d88c1a5aSDimitry Andric         Cand = BotCand;
258d88c1a5aSDimitry Andric       }
259d88c1a5aSDimitry Andric     }
260d88c1a5aSDimitry Andric   }
261d88c1a5aSDimitry Andric   DEBUG(
262d88c1a5aSDimitry Andric     dbgs() << "Picking: ";
263d88c1a5aSDimitry Andric     traceCandidate(Cand);
264d88c1a5aSDimitry Andric   );
265d88c1a5aSDimitry Andric 
266d88c1a5aSDimitry Andric   IsTopNode = Cand.AtTop;
267d88c1a5aSDimitry Andric   return Cand.SU;
268d88c1a5aSDimitry Andric }
269d88c1a5aSDimitry Andric 
270d88c1a5aSDimitry Andric // This function is mostly cut and pasted from
271d88c1a5aSDimitry Andric // GenericScheduler::pickNode()
272d88c1a5aSDimitry Andric SUnit *GCNMaxOccupancySchedStrategy::pickNode(bool &IsTopNode) {
273d88c1a5aSDimitry Andric   if (DAG->top() == DAG->bottom()) {
274d88c1a5aSDimitry Andric     assert(Top.Available.empty() && Top.Pending.empty() &&
275d88c1a5aSDimitry Andric            Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
276d88c1a5aSDimitry Andric     return nullptr;
277d88c1a5aSDimitry Andric   }
278d88c1a5aSDimitry Andric   SUnit *SU;
279d88c1a5aSDimitry Andric   do {
280d88c1a5aSDimitry Andric     if (RegionPolicy.OnlyTopDown) {
281d88c1a5aSDimitry Andric       SU = Top.pickOnlyChoice();
282d88c1a5aSDimitry Andric       if (!SU) {
283d88c1a5aSDimitry Andric         CandPolicy NoPolicy;
284d88c1a5aSDimitry Andric         TopCand.reset(NoPolicy);
285d88c1a5aSDimitry Andric         pickNodeFromQueue(Top, NoPolicy, DAG->getTopRPTracker(), TopCand);
286d88c1a5aSDimitry Andric         assert(TopCand.Reason != NoCand && "failed to find a candidate");
287d88c1a5aSDimitry Andric         SU = TopCand.SU;
288d88c1a5aSDimitry Andric       }
289d88c1a5aSDimitry Andric       IsTopNode = true;
290d88c1a5aSDimitry Andric     } else if (RegionPolicy.OnlyBottomUp) {
291d88c1a5aSDimitry Andric       SU = Bot.pickOnlyChoice();
292d88c1a5aSDimitry Andric       if (!SU) {
293d88c1a5aSDimitry Andric         CandPolicy NoPolicy;
294d88c1a5aSDimitry Andric         BotCand.reset(NoPolicy);
295d88c1a5aSDimitry Andric         pickNodeFromQueue(Bot, NoPolicy, DAG->getBotRPTracker(), BotCand);
296d88c1a5aSDimitry Andric         assert(BotCand.Reason != NoCand && "failed to find a candidate");
297d88c1a5aSDimitry Andric         SU = BotCand.SU;
298d88c1a5aSDimitry Andric       }
299d88c1a5aSDimitry Andric       IsTopNode = false;
300d88c1a5aSDimitry Andric     } else {
301d88c1a5aSDimitry Andric       SU = pickNodeBidirectional(IsTopNode);
302d88c1a5aSDimitry Andric     }
303d88c1a5aSDimitry Andric   } while (SU->isScheduled);
304d88c1a5aSDimitry Andric 
305d88c1a5aSDimitry Andric   if (SU->isTopReady())
306d88c1a5aSDimitry Andric     Top.removeReady(SU);
307d88c1a5aSDimitry Andric   if (SU->isBottomReady())
308d88c1a5aSDimitry Andric     Bot.removeReady(SU);
309d88c1a5aSDimitry Andric 
310d88c1a5aSDimitry Andric   DEBUG(dbgs() << "Scheduling SU(" << SU->NodeNum << ") " << *SU->getInstr());
311d88c1a5aSDimitry Andric   return SU;
312d88c1a5aSDimitry Andric }
313