18010b631SJonas Paulsson //-- SystemZMachineScheduler.cpp - SystemZ Scheduler Interface -*- C++ -*---==//
28010b631SJonas Paulsson //
38010b631SJonas Paulsson //                     The LLVM Compiler Infrastructure
48010b631SJonas Paulsson //
58010b631SJonas Paulsson // This file is distributed under the University of Illinois Open Source
68010b631SJonas Paulsson // License. See LICENSE.TXT for details.
78010b631SJonas Paulsson //
88010b631SJonas Paulsson //===----------------------------------------------------------------------===//
98010b631SJonas Paulsson //
108010b631SJonas Paulsson // -------------------------- Post RA scheduling ---------------------------- //
118010b631SJonas Paulsson // SystemZPostRASchedStrategy is a scheduling strategy which is plugged into
128010b631SJonas Paulsson // the MachineScheduler. It has a sorted Available set of SUs and a pickNode()
138010b631SJonas Paulsson // implementation that looks to optimize decoder grouping and balance the
1457a705d9SJonas Paulsson // usage of processor resources. Scheduler states are saved for the end
1557a705d9SJonas Paulsson // region of each MBB, so that a successor block can learn from it.
168010b631SJonas Paulsson //===----------------------------------------------------------------------===//
178010b631SJonas Paulsson 
188010b631SJonas Paulsson #include "SystemZMachineScheduler.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::
276da25f4fSRafael 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.
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) {
4957a705d9SJonas Paulsson     for (auto I = MBB->pred_begin(); I != MBB->pred_end(); ++I)
5057a705d9SJonas Paulsson       if (Loop->contains(*I))
5157a705d9SJonas Paulsson         PredMBB = (*I == MBB ? nullptr : *I);
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::
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) {
68*801bf7ebSShiva Chen     if (I->isPosition() || I->isDebugInstr())
6957a705d9SJonas Paulsson       continue;
7057a705d9SJonas Paulsson     HazardRec->emitInstruction(&*I);
7157a705d9SJonas Paulsson   }
7257a705d9SJonas Paulsson }
7357a705d9SJonas Paulsson 
7461fbcf58SJonas Paulsson void SystemZPostRASchedStrategy::initialize(ScheduleDAGMI *dag) {
7561fbcf58SJonas Paulsson   DEBUG(HazardRec->dumpState(););
7661fbcf58SJonas Paulsson }
7761fbcf58SJonas Paulsson 
7857a705d9SJonas Paulsson void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) {
7957a705d9SJonas Paulsson   assert ((SchedStates.find(NextMBB) == SchedStates.end()) &&
8057a705d9SJonas Paulsson           "Entering MBB twice?");
8161fbcf58SJonas Paulsson   DEBUG(dbgs() << "** Entering " << printMBBReference(*NextMBB));
8257a705d9SJonas Paulsson 
8357a705d9SJonas Paulsson   MBB = NextMBB;
8461fbcf58SJonas Paulsson 
8557a705d9SJonas Paulsson   /// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to
8657a705d9SJonas Paulsson   /// point to it.
8757a705d9SJonas Paulsson   HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel);
8857a705d9SJonas Paulsson   DEBUG(const MachineLoop *Loop = MLI->getLoopFor(MBB);
8957a705d9SJonas Paulsson         if(Loop && Loop->getHeader() == MBB)
9057a705d9SJonas Paulsson           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 
10161fbcf58SJonas Paulsson   DEBUG(dbgs() << "** Continued scheduling from "
10225528d6dSFrancis Visoiu Mistrih         << printMBBReference(*SinglePredMBB) << "\n";);
10357a705d9SJonas Paulsson 
10457a705d9SJonas Paulsson   HazardRec->copyState(SchedStates[SinglePredMBB]);
10561fbcf58SJonas Paulsson   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".
10957a705d9SJonas Paulsson   for (MachineBasicBlock::iterator I = SinglePredMBB->getFirstTerminator();
11057a705d9SJonas Paulsson        I != SinglePredMBB->end(); I++) {
11161fbcf58SJonas Paulsson     DEBUG(dbgs() << "** Emitting incoming branch: "; I->dump(););
11257a705d9SJonas Paulsson     bool TakenBranch = (I->isBranch() &&
11357a705d9SJonas Paulsson       (TII->getBranchInfo(*I).Target->isReg() || // Relative branch
11457a705d9SJonas Paulsson        TII->getBranchInfo(*I).Target->getMBB() == MBB));
11557a705d9SJonas Paulsson     HazardRec->emitInstruction(&*I, TakenBranch);
11657a705d9SJonas Paulsson     if (TakenBranch)
11757a705d9SJonas Paulsson       break;
11857a705d9SJonas Paulsson   }
11957a705d9SJonas Paulsson }
12057a705d9SJonas Paulsson 
12157a705d9SJonas Paulsson void SystemZPostRASchedStrategy::leaveMBB() {
12261fbcf58SJonas Paulsson   DEBUG(dbgs() << "** Leaving " << printMBBReference(*MBB) << "\n";);
12357a705d9SJonas Paulsson 
12457a705d9SJonas Paulsson   // Advance to first terminator. The successor block will handle terminators
12557a705d9SJonas Paulsson   // dependent on CFG layout (T/NT branch etc).
12657a705d9SJonas Paulsson   advanceTo(MBB->getFirstTerminator());
12757a705d9SJonas Paulsson }
12857a705d9SJonas Paulsson 
1298010b631SJonas Paulsson SystemZPostRASchedStrategy::
1308010b631SJonas Paulsson SystemZPostRASchedStrategy(const MachineSchedContext *C)
13157a705d9SJonas Paulsson   : MLI(C->MLI),
13257a705d9SJonas Paulsson     TII(static_cast<const SystemZInstrInfo *>
13357a705d9SJonas Paulsson         (C->MF->getSubtarget().getInstrInfo())),
13457a705d9SJonas Paulsson     MBB(nullptr), HazardRec(nullptr) {
13557a705d9SJonas Paulsson   const TargetSubtargetInfo *ST = &C->MF->getSubtarget();
1360d7df36cSSanjay Patel   SchedModel.init(ST);
13757a705d9SJonas Paulsson }
1388010b631SJonas Paulsson 
13957a705d9SJonas Paulsson SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() {
14057a705d9SJonas Paulsson   // Delete hazard recognizers kept around for each MBB.
14157a705d9SJonas Paulsson   for (auto I : SchedStates) {
14257a705d9SJonas Paulsson     SystemZHazardRecognizer *hazrec = I.second;
14357a705d9SJonas Paulsson     delete hazrec;
14457a705d9SJonas Paulsson   }
14557a705d9SJonas Paulsson }
14657a705d9SJonas Paulsson 
14757a705d9SJonas Paulsson void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin,
14857a705d9SJonas Paulsson                                             MachineBasicBlock::iterator End,
14957a705d9SJonas Paulsson                                             unsigned NumRegionInstrs) {
15057a705d9SJonas Paulsson   // Don't emit the terminators.
15157a705d9SJonas Paulsson   if (Begin->isTerminator())
15257a705d9SJonas Paulsson     return;
15357a705d9SJonas Paulsson 
15457a705d9SJonas Paulsson   // Emit any instructions before start of region.
15557a705d9SJonas Paulsson   advanceTo(Begin);
1568010b631SJonas Paulsson }
1578010b631SJonas Paulsson 
1588010b631SJonas Paulsson // Pick the next node to schedule.
1598010b631SJonas Paulsson SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) {
1608010b631SJonas Paulsson   // Only scheduling top-down.
1618010b631SJonas Paulsson   IsTopNode = true;
1628010b631SJonas Paulsson 
1638010b631SJonas Paulsson   if (Available.empty())
1648010b631SJonas Paulsson     return nullptr;
1658010b631SJonas Paulsson 
1668010b631SJonas Paulsson   // If only one choice, return it.
1678010b631SJonas Paulsson   if (Available.size() == 1) {
16861fbcf58SJonas Paulsson     DEBUG(dbgs() << "** Only one: ";
16957a705d9SJonas Paulsson           HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);
1708010b631SJonas Paulsson     return *Available.begin();
1718010b631SJonas Paulsson   }
1728010b631SJonas Paulsson 
1738010b631SJonas Paulsson   // All nodes that are possible to schedule are stored by in the
1748010b631SJonas Paulsson   // Available set.
17561fbcf58SJonas Paulsson   DEBUG(dbgs() << "** Available: "; Available.dump(*HazardRec););
1768010b631SJonas Paulsson 
1778010b631SJonas Paulsson   Candidate Best;
1788010b631SJonas Paulsson   for (auto *SU : Available) {
1798010b631SJonas Paulsson 
1808010b631SJonas Paulsson     // SU is the next candidate to be compared against current Best.
18157a705d9SJonas Paulsson     Candidate c(SU, *HazardRec);
1828010b631SJonas Paulsson 
1838010b631SJonas Paulsson     // Remeber which SU is the best candidate.
1848010b631SJonas Paulsson     if (Best.SU == nullptr || c < Best) {
1858010b631SJonas Paulsson       Best = c;
18661fbcf58SJonas Paulsson       DEBUG(dbgs() << "** Best so far: ";);
18761fbcf58SJonas Paulsson     } else
18861fbcf58SJonas Paulsson       DEBUG(dbgs() << "** Tried      : ";);
18961fbcf58SJonas Paulsson     DEBUG(HazardRec->dumpSU(c.SU, dbgs());
19061fbcf58SJonas Paulsson           c.dumpCosts();
19161fbcf58SJonas Paulsson           dbgs() << " Height:" << c.SU->getHeight();
1928010b631SJonas Paulsson           dbgs() << "\n";);
1938010b631SJonas Paulsson 
1948010b631SJonas Paulsson     // Once we know we have seen all SUs that affect grouping or use unbuffered
1958010b631SJonas Paulsson     // resources, we can stop iterating if Best looks good.
1968010b631SJonas Paulsson     if (!SU->isScheduleHigh && Best.noCost())
1978010b631SJonas Paulsson       break;
1988010b631SJonas Paulsson   }
1998010b631SJonas Paulsson 
2008010b631SJonas Paulsson   assert (Best.SU != nullptr);
2018010b631SJonas Paulsson   return Best.SU;
2028010b631SJonas Paulsson }
2038010b631SJonas Paulsson 
2048010b631SJonas Paulsson SystemZPostRASchedStrategy::Candidate::
2058010b631SJonas Paulsson Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() {
2068010b631SJonas Paulsson   SU = SU_;
2078010b631SJonas Paulsson 
2088010b631SJonas Paulsson   // Check the grouping cost. For a node that must begin / end a
2098010b631SJonas Paulsson   // group, it is positive if it would do so prematurely, or negative
2108010b631SJonas Paulsson   // if it would fit naturally into the schedule.
2118010b631SJonas Paulsson   GroupingCost = HazardRec.groupingCost(SU);
2128010b631SJonas Paulsson 
2138010b631SJonas Paulsson   // Check the resources cost for this SU.
2148010b631SJonas Paulsson   ResourcesCost = HazardRec.resourcesCost(SU);
2158010b631SJonas Paulsson }
2168010b631SJonas Paulsson 
2178010b631SJonas Paulsson bool SystemZPostRASchedStrategy::Candidate::
2188010b631SJonas Paulsson operator<(const Candidate &other) {
2198010b631SJonas Paulsson 
2208010b631SJonas Paulsson   // Check decoder grouping.
2218010b631SJonas Paulsson   if (GroupingCost < other.GroupingCost)
2228010b631SJonas Paulsson     return true;
2238010b631SJonas Paulsson   if (GroupingCost > other.GroupingCost)
2248010b631SJonas Paulsson     return false;
2258010b631SJonas Paulsson 
2268010b631SJonas Paulsson   // Compare the use of resources.
2278010b631SJonas Paulsson   if (ResourcesCost < other.ResourcesCost)
2288010b631SJonas Paulsson     return true;
2298010b631SJonas Paulsson   if (ResourcesCost > other.ResourcesCost)
2308010b631SJonas Paulsson     return false;
2318010b631SJonas Paulsson 
2328010b631SJonas Paulsson   // Higher SU is otherwise generally better.
2338010b631SJonas Paulsson   if (SU->getHeight() > other.SU->getHeight())
2348010b631SJonas Paulsson     return true;
2358010b631SJonas Paulsson   if (SU->getHeight() < other.SU->getHeight())
2368010b631SJonas Paulsson     return false;
2378010b631SJonas Paulsson 
2388010b631SJonas Paulsson   // If all same, fall back to original order.
2398010b631SJonas Paulsson   if (SU->NodeNum < other.SU->NodeNum)
2408010b631SJonas Paulsson     return true;
2418010b631SJonas Paulsson 
2428010b631SJonas Paulsson   return false;
2438010b631SJonas Paulsson }
2448010b631SJonas Paulsson 
2458010b631SJonas Paulsson void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
24661fbcf58SJonas Paulsson   DEBUG(dbgs() << "** Scheduling SU(" << SU->NodeNum << ") ";
24761fbcf58SJonas Paulsson         if (Available.size() == 1)
24861fbcf58SJonas Paulsson           dbgs() << "(only one) ";
24961fbcf58SJonas Paulsson         Candidate c(SU, *HazardRec);
25061fbcf58SJonas Paulsson         c.dumpCosts();
25161fbcf58SJonas Paulsson         dbgs() << "\n";);
2528010b631SJonas Paulsson 
2538010b631SJonas Paulsson   // Remove SU from Available set and update HazardRec.
2548010b631SJonas Paulsson   Available.erase(SU);
25557a705d9SJonas Paulsson   HazardRec->EmitInstruction(SU);
2568010b631SJonas Paulsson }
2578010b631SJonas Paulsson 
2588010b631SJonas Paulsson void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {
2598010b631SJonas Paulsson   // Set isScheduleHigh flag on all SUs that we want to consider first in
2608010b631SJonas Paulsson   // pickNode().
26157a705d9SJonas Paulsson   const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU);
2628010b631SJonas Paulsson   bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup));
2638010b631SJonas Paulsson   SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered);
2648010b631SJonas Paulsson 
2658010b631SJonas Paulsson   // Put all released SUs in the Available set.
2668010b631SJonas Paulsson   Available.insert(SU);
2678010b631SJonas Paulsson }
268