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:: 270b57cec5SDimitry 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. 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:: 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 740b57cec5SDimitry Andric void SystemZPostRASchedStrategy::initialize(ScheduleDAGMI *dag) { 75*e8d8bef9SDimitry Andric Available.clear(); // -misched-cutoff. 760b57cec5SDimitry Andric LLVM_DEBUG(HazardRec->dumpState();); 770b57cec5SDimitry Andric } 780b57cec5SDimitry Andric 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 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:: 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 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 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. 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:: 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:: 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 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 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