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) {
490b57cec5SDimitry Andric for (auto I = MBB->pred_begin(); I != MBB->pred_end(); ++I)
500b57cec5SDimitry Andric if (Loop->contains(*I))
510b57cec5SDimitry Andric PredMBB = (*I == MBB ? nullptr : *I);
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) {
75*af732203SDimitry 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".
1090b57cec5SDimitry Andric for (MachineBasicBlock::iterator I = SinglePredMBB->getFirstTerminator();
1100b57cec5SDimitry Andric I != SinglePredMBB->end(); I++) {
1110b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Emitting incoming branch: "; I->dump(););
1120b57cec5SDimitry Andric bool TakenBranch = (I->isBranch() &&
1130b57cec5SDimitry Andric (TII->getBranchInfo(*I).isIndirect() ||
1140b57cec5SDimitry Andric TII->getBranchInfo(*I).getMBBTarget() == MBB));
1150b57cec5SDimitry Andric HazardRec->emitInstruction(&*I, TakenBranch);
1160b57cec5SDimitry Andric if (TakenBranch)
1170b57cec5SDimitry Andric break;
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric }
1200b57cec5SDimitry Andric
leaveMBB()1210b57cec5SDimitry Andric void SystemZPostRASchedStrategy::leaveMBB() {
1220b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Leaving " << printMBBReference(*MBB) << "\n";);
1230b57cec5SDimitry Andric
1240b57cec5SDimitry Andric // Advance to first terminator. The successor block will handle terminators
1250b57cec5SDimitry Andric // dependent on CFG layout (T/NT branch etc).
1260b57cec5SDimitry Andric advanceTo(MBB->getFirstTerminator());
1270b57cec5SDimitry Andric }
1280b57cec5SDimitry Andric
1290b57cec5SDimitry Andric SystemZPostRASchedStrategy::
SystemZPostRASchedStrategy(const MachineSchedContext * C)1300b57cec5SDimitry Andric SystemZPostRASchedStrategy(const MachineSchedContext *C)
1310b57cec5SDimitry Andric : MLI(C->MLI),
1320b57cec5SDimitry Andric TII(static_cast<const SystemZInstrInfo *>
1330b57cec5SDimitry Andric (C->MF->getSubtarget().getInstrInfo())),
1340b57cec5SDimitry Andric MBB(nullptr), HazardRec(nullptr) {
1350b57cec5SDimitry Andric const TargetSubtargetInfo *ST = &C->MF->getSubtarget();
1360b57cec5SDimitry Andric SchedModel.init(ST);
1370b57cec5SDimitry Andric }
1380b57cec5SDimitry Andric
~SystemZPostRASchedStrategy()1390b57cec5SDimitry Andric SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() {
1400b57cec5SDimitry Andric // Delete hazard recognizers kept around for each MBB.
1410b57cec5SDimitry Andric for (auto I : SchedStates) {
1420b57cec5SDimitry Andric SystemZHazardRecognizer *hazrec = I.second;
1430b57cec5SDimitry Andric delete hazrec;
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric }
1460b57cec5SDimitry Andric
initPolicy(MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End,unsigned NumRegionInstrs)1470b57cec5SDimitry Andric void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin,
1480b57cec5SDimitry Andric MachineBasicBlock::iterator End,
1490b57cec5SDimitry Andric unsigned NumRegionInstrs) {
1500b57cec5SDimitry Andric // Don't emit the terminators.
1510b57cec5SDimitry Andric if (Begin->isTerminator())
1520b57cec5SDimitry Andric return;
1530b57cec5SDimitry Andric
1540b57cec5SDimitry Andric // Emit any instructions before start of region.
1550b57cec5SDimitry Andric advanceTo(Begin);
1560b57cec5SDimitry Andric }
1570b57cec5SDimitry Andric
1580b57cec5SDimitry Andric // Pick the next node to schedule.
pickNode(bool & IsTopNode)1590b57cec5SDimitry Andric SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) {
1600b57cec5SDimitry Andric // Only scheduling top-down.
1610b57cec5SDimitry Andric IsTopNode = true;
1620b57cec5SDimitry Andric
1630b57cec5SDimitry Andric if (Available.empty())
1640b57cec5SDimitry Andric return nullptr;
1650b57cec5SDimitry Andric
1660b57cec5SDimitry Andric // If only one choice, return it.
1670b57cec5SDimitry Andric if (Available.size() == 1) {
1680b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Only one: ";
1690b57cec5SDimitry Andric HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);
1700b57cec5SDimitry Andric return *Available.begin();
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric
1730b57cec5SDimitry Andric // All nodes that are possible to schedule are stored in the Available set.
1740b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Available: "; Available.dump(*HazardRec););
1750b57cec5SDimitry Andric
1760b57cec5SDimitry Andric Candidate Best;
1770b57cec5SDimitry Andric for (auto *SU : Available) {
1780b57cec5SDimitry Andric
1790b57cec5SDimitry Andric // SU is the next candidate to be compared against current Best.
1800b57cec5SDimitry Andric Candidate c(SU, *HazardRec);
1810b57cec5SDimitry Andric
1820b57cec5SDimitry Andric // Remeber which SU is the best candidate.
1830b57cec5SDimitry Andric if (Best.SU == nullptr || c < Best) {
1840b57cec5SDimitry Andric Best = c;
1850b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Best so far: ";);
1860b57cec5SDimitry Andric } else
1870b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Tried : ";);
1880b57cec5SDimitry Andric LLVM_DEBUG(HazardRec->dumpSU(c.SU, dbgs()); c.dumpCosts();
1890b57cec5SDimitry Andric dbgs() << " Height:" << c.SU->getHeight(); dbgs() << "\n";);
1900b57cec5SDimitry Andric
1910b57cec5SDimitry Andric // Once we know we have seen all SUs that affect grouping or use unbuffered
1920b57cec5SDimitry Andric // resources, we can stop iterating if Best looks good.
1930b57cec5SDimitry Andric if (!SU->isScheduleHigh && Best.noCost())
1940b57cec5SDimitry Andric break;
1950b57cec5SDimitry Andric }
1960b57cec5SDimitry Andric
1970b57cec5SDimitry Andric assert (Best.SU != nullptr);
1980b57cec5SDimitry Andric return Best.SU;
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric
2010b57cec5SDimitry Andric SystemZPostRASchedStrategy::Candidate::
Candidate(SUnit * SU_,SystemZHazardRecognizer & HazardRec)2020b57cec5SDimitry Andric Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() {
2030b57cec5SDimitry Andric SU = SU_;
2040b57cec5SDimitry Andric
2050b57cec5SDimitry Andric // Check the grouping cost. For a node that must begin / end a
2060b57cec5SDimitry Andric // group, it is positive if it would do so prematurely, or negative
2070b57cec5SDimitry Andric // if it would fit naturally into the schedule.
2080b57cec5SDimitry Andric GroupingCost = HazardRec.groupingCost(SU);
2090b57cec5SDimitry Andric
2100b57cec5SDimitry Andric // Check the resources cost for this SU.
2110b57cec5SDimitry Andric ResourcesCost = HazardRec.resourcesCost(SU);
2120b57cec5SDimitry Andric }
2130b57cec5SDimitry Andric
2140b57cec5SDimitry Andric bool SystemZPostRASchedStrategy::Candidate::
operator <(const Candidate & other)2150b57cec5SDimitry Andric operator<(const Candidate &other) {
2160b57cec5SDimitry Andric
2170b57cec5SDimitry Andric // Check decoder grouping.
2180b57cec5SDimitry Andric if (GroupingCost < other.GroupingCost)
2190b57cec5SDimitry Andric return true;
2200b57cec5SDimitry Andric if (GroupingCost > other.GroupingCost)
2210b57cec5SDimitry Andric return false;
2220b57cec5SDimitry Andric
2230b57cec5SDimitry Andric // Compare the use of resources.
2240b57cec5SDimitry Andric if (ResourcesCost < other.ResourcesCost)
2250b57cec5SDimitry Andric return true;
2260b57cec5SDimitry Andric if (ResourcesCost > other.ResourcesCost)
2270b57cec5SDimitry Andric return false;
2280b57cec5SDimitry Andric
2290b57cec5SDimitry Andric // Higher SU is otherwise generally better.
2300b57cec5SDimitry Andric if (SU->getHeight() > other.SU->getHeight())
2310b57cec5SDimitry Andric return true;
2320b57cec5SDimitry Andric if (SU->getHeight() < other.SU->getHeight())
2330b57cec5SDimitry Andric return false;
2340b57cec5SDimitry Andric
2350b57cec5SDimitry Andric // If all same, fall back to original order.
2360b57cec5SDimitry Andric if (SU->NodeNum < other.SU->NodeNum)
2370b57cec5SDimitry Andric return true;
2380b57cec5SDimitry Andric
2390b57cec5SDimitry Andric return false;
2400b57cec5SDimitry Andric }
2410b57cec5SDimitry Andric
schedNode(SUnit * SU,bool IsTopNode)2420b57cec5SDimitry Andric void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
2430b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Scheduling SU(" << SU->NodeNum << ") ";
2440b57cec5SDimitry Andric if (Available.size() == 1) dbgs() << "(only one) ";
2450b57cec5SDimitry Andric Candidate c(SU, *HazardRec); c.dumpCosts(); dbgs() << "\n";);
2460b57cec5SDimitry Andric
2470b57cec5SDimitry Andric // Remove SU from Available set and update HazardRec.
2480b57cec5SDimitry Andric Available.erase(SU);
2490b57cec5SDimitry Andric HazardRec->EmitInstruction(SU);
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric
releaseTopNode(SUnit * SU)2520b57cec5SDimitry Andric void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {
2530b57cec5SDimitry Andric // Set isScheduleHigh flag on all SUs that we want to consider first in
2540b57cec5SDimitry Andric // pickNode().
2550b57cec5SDimitry Andric const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU);
2560b57cec5SDimitry Andric bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup));
2570b57cec5SDimitry Andric SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered);
2580b57cec5SDimitry Andric
2590b57cec5SDimitry Andric // Put all released SUs in the Available set.
2600b57cec5SDimitry Andric Available.insert(SU);
2610b57cec5SDimitry Andric }
262