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" 18*8bcb0991SDimitry 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) { 750b57cec5SDimitry Andric LLVM_DEBUG(HazardRec->dumpState();); 760b57cec5SDimitry Andric } 770b57cec5SDimitry Andric 780b57cec5SDimitry Andric void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) { 790b57cec5SDimitry Andric assert ((SchedStates.find(NextMBB) == SchedStates.end()) && 800b57cec5SDimitry Andric "Entering MBB twice?"); 810b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Entering " << printMBBReference(*NextMBB)); 820b57cec5SDimitry Andric 830b57cec5SDimitry Andric MBB = NextMBB; 840b57cec5SDimitry Andric 850b57cec5SDimitry Andric /// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to 860b57cec5SDimitry Andric /// point to it. 870b57cec5SDimitry Andric HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel); 880b57cec5SDimitry Andric LLVM_DEBUG(const MachineLoop *Loop = MLI->getLoopFor(MBB); 890b57cec5SDimitry Andric if (Loop && Loop->getHeader() == MBB) dbgs() << " (Loop header)"; 900b57cec5SDimitry Andric dbgs() << ":\n";); 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric // Try to take over the state from a single predecessor, if it has been 930b57cec5SDimitry Andric // scheduled. If this is not possible, we are done. 940b57cec5SDimitry Andric MachineBasicBlock *SinglePredMBB = 950b57cec5SDimitry Andric getSingleSchedPred(MBB, MLI->getLoopFor(MBB)); 960b57cec5SDimitry Andric if (SinglePredMBB == nullptr || 970b57cec5SDimitry Andric SchedStates.find(SinglePredMBB) == SchedStates.end()) 980b57cec5SDimitry Andric return; 990b57cec5SDimitry Andric 1000b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Continued scheduling from " 1010b57cec5SDimitry Andric << printMBBReference(*SinglePredMBB) << "\n";); 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric HazardRec->copyState(SchedStates[SinglePredMBB]); 1040b57cec5SDimitry Andric LLVM_DEBUG(HazardRec->dumpState();); 1050b57cec5SDimitry Andric 1060b57cec5SDimitry Andric // Emit incoming terminator(s). Be optimistic and assume that branch 1070b57cec5SDimitry Andric // prediction will generally do "the right thing". 1080b57cec5SDimitry Andric for (MachineBasicBlock::iterator I = SinglePredMBB->getFirstTerminator(); 1090b57cec5SDimitry Andric I != SinglePredMBB->end(); I++) { 1100b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Emitting incoming branch: "; I->dump();); 1110b57cec5SDimitry Andric bool TakenBranch = (I->isBranch() && 1120b57cec5SDimitry Andric (TII->getBranchInfo(*I).isIndirect() || 1130b57cec5SDimitry Andric TII->getBranchInfo(*I).getMBBTarget() == MBB)); 1140b57cec5SDimitry Andric HazardRec->emitInstruction(&*I, TakenBranch); 1150b57cec5SDimitry Andric if (TakenBranch) 1160b57cec5SDimitry Andric break; 1170b57cec5SDimitry Andric } 1180b57cec5SDimitry Andric } 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric void SystemZPostRASchedStrategy::leaveMBB() { 1210b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Leaving " << printMBBReference(*MBB) << "\n";); 1220b57cec5SDimitry Andric 1230b57cec5SDimitry Andric // Advance to first terminator. The successor block will handle terminators 1240b57cec5SDimitry Andric // dependent on CFG layout (T/NT branch etc). 1250b57cec5SDimitry Andric advanceTo(MBB->getFirstTerminator()); 1260b57cec5SDimitry Andric } 1270b57cec5SDimitry Andric 1280b57cec5SDimitry Andric SystemZPostRASchedStrategy:: 1290b57cec5SDimitry Andric SystemZPostRASchedStrategy(const MachineSchedContext *C) 1300b57cec5SDimitry Andric : MLI(C->MLI), 1310b57cec5SDimitry Andric TII(static_cast<const SystemZInstrInfo *> 1320b57cec5SDimitry Andric (C->MF->getSubtarget().getInstrInfo())), 1330b57cec5SDimitry Andric MBB(nullptr), HazardRec(nullptr) { 1340b57cec5SDimitry Andric const TargetSubtargetInfo *ST = &C->MF->getSubtarget(); 1350b57cec5SDimitry Andric SchedModel.init(ST); 1360b57cec5SDimitry Andric } 1370b57cec5SDimitry Andric 1380b57cec5SDimitry Andric SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() { 1390b57cec5SDimitry Andric // Delete hazard recognizers kept around for each MBB. 1400b57cec5SDimitry Andric for (auto I : SchedStates) { 1410b57cec5SDimitry Andric SystemZHazardRecognizer *hazrec = I.second; 1420b57cec5SDimitry Andric delete hazrec; 1430b57cec5SDimitry Andric } 1440b57cec5SDimitry Andric } 1450b57cec5SDimitry Andric 1460b57cec5SDimitry Andric void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin, 1470b57cec5SDimitry Andric MachineBasicBlock::iterator End, 1480b57cec5SDimitry Andric unsigned NumRegionInstrs) { 1490b57cec5SDimitry Andric // Don't emit the terminators. 1500b57cec5SDimitry Andric if (Begin->isTerminator()) 1510b57cec5SDimitry Andric return; 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric // Emit any instructions before start of region. 1540b57cec5SDimitry Andric advanceTo(Begin); 1550b57cec5SDimitry Andric } 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric // Pick the next node to schedule. 1580b57cec5SDimitry Andric SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) { 1590b57cec5SDimitry Andric // Only scheduling top-down. 1600b57cec5SDimitry Andric IsTopNode = true; 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric if (Available.empty()) 1630b57cec5SDimitry Andric return nullptr; 1640b57cec5SDimitry Andric 1650b57cec5SDimitry Andric // If only one choice, return it. 1660b57cec5SDimitry Andric if (Available.size() == 1) { 1670b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Only one: "; 1680b57cec5SDimitry Andric HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";); 1690b57cec5SDimitry Andric return *Available.begin(); 1700b57cec5SDimitry Andric } 1710b57cec5SDimitry Andric 1720b57cec5SDimitry Andric // All nodes that are possible to schedule are stored in the Available set. 1730b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Available: "; Available.dump(*HazardRec);); 1740b57cec5SDimitry Andric 1750b57cec5SDimitry Andric Candidate Best; 1760b57cec5SDimitry Andric for (auto *SU : Available) { 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric // SU is the next candidate to be compared against current Best. 1790b57cec5SDimitry Andric Candidate c(SU, *HazardRec); 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric // Remeber which SU is the best candidate. 1820b57cec5SDimitry Andric if (Best.SU == nullptr || c < Best) { 1830b57cec5SDimitry Andric Best = c; 1840b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Best so far: ";); 1850b57cec5SDimitry Andric } else 1860b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Tried : ";); 1870b57cec5SDimitry Andric LLVM_DEBUG(HazardRec->dumpSU(c.SU, dbgs()); c.dumpCosts(); 1880b57cec5SDimitry Andric dbgs() << " Height:" << c.SU->getHeight(); dbgs() << "\n";); 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric // Once we know we have seen all SUs that affect grouping or use unbuffered 1910b57cec5SDimitry Andric // resources, we can stop iterating if Best looks good. 1920b57cec5SDimitry Andric if (!SU->isScheduleHigh && Best.noCost()) 1930b57cec5SDimitry Andric break; 1940b57cec5SDimitry Andric } 1950b57cec5SDimitry Andric 1960b57cec5SDimitry Andric assert (Best.SU != nullptr); 1970b57cec5SDimitry Andric return Best.SU; 1980b57cec5SDimitry Andric } 1990b57cec5SDimitry Andric 2000b57cec5SDimitry Andric SystemZPostRASchedStrategy::Candidate:: 2010b57cec5SDimitry Andric Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() { 2020b57cec5SDimitry Andric SU = SU_; 2030b57cec5SDimitry Andric 2040b57cec5SDimitry Andric // Check the grouping cost. For a node that must begin / end a 2050b57cec5SDimitry Andric // group, it is positive if it would do so prematurely, or negative 2060b57cec5SDimitry Andric // if it would fit naturally into the schedule. 2070b57cec5SDimitry Andric GroupingCost = HazardRec.groupingCost(SU); 2080b57cec5SDimitry Andric 2090b57cec5SDimitry Andric // Check the resources cost for this SU. 2100b57cec5SDimitry Andric ResourcesCost = HazardRec.resourcesCost(SU); 2110b57cec5SDimitry Andric } 2120b57cec5SDimitry Andric 2130b57cec5SDimitry Andric bool SystemZPostRASchedStrategy::Candidate:: 2140b57cec5SDimitry Andric operator<(const Candidate &other) { 2150b57cec5SDimitry Andric 2160b57cec5SDimitry Andric // Check decoder grouping. 2170b57cec5SDimitry Andric if (GroupingCost < other.GroupingCost) 2180b57cec5SDimitry Andric return true; 2190b57cec5SDimitry Andric if (GroupingCost > other.GroupingCost) 2200b57cec5SDimitry Andric return false; 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric // Compare the use of resources. 2230b57cec5SDimitry Andric if (ResourcesCost < other.ResourcesCost) 2240b57cec5SDimitry Andric return true; 2250b57cec5SDimitry Andric if (ResourcesCost > other.ResourcesCost) 2260b57cec5SDimitry Andric return false; 2270b57cec5SDimitry Andric 2280b57cec5SDimitry Andric // Higher SU is otherwise generally better. 2290b57cec5SDimitry Andric if (SU->getHeight() > other.SU->getHeight()) 2300b57cec5SDimitry Andric return true; 2310b57cec5SDimitry Andric if (SU->getHeight() < other.SU->getHeight()) 2320b57cec5SDimitry Andric return false; 2330b57cec5SDimitry Andric 2340b57cec5SDimitry Andric // If all same, fall back to original order. 2350b57cec5SDimitry Andric if (SU->NodeNum < other.SU->NodeNum) 2360b57cec5SDimitry Andric return true; 2370b57cec5SDimitry Andric 2380b57cec5SDimitry Andric return false; 2390b57cec5SDimitry Andric } 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) { 2420b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Scheduling SU(" << SU->NodeNum << ") "; 2430b57cec5SDimitry Andric if (Available.size() == 1) dbgs() << "(only one) "; 2440b57cec5SDimitry Andric Candidate c(SU, *HazardRec); c.dumpCosts(); dbgs() << "\n";); 2450b57cec5SDimitry Andric 2460b57cec5SDimitry Andric // Remove SU from Available set and update HazardRec. 2470b57cec5SDimitry Andric Available.erase(SU); 2480b57cec5SDimitry Andric HazardRec->EmitInstruction(SU); 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) { 2520b57cec5SDimitry Andric // Set isScheduleHigh flag on all SUs that we want to consider first in 2530b57cec5SDimitry Andric // pickNode(). 2540b57cec5SDimitry Andric const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU); 2550b57cec5SDimitry Andric bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup)); 2560b57cec5SDimitry Andric SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered); 2570b57cec5SDimitry Andric 2580b57cec5SDimitry Andric // Put all released SUs in the Available set. 2590b57cec5SDimitry Andric Available.insert(SU); 2600b57cec5SDimitry Andric } 261