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