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