xref: /freebsd/contrib/llvm-project/llvm/lib/Target/Hexagon/HexagonMachineScheduler.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //===- HexagonMachineScheduler.cpp - MI Scheduler for Hexagon -------------===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // MachineScheduler schedules machine instructions after phi elimination. It
10*0b57cec5SDimitry Andric // preserves LiveIntervals so it can be invoked before register allocation.
11*0b57cec5SDimitry Andric //
12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
13*0b57cec5SDimitry Andric 
14*0b57cec5SDimitry Andric #include "HexagonMachineScheduler.h"
15*0b57cec5SDimitry Andric #include "HexagonInstrInfo.h"
16*0b57cec5SDimitry Andric #include "HexagonSubtarget.h"
17*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
18*0b57cec5SDimitry Andric #include "llvm/CodeGen/DFAPacketizer.h"
19*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineBasicBlock.h"
20*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h"
21*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineInstr.h"
22*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
23*0b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterClassInfo.h"
24*0b57cec5SDimitry Andric #include "llvm/CodeGen/RegisterPressure.h"
25*0b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h"
26*0b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleHazardRecognizer.h"
27*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
28*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetOpcodes.h"
29*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h"
30*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSchedule.h"
31*0b57cec5SDimitry Andric #include "llvm/CodeGen/TargetSubtargetInfo.h"
32*0b57cec5SDimitry Andric #include "llvm/IR/Function.h"
33*0b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
34*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
35*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
36*0b57cec5SDimitry Andric #include <algorithm>
37*0b57cec5SDimitry Andric #include <cassert>
38*0b57cec5SDimitry Andric #include <iomanip>
39*0b57cec5SDimitry Andric #include <limits>
40*0b57cec5SDimitry Andric #include <memory>
41*0b57cec5SDimitry Andric #include <sstream>
42*0b57cec5SDimitry Andric 
43*0b57cec5SDimitry Andric using namespace llvm;
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler"
46*0b57cec5SDimitry Andric 
47*0b57cec5SDimitry Andric static cl::opt<bool> IgnoreBBRegPressure("ignore-bb-reg-pressure",
48*0b57cec5SDimitry Andric     cl::Hidden, cl::ZeroOrMore, cl::init(false));
49*0b57cec5SDimitry Andric 
50*0b57cec5SDimitry Andric static cl::opt<bool> UseNewerCandidate("use-newer-candidate",
51*0b57cec5SDimitry Andric     cl::Hidden, cl::ZeroOrMore, cl::init(true));
52*0b57cec5SDimitry Andric 
53*0b57cec5SDimitry Andric static cl::opt<unsigned> SchedDebugVerboseLevel("misched-verbose-level",
54*0b57cec5SDimitry Andric     cl::Hidden, cl::ZeroOrMore, cl::init(1));
55*0b57cec5SDimitry Andric 
56*0b57cec5SDimitry Andric // Check if the scheduler should penalize instructions that are available to
57*0b57cec5SDimitry Andric // early due to a zero-latency dependence.
58*0b57cec5SDimitry Andric static cl::opt<bool> CheckEarlyAvail("check-early-avail", cl::Hidden,
59*0b57cec5SDimitry Andric     cl::ZeroOrMore, cl::init(true));
60*0b57cec5SDimitry Andric 
61*0b57cec5SDimitry Andric // This value is used to determine if a register class is a high pressure set.
62*0b57cec5SDimitry Andric // We compute the maximum number of registers needed and divided by the total
63*0b57cec5SDimitry Andric // available. Then, we compare the result to this value.
64*0b57cec5SDimitry Andric static cl::opt<float> RPThreshold("hexagon-reg-pressure", cl::Hidden,
65*0b57cec5SDimitry Andric     cl::init(0.75f), cl::desc("High register pressure threhold."));
66*0b57cec5SDimitry Andric 
67*0b57cec5SDimitry Andric /// Return true if there is a dependence between SUd and SUu.
68*0b57cec5SDimitry Andric static bool hasDependence(const SUnit *SUd, const SUnit *SUu,
69*0b57cec5SDimitry Andric                           const HexagonInstrInfo &QII) {
70*0b57cec5SDimitry Andric   if (SUd->Succs.size() == 0)
71*0b57cec5SDimitry Andric     return false;
72*0b57cec5SDimitry Andric 
73*0b57cec5SDimitry Andric   // Enable .cur formation.
74*0b57cec5SDimitry Andric   if (QII.mayBeCurLoad(*SUd->getInstr()))
75*0b57cec5SDimitry Andric     return false;
76*0b57cec5SDimitry Andric 
77*0b57cec5SDimitry Andric   if (QII.canExecuteInBundle(*SUd->getInstr(), *SUu->getInstr()))
78*0b57cec5SDimitry Andric     return false;
79*0b57cec5SDimitry Andric 
80*0b57cec5SDimitry Andric   for (const auto &S : SUd->Succs) {
81*0b57cec5SDimitry Andric     // Since we do not add pseudos to packets, might as well
82*0b57cec5SDimitry Andric     // ignore order dependencies.
83*0b57cec5SDimitry Andric     if (S.isCtrl())
84*0b57cec5SDimitry Andric       continue;
85*0b57cec5SDimitry Andric 
86*0b57cec5SDimitry Andric     if (S.getSUnit() == SUu && S.getLatency() > 0)
87*0b57cec5SDimitry Andric       return true;
88*0b57cec5SDimitry Andric   }
89*0b57cec5SDimitry Andric   return false;
90*0b57cec5SDimitry Andric }
91*0b57cec5SDimitry Andric 
92*0b57cec5SDimitry Andric /// Check if scheduling of this SU is possible
93*0b57cec5SDimitry Andric /// in the current packet.
94*0b57cec5SDimitry Andric /// It is _not_ precise (statefull), it is more like
95*0b57cec5SDimitry Andric /// another heuristic. Many corner cases are figured
96*0b57cec5SDimitry Andric /// empirically.
97*0b57cec5SDimitry Andric bool VLIWResourceModel::isResourceAvailable(SUnit *SU, bool IsTop) {
98*0b57cec5SDimitry Andric   if (!SU || !SU->getInstr())
99*0b57cec5SDimitry Andric     return false;
100*0b57cec5SDimitry Andric 
101*0b57cec5SDimitry Andric   // First see if the pipeline could receive this instruction
102*0b57cec5SDimitry Andric   // in the current cycle.
103*0b57cec5SDimitry Andric   switch (SU->getInstr()->getOpcode()) {
104*0b57cec5SDimitry Andric   default:
105*0b57cec5SDimitry Andric     if (!ResourcesModel->canReserveResources(*SU->getInstr()))
106*0b57cec5SDimitry Andric       return false;
107*0b57cec5SDimitry Andric     break;
108*0b57cec5SDimitry Andric   case TargetOpcode::EXTRACT_SUBREG:
109*0b57cec5SDimitry Andric   case TargetOpcode::INSERT_SUBREG:
110*0b57cec5SDimitry Andric   case TargetOpcode::SUBREG_TO_REG:
111*0b57cec5SDimitry Andric   case TargetOpcode::REG_SEQUENCE:
112*0b57cec5SDimitry Andric   case TargetOpcode::IMPLICIT_DEF:
113*0b57cec5SDimitry Andric   case TargetOpcode::COPY:
114*0b57cec5SDimitry Andric   case TargetOpcode::INLINEASM:
115*0b57cec5SDimitry Andric   case TargetOpcode::INLINEASM_BR:
116*0b57cec5SDimitry Andric     break;
117*0b57cec5SDimitry Andric   }
118*0b57cec5SDimitry Andric 
119*0b57cec5SDimitry Andric   MachineBasicBlock *MBB = SU->getInstr()->getParent();
120*0b57cec5SDimitry Andric   auto &QST = MBB->getParent()->getSubtarget<HexagonSubtarget>();
121*0b57cec5SDimitry Andric   const auto &QII = *QST.getInstrInfo();
122*0b57cec5SDimitry Andric 
123*0b57cec5SDimitry Andric   // Now see if there are no other dependencies to instructions already
124*0b57cec5SDimitry Andric   // in the packet.
125*0b57cec5SDimitry Andric   if (IsTop) {
126*0b57cec5SDimitry Andric     for (unsigned i = 0, e = Packet.size(); i != e; ++i)
127*0b57cec5SDimitry Andric       if (hasDependence(Packet[i], SU, QII))
128*0b57cec5SDimitry Andric         return false;
129*0b57cec5SDimitry Andric   } else {
130*0b57cec5SDimitry Andric     for (unsigned i = 0, e = Packet.size(); i != e; ++i)
131*0b57cec5SDimitry Andric       if (hasDependence(SU, Packet[i], QII))
132*0b57cec5SDimitry Andric         return false;
133*0b57cec5SDimitry Andric   }
134*0b57cec5SDimitry Andric   return true;
135*0b57cec5SDimitry Andric }
136*0b57cec5SDimitry Andric 
137*0b57cec5SDimitry Andric /// Keep track of available resources.
138*0b57cec5SDimitry Andric bool VLIWResourceModel::reserveResources(SUnit *SU, bool IsTop) {
139*0b57cec5SDimitry Andric   bool startNewCycle = false;
140*0b57cec5SDimitry Andric   // Artificially reset state.
141*0b57cec5SDimitry Andric   if (!SU) {
142*0b57cec5SDimitry Andric     ResourcesModel->clearResources();
143*0b57cec5SDimitry Andric     Packet.clear();
144*0b57cec5SDimitry Andric     TotalPackets++;
145*0b57cec5SDimitry Andric     return false;
146*0b57cec5SDimitry Andric   }
147*0b57cec5SDimitry Andric   // If this SU does not fit in the packet or the packet is now full
148*0b57cec5SDimitry Andric   // start a new one.
149*0b57cec5SDimitry Andric   if (!isResourceAvailable(SU, IsTop) ||
150*0b57cec5SDimitry Andric       Packet.size() >= SchedModel->getIssueWidth()) {
151*0b57cec5SDimitry Andric     ResourcesModel->clearResources();
152*0b57cec5SDimitry Andric     Packet.clear();
153*0b57cec5SDimitry Andric     TotalPackets++;
154*0b57cec5SDimitry Andric     startNewCycle = true;
155*0b57cec5SDimitry Andric   }
156*0b57cec5SDimitry Andric 
157*0b57cec5SDimitry Andric   switch (SU->getInstr()->getOpcode()) {
158*0b57cec5SDimitry Andric   default:
159*0b57cec5SDimitry Andric     ResourcesModel->reserveResources(*SU->getInstr());
160*0b57cec5SDimitry Andric     break;
161*0b57cec5SDimitry Andric   case TargetOpcode::EXTRACT_SUBREG:
162*0b57cec5SDimitry Andric   case TargetOpcode::INSERT_SUBREG:
163*0b57cec5SDimitry Andric   case TargetOpcode::SUBREG_TO_REG:
164*0b57cec5SDimitry Andric   case TargetOpcode::REG_SEQUENCE:
165*0b57cec5SDimitry Andric   case TargetOpcode::IMPLICIT_DEF:
166*0b57cec5SDimitry Andric   case TargetOpcode::KILL:
167*0b57cec5SDimitry Andric   case TargetOpcode::CFI_INSTRUCTION:
168*0b57cec5SDimitry Andric   case TargetOpcode::EH_LABEL:
169*0b57cec5SDimitry Andric   case TargetOpcode::COPY:
170*0b57cec5SDimitry Andric   case TargetOpcode::INLINEASM:
171*0b57cec5SDimitry Andric   case TargetOpcode::INLINEASM_BR:
172*0b57cec5SDimitry Andric     break;
173*0b57cec5SDimitry Andric   }
174*0b57cec5SDimitry Andric   Packet.push_back(SU);
175*0b57cec5SDimitry Andric 
176*0b57cec5SDimitry Andric #ifndef NDEBUG
177*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Packet[" << TotalPackets << "]:\n");
178*0b57cec5SDimitry Andric   for (unsigned i = 0, e = Packet.size(); i != e; ++i) {
179*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "\t[" << i << "] SU(");
180*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << Packet[i]->NodeNum << ")\t");
181*0b57cec5SDimitry Andric     LLVM_DEBUG(Packet[i]->getInstr()->dump());
182*0b57cec5SDimitry Andric   }
183*0b57cec5SDimitry Andric #endif
184*0b57cec5SDimitry Andric 
185*0b57cec5SDimitry Andric   return startNewCycle;
186*0b57cec5SDimitry Andric }
187*0b57cec5SDimitry Andric 
188*0b57cec5SDimitry Andric /// schedule - Called back from MachineScheduler::runOnMachineFunction
189*0b57cec5SDimitry Andric /// after setting up the current scheduling region. [RegionBegin, RegionEnd)
190*0b57cec5SDimitry Andric /// only includes instructions that have DAG nodes, not scheduling boundaries.
191*0b57cec5SDimitry Andric void VLIWMachineScheduler::schedule() {
192*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "********** MI Converging Scheduling VLIW "
193*0b57cec5SDimitry Andric                     << printMBBReference(*BB) << " " << BB->getName()
194*0b57cec5SDimitry Andric                     << " in_func " << BB->getParent()->getName()
195*0b57cec5SDimitry Andric                     << " at loop depth " << MLI->getLoopDepth(BB) << " \n");
196*0b57cec5SDimitry Andric 
197*0b57cec5SDimitry Andric   buildDAGWithRegPressure();
198*0b57cec5SDimitry Andric 
199*0b57cec5SDimitry Andric   Topo.InitDAGTopologicalSorting();
200*0b57cec5SDimitry Andric 
201*0b57cec5SDimitry Andric   // Postprocess the DAG to add platform-specific artificial dependencies.
202*0b57cec5SDimitry Andric   postprocessDAG();
203*0b57cec5SDimitry Andric 
204*0b57cec5SDimitry Andric   SmallVector<SUnit*, 8> TopRoots, BotRoots;
205*0b57cec5SDimitry Andric   findRootsAndBiasEdges(TopRoots, BotRoots);
206*0b57cec5SDimitry Andric 
207*0b57cec5SDimitry Andric   // Initialize the strategy before modifying the DAG.
208*0b57cec5SDimitry Andric   SchedImpl->initialize(this);
209*0b57cec5SDimitry Andric 
210*0b57cec5SDimitry Andric   LLVM_DEBUG(unsigned maxH = 0;
211*0b57cec5SDimitry Andric              for (unsigned su = 0, e = SUnits.size(); su != e;
212*0b57cec5SDimitry Andric                   ++su) if (SUnits[su].getHeight() > maxH) maxH =
213*0b57cec5SDimitry Andric                  SUnits[su].getHeight();
214*0b57cec5SDimitry Andric              dbgs() << "Max Height " << maxH << "\n";);
215*0b57cec5SDimitry Andric   LLVM_DEBUG(unsigned maxD = 0;
216*0b57cec5SDimitry Andric              for (unsigned su = 0, e = SUnits.size(); su != e;
217*0b57cec5SDimitry Andric                   ++su) if (SUnits[su].getDepth() > maxD) maxD =
218*0b57cec5SDimitry Andric                  SUnits[su].getDepth();
219*0b57cec5SDimitry Andric              dbgs() << "Max Depth " << maxD << "\n";);
220*0b57cec5SDimitry Andric   LLVM_DEBUG(dump());
221*0b57cec5SDimitry Andric 
222*0b57cec5SDimitry Andric   initQueues(TopRoots, BotRoots);
223*0b57cec5SDimitry Andric 
224*0b57cec5SDimitry Andric   bool IsTopNode = false;
225*0b57cec5SDimitry Andric   while (true) {
226*0b57cec5SDimitry Andric     LLVM_DEBUG(
227*0b57cec5SDimitry Andric         dbgs() << "** VLIWMachineScheduler::schedule picking next node\n");
228*0b57cec5SDimitry Andric     SUnit *SU = SchedImpl->pickNode(IsTopNode);
229*0b57cec5SDimitry Andric     if (!SU) break;
230*0b57cec5SDimitry Andric 
231*0b57cec5SDimitry Andric     if (!checkSchedLimit())
232*0b57cec5SDimitry Andric       break;
233*0b57cec5SDimitry Andric 
234*0b57cec5SDimitry Andric     scheduleMI(SU, IsTopNode);
235*0b57cec5SDimitry Andric 
236*0b57cec5SDimitry Andric     // Notify the scheduling strategy after updating the DAG.
237*0b57cec5SDimitry Andric     SchedImpl->schedNode(SU, IsTopNode);
238*0b57cec5SDimitry Andric 
239*0b57cec5SDimitry Andric     updateQueues(SU, IsTopNode);
240*0b57cec5SDimitry Andric   }
241*0b57cec5SDimitry Andric   assert(CurrentTop == CurrentBottom && "Nonempty unscheduled zone.");
242*0b57cec5SDimitry Andric 
243*0b57cec5SDimitry Andric   placeDebugValues();
244*0b57cec5SDimitry Andric 
245*0b57cec5SDimitry Andric   LLVM_DEBUG({
246*0b57cec5SDimitry Andric     dbgs() << "*** Final schedule for "
247*0b57cec5SDimitry Andric            << printMBBReference(*begin()->getParent()) << " ***\n";
248*0b57cec5SDimitry Andric     dumpSchedule();
249*0b57cec5SDimitry Andric     dbgs() << '\n';
250*0b57cec5SDimitry Andric   });
251*0b57cec5SDimitry Andric }
252*0b57cec5SDimitry Andric 
253*0b57cec5SDimitry Andric void ConvergingVLIWScheduler::initialize(ScheduleDAGMI *dag) {
254*0b57cec5SDimitry Andric   DAG = static_cast<VLIWMachineScheduler*>(dag);
255*0b57cec5SDimitry Andric   SchedModel = DAG->getSchedModel();
256*0b57cec5SDimitry Andric 
257*0b57cec5SDimitry Andric   Top.init(DAG, SchedModel);
258*0b57cec5SDimitry Andric   Bot.init(DAG, SchedModel);
259*0b57cec5SDimitry Andric 
260*0b57cec5SDimitry Andric   // Initialize the HazardRecognizers. If itineraries don't exist, are empty, or
261*0b57cec5SDimitry Andric   // are disabled, then these HazardRecs will be disabled.
262*0b57cec5SDimitry Andric   const InstrItineraryData *Itin = DAG->getSchedModel()->getInstrItineraries();
263*0b57cec5SDimitry Andric   const TargetSubtargetInfo &STI = DAG->MF.getSubtarget();
264*0b57cec5SDimitry Andric   const TargetInstrInfo *TII = STI.getInstrInfo();
265*0b57cec5SDimitry Andric   delete Top.HazardRec;
266*0b57cec5SDimitry Andric   delete Bot.HazardRec;
267*0b57cec5SDimitry Andric   Top.HazardRec = TII->CreateTargetMIHazardRecognizer(Itin, DAG);
268*0b57cec5SDimitry Andric   Bot.HazardRec = TII->CreateTargetMIHazardRecognizer(Itin, DAG);
269*0b57cec5SDimitry Andric 
270*0b57cec5SDimitry Andric   delete Top.ResourceModel;
271*0b57cec5SDimitry Andric   delete Bot.ResourceModel;
272*0b57cec5SDimitry Andric   Top.ResourceModel = new VLIWResourceModel(STI, DAG->getSchedModel());
273*0b57cec5SDimitry Andric   Bot.ResourceModel = new VLIWResourceModel(STI, DAG->getSchedModel());
274*0b57cec5SDimitry Andric 
275*0b57cec5SDimitry Andric   const std::vector<unsigned> &MaxPressure =
276*0b57cec5SDimitry Andric     DAG->getRegPressure().MaxSetPressure;
277*0b57cec5SDimitry Andric   HighPressureSets.assign(MaxPressure.size(), 0);
278*0b57cec5SDimitry Andric   for (unsigned i = 0, e = MaxPressure.size(); i < e; ++i) {
279*0b57cec5SDimitry Andric     unsigned Limit = DAG->getRegClassInfo()->getRegPressureSetLimit(i);
280*0b57cec5SDimitry Andric     HighPressureSets[i] =
281*0b57cec5SDimitry Andric       ((float) MaxPressure[i] > ((float) Limit * RPThreshold));
282*0b57cec5SDimitry Andric   }
283*0b57cec5SDimitry Andric 
284*0b57cec5SDimitry Andric   assert((!ForceTopDown || !ForceBottomUp) &&
285*0b57cec5SDimitry Andric          "-misched-topdown incompatible with -misched-bottomup");
286*0b57cec5SDimitry Andric }
287*0b57cec5SDimitry Andric 
288*0b57cec5SDimitry Andric void ConvergingVLIWScheduler::releaseTopNode(SUnit *SU) {
289*0b57cec5SDimitry Andric   if (SU->isScheduled)
290*0b57cec5SDimitry Andric     return;
291*0b57cec5SDimitry Andric 
292*0b57cec5SDimitry Andric   for (const SDep &PI : SU->Preds) {
293*0b57cec5SDimitry Andric     unsigned PredReadyCycle = PI.getSUnit()->TopReadyCycle;
294*0b57cec5SDimitry Andric     unsigned MinLatency = PI.getLatency();
295*0b57cec5SDimitry Andric #ifndef NDEBUG
296*0b57cec5SDimitry Andric     Top.MaxMinLatency = std::max(MinLatency, Top.MaxMinLatency);
297*0b57cec5SDimitry Andric #endif
298*0b57cec5SDimitry Andric     if (SU->TopReadyCycle < PredReadyCycle + MinLatency)
299*0b57cec5SDimitry Andric       SU->TopReadyCycle = PredReadyCycle + MinLatency;
300*0b57cec5SDimitry Andric   }
301*0b57cec5SDimitry Andric   Top.releaseNode(SU, SU->TopReadyCycle);
302*0b57cec5SDimitry Andric }
303*0b57cec5SDimitry Andric 
304*0b57cec5SDimitry Andric void ConvergingVLIWScheduler::releaseBottomNode(SUnit *SU) {
305*0b57cec5SDimitry Andric   if (SU->isScheduled)
306*0b57cec5SDimitry Andric     return;
307*0b57cec5SDimitry Andric 
308*0b57cec5SDimitry Andric   assert(SU->getInstr() && "Scheduled SUnit must have instr");
309*0b57cec5SDimitry Andric 
310*0b57cec5SDimitry Andric   for (SUnit::succ_iterator I = SU->Succs.begin(), E = SU->Succs.end();
311*0b57cec5SDimitry Andric        I != E; ++I) {
312*0b57cec5SDimitry Andric     unsigned SuccReadyCycle = I->getSUnit()->BotReadyCycle;
313*0b57cec5SDimitry Andric     unsigned MinLatency = I->getLatency();
314*0b57cec5SDimitry Andric #ifndef NDEBUG
315*0b57cec5SDimitry Andric     Bot.MaxMinLatency = std::max(MinLatency, Bot.MaxMinLatency);
316*0b57cec5SDimitry Andric #endif
317*0b57cec5SDimitry Andric     if (SU->BotReadyCycle < SuccReadyCycle + MinLatency)
318*0b57cec5SDimitry Andric       SU->BotReadyCycle = SuccReadyCycle + MinLatency;
319*0b57cec5SDimitry Andric   }
320*0b57cec5SDimitry Andric   Bot.releaseNode(SU, SU->BotReadyCycle);
321*0b57cec5SDimitry Andric }
322*0b57cec5SDimitry Andric 
323*0b57cec5SDimitry Andric /// Does this SU have a hazard within the current instruction group.
324*0b57cec5SDimitry Andric ///
325*0b57cec5SDimitry Andric /// The scheduler supports two modes of hazard recognition. The first is the
326*0b57cec5SDimitry Andric /// ScheduleHazardRecognizer API. It is a fully general hazard recognizer that
327*0b57cec5SDimitry Andric /// supports highly complicated in-order reservation tables
328*0b57cec5SDimitry Andric /// (ScoreboardHazardRecognizer) and arbitrary target-specific logic.
329*0b57cec5SDimitry Andric ///
330*0b57cec5SDimitry Andric /// The second is a streamlined mechanism that checks for hazards based on
331*0b57cec5SDimitry Andric /// simple counters that the scheduler itself maintains. It explicitly checks
332*0b57cec5SDimitry Andric /// for instruction dispatch limitations, including the number of micro-ops that
333*0b57cec5SDimitry Andric /// can dispatch per cycle.
334*0b57cec5SDimitry Andric ///
335*0b57cec5SDimitry Andric /// TODO: Also check whether the SU must start a new group.
336*0b57cec5SDimitry Andric bool ConvergingVLIWScheduler::VLIWSchedBoundary::checkHazard(SUnit *SU) {
337*0b57cec5SDimitry Andric   if (HazardRec->isEnabled())
338*0b57cec5SDimitry Andric     return HazardRec->getHazardType(SU) != ScheduleHazardRecognizer::NoHazard;
339*0b57cec5SDimitry Andric 
340*0b57cec5SDimitry Andric   unsigned uops = SchedModel->getNumMicroOps(SU->getInstr());
341*0b57cec5SDimitry Andric   if (IssueCount + uops > SchedModel->getIssueWidth())
342*0b57cec5SDimitry Andric     return true;
343*0b57cec5SDimitry Andric 
344*0b57cec5SDimitry Andric   return false;
345*0b57cec5SDimitry Andric }
346*0b57cec5SDimitry Andric 
347*0b57cec5SDimitry Andric void ConvergingVLIWScheduler::VLIWSchedBoundary::releaseNode(SUnit *SU,
348*0b57cec5SDimitry Andric                                                      unsigned ReadyCycle) {
349*0b57cec5SDimitry Andric   if (ReadyCycle < MinReadyCycle)
350*0b57cec5SDimitry Andric     MinReadyCycle = ReadyCycle;
351*0b57cec5SDimitry Andric 
352*0b57cec5SDimitry Andric   // Check for interlocks first. For the purpose of other heuristics, an
353*0b57cec5SDimitry Andric   // instruction that cannot issue appears as if it's not in the ReadyQueue.
354*0b57cec5SDimitry Andric   if (ReadyCycle > CurrCycle || checkHazard(SU))
355*0b57cec5SDimitry Andric 
356*0b57cec5SDimitry Andric     Pending.push(SU);
357*0b57cec5SDimitry Andric   else
358*0b57cec5SDimitry Andric     Available.push(SU);
359*0b57cec5SDimitry Andric }
360*0b57cec5SDimitry Andric 
361*0b57cec5SDimitry Andric /// Move the boundary of scheduled code by one cycle.
362*0b57cec5SDimitry Andric void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpCycle() {
363*0b57cec5SDimitry Andric   unsigned Width = SchedModel->getIssueWidth();
364*0b57cec5SDimitry Andric   IssueCount = (IssueCount <= Width) ? 0 : IssueCount - Width;
365*0b57cec5SDimitry Andric 
366*0b57cec5SDimitry Andric   assert(MinReadyCycle < std::numeric_limits<unsigned>::max() &&
367*0b57cec5SDimitry Andric          "MinReadyCycle uninitialized");
368*0b57cec5SDimitry Andric   unsigned NextCycle = std::max(CurrCycle + 1, MinReadyCycle);
369*0b57cec5SDimitry Andric 
370*0b57cec5SDimitry Andric   if (!HazardRec->isEnabled()) {
371*0b57cec5SDimitry Andric     // Bypass HazardRec virtual calls.
372*0b57cec5SDimitry Andric     CurrCycle = NextCycle;
373*0b57cec5SDimitry Andric   } else {
374*0b57cec5SDimitry Andric     // Bypass getHazardType calls in case of long latency.
375*0b57cec5SDimitry Andric     for (; CurrCycle != NextCycle; ++CurrCycle) {
376*0b57cec5SDimitry Andric       if (isTop())
377*0b57cec5SDimitry Andric         HazardRec->AdvanceCycle();
378*0b57cec5SDimitry Andric       else
379*0b57cec5SDimitry Andric         HazardRec->RecedeCycle();
380*0b57cec5SDimitry Andric     }
381*0b57cec5SDimitry Andric   }
382*0b57cec5SDimitry Andric   CheckPending = true;
383*0b57cec5SDimitry Andric 
384*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "*** Next cycle " << Available.getName() << " cycle "
385*0b57cec5SDimitry Andric                     << CurrCycle << '\n');
386*0b57cec5SDimitry Andric }
387*0b57cec5SDimitry Andric 
388*0b57cec5SDimitry Andric /// Move the boundary of scheduled code by one SUnit.
389*0b57cec5SDimitry Andric void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpNode(SUnit *SU) {
390*0b57cec5SDimitry Andric   bool startNewCycle = false;
391*0b57cec5SDimitry Andric 
392*0b57cec5SDimitry Andric   // Update the reservation table.
393*0b57cec5SDimitry Andric   if (HazardRec->isEnabled()) {
394*0b57cec5SDimitry Andric     if (!isTop() && SU->isCall) {
395*0b57cec5SDimitry Andric       // Calls are scheduled with their preceding instructions. For bottom-up
396*0b57cec5SDimitry Andric       // scheduling, clear the pipeline state before emitting.
397*0b57cec5SDimitry Andric       HazardRec->Reset();
398*0b57cec5SDimitry Andric     }
399*0b57cec5SDimitry Andric     HazardRec->EmitInstruction(SU);
400*0b57cec5SDimitry Andric   }
401*0b57cec5SDimitry Andric 
402*0b57cec5SDimitry Andric   // Update DFA model.
403*0b57cec5SDimitry Andric   startNewCycle = ResourceModel->reserveResources(SU, isTop());
404*0b57cec5SDimitry Andric 
405*0b57cec5SDimitry Andric   // Check the instruction group dispatch limit.
406*0b57cec5SDimitry Andric   // TODO: Check if this SU must end a dispatch group.
407*0b57cec5SDimitry Andric   IssueCount += SchedModel->getNumMicroOps(SU->getInstr());
408*0b57cec5SDimitry Andric   if (startNewCycle) {
409*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "*** Max instrs at cycle " << CurrCycle << '\n');
410*0b57cec5SDimitry Andric     bumpCycle();
411*0b57cec5SDimitry Andric   }
412*0b57cec5SDimitry Andric   else
413*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "*** IssueCount " << IssueCount << " at cycle "
414*0b57cec5SDimitry Andric                       << CurrCycle << '\n');
415*0b57cec5SDimitry Andric }
416*0b57cec5SDimitry Andric 
417*0b57cec5SDimitry Andric /// Release pending ready nodes in to the available queue. This makes them
418*0b57cec5SDimitry Andric /// visible to heuristics.
419*0b57cec5SDimitry Andric void ConvergingVLIWScheduler::VLIWSchedBoundary::releasePending() {
420*0b57cec5SDimitry Andric   // If the available queue is empty, it is safe to reset MinReadyCycle.
421*0b57cec5SDimitry Andric   if (Available.empty())
422*0b57cec5SDimitry Andric     MinReadyCycle = std::numeric_limits<unsigned>::max();
423*0b57cec5SDimitry Andric 
424*0b57cec5SDimitry Andric   // Check to see if any of the pending instructions are ready to issue.  If
425*0b57cec5SDimitry Andric   // so, add them to the available queue.
426*0b57cec5SDimitry Andric   for (unsigned i = 0, e = Pending.size(); i != e; ++i) {
427*0b57cec5SDimitry Andric     SUnit *SU = *(Pending.begin()+i);
428*0b57cec5SDimitry Andric     unsigned ReadyCycle = isTop() ? SU->TopReadyCycle : SU->BotReadyCycle;
429*0b57cec5SDimitry Andric 
430*0b57cec5SDimitry Andric     if (ReadyCycle < MinReadyCycle)
431*0b57cec5SDimitry Andric       MinReadyCycle = ReadyCycle;
432*0b57cec5SDimitry Andric 
433*0b57cec5SDimitry Andric     if (ReadyCycle > CurrCycle)
434*0b57cec5SDimitry Andric       continue;
435*0b57cec5SDimitry Andric 
436*0b57cec5SDimitry Andric     if (checkHazard(SU))
437*0b57cec5SDimitry Andric       continue;
438*0b57cec5SDimitry Andric 
439*0b57cec5SDimitry Andric     Available.push(SU);
440*0b57cec5SDimitry Andric     Pending.remove(Pending.begin()+i);
441*0b57cec5SDimitry Andric     --i; --e;
442*0b57cec5SDimitry Andric   }
443*0b57cec5SDimitry Andric   CheckPending = false;
444*0b57cec5SDimitry Andric }
445*0b57cec5SDimitry Andric 
446*0b57cec5SDimitry Andric /// Remove SU from the ready set for this boundary.
447*0b57cec5SDimitry Andric void ConvergingVLIWScheduler::VLIWSchedBoundary::removeReady(SUnit *SU) {
448*0b57cec5SDimitry Andric   if (Available.isInQueue(SU))
449*0b57cec5SDimitry Andric     Available.remove(Available.find(SU));
450*0b57cec5SDimitry Andric   else {
451*0b57cec5SDimitry Andric     assert(Pending.isInQueue(SU) && "bad ready count");
452*0b57cec5SDimitry Andric     Pending.remove(Pending.find(SU));
453*0b57cec5SDimitry Andric   }
454*0b57cec5SDimitry Andric }
455*0b57cec5SDimitry Andric 
456*0b57cec5SDimitry Andric /// If this queue only has one ready candidate, return it. As a side effect,
457*0b57cec5SDimitry Andric /// advance the cycle until at least one node is ready. If multiple instructions
458*0b57cec5SDimitry Andric /// are ready, return NULL.
459*0b57cec5SDimitry Andric SUnit *ConvergingVLIWScheduler::VLIWSchedBoundary::pickOnlyChoice() {
460*0b57cec5SDimitry Andric   if (CheckPending)
461*0b57cec5SDimitry Andric     releasePending();
462*0b57cec5SDimitry Andric 
463*0b57cec5SDimitry Andric   auto AdvanceCycle = [this]() {
464*0b57cec5SDimitry Andric     if (Available.empty())
465*0b57cec5SDimitry Andric       return true;
466*0b57cec5SDimitry Andric     if (Available.size() == 1 && Pending.size() > 0)
467*0b57cec5SDimitry Andric       return !ResourceModel->isResourceAvailable(*Available.begin(), isTop()) ||
468*0b57cec5SDimitry Andric         getWeakLeft(*Available.begin(), isTop()) != 0;
469*0b57cec5SDimitry Andric     return false;
470*0b57cec5SDimitry Andric   };
471*0b57cec5SDimitry Andric   for (unsigned i = 0; AdvanceCycle(); ++i) {
472*0b57cec5SDimitry Andric     assert(i <= (HazardRec->getMaxLookAhead() + MaxMinLatency) &&
473*0b57cec5SDimitry Andric            "permanent hazard"); (void)i;
474*0b57cec5SDimitry Andric     ResourceModel->reserveResources(nullptr, isTop());
475*0b57cec5SDimitry Andric     bumpCycle();
476*0b57cec5SDimitry Andric     releasePending();
477*0b57cec5SDimitry Andric   }
478*0b57cec5SDimitry Andric   if (Available.size() == 1)
479*0b57cec5SDimitry Andric     return *Available.begin();
480*0b57cec5SDimitry Andric   return nullptr;
481*0b57cec5SDimitry Andric }
482*0b57cec5SDimitry Andric 
483*0b57cec5SDimitry Andric #ifndef NDEBUG
484*0b57cec5SDimitry Andric void ConvergingVLIWScheduler::traceCandidate(const char *Label,
485*0b57cec5SDimitry Andric       const ReadyQueue &Q, SUnit *SU, int Cost, PressureChange P) {
486*0b57cec5SDimitry Andric   dbgs() << Label << " " << Q.getName() << " ";
487*0b57cec5SDimitry Andric   if (P.isValid())
488*0b57cec5SDimitry Andric     dbgs() << DAG->TRI->getRegPressureSetName(P.getPSet()) << ":"
489*0b57cec5SDimitry Andric            << P.getUnitInc() << " ";
490*0b57cec5SDimitry Andric   else
491*0b57cec5SDimitry Andric     dbgs() << "     ";
492*0b57cec5SDimitry Andric   dbgs() << "cost(" << Cost << ")\t";
493*0b57cec5SDimitry Andric   DAG->dumpNode(*SU);
494*0b57cec5SDimitry Andric }
495*0b57cec5SDimitry Andric 
496*0b57cec5SDimitry Andric // Very detailed queue dump, to be used with higher verbosity levels.
497*0b57cec5SDimitry Andric void ConvergingVLIWScheduler::readyQueueVerboseDump(
498*0b57cec5SDimitry Andric       const RegPressureTracker &RPTracker, SchedCandidate &Candidate,
499*0b57cec5SDimitry Andric       ReadyQueue &Q) {
500*0b57cec5SDimitry Andric   RegPressureTracker &TempTracker = const_cast<RegPressureTracker &>(RPTracker);
501*0b57cec5SDimitry Andric 
502*0b57cec5SDimitry Andric   dbgs() << ">>> " << Q.getName() << "\n";
503*0b57cec5SDimitry Andric   for (ReadyQueue::iterator I = Q.begin(), E = Q.end(); I != E; ++I) {
504*0b57cec5SDimitry Andric     RegPressureDelta RPDelta;
505*0b57cec5SDimitry Andric     TempTracker.getMaxPressureDelta((*I)->getInstr(), RPDelta,
506*0b57cec5SDimitry Andric                                     DAG->getRegionCriticalPSets(),
507*0b57cec5SDimitry Andric                                     DAG->getRegPressure().MaxSetPressure);
508*0b57cec5SDimitry Andric     std::stringstream dbgstr;
509*0b57cec5SDimitry Andric     dbgstr << "SU(" << std::setw(3) << (*I)->NodeNum << ")";
510*0b57cec5SDimitry Andric     dbgs() << dbgstr.str();
511*0b57cec5SDimitry Andric     SchedulingCost(Q, *I, Candidate, RPDelta, true);
512*0b57cec5SDimitry Andric     dbgs() << "\t";
513*0b57cec5SDimitry Andric     (*I)->getInstr()->dump();
514*0b57cec5SDimitry Andric   }
515*0b57cec5SDimitry Andric   dbgs() << "\n";
516*0b57cec5SDimitry Andric }
517*0b57cec5SDimitry Andric #endif
518*0b57cec5SDimitry Andric 
519*0b57cec5SDimitry Andric /// isSingleUnscheduledPred - If SU2 is the only unscheduled predecessor
520*0b57cec5SDimitry Andric /// of SU, return true (we may have duplicates)
521*0b57cec5SDimitry Andric static inline bool isSingleUnscheduledPred(SUnit *SU, SUnit *SU2) {
522*0b57cec5SDimitry Andric   if (SU->NumPredsLeft == 0)
523*0b57cec5SDimitry Andric     return false;
524*0b57cec5SDimitry Andric 
525*0b57cec5SDimitry Andric   for (auto &Pred : SU->Preds) {
526*0b57cec5SDimitry Andric     // We found an available, but not scheduled, predecessor.
527*0b57cec5SDimitry Andric     if (!Pred.getSUnit()->isScheduled && (Pred.getSUnit() != SU2))
528*0b57cec5SDimitry Andric       return false;
529*0b57cec5SDimitry Andric   }
530*0b57cec5SDimitry Andric 
531*0b57cec5SDimitry Andric   return true;
532*0b57cec5SDimitry Andric }
533*0b57cec5SDimitry Andric 
534*0b57cec5SDimitry Andric /// isSingleUnscheduledSucc - If SU2 is the only unscheduled successor
535*0b57cec5SDimitry Andric /// of SU, return true (we may have duplicates)
536*0b57cec5SDimitry Andric static inline bool isSingleUnscheduledSucc(SUnit *SU, SUnit *SU2) {
537*0b57cec5SDimitry Andric   if (SU->NumSuccsLeft == 0)
538*0b57cec5SDimitry Andric     return false;
539*0b57cec5SDimitry Andric 
540*0b57cec5SDimitry Andric   for (auto &Succ : SU->Succs) {
541*0b57cec5SDimitry Andric     // We found an available, but not scheduled, successor.
542*0b57cec5SDimitry Andric     if (!Succ.getSUnit()->isScheduled && (Succ.getSUnit() != SU2))
543*0b57cec5SDimitry Andric       return false;
544*0b57cec5SDimitry Andric   }
545*0b57cec5SDimitry Andric   return true;
546*0b57cec5SDimitry Andric }
547*0b57cec5SDimitry Andric 
548*0b57cec5SDimitry Andric /// Check if the instruction changes the register pressure of a register in the
549*0b57cec5SDimitry Andric /// high pressure set. The function returns a negative value if the pressure
550*0b57cec5SDimitry Andric /// decreases and a positive value is the pressure increases. If the instruction
551*0b57cec5SDimitry Andric /// doesn't use a high pressure register or doesn't change the register
552*0b57cec5SDimitry Andric /// pressure, then return 0.
553*0b57cec5SDimitry Andric int ConvergingVLIWScheduler::pressureChange(const SUnit *SU, bool isBotUp) {
554*0b57cec5SDimitry Andric   PressureDiff &PD = DAG->getPressureDiff(SU);
555*0b57cec5SDimitry Andric   for (auto &P : PD) {
556*0b57cec5SDimitry Andric     if (!P.isValid())
557*0b57cec5SDimitry Andric       continue;
558*0b57cec5SDimitry Andric     // The pressure differences are computed bottom-up, so the comparision for
559*0b57cec5SDimitry Andric     // an increase is positive in the bottom direction, but negative in the
560*0b57cec5SDimitry Andric     //  top-down direction.
561*0b57cec5SDimitry Andric     if (HighPressureSets[P.getPSet()])
562*0b57cec5SDimitry Andric       return (isBotUp ? P.getUnitInc() : -P.getUnitInc());
563*0b57cec5SDimitry Andric   }
564*0b57cec5SDimitry Andric   return 0;
565*0b57cec5SDimitry Andric }
566*0b57cec5SDimitry Andric 
567*0b57cec5SDimitry Andric // Constants used to denote relative importance of
568*0b57cec5SDimitry Andric // heuristic components for cost computation.
569*0b57cec5SDimitry Andric static const unsigned PriorityOne = 200;
570*0b57cec5SDimitry Andric static const unsigned PriorityTwo = 50;
571*0b57cec5SDimitry Andric static const unsigned PriorityThree = 75;
572*0b57cec5SDimitry Andric static const unsigned ScaleTwo = 10;
573*0b57cec5SDimitry Andric 
574*0b57cec5SDimitry Andric /// Single point to compute overall scheduling cost.
575*0b57cec5SDimitry Andric /// TODO: More heuristics will be used soon.
576*0b57cec5SDimitry Andric int ConvergingVLIWScheduler::SchedulingCost(ReadyQueue &Q, SUnit *SU,
577*0b57cec5SDimitry Andric                                             SchedCandidate &Candidate,
578*0b57cec5SDimitry Andric                                             RegPressureDelta &Delta,
579*0b57cec5SDimitry Andric                                             bool verbose) {
580*0b57cec5SDimitry Andric   // Initial trivial priority.
581*0b57cec5SDimitry Andric   int ResCount = 1;
582*0b57cec5SDimitry Andric 
583*0b57cec5SDimitry Andric   // Do not waste time on a node that is already scheduled.
584*0b57cec5SDimitry Andric   if (!SU || SU->isScheduled)
585*0b57cec5SDimitry Andric     return ResCount;
586*0b57cec5SDimitry Andric 
587*0b57cec5SDimitry Andric   LLVM_DEBUG(if (verbose) dbgs()
588*0b57cec5SDimitry Andric              << ((Q.getID() == TopQID) ? "(top|" : "(bot|"));
589*0b57cec5SDimitry Andric   // Forced priority is high.
590*0b57cec5SDimitry Andric   if (SU->isScheduleHigh) {
591*0b57cec5SDimitry Andric     ResCount += PriorityOne;
592*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "H|");
593*0b57cec5SDimitry Andric   }
594*0b57cec5SDimitry Andric 
595*0b57cec5SDimitry Andric   unsigned IsAvailableAmt = 0;
596*0b57cec5SDimitry Andric   // Critical path first.
597*0b57cec5SDimitry Andric   if (Q.getID() == TopQID) {
598*0b57cec5SDimitry Andric     if (Top.isLatencyBound(SU)) {
599*0b57cec5SDimitry Andric       LLVM_DEBUG(if (verbose) dbgs() << "LB|");
600*0b57cec5SDimitry Andric       ResCount += (SU->getHeight() * ScaleTwo);
601*0b57cec5SDimitry Andric     }
602*0b57cec5SDimitry Andric 
603*0b57cec5SDimitry Andric     LLVM_DEBUG(if (verbose) {
604*0b57cec5SDimitry Andric       std::stringstream dbgstr;
605*0b57cec5SDimitry Andric       dbgstr << "h" << std::setw(3) << SU->getHeight() << "|";
606*0b57cec5SDimitry Andric       dbgs() << dbgstr.str();
607*0b57cec5SDimitry Andric     });
608*0b57cec5SDimitry Andric 
609*0b57cec5SDimitry Andric     // If resources are available for it, multiply the
610*0b57cec5SDimitry Andric     // chance of scheduling.
611*0b57cec5SDimitry Andric     if (Top.ResourceModel->isResourceAvailable(SU, true)) {
612*0b57cec5SDimitry Andric       IsAvailableAmt = (PriorityTwo + PriorityThree);
613*0b57cec5SDimitry Andric       ResCount += IsAvailableAmt;
614*0b57cec5SDimitry Andric       LLVM_DEBUG(if (verbose) dbgs() << "A|");
615*0b57cec5SDimitry Andric     } else
616*0b57cec5SDimitry Andric       LLVM_DEBUG(if (verbose) dbgs() << " |");
617*0b57cec5SDimitry Andric   } else {
618*0b57cec5SDimitry Andric     if (Bot.isLatencyBound(SU)) {
619*0b57cec5SDimitry Andric       LLVM_DEBUG(if (verbose) dbgs() << "LB|");
620*0b57cec5SDimitry Andric       ResCount += (SU->getDepth() * ScaleTwo);
621*0b57cec5SDimitry Andric     }
622*0b57cec5SDimitry Andric 
623*0b57cec5SDimitry Andric     LLVM_DEBUG(if (verbose) {
624*0b57cec5SDimitry Andric       std::stringstream dbgstr;
625*0b57cec5SDimitry Andric       dbgstr << "d" << std::setw(3) << SU->getDepth() << "|";
626*0b57cec5SDimitry Andric       dbgs() << dbgstr.str();
627*0b57cec5SDimitry Andric     });
628*0b57cec5SDimitry Andric 
629*0b57cec5SDimitry Andric     // If resources are available for it, multiply the
630*0b57cec5SDimitry Andric     // chance of scheduling.
631*0b57cec5SDimitry Andric     if (Bot.ResourceModel->isResourceAvailable(SU, false)) {
632*0b57cec5SDimitry Andric       IsAvailableAmt = (PriorityTwo + PriorityThree);
633*0b57cec5SDimitry Andric       ResCount += IsAvailableAmt;
634*0b57cec5SDimitry Andric       LLVM_DEBUG(if (verbose) dbgs() << "A|");
635*0b57cec5SDimitry Andric     } else
636*0b57cec5SDimitry Andric       LLVM_DEBUG(if (verbose) dbgs() << " |");
637*0b57cec5SDimitry Andric   }
638*0b57cec5SDimitry Andric 
639*0b57cec5SDimitry Andric   unsigned NumNodesBlocking = 0;
640*0b57cec5SDimitry Andric   if (Q.getID() == TopQID) {
641*0b57cec5SDimitry Andric     // How many SUs does it block from scheduling?
642*0b57cec5SDimitry Andric     // Look at all of the successors of this node.
643*0b57cec5SDimitry Andric     // Count the number of nodes that
644*0b57cec5SDimitry Andric     // this node is the sole unscheduled node for.
645*0b57cec5SDimitry Andric     if (Top.isLatencyBound(SU))
646*0b57cec5SDimitry Andric       for (const SDep &SI : SU->Succs)
647*0b57cec5SDimitry Andric         if (isSingleUnscheduledPred(SI.getSUnit(), SU))
648*0b57cec5SDimitry Andric           ++NumNodesBlocking;
649*0b57cec5SDimitry Andric   } else {
650*0b57cec5SDimitry Andric     // How many unscheduled predecessors block this node?
651*0b57cec5SDimitry Andric     if (Bot.isLatencyBound(SU))
652*0b57cec5SDimitry Andric       for (const SDep &PI : SU->Preds)
653*0b57cec5SDimitry Andric         if (isSingleUnscheduledSucc(PI.getSUnit(), SU))
654*0b57cec5SDimitry Andric           ++NumNodesBlocking;
655*0b57cec5SDimitry Andric   }
656*0b57cec5SDimitry Andric   ResCount += (NumNodesBlocking * ScaleTwo);
657*0b57cec5SDimitry Andric 
658*0b57cec5SDimitry Andric   LLVM_DEBUG(if (verbose) {
659*0b57cec5SDimitry Andric     std::stringstream dbgstr;
660*0b57cec5SDimitry Andric     dbgstr << "blk " << std::setw(2) << NumNodesBlocking << ")|";
661*0b57cec5SDimitry Andric     dbgs() << dbgstr.str();
662*0b57cec5SDimitry Andric   });
663*0b57cec5SDimitry Andric 
664*0b57cec5SDimitry Andric   // Factor in reg pressure as a heuristic.
665*0b57cec5SDimitry Andric   if (!IgnoreBBRegPressure) {
666*0b57cec5SDimitry Andric     // Decrease priority by the amount that register pressure exceeds the limit.
667*0b57cec5SDimitry Andric     ResCount -= (Delta.Excess.getUnitInc()*PriorityOne);
668*0b57cec5SDimitry Andric     // Decrease priority if register pressure exceeds the limit.
669*0b57cec5SDimitry Andric     ResCount -= (Delta.CriticalMax.getUnitInc()*PriorityOne);
670*0b57cec5SDimitry Andric     // Decrease priority slightly if register pressure would increase over the
671*0b57cec5SDimitry Andric     // current maximum.
672*0b57cec5SDimitry Andric     ResCount -= (Delta.CurrentMax.getUnitInc()*PriorityTwo);
673*0b57cec5SDimitry Andric     // If there are register pressure issues, then we remove the value added for
674*0b57cec5SDimitry Andric     // the instruction being available. The rationale is that we really don't
675*0b57cec5SDimitry Andric     // want to schedule an instruction that causes a spill.
676*0b57cec5SDimitry Andric     if (IsAvailableAmt && pressureChange(SU, Q.getID() != TopQID) > 0 &&
677*0b57cec5SDimitry Andric         (Delta.Excess.getUnitInc() || Delta.CriticalMax.getUnitInc() ||
678*0b57cec5SDimitry Andric          Delta.CurrentMax.getUnitInc()))
679*0b57cec5SDimitry Andric       ResCount -= IsAvailableAmt;
680*0b57cec5SDimitry Andric     LLVM_DEBUG(if (verbose) {
681*0b57cec5SDimitry Andric       dbgs() << "RP " << Delta.Excess.getUnitInc() << "/"
682*0b57cec5SDimitry Andric              << Delta.CriticalMax.getUnitInc() << "/"
683*0b57cec5SDimitry Andric              << Delta.CurrentMax.getUnitInc() << ")|";
684*0b57cec5SDimitry Andric     });
685*0b57cec5SDimitry Andric   }
686*0b57cec5SDimitry Andric 
687*0b57cec5SDimitry Andric   // Give a little extra priority to a .cur instruction if there is a resource
688*0b57cec5SDimitry Andric   // available for it.
689*0b57cec5SDimitry Andric   auto &QST = DAG->MF.getSubtarget<HexagonSubtarget>();
690*0b57cec5SDimitry Andric   auto &QII = *QST.getInstrInfo();
691*0b57cec5SDimitry Andric   if (SU->isInstr() && QII.mayBeCurLoad(*SU->getInstr())) {
692*0b57cec5SDimitry Andric     if (Q.getID() == TopQID &&
693*0b57cec5SDimitry Andric         Top.ResourceModel->isResourceAvailable(SU, true)) {
694*0b57cec5SDimitry Andric       ResCount += PriorityTwo;
695*0b57cec5SDimitry Andric       LLVM_DEBUG(if (verbose) dbgs() << "C|");
696*0b57cec5SDimitry Andric     } else if (Q.getID() == BotQID &&
697*0b57cec5SDimitry Andric                Bot.ResourceModel->isResourceAvailable(SU, false)) {
698*0b57cec5SDimitry Andric       ResCount += PriorityTwo;
699*0b57cec5SDimitry Andric       LLVM_DEBUG(if (verbose) dbgs() << "C|");
700*0b57cec5SDimitry Andric     }
701*0b57cec5SDimitry Andric   }
702*0b57cec5SDimitry Andric 
703*0b57cec5SDimitry Andric   // Give preference to a zero latency instruction if the dependent
704*0b57cec5SDimitry Andric   // instruction is in the current packet.
705*0b57cec5SDimitry Andric   if (Q.getID() == TopQID && getWeakLeft(SU, true) == 0) {
706*0b57cec5SDimitry Andric     for (const SDep &PI : SU->Preds) {
707*0b57cec5SDimitry Andric       if (!PI.getSUnit()->getInstr()->isPseudo() && PI.isAssignedRegDep() &&
708*0b57cec5SDimitry Andric           PI.getLatency() == 0 &&
709*0b57cec5SDimitry Andric           Top.ResourceModel->isInPacket(PI.getSUnit())) {
710*0b57cec5SDimitry Andric         ResCount += PriorityThree;
711*0b57cec5SDimitry Andric         LLVM_DEBUG(if (verbose) dbgs() << "Z|");
712*0b57cec5SDimitry Andric       }
713*0b57cec5SDimitry Andric     }
714*0b57cec5SDimitry Andric   } else if (Q.getID() == BotQID && getWeakLeft(SU, false) == 0) {
715*0b57cec5SDimitry Andric     for (const SDep &SI : SU->Succs) {
716*0b57cec5SDimitry Andric       if (!SI.getSUnit()->getInstr()->isPseudo() && SI.isAssignedRegDep() &&
717*0b57cec5SDimitry Andric           SI.getLatency() == 0 &&
718*0b57cec5SDimitry Andric           Bot.ResourceModel->isInPacket(SI.getSUnit())) {
719*0b57cec5SDimitry Andric         ResCount += PriorityThree;
720*0b57cec5SDimitry Andric         LLVM_DEBUG(if (verbose) dbgs() << "Z|");
721*0b57cec5SDimitry Andric       }
722*0b57cec5SDimitry Andric     }
723*0b57cec5SDimitry Andric   }
724*0b57cec5SDimitry Andric 
725*0b57cec5SDimitry Andric   // If the instruction has a non-zero latency dependence with an instruction in
726*0b57cec5SDimitry Andric   // the current packet, then it should not be scheduled yet. The case occurs
727*0b57cec5SDimitry Andric   // when the dependent instruction is scheduled in a new packet, so the
728*0b57cec5SDimitry Andric   // scheduler updates the current cycle and pending instructions become
729*0b57cec5SDimitry Andric   // available.
730*0b57cec5SDimitry Andric   if (CheckEarlyAvail) {
731*0b57cec5SDimitry Andric     if (Q.getID() == TopQID) {
732*0b57cec5SDimitry Andric       for (const auto &PI : SU->Preds) {
733*0b57cec5SDimitry Andric         if (PI.getLatency() > 0 &&
734*0b57cec5SDimitry Andric             Top.ResourceModel->isInPacket(PI.getSUnit())) {
735*0b57cec5SDimitry Andric           ResCount -= PriorityOne;
736*0b57cec5SDimitry Andric           LLVM_DEBUG(if (verbose) dbgs() << "D|");
737*0b57cec5SDimitry Andric         }
738*0b57cec5SDimitry Andric       }
739*0b57cec5SDimitry Andric     } else {
740*0b57cec5SDimitry Andric       for (const auto &SI : SU->Succs) {
741*0b57cec5SDimitry Andric         if (SI.getLatency() > 0 &&
742*0b57cec5SDimitry Andric             Bot.ResourceModel->isInPacket(SI.getSUnit())) {
743*0b57cec5SDimitry Andric           ResCount -= PriorityOne;
744*0b57cec5SDimitry Andric           LLVM_DEBUG(if (verbose) dbgs() << "D|");
745*0b57cec5SDimitry Andric         }
746*0b57cec5SDimitry Andric       }
747*0b57cec5SDimitry Andric     }
748*0b57cec5SDimitry Andric   }
749*0b57cec5SDimitry Andric 
750*0b57cec5SDimitry Andric   LLVM_DEBUG(if (verbose) {
751*0b57cec5SDimitry Andric     std::stringstream dbgstr;
752*0b57cec5SDimitry Andric     dbgstr << "Total " << std::setw(4) << ResCount << ")";
753*0b57cec5SDimitry Andric     dbgs() << dbgstr.str();
754*0b57cec5SDimitry Andric   });
755*0b57cec5SDimitry Andric 
756*0b57cec5SDimitry Andric   return ResCount;
757*0b57cec5SDimitry Andric }
758*0b57cec5SDimitry Andric 
759*0b57cec5SDimitry Andric /// Pick the best candidate from the top queue.
760*0b57cec5SDimitry Andric ///
761*0b57cec5SDimitry Andric /// TODO: getMaxPressureDelta results can be mostly cached for each SUnit during
762*0b57cec5SDimitry Andric /// DAG building. To adjust for the current scheduling location we need to
763*0b57cec5SDimitry Andric /// maintain the number of vreg uses remaining to be top-scheduled.
764*0b57cec5SDimitry Andric ConvergingVLIWScheduler::CandResult ConvergingVLIWScheduler::
765*0b57cec5SDimitry Andric pickNodeFromQueue(VLIWSchedBoundary &Zone, const RegPressureTracker &RPTracker,
766*0b57cec5SDimitry Andric                   SchedCandidate &Candidate) {
767*0b57cec5SDimitry Andric   ReadyQueue &Q = Zone.Available;
768*0b57cec5SDimitry Andric   LLVM_DEBUG(if (SchedDebugVerboseLevel > 1)
769*0b57cec5SDimitry Andric                  readyQueueVerboseDump(RPTracker, Candidate, Q);
770*0b57cec5SDimitry Andric              else Q.dump(););
771*0b57cec5SDimitry Andric 
772*0b57cec5SDimitry Andric   // getMaxPressureDelta temporarily modifies the tracker.
773*0b57cec5SDimitry Andric   RegPressureTracker &TempTracker = const_cast<RegPressureTracker&>(RPTracker);
774*0b57cec5SDimitry Andric 
775*0b57cec5SDimitry Andric   // BestSU remains NULL if no top candidates beat the best existing candidate.
776*0b57cec5SDimitry Andric   CandResult FoundCandidate = NoCand;
777*0b57cec5SDimitry Andric   for (ReadyQueue::iterator I = Q.begin(), E = Q.end(); I != E; ++I) {
778*0b57cec5SDimitry Andric     RegPressureDelta RPDelta;
779*0b57cec5SDimitry Andric     TempTracker.getMaxPressureDelta((*I)->getInstr(), RPDelta,
780*0b57cec5SDimitry Andric                                     DAG->getRegionCriticalPSets(),
781*0b57cec5SDimitry Andric                                     DAG->getRegPressure().MaxSetPressure);
782*0b57cec5SDimitry Andric 
783*0b57cec5SDimitry Andric     int CurrentCost = SchedulingCost(Q, *I, Candidate, RPDelta, false);
784*0b57cec5SDimitry Andric 
785*0b57cec5SDimitry Andric     // Initialize the candidate if needed.
786*0b57cec5SDimitry Andric     if (!Candidate.SU) {
787*0b57cec5SDimitry Andric       LLVM_DEBUG(traceCandidate("DCAND", Q, *I, CurrentCost));
788*0b57cec5SDimitry Andric       Candidate.SU = *I;
789*0b57cec5SDimitry Andric       Candidate.RPDelta = RPDelta;
790*0b57cec5SDimitry Andric       Candidate.SCost = CurrentCost;
791*0b57cec5SDimitry Andric       FoundCandidate = NodeOrder;
792*0b57cec5SDimitry Andric       continue;
793*0b57cec5SDimitry Andric     }
794*0b57cec5SDimitry Andric 
795*0b57cec5SDimitry Andric     // Choose node order for negative cost candidates. There is no good
796*0b57cec5SDimitry Andric     // candidate in this case.
797*0b57cec5SDimitry Andric     if (CurrentCost < 0 && Candidate.SCost < 0) {
798*0b57cec5SDimitry Andric       if ((Q.getID() == TopQID && (*I)->NodeNum < Candidate.SU->NodeNum)
799*0b57cec5SDimitry Andric           || (Q.getID() == BotQID && (*I)->NodeNum > Candidate.SU->NodeNum)) {
800*0b57cec5SDimitry Andric         LLVM_DEBUG(traceCandidate("NCAND", Q, *I, CurrentCost));
801*0b57cec5SDimitry Andric         Candidate.SU = *I;
802*0b57cec5SDimitry Andric         Candidate.RPDelta = RPDelta;
803*0b57cec5SDimitry Andric         Candidate.SCost = CurrentCost;
804*0b57cec5SDimitry Andric         FoundCandidate = NodeOrder;
805*0b57cec5SDimitry Andric       }
806*0b57cec5SDimitry Andric       continue;
807*0b57cec5SDimitry Andric     }
808*0b57cec5SDimitry Andric 
809*0b57cec5SDimitry Andric     // Best cost.
810*0b57cec5SDimitry Andric     if (CurrentCost > Candidate.SCost) {
811*0b57cec5SDimitry Andric       LLVM_DEBUG(traceCandidate("CCAND", Q, *I, CurrentCost));
812*0b57cec5SDimitry Andric       Candidate.SU = *I;
813*0b57cec5SDimitry Andric       Candidate.RPDelta = RPDelta;
814*0b57cec5SDimitry Andric       Candidate.SCost = CurrentCost;
815*0b57cec5SDimitry Andric       FoundCandidate = BestCost;
816*0b57cec5SDimitry Andric       continue;
817*0b57cec5SDimitry Andric     }
818*0b57cec5SDimitry Andric 
819*0b57cec5SDimitry Andric     // Choose an instruction that does not depend on an artificial edge.
820*0b57cec5SDimitry Andric     unsigned CurrWeak = getWeakLeft(*I, (Q.getID() == TopQID));
821*0b57cec5SDimitry Andric     unsigned CandWeak = getWeakLeft(Candidate.SU, (Q.getID() == TopQID));
822*0b57cec5SDimitry Andric     if (CurrWeak != CandWeak) {
823*0b57cec5SDimitry Andric       if (CurrWeak < CandWeak) {
824*0b57cec5SDimitry Andric         LLVM_DEBUG(traceCandidate("WCAND", Q, *I, CurrentCost));
825*0b57cec5SDimitry Andric         Candidate.SU = *I;
826*0b57cec5SDimitry Andric         Candidate.RPDelta = RPDelta;
827*0b57cec5SDimitry Andric         Candidate.SCost = CurrentCost;
828*0b57cec5SDimitry Andric         FoundCandidate = Weak;
829*0b57cec5SDimitry Andric       }
830*0b57cec5SDimitry Andric       continue;
831*0b57cec5SDimitry Andric     }
832*0b57cec5SDimitry Andric 
833*0b57cec5SDimitry Andric     if (CurrentCost == Candidate.SCost && Zone.isLatencyBound(*I)) {
834*0b57cec5SDimitry Andric       unsigned CurrSize, CandSize;
835*0b57cec5SDimitry Andric       if (Q.getID() == TopQID) {
836*0b57cec5SDimitry Andric         CurrSize = (*I)->Succs.size();
837*0b57cec5SDimitry Andric         CandSize = Candidate.SU->Succs.size();
838*0b57cec5SDimitry Andric       } else {
839*0b57cec5SDimitry Andric         CurrSize = (*I)->Preds.size();
840*0b57cec5SDimitry Andric         CandSize = Candidate.SU->Preds.size();
841*0b57cec5SDimitry Andric       }
842*0b57cec5SDimitry Andric       if (CurrSize > CandSize) {
843*0b57cec5SDimitry Andric         LLVM_DEBUG(traceCandidate("SPCAND", Q, *I, CurrentCost));
844*0b57cec5SDimitry Andric         Candidate.SU = *I;
845*0b57cec5SDimitry Andric         Candidate.RPDelta = RPDelta;
846*0b57cec5SDimitry Andric         Candidate.SCost = CurrentCost;
847*0b57cec5SDimitry Andric         FoundCandidate = BestCost;
848*0b57cec5SDimitry Andric       }
849*0b57cec5SDimitry Andric       // Keep the old candidate if it's a better candidate. That is, don't use
850*0b57cec5SDimitry Andric       // the subsequent tie breaker.
851*0b57cec5SDimitry Andric       if (CurrSize != CandSize)
852*0b57cec5SDimitry Andric         continue;
853*0b57cec5SDimitry Andric     }
854*0b57cec5SDimitry Andric 
855*0b57cec5SDimitry Andric     // Tie breaker.
856*0b57cec5SDimitry Andric     // To avoid scheduling indeterminism, we need a tie breaker
857*0b57cec5SDimitry Andric     // for the case when cost is identical for two nodes.
858*0b57cec5SDimitry Andric     if (UseNewerCandidate && CurrentCost == Candidate.SCost) {
859*0b57cec5SDimitry Andric       if ((Q.getID() == TopQID && (*I)->NodeNum < Candidate.SU->NodeNum)
860*0b57cec5SDimitry Andric           || (Q.getID() == BotQID && (*I)->NodeNum > Candidate.SU->NodeNum)) {
861*0b57cec5SDimitry Andric         LLVM_DEBUG(traceCandidate("TCAND", Q, *I, CurrentCost));
862*0b57cec5SDimitry Andric         Candidate.SU = *I;
863*0b57cec5SDimitry Andric         Candidate.RPDelta = RPDelta;
864*0b57cec5SDimitry Andric         Candidate.SCost = CurrentCost;
865*0b57cec5SDimitry Andric         FoundCandidate = NodeOrder;
866*0b57cec5SDimitry Andric         continue;
867*0b57cec5SDimitry Andric       }
868*0b57cec5SDimitry Andric     }
869*0b57cec5SDimitry Andric 
870*0b57cec5SDimitry Andric     // Fall through to original instruction order.
871*0b57cec5SDimitry Andric     // Only consider node order if Candidate was chosen from this Q.
872*0b57cec5SDimitry Andric     if (FoundCandidate == NoCand)
873*0b57cec5SDimitry Andric       continue;
874*0b57cec5SDimitry Andric   }
875*0b57cec5SDimitry Andric   return FoundCandidate;
876*0b57cec5SDimitry Andric }
877*0b57cec5SDimitry Andric 
878*0b57cec5SDimitry Andric /// Pick the best candidate node from either the top or bottom queue.
879*0b57cec5SDimitry Andric SUnit *ConvergingVLIWScheduler::pickNodeBidrectional(bool &IsTopNode) {
880*0b57cec5SDimitry Andric   // Schedule as far as possible in the direction of no choice. This is most
881*0b57cec5SDimitry Andric   // efficient, but also provides the best heuristics for CriticalPSets.
882*0b57cec5SDimitry Andric   if (SUnit *SU = Bot.pickOnlyChoice()) {
883*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Picked only Bottom\n");
884*0b57cec5SDimitry Andric     IsTopNode = false;
885*0b57cec5SDimitry Andric     return SU;
886*0b57cec5SDimitry Andric   }
887*0b57cec5SDimitry Andric   if (SUnit *SU = Top.pickOnlyChoice()) {
888*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Picked only Top\n");
889*0b57cec5SDimitry Andric     IsTopNode = true;
890*0b57cec5SDimitry Andric     return SU;
891*0b57cec5SDimitry Andric   }
892*0b57cec5SDimitry Andric   SchedCandidate BotCand;
893*0b57cec5SDimitry Andric   // Prefer bottom scheduling when heuristics are silent.
894*0b57cec5SDimitry Andric   CandResult BotResult = pickNodeFromQueue(Bot,
895*0b57cec5SDimitry Andric                                            DAG->getBotRPTracker(), BotCand);
896*0b57cec5SDimitry Andric   assert(BotResult != NoCand && "failed to find the first candidate");
897*0b57cec5SDimitry Andric 
898*0b57cec5SDimitry Andric   // If either Q has a single candidate that provides the least increase in
899*0b57cec5SDimitry Andric   // Excess pressure, we can immediately schedule from that Q.
900*0b57cec5SDimitry Andric   //
901*0b57cec5SDimitry Andric   // RegionCriticalPSets summarizes the pressure within the scheduled region and
902*0b57cec5SDimitry Andric   // affects picking from either Q. If scheduling in one direction must
903*0b57cec5SDimitry Andric   // increase pressure for one of the excess PSets, then schedule in that
904*0b57cec5SDimitry Andric   // direction first to provide more freedom in the other direction.
905*0b57cec5SDimitry Andric   if (BotResult == SingleExcess || BotResult == SingleCritical) {
906*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Prefered Bottom Node\n");
907*0b57cec5SDimitry Andric     IsTopNode = false;
908*0b57cec5SDimitry Andric     return BotCand.SU;
909*0b57cec5SDimitry Andric   }
910*0b57cec5SDimitry Andric   // Check if the top Q has a better candidate.
911*0b57cec5SDimitry Andric   SchedCandidate TopCand;
912*0b57cec5SDimitry Andric   CandResult TopResult = pickNodeFromQueue(Top,
913*0b57cec5SDimitry Andric                                            DAG->getTopRPTracker(), TopCand);
914*0b57cec5SDimitry Andric   assert(TopResult != NoCand && "failed to find the first candidate");
915*0b57cec5SDimitry Andric 
916*0b57cec5SDimitry Andric   if (TopResult == SingleExcess || TopResult == SingleCritical) {
917*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Prefered Top Node\n");
918*0b57cec5SDimitry Andric     IsTopNode = true;
919*0b57cec5SDimitry Andric     return TopCand.SU;
920*0b57cec5SDimitry Andric   }
921*0b57cec5SDimitry Andric   // If either Q has a single candidate that minimizes pressure above the
922*0b57cec5SDimitry Andric   // original region's pressure pick it.
923*0b57cec5SDimitry Andric   if (BotResult == SingleMax) {
924*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Prefered Bottom Node SingleMax\n");
925*0b57cec5SDimitry Andric     IsTopNode = false;
926*0b57cec5SDimitry Andric     return BotCand.SU;
927*0b57cec5SDimitry Andric   }
928*0b57cec5SDimitry Andric   if (TopResult == SingleMax) {
929*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Prefered Top Node SingleMax\n");
930*0b57cec5SDimitry Andric     IsTopNode = true;
931*0b57cec5SDimitry Andric     return TopCand.SU;
932*0b57cec5SDimitry Andric   }
933*0b57cec5SDimitry Andric   if (TopCand.SCost > BotCand.SCost) {
934*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "Prefered Top Node Cost\n");
935*0b57cec5SDimitry Andric     IsTopNode = true;
936*0b57cec5SDimitry Andric     return TopCand.SU;
937*0b57cec5SDimitry Andric   }
938*0b57cec5SDimitry Andric   // Otherwise prefer the bottom candidate in node order.
939*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "Prefered Bottom in Node order\n");
940*0b57cec5SDimitry Andric   IsTopNode = false;
941*0b57cec5SDimitry Andric   return BotCand.SU;
942*0b57cec5SDimitry Andric }
943*0b57cec5SDimitry Andric 
944*0b57cec5SDimitry Andric /// Pick the best node to balance the schedule. Implements MachineSchedStrategy.
945*0b57cec5SDimitry Andric SUnit *ConvergingVLIWScheduler::pickNode(bool &IsTopNode) {
946*0b57cec5SDimitry Andric   if (DAG->top() == DAG->bottom()) {
947*0b57cec5SDimitry Andric     assert(Top.Available.empty() && Top.Pending.empty() &&
948*0b57cec5SDimitry Andric            Bot.Available.empty() && Bot.Pending.empty() && "ReadyQ garbage");
949*0b57cec5SDimitry Andric     return nullptr;
950*0b57cec5SDimitry Andric   }
951*0b57cec5SDimitry Andric   SUnit *SU;
952*0b57cec5SDimitry Andric   if (ForceTopDown) {
953*0b57cec5SDimitry Andric     SU = Top.pickOnlyChoice();
954*0b57cec5SDimitry Andric     if (!SU) {
955*0b57cec5SDimitry Andric       SchedCandidate TopCand;
956*0b57cec5SDimitry Andric       CandResult TopResult =
957*0b57cec5SDimitry Andric         pickNodeFromQueue(Top, DAG->getTopRPTracker(), TopCand);
958*0b57cec5SDimitry Andric       assert(TopResult != NoCand && "failed to find the first candidate");
959*0b57cec5SDimitry Andric       (void)TopResult;
960*0b57cec5SDimitry Andric       SU = TopCand.SU;
961*0b57cec5SDimitry Andric     }
962*0b57cec5SDimitry Andric     IsTopNode = true;
963*0b57cec5SDimitry Andric   } else if (ForceBottomUp) {
964*0b57cec5SDimitry Andric     SU = Bot.pickOnlyChoice();
965*0b57cec5SDimitry Andric     if (!SU) {
966*0b57cec5SDimitry Andric       SchedCandidate BotCand;
967*0b57cec5SDimitry Andric       CandResult BotResult =
968*0b57cec5SDimitry Andric         pickNodeFromQueue(Bot, DAG->getBotRPTracker(), BotCand);
969*0b57cec5SDimitry Andric       assert(BotResult != NoCand && "failed to find the first candidate");
970*0b57cec5SDimitry Andric       (void)BotResult;
971*0b57cec5SDimitry Andric       SU = BotCand.SU;
972*0b57cec5SDimitry Andric     }
973*0b57cec5SDimitry Andric     IsTopNode = false;
974*0b57cec5SDimitry Andric   } else {
975*0b57cec5SDimitry Andric     SU = pickNodeBidrectional(IsTopNode);
976*0b57cec5SDimitry Andric   }
977*0b57cec5SDimitry Andric   if (SU->isTopReady())
978*0b57cec5SDimitry Andric     Top.removeReady(SU);
979*0b57cec5SDimitry Andric   if (SU->isBottomReady())
980*0b57cec5SDimitry Andric     Bot.removeReady(SU);
981*0b57cec5SDimitry Andric 
982*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "*** " << (IsTopNode ? "Top" : "Bottom")
983*0b57cec5SDimitry Andric                     << " Scheduling instruction in cycle "
984*0b57cec5SDimitry Andric                     << (IsTopNode ? Top.CurrCycle : Bot.CurrCycle) << " ("
985*0b57cec5SDimitry Andric                     << reportPackets() << ")\n";
986*0b57cec5SDimitry Andric              DAG->dumpNode(*SU));
987*0b57cec5SDimitry Andric   return SU;
988*0b57cec5SDimitry Andric }
989*0b57cec5SDimitry Andric 
990*0b57cec5SDimitry Andric /// Update the scheduler's state after scheduling a node. This is the same node
991*0b57cec5SDimitry Andric /// that was just returned by pickNode(). However, VLIWMachineScheduler needs
992*0b57cec5SDimitry Andric /// to update it's state based on the current cycle before MachineSchedStrategy
993*0b57cec5SDimitry Andric /// does.
994*0b57cec5SDimitry Andric void ConvergingVLIWScheduler::schedNode(SUnit *SU, bool IsTopNode) {
995*0b57cec5SDimitry Andric   if (IsTopNode) {
996*0b57cec5SDimitry Andric     Top.bumpNode(SU);
997*0b57cec5SDimitry Andric     SU->TopReadyCycle = Top.CurrCycle;
998*0b57cec5SDimitry Andric   } else {
999*0b57cec5SDimitry Andric     Bot.bumpNode(SU);
1000*0b57cec5SDimitry Andric     SU->BotReadyCycle = Bot.CurrCycle;
1001*0b57cec5SDimitry Andric   }
1002*0b57cec5SDimitry Andric }
1003