10b57cec5SDimitry Andric //-- SystemZMachineScheduler.cpp - SystemZ Scheduler Interface -*- C++ -*---==//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // -------------------------- Post RA scheduling ---------------------------- //
100b57cec5SDimitry Andric // SystemZPostRASchedStrategy is a scheduling strategy which is plugged into
110b57cec5SDimitry Andric // the MachineScheduler. It has a sorted Available set of SUs and a pickNode()
120b57cec5SDimitry Andric // implementation that looks to optimize decoder grouping and balance the
130b57cec5SDimitry Andric // usage of processor resources. Scheduler states are saved for the end
140b57cec5SDimitry Andric // region of each MBB, so that a successor block can learn from it.
150b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
160b57cec5SDimitry Andric
170b57cec5SDimitry Andric #include "SystemZMachineScheduler.h"
188bcb0991SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
190b57cec5SDimitry Andric
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric
220b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler"
230b57cec5SDimitry Andric
240b57cec5SDimitry Andric #ifndef NDEBUG
250b57cec5SDimitry Andric // Print the set of SUs
260b57cec5SDimitry Andric void SystemZPostRASchedStrategy::SUSet::
dump(SystemZHazardRecognizer & HazardRec) const270b57cec5SDimitry Andric dump(SystemZHazardRecognizer &HazardRec) const {
280b57cec5SDimitry Andric dbgs() << "{";
290b57cec5SDimitry Andric for (auto &SU : *this) {
300b57cec5SDimitry Andric HazardRec.dumpSU(SU, dbgs());
310b57cec5SDimitry Andric if (SU != *rbegin())
320b57cec5SDimitry Andric dbgs() << ", ";
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric dbgs() << "}\n";
350b57cec5SDimitry Andric }
360b57cec5SDimitry Andric #endif
370b57cec5SDimitry Andric
380b57cec5SDimitry Andric // Try to find a single predecessor that would be interesting for the
390b57cec5SDimitry Andric // scheduler in the top-most region of MBB.
getSingleSchedPred(MachineBasicBlock * MBB,const MachineLoop * Loop)400b57cec5SDimitry Andric static MachineBasicBlock *getSingleSchedPred(MachineBasicBlock *MBB,
410b57cec5SDimitry Andric const MachineLoop *Loop) {
420b57cec5SDimitry Andric MachineBasicBlock *PredMBB = nullptr;
430b57cec5SDimitry Andric if (MBB->pred_size() == 1)
440b57cec5SDimitry Andric PredMBB = *MBB->pred_begin();
450b57cec5SDimitry Andric
460b57cec5SDimitry Andric // The loop header has two predecessors, return the latch, but not for a
470b57cec5SDimitry Andric // single block loop.
480b57cec5SDimitry Andric if (MBB->pred_size() == 2 && Loop != nullptr && Loop->getHeader() == MBB) {
49*349cc55cSDimitry Andric for (MachineBasicBlock *Pred : MBB->predecessors())
50*349cc55cSDimitry Andric if (Loop->contains(Pred))
51*349cc55cSDimitry Andric PredMBB = (Pred == MBB ? nullptr : Pred);
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric
540b57cec5SDimitry Andric assert ((PredMBB == nullptr || !Loop || Loop->contains(PredMBB))
550b57cec5SDimitry Andric && "Loop MBB should not consider predecessor outside of loop.");
560b57cec5SDimitry Andric
570b57cec5SDimitry Andric return PredMBB;
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric
600b57cec5SDimitry Andric void SystemZPostRASchedStrategy::
advanceTo(MachineBasicBlock::iterator NextBegin)610b57cec5SDimitry Andric advanceTo(MachineBasicBlock::iterator NextBegin) {
620b57cec5SDimitry Andric MachineBasicBlock::iterator LastEmittedMI = HazardRec->getLastEmittedMI();
630b57cec5SDimitry Andric MachineBasicBlock::iterator I =
640b57cec5SDimitry Andric ((LastEmittedMI != nullptr && LastEmittedMI->getParent() == MBB) ?
650b57cec5SDimitry Andric std::next(LastEmittedMI) : MBB->begin());
660b57cec5SDimitry Andric
670b57cec5SDimitry Andric for (; I != NextBegin; ++I) {
680b57cec5SDimitry Andric if (I->isPosition() || I->isDebugInstr())
690b57cec5SDimitry Andric continue;
700b57cec5SDimitry Andric HazardRec->emitInstruction(&*I);
710b57cec5SDimitry Andric }
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric
initialize(ScheduleDAGMI * dag)740b57cec5SDimitry Andric void SystemZPostRASchedStrategy::initialize(ScheduleDAGMI *dag) {
75e8d8bef9SDimitry Andric Available.clear(); // -misched-cutoff.
760b57cec5SDimitry Andric LLVM_DEBUG(HazardRec->dumpState(););
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric
enterMBB(MachineBasicBlock * NextMBB)790b57cec5SDimitry Andric void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) {
800b57cec5SDimitry Andric assert ((SchedStates.find(NextMBB) == SchedStates.end()) &&
810b57cec5SDimitry Andric "Entering MBB twice?");
820b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Entering " << printMBBReference(*NextMBB));
830b57cec5SDimitry Andric
840b57cec5SDimitry Andric MBB = NextMBB;
850b57cec5SDimitry Andric
860b57cec5SDimitry Andric /// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to
870b57cec5SDimitry Andric /// point to it.
880b57cec5SDimitry Andric HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel);
890b57cec5SDimitry Andric LLVM_DEBUG(const MachineLoop *Loop = MLI->getLoopFor(MBB);
900b57cec5SDimitry Andric if (Loop && Loop->getHeader() == MBB) dbgs() << " (Loop header)";
910b57cec5SDimitry Andric dbgs() << ":\n";);
920b57cec5SDimitry Andric
930b57cec5SDimitry Andric // Try to take over the state from a single predecessor, if it has been
940b57cec5SDimitry Andric // scheduled. If this is not possible, we are done.
950b57cec5SDimitry Andric MachineBasicBlock *SinglePredMBB =
960b57cec5SDimitry Andric getSingleSchedPred(MBB, MLI->getLoopFor(MBB));
970b57cec5SDimitry Andric if (SinglePredMBB == nullptr ||
980b57cec5SDimitry Andric SchedStates.find(SinglePredMBB) == SchedStates.end())
990b57cec5SDimitry Andric return;
1000b57cec5SDimitry Andric
1010b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Continued scheduling from "
1020b57cec5SDimitry Andric << printMBBReference(*SinglePredMBB) << "\n";);
1030b57cec5SDimitry Andric
1040b57cec5SDimitry Andric HazardRec->copyState(SchedStates[SinglePredMBB]);
1050b57cec5SDimitry Andric LLVM_DEBUG(HazardRec->dumpState(););
1060b57cec5SDimitry Andric
1070b57cec5SDimitry Andric // Emit incoming terminator(s). Be optimistic and assume that branch
1080b57cec5SDimitry Andric // prediction will generally do "the right thing".
109*349cc55cSDimitry Andric for (MachineInstr &MI : SinglePredMBB->terminators()) {
110*349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "** Emitting incoming branch: "; MI.dump(););
111*349cc55cSDimitry Andric bool TakenBranch = (MI.isBranch() &&
112*349cc55cSDimitry Andric (TII->getBranchInfo(MI).isIndirect() ||
113*349cc55cSDimitry Andric TII->getBranchInfo(MI).getMBBTarget() == MBB));
114*349cc55cSDimitry Andric HazardRec->emitInstruction(&MI, TakenBranch);
1150b57cec5SDimitry Andric if (TakenBranch)
1160b57cec5SDimitry Andric break;
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric
leaveMBB()1200b57cec5SDimitry Andric void SystemZPostRASchedStrategy::leaveMBB() {
1210b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Leaving " << printMBBReference(*MBB) << "\n";);
1220b57cec5SDimitry Andric
1230b57cec5SDimitry Andric // Advance to first terminator. The successor block will handle terminators
1240b57cec5SDimitry Andric // dependent on CFG layout (T/NT branch etc).
1250b57cec5SDimitry Andric advanceTo(MBB->getFirstTerminator());
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric
1280b57cec5SDimitry Andric SystemZPostRASchedStrategy::
SystemZPostRASchedStrategy(const MachineSchedContext * C)1290b57cec5SDimitry Andric SystemZPostRASchedStrategy(const MachineSchedContext *C)
1300b57cec5SDimitry Andric : MLI(C->MLI),
1310b57cec5SDimitry Andric TII(static_cast<const SystemZInstrInfo *>
1320b57cec5SDimitry Andric (C->MF->getSubtarget().getInstrInfo())),
1330b57cec5SDimitry Andric MBB(nullptr), HazardRec(nullptr) {
1340b57cec5SDimitry Andric const TargetSubtargetInfo *ST = &C->MF->getSubtarget();
1350b57cec5SDimitry Andric SchedModel.init(ST);
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric
~SystemZPostRASchedStrategy()1380b57cec5SDimitry Andric SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() {
1390b57cec5SDimitry Andric // Delete hazard recognizers kept around for each MBB.
1400b57cec5SDimitry Andric for (auto I : SchedStates) {
1410b57cec5SDimitry Andric SystemZHazardRecognizer *hazrec = I.second;
1420b57cec5SDimitry Andric delete hazrec;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric
initPolicy(MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End,unsigned NumRegionInstrs)1460b57cec5SDimitry Andric void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin,
1470b57cec5SDimitry Andric MachineBasicBlock::iterator End,
1480b57cec5SDimitry Andric unsigned NumRegionInstrs) {
1490b57cec5SDimitry Andric // Don't emit the terminators.
1500b57cec5SDimitry Andric if (Begin->isTerminator())
1510b57cec5SDimitry Andric return;
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric // Emit any instructions before start of region.
1540b57cec5SDimitry Andric advanceTo(Begin);
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric
1570b57cec5SDimitry Andric // Pick the next node to schedule.
pickNode(bool & IsTopNode)1580b57cec5SDimitry Andric SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) {
1590b57cec5SDimitry Andric // Only scheduling top-down.
1600b57cec5SDimitry Andric IsTopNode = true;
1610b57cec5SDimitry Andric
1620b57cec5SDimitry Andric if (Available.empty())
1630b57cec5SDimitry Andric return nullptr;
1640b57cec5SDimitry Andric
1650b57cec5SDimitry Andric // If only one choice, return it.
1660b57cec5SDimitry Andric if (Available.size() == 1) {
1670b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Only one: ";
1680b57cec5SDimitry Andric HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);
1690b57cec5SDimitry Andric return *Available.begin();
1700b57cec5SDimitry Andric }
1710b57cec5SDimitry Andric
1720b57cec5SDimitry Andric // All nodes that are possible to schedule are stored in the Available set.
1730b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Available: "; Available.dump(*HazardRec););
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric Candidate Best;
1760b57cec5SDimitry Andric for (auto *SU : Available) {
1770b57cec5SDimitry Andric
1780b57cec5SDimitry Andric // SU is the next candidate to be compared against current Best.
1790b57cec5SDimitry Andric Candidate c(SU, *HazardRec);
1800b57cec5SDimitry Andric
1810b57cec5SDimitry Andric // Remeber which SU is the best candidate.
1820b57cec5SDimitry Andric if (Best.SU == nullptr || c < Best) {
1830b57cec5SDimitry Andric Best = c;
1840b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Best so far: ";);
1850b57cec5SDimitry Andric } else
1860b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Tried : ";);
1870b57cec5SDimitry Andric LLVM_DEBUG(HazardRec->dumpSU(c.SU, dbgs()); c.dumpCosts();
1880b57cec5SDimitry Andric dbgs() << " Height:" << c.SU->getHeight(); dbgs() << "\n";);
1890b57cec5SDimitry Andric
1900b57cec5SDimitry Andric // Once we know we have seen all SUs that affect grouping or use unbuffered
1910b57cec5SDimitry Andric // resources, we can stop iterating if Best looks good.
1920b57cec5SDimitry Andric if (!SU->isScheduleHigh && Best.noCost())
1930b57cec5SDimitry Andric break;
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric
1960b57cec5SDimitry Andric assert (Best.SU != nullptr);
1970b57cec5SDimitry Andric return Best.SU;
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric
2000b57cec5SDimitry Andric SystemZPostRASchedStrategy::Candidate::
Candidate(SUnit * SU_,SystemZHazardRecognizer & HazardRec)2010b57cec5SDimitry Andric Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() {
2020b57cec5SDimitry Andric SU = SU_;
2030b57cec5SDimitry Andric
2040b57cec5SDimitry Andric // Check the grouping cost. For a node that must begin / end a
2050b57cec5SDimitry Andric // group, it is positive if it would do so prematurely, or negative
2060b57cec5SDimitry Andric // if it would fit naturally into the schedule.
2070b57cec5SDimitry Andric GroupingCost = HazardRec.groupingCost(SU);
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric // Check the resources cost for this SU.
2100b57cec5SDimitry Andric ResourcesCost = HazardRec.resourcesCost(SU);
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric
2130b57cec5SDimitry Andric bool SystemZPostRASchedStrategy::Candidate::
operator <(const Candidate & other)2140b57cec5SDimitry Andric operator<(const Candidate &other) {
2150b57cec5SDimitry Andric
2160b57cec5SDimitry Andric // Check decoder grouping.
2170b57cec5SDimitry Andric if (GroupingCost < other.GroupingCost)
2180b57cec5SDimitry Andric return true;
2190b57cec5SDimitry Andric if (GroupingCost > other.GroupingCost)
2200b57cec5SDimitry Andric return false;
2210b57cec5SDimitry Andric
2220b57cec5SDimitry Andric // Compare the use of resources.
2230b57cec5SDimitry Andric if (ResourcesCost < other.ResourcesCost)
2240b57cec5SDimitry Andric return true;
2250b57cec5SDimitry Andric if (ResourcesCost > other.ResourcesCost)
2260b57cec5SDimitry Andric return false;
2270b57cec5SDimitry Andric
2280b57cec5SDimitry Andric // Higher SU is otherwise generally better.
2290b57cec5SDimitry Andric if (SU->getHeight() > other.SU->getHeight())
2300b57cec5SDimitry Andric return true;
2310b57cec5SDimitry Andric if (SU->getHeight() < other.SU->getHeight())
2320b57cec5SDimitry Andric return false;
2330b57cec5SDimitry Andric
2340b57cec5SDimitry Andric // If all same, fall back to original order.
2350b57cec5SDimitry Andric if (SU->NodeNum < other.SU->NodeNum)
2360b57cec5SDimitry Andric return true;
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric return false;
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric
schedNode(SUnit * SU,bool IsTopNode)2410b57cec5SDimitry Andric void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
2420b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Scheduling SU(" << SU->NodeNum << ") ";
2430b57cec5SDimitry Andric if (Available.size() == 1) dbgs() << "(only one) ";
2440b57cec5SDimitry Andric Candidate c(SU, *HazardRec); c.dumpCosts(); dbgs() << "\n";);
2450b57cec5SDimitry Andric
2460b57cec5SDimitry Andric // Remove SU from Available set and update HazardRec.
2470b57cec5SDimitry Andric Available.erase(SU);
2480b57cec5SDimitry Andric HazardRec->EmitInstruction(SU);
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric
releaseTopNode(SUnit * SU)2510b57cec5SDimitry Andric void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {
2520b57cec5SDimitry Andric // Set isScheduleHigh flag on all SUs that we want to consider first in
2530b57cec5SDimitry Andric // pickNode().
2540b57cec5SDimitry Andric const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU);
2550b57cec5SDimitry Andric bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup));
2560b57cec5SDimitry Andric SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered);
2570b57cec5SDimitry Andric
2580b57cec5SDimitry Andric // Put all released SUs in the Available set.
2590b57cec5SDimitry Andric Available.insert(SU);
2600b57cec5SDimitry Andric }
261