46 #define DEBUG_TYPE "machine-scheduler" 71 if (SUd->
Succs.size() == 0)
81 for (
const auto &S : SUd->
Succs) {
87 if (S.getSUnit() == SUu && S.getLatency() > 0)
109 case TargetOpcode::EXTRACT_SUBREG:
110 case TargetOpcode::INSERT_SUBREG:
111 case TargetOpcode::SUBREG_TO_REG:
112 case TargetOpcode::REG_SEQUENCE:
113 case TargetOpcode::IMPLICIT_DEF:
114 case TargetOpcode::COPY:
126 for (
unsigned i = 0, e = Packet.size(); i != e; ++i)
130 for (
unsigned i = 0, e = Packet.size(); i != e; ++i)
139 bool startNewCycle =
false;
154 startNewCycle =
true;
161 case TargetOpcode::EXTRACT_SUBREG:
162 case TargetOpcode::INSERT_SUBREG:
163 case TargetOpcode::SUBREG_TO_REG:
164 case TargetOpcode::REG_SEQUENCE:
165 case TargetOpcode::IMPLICIT_DEF:
167 case TargetOpcode::CFI_INSTRUCTION:
169 case TargetOpcode::COPY:
173 Packet.push_back(SU);
177 for (
unsigned i = 0, e = Packet.size(); i != e; ++i) {
184 return startNewCycle;
193 <<
" in_func " << BB->getParent()->getName()
194 <<
" at loop depth " << MLI->getLoopDepth(BB) <<
" \n");
196 buildDAGWithRegPressure();
198 Topo.InitDAGTopologicalSorting();
204 findRootsAndBiasEdges(TopRoots, BotRoots);
207 SchedImpl->initialize(
this);
210 for (
unsigned su = 0, e = SUnits.size(); su != e;
211 ++su)
if (SUnits[su].getHeight() > maxH) maxH =
212 SUnits[su].getHeight();
213 dbgs() <<
"Max Height " << maxH <<
"\n";);
215 for (
unsigned su = 0, e = SUnits.size(); su != e;
216 ++su)
if (SUnits[su].getDepth() > maxD) maxD =
217 SUnits[su].getDepth();
218 dbgs() <<
"Max Depth " << maxD <<
"\n";);
221 initQueues(TopRoots, BotRoots);
223 bool IsTopNode =
false;
226 dbgs() <<
"** VLIWMachineScheduler::schedule picking next node\n");
227 SUnit *SU = SchedImpl->pickNode(IsTopNode);
230 if (!checkSchedLimit())
233 scheduleMI(SU, IsTopNode);
236 SchedImpl->schedNode(SU, IsTopNode);
238 updateQueues(SU, IsTopNode);
240 assert(CurrentTop == CurrentBottom &&
"Nonempty unscheduled zone.");
245 dbgs() <<
"*** Final schedule for " 254 SchedModel = DAG->getSchedModel();
256 Top.
init(DAG, SchedModel);
257 Bot.init(DAG, SchedModel);
264 delete Top.HazardRec;
265 delete Bot.HazardRec;
269 delete Top.ResourceModel;
270 delete Bot.ResourceModel;
274 const std::vector<unsigned> &MaxPressure =
275 DAG->getRegPressure().MaxSetPressure;
276 HighPressureSets.assign(MaxPressure.size(), 0);
277 for (
unsigned i = 0, e = MaxPressure.size(); i < e; ++i) {
278 unsigned Limit = DAG->getRegClassInfo()->getRegPressureSetLimit(i);
279 HighPressureSets[i] =
280 ((float) MaxPressure[i] > ((
float) Limit *
RPThreshold));
284 "-misched-topdown incompatible with -misched-bottomup");
295 Top.MaxMinLatency =
std::max(MinLatency, Top.MaxMinLatency);
311 unsigned SuccReadyCycle =
I->getSUnit()->BotReadyCycle;
312 unsigned MinLatency =
I->getLatency();
314 Bot.MaxMinLatency =
std::max(MinLatency, Bot.MaxMinLatency);
335 bool ConvergingVLIWScheduler::VLIWSchedBoundary::checkHazard(
SUnit *SU) {
336 if (HazardRec->isEnabled())
346 void ConvergingVLIWScheduler::VLIWSchedBoundary::releaseNode(
SUnit *SU,
347 unsigned ReadyCycle) {
348 if (ReadyCycle < MinReadyCycle)
349 MinReadyCycle = ReadyCycle;
353 if (ReadyCycle > CurrCycle || checkHazard(SU))
361 void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpCycle() {
363 IssueCount = (IssueCount <= Width) ? 0 : IssueCount - Width;
366 "MinReadyCycle uninitialized");
367 unsigned NextCycle =
std::max(CurrCycle + 1, MinReadyCycle);
369 if (!HazardRec->isEnabled()) {
371 CurrCycle = NextCycle;
374 for (; CurrCycle != NextCycle; ++CurrCycle) {
376 HazardRec->AdvanceCycle();
378 HazardRec->RecedeCycle();
383 LLVM_DEBUG(
dbgs() <<
"*** Next cycle " << Available.getName() <<
" cycle " 384 << CurrCycle <<
'\n');
388 void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpNode(
SUnit *SU) {
389 bool startNewCycle =
false;
392 if (HazardRec->isEnabled()) {
393 if (!isTop() && SU->
isCall) {
398 HazardRec->EmitInstruction(SU);
402 startNewCycle = ResourceModel->reserveResources(SU, isTop());
408 LLVM_DEBUG(
dbgs() <<
"*** Max instrs at cycle " << CurrCycle <<
'\n');
412 LLVM_DEBUG(
dbgs() <<
"*** IssueCount " << IssueCount <<
" at cycle " 413 << CurrCycle <<
'\n');
418 void ConvergingVLIWScheduler::VLIWSchedBoundary::releasePending() {
420 if (Available.empty())
425 for (
unsigned i = 0, e = Pending.size(); i != e; ++i) {
426 SUnit *SU = *(Pending.begin()+i);
429 if (ReadyCycle < MinReadyCycle)
430 MinReadyCycle = ReadyCycle;
432 if (ReadyCycle > CurrCycle)
439 Pending.remove(Pending.begin()+i);
442 CheckPending =
false;
446 void ConvergingVLIWScheduler::VLIWSchedBoundary::removeReady(
SUnit *SU) {
447 if (Available.isInQueue(SU))
448 Available.remove(Available.find(SU));
450 assert(Pending.isInQueue(SU) &&
"bad ready count");
451 Pending.remove(Pending.find(SU));
458 SUnit *ConvergingVLIWScheduler::VLIWSchedBoundary::pickOnlyChoice() {
462 auto AdvanceCycle = [
this]() {
463 if (Available.empty())
465 if (Available.size() == 1 && Pending.size() > 0)
466 return !ResourceModel->isResourceAvailable(*Available.begin(), isTop()) ||
470 for (
unsigned i = 0; AdvanceCycle(); ++i) {
471 assert(i <= (HazardRec->getMaxLookAhead() + MaxMinLatency) &&
472 "permanent hazard"); (void)i;
473 ResourceModel->reserveResources(
nullptr, isTop());
477 if (Available.size() == 1)
478 return *Available.begin();
487 dbgs() << DAG->TRI->getRegPressureSetName(P.
getPSet()) <<
":" 491 dbgs() <<
"cost(" << Cost <<
")\t";
505 DAG->getRegionCriticalPSets(),
506 DAG->getRegPressure().MaxSetPressure);
507 std::stringstream dbgstr;
508 dbgstr <<
"SU(" << std::setw(3) << (*I)->NodeNum <<
")";
509 dbgs() << dbgstr.str();
510 SchedulingCost(Q, *
I, Candidate, RPDelta,
true);
512 (*I)->getInstr()->dump();
524 for (
auto &Pred : SU->
Preds) {
526 if (!Pred.getSUnit()->isScheduled && (Pred.getSUnit() != SU2))
539 for (
auto &Succ : SU->
Succs) {
541 if (!Succ.getSUnit()->isScheduled && (Succ.getSUnit() != SU2))
560 if (HighPressureSets[
P.getPSet()])
561 return (isBotUp ?
P.getUnitInc() : -
P.getUnitInc());
576 SchedCandidate &Candidate,
587 << ((Q.
getID() == TopQID) ?
"(top|" :
"(bot|"));
594 unsigned IsAvailableAmt = 0;
596 if (Q.
getID() == TopQID) {
597 if (Top.isLatencyBound(SU)) {
603 std::stringstream dbgstr;
604 dbgstr <<
"h" << std::setw(3) << SU->
getHeight() <<
"|";
605 dbgs() << dbgstr.str();
610 if (Top.ResourceModel->isResourceAvailable(SU,
true)) {
612 ResCount += IsAvailableAmt;
617 if (Bot.isLatencyBound(SU)) {
623 std::stringstream dbgstr;
624 dbgstr <<
"d" << std::setw(3) << SU->
getDepth() <<
"|";
625 dbgs() << dbgstr.str();
630 if (Bot.ResourceModel->isResourceAvailable(SU,
false)) {
632 ResCount += IsAvailableAmt;
638 unsigned NumNodesBlocking = 0;
639 if (Q.
getID() == TopQID) {
644 if (Top.isLatencyBound(SU))
650 if (Bot.isLatencyBound(SU))
655 ResCount += (NumNodesBlocking *
ScaleTwo);
658 std::stringstream dbgstr;
659 dbgstr <<
"blk " << std::setw(2) << NumNodesBlocking <<
")|";
660 dbgs() << dbgstr.str();
675 if (IsAvailableAmt && pressureChange(SU, Q.
getID() != TopQID) > 0 &&
678 ResCount -= IsAvailableAmt;
691 if (Q.
getID() == TopQID &&
692 Top.ResourceModel->isResourceAvailable(SU,
true)) {
695 }
else if (Q.
getID() == BotQID &&
696 Bot.ResourceModel->isResourceAvailable(SU,
false)) {
708 Top.ResourceModel->isInPacket(PI.
getSUnit())) {
717 Bot.ResourceModel->isInPacket(SI.
getSUnit())) {
730 if (Q.
getID() == TopQID) {
731 for (
const auto &PI : SU->
Preds) {
732 if (PI.getLatency() > 0 &&
733 Top.ResourceModel->isInPacket(PI.getSUnit())) {
739 for (
const auto &
SI : SU->
Succs) {
740 if (
SI.getLatency() > 0 &&
741 Bot.ResourceModel->isInPacket(
SI.getSUnit())) {
750 std::stringstream dbgstr;
751 dbgstr <<
"Total " << std::setw(4) << ResCount <<
")";
752 dbgs() << dbgstr.str();
765 SchedCandidate &Candidate) {
768 readyQueueVerboseDump(RPTracker, Candidate, Q);
775 CandResult FoundCandidate =
NoCand;
778 TempTracker.getMaxPressureDelta((*I)->getInstr(), RPDelta,
779 DAG->getRegionCriticalPSets(),
780 DAG->getRegPressure().MaxSetPressure);
782 int CurrentCost = SchedulingCost(Q, *
I, Candidate, RPDelta,
false);
786 LLVM_DEBUG(traceCandidate(
"DCAND", Q, *
I, CurrentCost));
788 Candidate.RPDelta = RPDelta;
789 Candidate.SCost = CurrentCost;
796 if (CurrentCost < 0 && Candidate.SCost < 0) {
797 if ((Q.
getID() == TopQID && (*I)->NodeNum < Candidate.SU->NodeNum)
798 || (Q.
getID() == BotQID && (*I)->NodeNum > Candidate.SU->NodeNum)) {
799 LLVM_DEBUG(traceCandidate(
"NCAND", Q, *
I, CurrentCost));
801 Candidate.RPDelta = RPDelta;
802 Candidate.SCost = CurrentCost;
809 if (CurrentCost > Candidate.SCost) {
810 LLVM_DEBUG(traceCandidate(
"CCAND", Q, *
I, CurrentCost));
812 Candidate.RPDelta = RPDelta;
813 Candidate.SCost = CurrentCost;
814 FoundCandidate = BestCost;
821 if (CurrWeak != CandWeak) {
822 if (CurrWeak < CandWeak) {
823 LLVM_DEBUG(traceCandidate(
"WCAND", Q, *
I, CurrentCost));
825 Candidate.RPDelta = RPDelta;
826 Candidate.SCost = CurrentCost;
827 FoundCandidate = Weak;
832 if (CurrentCost == Candidate.SCost && Zone.isLatencyBound(*
I)) {
833 unsigned CurrSize, CandSize;
834 if (Q.
getID() == TopQID) {
835 CurrSize = (*I)->Succs.size();
836 CandSize = Candidate.SU->Succs.size();
838 CurrSize = (*I)->Preds.size();
839 CandSize = Candidate.SU->Preds.size();
841 if (CurrSize > CandSize) {
842 LLVM_DEBUG(traceCandidate(
"SPCAND", Q, *
I, CurrentCost));
844 Candidate.RPDelta = RPDelta;
845 Candidate.SCost = CurrentCost;
846 FoundCandidate = BestCost;
850 if (CurrSize != CandSize)
858 if ((Q.
getID() == TopQID && (*I)->NodeNum < Candidate.SU->NodeNum)
859 || (Q.
getID() == BotQID && (*I)->NodeNum > Candidate.SU->NodeNum)) {
860 LLVM_DEBUG(traceCandidate(
"TCAND", Q, *
I, CurrentCost));
862 Candidate.RPDelta = RPDelta;
863 Candidate.SCost = CurrentCost;
871 if (FoundCandidate ==
NoCand)
874 return FoundCandidate;
881 if (
SUnit *SU = Bot.pickOnlyChoice()) {
886 if (
SUnit *SU = Top.pickOnlyChoice()) {
891 SchedCandidate BotCand;
893 CandResult BotResult = pickNodeFromQueue(Bot,
894 DAG->getBotRPTracker(), BotCand);
895 assert(BotResult !=
NoCand &&
"failed to find the first candidate");
904 if (BotResult == SingleExcess || BotResult == SingleCritical) {
910 SchedCandidate TopCand;
911 CandResult TopResult = pickNodeFromQueue(Top,
912 DAG->getTopRPTracker(), TopCand);
913 assert(TopResult !=
NoCand &&
"failed to find the first candidate");
915 if (TopResult == SingleExcess || TopResult == SingleCritical) {
922 if (BotResult == SingleMax) {
927 if (TopResult == SingleMax) {
932 if (TopCand.SCost > BotCand.SCost) {
945 if (DAG->top() == DAG->bottom()) {
946 assert(Top.Available.empty() && Top.Pending.empty() &&
947 Bot.Available.empty() && Bot.Pending.empty() &&
"ReadyQ garbage");
952 SU = Top.pickOnlyChoice();
954 SchedCandidate TopCand;
955 CandResult TopResult =
956 pickNodeFromQueue(Top, DAG->getTopRPTracker(), TopCand);
957 assert(TopResult !=
NoCand &&
"failed to find the first candidate");
963 SU = Bot.pickOnlyChoice();
965 SchedCandidate BotCand;
966 CandResult BotResult =
967 pickNodeFromQueue(Bot, DAG->getBotRPTracker(), BotCand);
968 assert(BotResult !=
NoCand &&
"failed to find the first candidate");
974 SU = pickNodeBidrectional(IsTopNode);
982 <<
" Scheduling instruction in cycle " 983 << (IsTopNode ? Top.CurrCycle : Bot.CurrCycle) <<
" (" 984 << reportPackets() <<
")\n";
VLIWResourceModel(const TargetSubtargetInfo &STI, const TargetSchedModel *SM)
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
void schedule() override
Schedule - This is called back from ScheduleDAGInstrs::Run() when it's time to do some work...
const_iterator begin(StringRef path, Style style=Style::native)
Get begin iterator over path.
static bool isSingleUnscheduledPred(SUnit *SU, SUnit *SU2)
isSingleUnscheduledPred - If SU2 is the only unscheduled predecessor of SU, return true (we may have ...
This class represents lattice values for constants.
Extend the standard ScheduleDAGMI to provide more context and override the top-level schedule() drive...
static cl::opt< unsigned > SchedDebugVerboseLevel("misched-verbose-level", cl::Hidden, cl::ZeroOrMore, cl::init(1))
void readyQueueVerboseDump(const RegPressureTracker &RPTracker, SchedCandidate &Candidate, ReadyQueue &Q)
int SchedulingCost(ReadyQueue &Q, SUnit *SU, SchedCandidate &Candidate, RegPressureDelta &Delta, bool verbose)
Single point to compute overall scheduling cost.
unsigned getDepth() const
Returns the depth of this node, which is the length of the maximum path up to any node which has no p...
bool isBottomReady() const
bool isAssignedRegDep() const
Tests if this is a Data dependence that is associated with a register.
ScheduleDAGMI is an implementation of ScheduleDAGInstrs that simply schedules machine instructions ac...
unsigned BotReadyCycle
Cycle relative to end when node is ready.
SmallVectorImpl< SDep >::iterator succ_iterator
SmallVector< SDep, 4 > Preds
All sunit predecessors.
bool isScheduled
True once scheduled.
SUnit * pickNodeBidrectional(bool &IsTopNode)
Pick the best candidate node from either the top or bottom queue.
static const unsigned ScaleTwo
unsigned getLatency() const
Returns the latency value for this edge, which roughly means the minimum number of cycles that must e...
unsigned NumSuccsLeft
of succs not scheduled.
const HexagonInstrInfo * TII
Printable printMBBReference(const MachineBasicBlock &MBB)
Prints a machine basic block reference.
bool canExecuteInBundle(const MachineInstr &First, const MachineInstr &Second) const
Can these instructions execute at the same time in a bundle.
static cl::opt< bool > IgnoreBBRegPressure("ignore-bb-reg-pressure", cl::Hidden, cl::ZeroOrMore, cl::init(false))
SUnit * pickNode(bool &IsTopNode) override
Pick the best node to balance the schedule. Implements MachineSchedStrategy.
StringRef getName() const
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
CandResult pickNodeFromQueue(VLIWSchedBoundary &Zone, const RegPressureTracker &RPTracker, SchedCandidate &Candidate)
Pick the best candidate from the top queue.
INLINEASM - Represents an inline asm block.
unsigned TopReadyCycle
Cycle relative to start when node is ready.
unsigned getNumMicroOps(const MachineInstr *MI, const MCSchedClassDesc *SC=nullptr) const
Return the number of issue slots required for this MI.
void releaseTopNode(SUnit *SU) override
When all predecessor dependencies have been resolved, free this node for top-down scheduling...
Itinerary data supplied by a subtarget to be used by a target.
unsigned NumPredsLeft
of preds not scheduled.
virtual const TargetInstrInfo * getInstrInfo() const
std::vector< SUnit * >::iterator iterator
TargetInstrInfo - Interface to description of machine instruction set.
initializer< Ty > init(const Ty &Val)
bool isCall
Is a function call.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
MachineInstr * getInstr() const
Returns the representative MachineInstr for this SUnit.
Helpers for implementing custom MachineSchedStrategy classes.
PressureChange CurrentMax
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
bool isPseudo(QueryType Type=IgnoreBundle) const
Return true if this is a pseudo instruction that doesn't correspond to a real machine instruction...
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
int pressureChange(const SUnit *SU, bool isBotUp)
Check if the instruction changes the register pressure of a register in the high pressure set...
Track the current register pressure at some position in the instruction stream, and remember the high...
List of PressureChanges in order of increasing, unique PSetID.
bool reserveResources(SUnit *SU, bool IsTop)
Keep track of available resources.
void init(const TargetSubtargetInfo *TSInfo)
Initialize the machine model for instruction scheduling.
unsigned getWeakLeft(const SUnit *SU, bool isTop)
EH_LABEL - Represents a label in mid basic block used to track locations needed for debug and excepti...
static bool isSingleUnscheduledSucc(SUnit *SU, SUnit *SU2)
isSingleUnscheduledSucc - If SU2 is the only unscheduled successor of SU, return true (we may have du...
bool isScheduleHigh
True if preferable to schedule high.
void schedNode(SUnit *SU, bool IsTopNode) override
Update the scheduler's state after scheduling a node.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
bool canReserveResources(const MCInstrDesc *MID)
void getMaxPressureDelta(const MachineInstr *MI, RegPressureDelta &Delta, ArrayRef< PressureChange > CriticalPSets, ArrayRef< unsigned > MaxPressureLimit)
Find the pressure set with the most change beyond its pressure limit after traversing this instructio...
void traceCandidate(const char *Label, const ReadyQueue &Q, SUnit *SU, int Cost, PressureChange P=PressureChange())
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
bool isResourceAvailable(SUnit *SU, bool IsTop)
Check if scheduling of this SU is possible in the current packet.
PressureChange CriticalMax
const MachineBasicBlock * getParent() const
TargetSubtargetInfo - Generic base class for all target subtargets.
unsigned getHeight() const
Returns the height of this node, which is the length of the maximum path down to any node which has n...
const MachineFunction * getParent() const
Return the MachineFunction containing this basic block.
static const unsigned PriorityOne
cl::opt< bool > ForceBottomUp
static bool hasDependence(const SUnit *SUd, const SUnit *SUu, const HexagonInstrInfo &QII)
Return true if there is a dependence between SUd and SUu.
Capture a change in pressure for a single pressure set.
static const unsigned PriorityThree
void releaseBottomNode(SUnit *SU) override
When all successor dependencies have been resolved, free this node for bottom-up scheduling.
Store the effects of a change in pressure on things that MI scheduler cares about.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
static cl::opt< bool > CheckEarlyAvail("check-early-avail", cl::Hidden, cl::ZeroOrMore, cl::init(true))
static const unsigned PriorityTwo
const HexagonInstrInfo * getInstrInfo() const override
virtual ScheduleHazardRecognizer * CreateTargetMIHazardRecognizer(const InstrItineraryData *, const ScheduleDAG *DAG) const
Allocate and return a hazard recognizer to use for this target when scheduling the machine instructio...
SmallVector< SDep, 4 > Succs
All sunit successors.
static const Function * getParent(const Value *V)
bool mayBeCurLoad(const MachineInstr &MI) const
unsigned getIssueWidth() const
Maximum number of micro-ops that may be scheduled per cycle.
static cl::opt< bool > UseNewerCandidate("use-newer-candidate", cl::Hidden, cl::ZeroOrMore, cl::init(true))
static cl::opt< float > RPThreshold("hexagon-reg-pressure", cl::Hidden, cl::init(0.75f), cl::desc("High register pressure threhold."))
bool isInstr() const
Returns true if this SUnit refers to a machine instruction as opposed to an SDNode.
const MCSchedModel & getSchedModel() const
Get the machine model for this subtarget's CPU.
Scheduling unit. This is a node in the scheduling DAG.
cl::opt< bool > ForceTopDown
void reserveResources(const MCInstrDesc *MID)
void initialize(ScheduleDAGMI *dag) override
Initialize the strategy after building the DAG for a new region.