18010b631SJonas Paulsson //-- SystemZMachineScheduler.cpp - SystemZ Scheduler Interface -*- C++ -*---==//
28010b631SJonas Paulsson //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68010b631SJonas Paulsson //
78010b631SJonas Paulsson //===----------------------------------------------------------------------===//
88010b631SJonas Paulsson //
98010b631SJonas Paulsson // -------------------------- Post RA scheduling ---------------------------- //
108010b631SJonas Paulsson // SystemZPostRASchedStrategy is a scheduling strategy which is plugged into
118010b631SJonas Paulsson // the MachineScheduler. It has a sorted Available set of SUs and a pickNode()
128010b631SJonas Paulsson // implementation that looks to optimize decoder grouping and balance the
1357a705d9SJonas Paulsson // usage of processor resources. Scheduler states are saved for the end
1457a705d9SJonas Paulsson // region of each MBB, so that a successor block can learn from it.
158010b631SJonas Paulsson //===----------------------------------------------------------------------===//
168010b631SJonas Paulsson
178010b631SJonas Paulsson #include "SystemZMachineScheduler.h"
18904cd3e0SReid Kleckner #include "llvm/CodeGen/MachineLoopInfo.h"
198010b631SJonas Paulsson
208010b631SJonas Paulsson using namespace llvm;
218010b631SJonas Paulsson
220cd23f56SEvandro Menezes #define DEBUG_TYPE "machine-scheduler"
238010b631SJonas Paulsson
248010b631SJonas Paulsson #ifndef NDEBUG
258010b631SJonas Paulsson // Print the set of SUs
268010b631SJonas Paulsson void SystemZPostRASchedStrategy::SUSet::
dump(SystemZHazardRecognizer & HazardRec) const276da25f4fSRafael Espindola dump(SystemZHazardRecognizer &HazardRec) const {
288010b631SJonas Paulsson dbgs() << "{";
298010b631SJonas Paulsson for (auto &SU : *this) {
308010b631SJonas Paulsson HazardRec.dumpSU(SU, dbgs());
318010b631SJonas Paulsson if (SU != *rbegin())
328010b631SJonas Paulsson dbgs() << ", ";
338010b631SJonas Paulsson }
348010b631SJonas Paulsson dbgs() << "}\n";
358010b631SJonas Paulsson }
368010b631SJonas Paulsson #endif
378010b631SJonas Paulsson
3857a705d9SJonas Paulsson // Try to find a single predecessor that would be interesting for the
3957a705d9SJonas Paulsson // scheduler in the top-most region of MBB.
getSingleSchedPred(MachineBasicBlock * MBB,const MachineLoop * Loop)4057a705d9SJonas Paulsson static MachineBasicBlock *getSingleSchedPred(MachineBasicBlock *MBB,
4157a705d9SJonas Paulsson const MachineLoop *Loop) {
4257a705d9SJonas Paulsson MachineBasicBlock *PredMBB = nullptr;
4357a705d9SJonas Paulsson if (MBB->pred_size() == 1)
4457a705d9SJonas Paulsson PredMBB = *MBB->pred_begin();
4557a705d9SJonas Paulsson
4657a705d9SJonas Paulsson // The loop header has two predecessors, return the latch, but not for a
4757a705d9SJonas Paulsson // single block loop.
4857a705d9SJonas Paulsson if (MBB->pred_size() == 2 && Loop != nullptr && Loop->getHeader() == MBB) {
49*ef2d0e0fSKazu Hirata for (MachineBasicBlock *Pred : MBB->predecessors())
50*ef2d0e0fSKazu Hirata if (Loop->contains(Pred))
51*ef2d0e0fSKazu Hirata PredMBB = (Pred == MBB ? nullptr : Pred);
5257a705d9SJonas Paulsson }
5357a705d9SJonas Paulsson
5457a705d9SJonas Paulsson assert ((PredMBB == nullptr || !Loop || Loop->contains(PredMBB))
5557a705d9SJonas Paulsson && "Loop MBB should not consider predecessor outside of loop.");
5657a705d9SJonas Paulsson
5757a705d9SJonas Paulsson return PredMBB;
5857a705d9SJonas Paulsson }
5957a705d9SJonas Paulsson
6057a705d9SJonas Paulsson void SystemZPostRASchedStrategy::
advanceTo(MachineBasicBlock::iterator NextBegin)6157a705d9SJonas Paulsson advanceTo(MachineBasicBlock::iterator NextBegin) {
6257a705d9SJonas Paulsson MachineBasicBlock::iterator LastEmittedMI = HazardRec->getLastEmittedMI();
6357a705d9SJonas Paulsson MachineBasicBlock::iterator I =
6457a705d9SJonas Paulsson ((LastEmittedMI != nullptr && LastEmittedMI->getParent() == MBB) ?
6557a705d9SJonas Paulsson std::next(LastEmittedMI) : MBB->begin());
6657a705d9SJonas Paulsson
6757a705d9SJonas Paulsson for (; I != NextBegin; ++I) {
68801bf7ebSShiva Chen if (I->isPosition() || I->isDebugInstr())
6957a705d9SJonas Paulsson continue;
7057a705d9SJonas Paulsson HazardRec->emitInstruction(&*I);
7157a705d9SJonas Paulsson }
7257a705d9SJonas Paulsson }
7357a705d9SJonas Paulsson
initialize(ScheduleDAGMI * dag)7461fbcf58SJonas Paulsson void SystemZPostRASchedStrategy::initialize(ScheduleDAGMI *dag) {
75ddd03842SJonas Paulsson Available.clear(); // -misched-cutoff.
76d34e60caSNicola Zaghen LLVM_DEBUG(HazardRec->dumpState(););
7761fbcf58SJonas Paulsson }
7861fbcf58SJonas Paulsson
enterMBB(MachineBasicBlock * NextMBB)7957a705d9SJonas Paulsson void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) {
8057a705d9SJonas Paulsson assert ((SchedStates.find(NextMBB) == SchedStates.end()) &&
8157a705d9SJonas Paulsson "Entering MBB twice?");
82d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "** Entering " << printMBBReference(*NextMBB));
8357a705d9SJonas Paulsson
8457a705d9SJonas Paulsson MBB = NextMBB;
8561fbcf58SJonas Paulsson
8657a705d9SJonas Paulsson /// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to
8757a705d9SJonas Paulsson /// point to it.
8857a705d9SJonas Paulsson HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel);
89d34e60caSNicola Zaghen LLVM_DEBUG(const MachineLoop *Loop = MLI->getLoopFor(MBB);
90d34e60caSNicola Zaghen if (Loop && Loop->getHeader() == MBB) dbgs() << " (Loop header)";
9157a705d9SJonas Paulsson dbgs() << ":\n";);
9257a705d9SJonas Paulsson
9357a705d9SJonas Paulsson // Try to take over the state from a single predecessor, if it has been
9457a705d9SJonas Paulsson // scheduled. If this is not possible, we are done.
9557a705d9SJonas Paulsson MachineBasicBlock *SinglePredMBB =
9657a705d9SJonas Paulsson getSingleSchedPred(MBB, MLI->getLoopFor(MBB));
9757a705d9SJonas Paulsson if (SinglePredMBB == nullptr ||
9857a705d9SJonas Paulsson SchedStates.find(SinglePredMBB) == SchedStates.end())
9957a705d9SJonas Paulsson return;
10057a705d9SJonas Paulsson
101d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "** Continued scheduling from "
10225528d6dSFrancis Visoiu Mistrih << printMBBReference(*SinglePredMBB) << "\n";);
10357a705d9SJonas Paulsson
10457a705d9SJonas Paulsson HazardRec->copyState(SchedStates[SinglePredMBB]);
105d34e60caSNicola Zaghen LLVM_DEBUG(HazardRec->dumpState(););
10657a705d9SJonas Paulsson
10757a705d9SJonas Paulsson // Emit incoming terminator(s). Be optimistic and assume that branch
10857a705d9SJonas Paulsson // prediction will generally do "the right thing".
10972710af2SKazu Hirata for (MachineInstr &MI : SinglePredMBB->terminators()) {
11072710af2SKazu Hirata LLVM_DEBUG(dbgs() << "** Emitting incoming branch: "; MI.dump(););
11172710af2SKazu Hirata bool TakenBranch = (MI.isBranch() &&
11272710af2SKazu Hirata (TII->getBranchInfo(MI).isIndirect() ||
11372710af2SKazu Hirata TII->getBranchInfo(MI).getMBBTarget() == MBB));
11472710af2SKazu Hirata HazardRec->emitInstruction(&MI, TakenBranch);
11557a705d9SJonas Paulsson if (TakenBranch)
11657a705d9SJonas Paulsson break;
11757a705d9SJonas Paulsson }
11857a705d9SJonas Paulsson }
11957a705d9SJonas Paulsson
leaveMBB()12057a705d9SJonas Paulsson void SystemZPostRASchedStrategy::leaveMBB() {
121d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "** Leaving " << printMBBReference(*MBB) << "\n";);
12257a705d9SJonas Paulsson
12357a705d9SJonas Paulsson // Advance to first terminator. The successor block will handle terminators
12457a705d9SJonas Paulsson // dependent on CFG layout (T/NT branch etc).
12557a705d9SJonas Paulsson advanceTo(MBB->getFirstTerminator());
12657a705d9SJonas Paulsson }
12757a705d9SJonas Paulsson
1288010b631SJonas Paulsson SystemZPostRASchedStrategy::
SystemZPostRASchedStrategy(const MachineSchedContext * C)1298010b631SJonas Paulsson SystemZPostRASchedStrategy(const MachineSchedContext *C)
13057a705d9SJonas Paulsson : MLI(C->MLI),
13157a705d9SJonas Paulsson TII(static_cast<const SystemZInstrInfo *>
13257a705d9SJonas Paulsson (C->MF->getSubtarget().getInstrInfo())),
13357a705d9SJonas Paulsson MBB(nullptr), HazardRec(nullptr) {
13457a705d9SJonas Paulsson const TargetSubtargetInfo *ST = &C->MF->getSubtarget();
1350d7df36cSSanjay Patel SchedModel.init(ST);
13657a705d9SJonas Paulsson }
1378010b631SJonas Paulsson
~SystemZPostRASchedStrategy()13857a705d9SJonas Paulsson SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() {
13957a705d9SJonas Paulsson // Delete hazard recognizers kept around for each MBB.
14057a705d9SJonas Paulsson for (auto I : SchedStates) {
14157a705d9SJonas Paulsson SystemZHazardRecognizer *hazrec = I.second;
14257a705d9SJonas Paulsson delete hazrec;
14357a705d9SJonas Paulsson }
14457a705d9SJonas Paulsson }
14557a705d9SJonas Paulsson
initPolicy(MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End,unsigned NumRegionInstrs)14657a705d9SJonas Paulsson void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin,
14757a705d9SJonas Paulsson MachineBasicBlock::iterator End,
14857a705d9SJonas Paulsson unsigned NumRegionInstrs) {
14957a705d9SJonas Paulsson // Don't emit the terminators.
15057a705d9SJonas Paulsson if (Begin->isTerminator())
15157a705d9SJonas Paulsson return;
15257a705d9SJonas Paulsson
15357a705d9SJonas Paulsson // Emit any instructions before start of region.
15457a705d9SJonas Paulsson advanceTo(Begin);
1558010b631SJonas Paulsson }
1568010b631SJonas Paulsson
1578010b631SJonas Paulsson // Pick the next node to schedule.
pickNode(bool & IsTopNode)1588010b631SJonas Paulsson SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) {
1598010b631SJonas Paulsson // Only scheduling top-down.
1608010b631SJonas Paulsson IsTopNode = true;
1618010b631SJonas Paulsson
1628010b631SJonas Paulsson if (Available.empty())
1638010b631SJonas Paulsson return nullptr;
1648010b631SJonas Paulsson
1658010b631SJonas Paulsson // If only one choice, return it.
1668010b631SJonas Paulsson if (Available.size() == 1) {
167d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "** Only one: ";
16857a705d9SJonas Paulsson HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);
1698010b631SJonas Paulsson return *Available.begin();
1708010b631SJonas Paulsson }
1718010b631SJonas Paulsson
1722f12e45dSJonas Paulsson // All nodes that are possible to schedule are stored in the Available set.
173d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "** Available: "; Available.dump(*HazardRec););
1748010b631SJonas Paulsson
1758010b631SJonas Paulsson Candidate Best;
1768010b631SJonas Paulsson for (auto *SU : Available) {
1778010b631SJonas Paulsson
1788010b631SJonas Paulsson // SU is the next candidate to be compared against current Best.
17957a705d9SJonas Paulsson Candidate c(SU, *HazardRec);
1808010b631SJonas Paulsson
1818010b631SJonas Paulsson // Remeber which SU is the best candidate.
1828010b631SJonas Paulsson if (Best.SU == nullptr || c < Best) {
1838010b631SJonas Paulsson Best = c;
184d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "** Best so far: ";);
18561fbcf58SJonas Paulsson } else
186d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "** Tried : ";);
187d34e60caSNicola Zaghen LLVM_DEBUG(HazardRec->dumpSU(c.SU, dbgs()); c.dumpCosts();
188d34e60caSNicola Zaghen dbgs() << " Height:" << c.SU->getHeight(); dbgs() << "\n";);
1898010b631SJonas Paulsson
1908010b631SJonas Paulsson // Once we know we have seen all SUs that affect grouping or use unbuffered
1918010b631SJonas Paulsson // resources, we can stop iterating if Best looks good.
1928010b631SJonas Paulsson if (!SU->isScheduleHigh && Best.noCost())
1938010b631SJonas Paulsson break;
1948010b631SJonas Paulsson }
1958010b631SJonas Paulsson
1968010b631SJonas Paulsson assert (Best.SU != nullptr);
1978010b631SJonas Paulsson return Best.SU;
1988010b631SJonas Paulsson }
1998010b631SJonas Paulsson
2008010b631SJonas Paulsson SystemZPostRASchedStrategy::Candidate::
Candidate(SUnit * SU_,SystemZHazardRecognizer & HazardRec)2018010b631SJonas Paulsson Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() {
2028010b631SJonas Paulsson SU = SU_;
2038010b631SJonas Paulsson
2048010b631SJonas Paulsson // Check the grouping cost. For a node that must begin / end a
2058010b631SJonas Paulsson // group, it is positive if it would do so prematurely, or negative
2068010b631SJonas Paulsson // if it would fit naturally into the schedule.
2078010b631SJonas Paulsson GroupingCost = HazardRec.groupingCost(SU);
2088010b631SJonas Paulsson
2098010b631SJonas Paulsson // Check the resources cost for this SU.
2108010b631SJonas Paulsson ResourcesCost = HazardRec.resourcesCost(SU);
2118010b631SJonas Paulsson }
2128010b631SJonas Paulsson
2138010b631SJonas Paulsson bool SystemZPostRASchedStrategy::Candidate::
operator <(const Candidate & other)2148010b631SJonas Paulsson operator<(const Candidate &other) {
2158010b631SJonas Paulsson
2168010b631SJonas Paulsson // Check decoder grouping.
2178010b631SJonas Paulsson if (GroupingCost < other.GroupingCost)
2188010b631SJonas Paulsson return true;
2198010b631SJonas Paulsson if (GroupingCost > other.GroupingCost)
2208010b631SJonas Paulsson return false;
2218010b631SJonas Paulsson
2228010b631SJonas Paulsson // Compare the use of resources.
2238010b631SJonas Paulsson if (ResourcesCost < other.ResourcesCost)
2248010b631SJonas Paulsson return true;
2258010b631SJonas Paulsson if (ResourcesCost > other.ResourcesCost)
2268010b631SJonas Paulsson return false;
2278010b631SJonas Paulsson
2288010b631SJonas Paulsson // Higher SU is otherwise generally better.
2298010b631SJonas Paulsson if (SU->getHeight() > other.SU->getHeight())
2308010b631SJonas Paulsson return true;
2318010b631SJonas Paulsson if (SU->getHeight() < other.SU->getHeight())
2328010b631SJonas Paulsson return false;
2338010b631SJonas Paulsson
2348010b631SJonas Paulsson // If all same, fall back to original order.
2358010b631SJonas Paulsson if (SU->NodeNum < other.SU->NodeNum)
2368010b631SJonas Paulsson return true;
2378010b631SJonas Paulsson
2388010b631SJonas Paulsson return false;
2398010b631SJonas Paulsson }
2408010b631SJonas Paulsson
schedNode(SUnit * SU,bool IsTopNode)2418010b631SJonas Paulsson void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
242d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "** Scheduling SU(" << SU->NodeNum << ") ";
243d34e60caSNicola Zaghen if (Available.size() == 1) dbgs() << "(only one) ";
244d34e60caSNicola Zaghen Candidate c(SU, *HazardRec); c.dumpCosts(); dbgs() << "\n";);
2458010b631SJonas Paulsson
2468010b631SJonas Paulsson // Remove SU from Available set and update HazardRec.
2478010b631SJonas Paulsson Available.erase(SU);
24857a705d9SJonas Paulsson HazardRec->EmitInstruction(SU);
2498010b631SJonas Paulsson }
2508010b631SJonas Paulsson
releaseTopNode(SUnit * SU)2518010b631SJonas Paulsson void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {
2528010b631SJonas Paulsson // Set isScheduleHigh flag on all SUs that we want to consider first in
2538010b631SJonas Paulsson // pickNode().
25457a705d9SJonas Paulsson const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU);
2558010b631SJonas Paulsson bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup));
2568010b631SJonas Paulsson SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered);
2578010b631SJonas Paulsson
2588010b631SJonas Paulsson // Put all released SUs in the Available set.
2598010b631SJonas Paulsson Available.insert(SU);
2608010b631SJonas Paulsson }
261