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
14*57a705d9SJonas Paulsson // usage of processor resources. Scheduler states are saved for the end
15*57a705d9SJonas 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 
38*57a705d9SJonas Paulsson // Try to find a single predecessor that would be interesting for the
39*57a705d9SJonas Paulsson // scheduler in the top-most region of MBB.
40*57a705d9SJonas Paulsson static MachineBasicBlock *getSingleSchedPred(MachineBasicBlock *MBB,
41*57a705d9SJonas Paulsson                                              const MachineLoop *Loop) {
42*57a705d9SJonas Paulsson   MachineBasicBlock *PredMBB = nullptr;
43*57a705d9SJonas Paulsson   if (MBB->pred_size() == 1)
44*57a705d9SJonas Paulsson     PredMBB = *MBB->pred_begin();
45*57a705d9SJonas Paulsson 
46*57a705d9SJonas Paulsson   // The loop header has two predecessors, return the latch, but not for a
47*57a705d9SJonas Paulsson   // single block loop.
48*57a705d9SJonas Paulsson   if (MBB->pred_size() == 2 && Loop != nullptr && Loop->getHeader() == MBB) {
49*57a705d9SJonas Paulsson     for (auto I = MBB->pred_begin(); I != MBB->pred_end(); ++I)
50*57a705d9SJonas Paulsson       if (Loop->contains(*I))
51*57a705d9SJonas Paulsson         PredMBB = (*I == MBB ? nullptr : *I);
52*57a705d9SJonas Paulsson   }
53*57a705d9SJonas Paulsson 
54*57a705d9SJonas Paulsson   assert ((PredMBB == nullptr || !Loop || Loop->contains(PredMBB))
55*57a705d9SJonas Paulsson           && "Loop MBB should not consider predecessor outside of loop.");
56*57a705d9SJonas Paulsson 
57*57a705d9SJonas Paulsson   return PredMBB;
58*57a705d9SJonas Paulsson }
59*57a705d9SJonas Paulsson 
60*57a705d9SJonas Paulsson void SystemZPostRASchedStrategy::
61*57a705d9SJonas Paulsson advanceTo(MachineBasicBlock::iterator NextBegin) {
62*57a705d9SJonas Paulsson   MachineBasicBlock::iterator LastEmittedMI = HazardRec->getLastEmittedMI();
63*57a705d9SJonas Paulsson   MachineBasicBlock::iterator I =
64*57a705d9SJonas Paulsson     ((LastEmittedMI != nullptr && LastEmittedMI->getParent() == MBB) ?
65*57a705d9SJonas Paulsson      std::next(LastEmittedMI) : MBB->begin());
66*57a705d9SJonas Paulsson 
67*57a705d9SJonas Paulsson   for (; I != NextBegin; ++I) {
68*57a705d9SJonas Paulsson     if (I->isPosition() || I->isDebugValue())
69*57a705d9SJonas Paulsson       continue;
70*57a705d9SJonas Paulsson     HazardRec->emitInstruction(&*I);
71*57a705d9SJonas Paulsson   }
72*57a705d9SJonas Paulsson }
73*57a705d9SJonas Paulsson 
74*57a705d9SJonas Paulsson void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) {
75*57a705d9SJonas Paulsson   assert ((SchedStates.find(NextMBB) == SchedStates.end()) &&
76*57a705d9SJonas Paulsson           "Entering MBB twice?");
77*57a705d9SJonas Paulsson   DEBUG (dbgs() << "+++ Entering MBB#" << NextMBB->getNumber());
78*57a705d9SJonas Paulsson 
79*57a705d9SJonas Paulsson   MBB = NextMBB;
80*57a705d9SJonas Paulsson   /// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to
81*57a705d9SJonas Paulsson   /// point to it.
82*57a705d9SJonas Paulsson   HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel);
83*57a705d9SJonas Paulsson   DEBUG (const MachineLoop *Loop = MLI->getLoopFor(MBB);
84*57a705d9SJonas Paulsson          if(Loop && Loop->getHeader() == MBB)
85*57a705d9SJonas Paulsson            dbgs() << " (Loop header)";
86*57a705d9SJonas Paulsson          dbgs() << ":\n";);
87*57a705d9SJonas Paulsson 
88*57a705d9SJonas Paulsson   // Try to take over the state from a single predecessor, if it has been
89*57a705d9SJonas Paulsson   // scheduled. If this is not possible, we are done.
90*57a705d9SJonas Paulsson   MachineBasicBlock *SinglePredMBB =
91*57a705d9SJonas Paulsson     getSingleSchedPred(MBB, MLI->getLoopFor(MBB));
92*57a705d9SJonas Paulsson   if (SinglePredMBB == nullptr ||
93*57a705d9SJonas Paulsson       SchedStates.find(SinglePredMBB) == SchedStates.end())
94*57a705d9SJonas Paulsson     return;
95*57a705d9SJonas Paulsson 
96*57a705d9SJonas Paulsson   DEBUG (dbgs() << "+++ Continued scheduling from MBB#"
97*57a705d9SJonas Paulsson          << SinglePredMBB->getNumber() << "\n";);
98*57a705d9SJonas Paulsson 
99*57a705d9SJonas Paulsson   HazardRec->copyState(SchedStates[SinglePredMBB]);
100*57a705d9SJonas Paulsson 
101*57a705d9SJonas Paulsson   // Emit incoming terminator(s). Be optimistic and assume that branch
102*57a705d9SJonas Paulsson   // prediction will generally do "the right thing".
103*57a705d9SJonas Paulsson   for (MachineBasicBlock::iterator I = SinglePredMBB->getFirstTerminator();
104*57a705d9SJonas Paulsson        I != SinglePredMBB->end(); I++) {
105*57a705d9SJonas Paulsson     DEBUG (dbgs() << "+++ Emitting incoming branch: "; I->dump(););
106*57a705d9SJonas Paulsson     bool TakenBranch = (I->isBranch() &&
107*57a705d9SJonas Paulsson       (TII->getBranchInfo(*I).Target->isReg() || // Relative branch
108*57a705d9SJonas Paulsson        TII->getBranchInfo(*I).Target->getMBB() == MBB));
109*57a705d9SJonas Paulsson     HazardRec->emitInstruction(&*I, TakenBranch);
110*57a705d9SJonas Paulsson     if (TakenBranch)
111*57a705d9SJonas Paulsson       break;
112*57a705d9SJonas Paulsson   }
113*57a705d9SJonas Paulsson }
114*57a705d9SJonas Paulsson 
115*57a705d9SJonas Paulsson void SystemZPostRASchedStrategy::leaveMBB() {
116*57a705d9SJonas Paulsson   DEBUG (dbgs() << "+++ Leaving MBB#" << MBB->getNumber() << "\n";);
117*57a705d9SJonas Paulsson 
118*57a705d9SJonas Paulsson   // Advance to first terminator. The successor block will handle terminators
119*57a705d9SJonas Paulsson   // dependent on CFG layout (T/NT branch etc).
120*57a705d9SJonas Paulsson   advanceTo(MBB->getFirstTerminator());
121*57a705d9SJonas Paulsson }
122*57a705d9SJonas Paulsson 
1238010b631SJonas Paulsson SystemZPostRASchedStrategy::
1248010b631SJonas Paulsson SystemZPostRASchedStrategy(const MachineSchedContext *C)
125*57a705d9SJonas Paulsson   : MLI(C->MLI),
126*57a705d9SJonas Paulsson     TII(static_cast<const SystemZInstrInfo *>
127*57a705d9SJonas Paulsson         (C->MF->getSubtarget().getInstrInfo())),
128*57a705d9SJonas Paulsson     MBB(nullptr), HazardRec(nullptr) {
129*57a705d9SJonas Paulsson   const TargetSubtargetInfo *ST = &C->MF->getSubtarget();
130*57a705d9SJonas Paulsson   SchedModel.init(ST->getSchedModel(), ST, TII);
131*57a705d9SJonas Paulsson }
1328010b631SJonas Paulsson 
133*57a705d9SJonas Paulsson SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() {
134*57a705d9SJonas Paulsson   // Delete hazard recognizers kept around for each MBB.
135*57a705d9SJonas Paulsson   for (auto I : SchedStates) {
136*57a705d9SJonas Paulsson     SystemZHazardRecognizer *hazrec = I.second;
137*57a705d9SJonas Paulsson     delete hazrec;
138*57a705d9SJonas Paulsson   }
139*57a705d9SJonas Paulsson }
140*57a705d9SJonas Paulsson 
141*57a705d9SJonas Paulsson void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin,
142*57a705d9SJonas Paulsson                                             MachineBasicBlock::iterator End,
143*57a705d9SJonas Paulsson                                             unsigned NumRegionInstrs) {
144*57a705d9SJonas Paulsson   // Don't emit the terminators.
145*57a705d9SJonas Paulsson   if (Begin->isTerminator())
146*57a705d9SJonas Paulsson     return;
147*57a705d9SJonas Paulsson 
148*57a705d9SJonas Paulsson   // Emit any instructions before start of region.
149*57a705d9SJonas Paulsson   advanceTo(Begin);
1508010b631SJonas Paulsson }
1518010b631SJonas Paulsson 
1528010b631SJonas Paulsson // Pick the next node to schedule.
1538010b631SJonas Paulsson SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) {
1548010b631SJonas Paulsson   // Only scheduling top-down.
1558010b631SJonas Paulsson   IsTopNode = true;
1568010b631SJonas Paulsson 
1578010b631SJonas Paulsson   if (Available.empty())
1588010b631SJonas Paulsson     return nullptr;
1598010b631SJonas Paulsson 
1608010b631SJonas Paulsson   // If only one choice, return it.
1618010b631SJonas Paulsson   if (Available.size() == 1) {
1628010b631SJonas Paulsson     DEBUG (dbgs() << "+++ Only one: ";
163*57a705d9SJonas Paulsson            HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);
1648010b631SJonas Paulsson     return *Available.begin();
1658010b631SJonas Paulsson   }
1668010b631SJonas Paulsson 
1678010b631SJonas Paulsson   // All nodes that are possible to schedule are stored by in the
1688010b631SJonas Paulsson   // Available set.
169*57a705d9SJonas Paulsson   DEBUG(dbgs() << "+++ Available: "; Available.dump(*HazardRec););
1708010b631SJonas Paulsson 
1718010b631SJonas Paulsson   Candidate Best;
1728010b631SJonas Paulsson   for (auto *SU : Available) {
1738010b631SJonas Paulsson 
1748010b631SJonas Paulsson     // SU is the next candidate to be compared against current Best.
175*57a705d9SJonas Paulsson     Candidate c(SU, *HazardRec);
1768010b631SJonas Paulsson 
1778010b631SJonas Paulsson     // Remeber which SU is the best candidate.
1788010b631SJonas Paulsson     if (Best.SU == nullptr || c < Best) {
1798010b631SJonas Paulsson       Best = c;
1808010b631SJonas Paulsson       DEBUG(dbgs() << "+++ Best sofar: ";
181*57a705d9SJonas Paulsson             HazardRec->dumpSU(Best.SU, dbgs());
1828010b631SJonas Paulsson             if (Best.GroupingCost != 0)
1838010b631SJonas Paulsson               dbgs() << "\tGrouping cost:" << Best.GroupingCost;
1848010b631SJonas Paulsson             if (Best.ResourcesCost != 0)
1858010b631SJonas Paulsson               dbgs() << " Resource cost:" << Best.ResourcesCost;
1868010b631SJonas Paulsson             dbgs() << " Height:" << Best.SU->getHeight();
1878010b631SJonas Paulsson             dbgs() << "\n";);
1888010b631SJonas Paulsson     }
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::
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::
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 
2418010b631SJonas Paulsson void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
2428010b631SJonas Paulsson   DEBUG(dbgs() << "+++ Scheduling SU(" << SU->NodeNum << ")\n";);
2438010b631SJonas Paulsson 
2448010b631SJonas Paulsson   // Remove SU from Available set and update HazardRec.
2458010b631SJonas Paulsson   Available.erase(SU);
246*57a705d9SJonas Paulsson   HazardRec->EmitInstruction(SU);
2478010b631SJonas Paulsson }
2488010b631SJonas Paulsson 
2498010b631SJonas Paulsson void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {
2508010b631SJonas Paulsson   // Set isScheduleHigh flag on all SUs that we want to consider first in
2518010b631SJonas Paulsson   // pickNode().
252*57a705d9SJonas Paulsson   const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU);
2538010b631SJonas Paulsson   bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup));
2548010b631SJonas Paulsson   SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered);
2558010b631SJonas Paulsson 
2568010b631SJonas Paulsson   // Put all released SUs in the Available set.
2578010b631SJonas Paulsson   Available.insert(SU);
2588010b631SJonas Paulsson }
259