21 #define DEBUG_TYPE "misched"
25 SUnit* LastSequentialCall =
nullptr;
28 for (
unsigned su = 0, e =
SUnits.size(); su != e; ++su) {
30 if (
SUnits[su].getInstr()->isCall())
31 LastSequentialCall = &(
SUnits[su]);
33 else if (
SUnits[su].getInstr()->isCompare() && LastSequentialCall)
65 for (
unsigned i = 0, e = Packet.size(); i != e; ++i) {
66 if (Packet[i]->Succs.size() == 0)
69 E = Packet[i]->Succs.end();
I != E; ++
I) {
75 if (
I->getSUnit() == SU)
84 bool startNewCycle =
false;
117 Packet.push_back(SU);
120 DEBUG(
dbgs() <<
"Packet[" << TotalPackets <<
"]:\n");
121 for (
unsigned i = 0, e = Packet.size(); i != e; ++i) {
123 DEBUG(
dbgs() << Packet[i]->NodeNum <<
")\t");
134 startNewCycle =
true;
137 return startNewCycle;
145 <<
"********** MI Converging Scheduling VLIW BB#" <<
BB->
getNumber()
166 DEBUG(
unsigned maxH = 0;
167 for (
unsigned su = 0, e =
SUnits.size(); su != e; ++su)
168 if (
SUnits[su].getHeight() > maxH)
169 maxH =
SUnits[su].getHeight();
170 dbgs() <<
"Max Height " << maxH <<
"\n";);
171 DEBUG(
unsigned maxD = 0;
172 for (
unsigned su = 0, e =
SUnits.size(); su != e; ++su)
173 if (
SUnits[su].getDepth() > maxD)
174 maxD =
SUnits[su].getDepth();
175 dbgs() <<
"Max Depth " << maxD <<
"\n";);
176 DEBUG(
for (
unsigned su = 0, e =
SUnits.size(); su != e; ++su)
177 SUnits[su].dumpAll(
this));
181 bool IsTopNode =
false;
202 Top.init(DAG, SchedModel);
203 Bot.init(DAG, SchedModel);
210 delete Top.HazardRec;
211 delete Bot.HazardRec;
215 delete Top.ResourceModel;
216 delete Bot.ResourceModel;
221 "-misched-topdown incompatible with -misched-bottomup");
230 unsigned PredReadyCycle =
I->getSUnit()->TopReadyCycle;
231 unsigned MinLatency =
I->getLatency();
233 Top.MaxMinLatency = std::max(MinLatency, Top.MaxMinLatency);
245 assert(SU->
getInstr() &&
"Scheduled SUnit must have instr");
249 unsigned SuccReadyCycle =
I->getSUnit()->BotReadyCycle;
250 unsigned MinLatency =
I->getLatency();
252 Bot.MaxMinLatency = std::max(MinLatency, Bot.MaxMinLatency);
273 bool ConvergingVLIWScheduler::VLIWSchedBoundary::checkHazard(
SUnit *SU) {
274 if (HazardRec->isEnabled())
277 unsigned uops = SchedModel->getNumMicroOps(SU->
getInstr());
278 if (IssueCount + uops > SchedModel->getIssueWidth())
284 void ConvergingVLIWScheduler::VLIWSchedBoundary::releaseNode(
SUnit *SU,
285 unsigned ReadyCycle) {
286 if (ReadyCycle < MinReadyCycle)
287 MinReadyCycle = ReadyCycle;
291 if (ReadyCycle > CurrCycle || checkHazard(SU))
299 void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpCycle() {
300 unsigned Width = SchedModel->getIssueWidth();
301 IssueCount = (IssueCount <= Width) ? 0 : IssueCount - Width;
303 assert(MinReadyCycle < UINT_MAX &&
"MinReadyCycle uninitialized");
304 unsigned NextCycle = std::max(CurrCycle + 1, MinReadyCycle);
306 if (!HazardRec->isEnabled()) {
308 CurrCycle = NextCycle;
311 for (; CurrCycle != NextCycle; ++CurrCycle) {
313 HazardRec->AdvanceCycle();
315 HazardRec->RecedeCycle();
320 DEBUG(
dbgs() <<
"*** " << Available.getName() <<
" cycle "
321 << CurrCycle <<
'\n');
325 void ConvergingVLIWScheduler::VLIWSchedBoundary::bumpNode(
SUnit *SU) {
326 bool startNewCycle =
false;
329 if (HazardRec->isEnabled()) {
330 if (!isTop() && SU->
isCall) {
335 HazardRec->EmitInstruction(SU);
339 startNewCycle = ResourceModel->reserveResources(SU);
343 IssueCount += SchedModel->getNumMicroOps(SU->
getInstr());
345 DEBUG(
dbgs() <<
"*** Max instrs at cycle " << CurrCycle <<
'\n');
349 DEBUG(
dbgs() <<
"*** IssueCount " << IssueCount
350 <<
" at cycle " << CurrCycle <<
'\n');
355 void ConvergingVLIWScheduler::VLIWSchedBoundary::releasePending() {
357 if (Available.empty())
358 MinReadyCycle = UINT_MAX;
362 for (
unsigned i = 0, e = Pending.size(); i != e; ++i) {
363 SUnit *SU = *(Pending.begin()+i);
366 if (ReadyCycle < MinReadyCycle)
367 MinReadyCycle = ReadyCycle;
369 if (ReadyCycle > CurrCycle)
376 Pending.remove(Pending.begin()+i);
379 CheckPending =
false;
383 void ConvergingVLIWScheduler::VLIWSchedBoundary::removeReady(
SUnit *SU) {
384 if (Available.isInQueue(SU))
385 Available.remove(Available.find(SU));
387 assert(Pending.isInQueue(SU) &&
"bad ready count");
388 Pending.remove(Pending.find(SU));
395 SUnit *ConvergingVLIWScheduler::VLIWSchedBoundary::pickOnlyChoice() {
399 for (
unsigned i = 0; Available.empty(); ++i) {
400 assert(i <= (HazardRec->getMaxLookAhead() + MaxMinLatency) &&
401 "permanent hazard"); (void)i;
402 ResourceModel->reserveResources(
nullptr);
406 if (Available.size() == 1)
407 return *Available.begin();
428 SUnit *OnlyAvailablePred =
nullptr;
431 SUnit &Pred = *
I->getSUnit();
435 if (OnlyAvailablePred && OnlyAvailablePred != &Pred)
437 OnlyAvailablePred = &Pred;
440 return OnlyAvailablePred;
446 SUnit *OnlyAvailableSucc =
nullptr;
449 SUnit &Succ = *
I->getSUnit();
453 if (OnlyAvailableSucc && OnlyAvailableSucc != &Succ)
455 OnlyAvailableSucc = &Succ;
458 return OnlyAvailableSucc;
471 SchedCandidate &Candidate,
491 if (Top.ResourceModel->isResourceAvailable(SU))
498 if (Bot.ResourceModel->isResourceAvailable(SU))
502 unsigned NumNodesBlocking = 0;
519 ResCount += (NumNodesBlocking *
ScaleTwo);
525 DEBUG(
if (verbose)
dbgs() <<
" Total(" << ResCount <<
")");
537 SchedCandidate &Candidate) {
544 CandResult FoundCandidate = NoCand;
547 TempTracker.getMaxPressureDelta((*I)->getInstr(), RPDelta,
556 Candidate.RPDelta = RPDelta;
557 Candidate.SCost = CurrentCost;
558 FoundCandidate = NodeOrder;
563 if (CurrentCost > Candidate.SCost) {
566 Candidate.RPDelta = RPDelta;
567 Candidate.SCost = CurrentCost;
568 FoundCandidate = BestCost;
574 if (FoundCandidate == NoCand)
577 return FoundCandidate;
584 if (
SUnit *SU = Bot.pickOnlyChoice()) {
588 if (
SUnit *SU = Top.pickOnlyChoice()) {
592 SchedCandidate BotCand;
596 assert(BotResult != NoCand &&
"failed to find the first candidate");
605 if (BotResult == SingleExcess || BotResult == SingleCritical) {
610 SchedCandidate TopCand;
613 assert(TopResult != NoCand &&
"failed to find the first candidate");
615 if (TopResult == SingleExcess || TopResult == SingleCritical) {
621 if (BotResult == SingleMax) {
625 if (TopResult == SingleMax) {
629 if (TopCand.SCost > BotCand.SCost) {
641 assert(Top.Available.empty() && Top.Pending.empty() &&
642 Bot.Available.empty() && Bot.Pending.empty() &&
"ReadyQ garbage");
647 SU = Top.pickOnlyChoice();
649 SchedCandidate TopCand;
650 CandResult TopResult =
652 assert(TopResult != NoCand &&
"failed to find the first candidate");
658 SU = Bot.pickOnlyChoice();
660 SchedCandidate BotCand;
661 CandResult BotResult =
663 assert(BotResult != NoCand &&
"failed to find the first candidate");
676 DEBUG(
dbgs() <<
"*** " << (IsTopNode ?
"Top" :
"Bottom")
677 <<
" Scheduling Instruction in cycle "
678 << (IsTopNode ? Top.CurrCycle : Bot.CurrCycle) <<
'\n';
bool canReserveResources(const llvm::MCInstrDesc *MID)
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...
const MachineFunction * getParent() const
getParent - Return the MachineFunction containing this basic block.
void schedule() override
Schedule - This is called back from ScheduleDAGInstrs::Run() when it's time to do some work...
Extend the standard ScheduleDAGMI to provide more context and override the top-level schedule() drive...
int getNumber() const
getNumber - MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a M...
int SchedulingCost(ReadyQueue &Q, SUnit *SU, SchedCandidate &Candidate, RegPressureDelta &Delta, bool verbose)
Single point to compute overall scheduling cost.
MachineBasicBlock::iterator CurrentTop
The top of the unscheduled zone.
MachineInstr * getInstr() const
getInstr - Return the representative MachineInstr for this SUnit.
CandResult pickNodeFromQueue(ReadyQueue &Q, const RegPressureTracker &RPTracker, SchedCandidate &Candidate)
Pick the best candidate from the top queue.
static SUnit * getSingleUnscheduledPred(SUnit *SU)
getSingleUnscheduledPred - If there is exactly one unscheduled predecessor of SU, return it...
const Function * getFunction() const
getFunction - Return the LLVM function that this machine code represents
MachineBasicBlock::iterator top() const
const RegPressureTracker & getTopRPTracker() const
ScheduleDAGMI is an implementation of ScheduleDAGInstrs that simply schedules machine instructions ac...
std::unique_ptr< MachineSchedStrategy > SchedImpl
const RegPressureTracker & getBotRPTracker() const
void updateQueues(SUnit *SU, bool IsTopNode)
Update scheduler DAG and queues after scheduling an instruction.
SmallVector< SDep, 4 > Preds
StringRef getName() const
Return a constant reference to the value's name.
const TargetSchedModel * getSchedModel() const
Get the machine model for instruction scheduling.
COPY - Target-independent register copy.
unsigned getHeight() const
getHeight - Return the height of this node, which is the length of the maximum path down to any node ...
SUnit * pickNodeBidrectional(bool &IsTopNode)
Pick the best candidate node from either the top or bottom queue.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
static const unsigned ScaleTwo
const HexagonInstrInfo * TII
virtual const char * getRegPressureSetName(unsigned Idx) const =0
Get the name of this register unit pressure set.
SUnit * pickNode(bool &IsTopNode) override
Pick the best node to balance the schedule. Implements MachineSchedStrategy.
static SUnit * getSingleUnscheduledSucc(SUnit *SU)
getSingleUnscheduledSucc - If there is exactly one unscheduled successor of SU, return it...
void scheduleMI(SUnit *SU, bool IsTopNode)
Move an instruction and update register pressure.
void releaseTopNode(SUnit *SU) override
When all predecessor dependencies have been resolved, free this node for top-down scheduling...
void buildDAGWithRegPressure()
Call ScheduleDAGInstrs::buildSchedGraph with register pressure tracking enabled.
Itinerary data supplied by a subtarget to be used by a target.
void reserveResources(const llvm::MCInstrDesc *MID)
unsigned getOpcode() const
Returns the opcode of this MachineInstr.
TargetInstrInfo - Interface to description of machine instruction set.
std::vector< SUnit * >::iterator iterator
SDep - Scheduling dependency.
IMPLICIT_DEF - This is the MachineInstr-level equivalent of undef.
void dump(const SparseBitVector< ElementSize > &LHS, raw_ostream &out)
Helpers for implementing custom MachineSchedStrategy classes.
const InstrItineraryData * getInstrItineraries() const
INSERT_SUBREG - This instruction takes three operands: a register that has subregisters, a register providing an insert value, and a subregister index.
Track the current register pressure at some position in the instruction stream, and remember the high...
void findRootsAndBiasEdges(SmallVectorImpl< SUnit * > &TopRoots, SmallVectorImpl< SUnit * > &BotRoots)
bool isResourceAvailable(SUnit *SU)
Check if scheduling of this SU is possible in the current packet.
const IntervalPressure & getRegPressure() const
Get register pressure for the entire scheduling region before scheduling.
static const unsigned FactorOne
REG_SEQUENCE - This variadic instruction is used to form a register that represents a consecutive seq...
An unknown scheduling barrier.
std::vector< unsigned > MaxSetPressure
Map of max reg pressure indexed by pressure set ID, not class ID.
void traceCandidate(const char *Label, const ReadyQueue &Q, SUnit *SU, PressureChange P=PressureChange())
EXTRACT_SUBREG - This instruction takes two operands: a register that has subregisters, and a subregister index.
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...
const MachineLoopInfo * MLI
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
StringRef getName() const
getName - Return the name of the corresponding LLVM basic block, or "(null)".
PressureChange CriticalMax
MachineBasicBlock::iterator bottom() const
KILL - This instruction is a noop that is used only to adjust the liveness of registers.
unsigned getDepth() const
getDepth - Return the depth of this node, which is the length of the maximum path up to any node whic...
TargetSubtargetInfo - Generic base class for all target subtargets.
const TargetRegisterInfo * TRI
static const unsigned PriorityOne
cl::opt< bool > ForceBottomUp
Capture a change in pressure for a single pressure set.
void postprocessDAG()
Perform platform-specific DAG postprocessing.
void placeDebugValues()
Reinsert debug_values recorded in ScheduleDAGInstrs::DbgValues.
bool reserveResources(SUnit *SU)
Keep track of available resources.
const std::vector< PressureChange > & getRegionCriticalPSets() const
void releaseBottomNode(SUnit *SU) override
When all successor dependencies have been resolved, free this node for bottom-up scheduling.
unsigned getLoopDepth(const MachineBasicBlock *BB) const
getLoopDepth - Return the loop nesting level of the specified block...
MachineBasicBlock::iterator CurrentBottom
The bottom of the unscheduled zone.
Store the effects of a change in pressure on things that MI scheduler cares about.
void initQueues(ArrayRef< SUnit * > TopRoots, ArrayRef< SUnit * > BotRoots)
Release ExitSU predecessors and setup scheduler queues.
virtual const TargetInstrInfo * getInstrInfo() const
static const unsigned PriorityTwo
SmallVector< SDep, 4 > Succs
unsigned getIssueWidth() const
Maximum number of micro-ops that may be scheduled per cycle.
bool isBottomReady() const
StringRef getName() const
MachineBasicBlock * BB
State specific to the current scheduling region.
SUBREG_TO_REG - This instruction is similar to INSERT_SUBREG except that the first operand is an imme...
std::vector< SUnit > SUnits
void dump(const ScheduleDAG *G) const
SUnit - Scheduling unit.
SUnit - Scheduling unit. This is a node in the scheduling DAG.
cl::opt< bool > ForceTopDown
void initialize(ScheduleDAGMI *dag) override
Initialize the strategy after building the DAG for a new region.