1*0b57cec5SDimitry Andric //-- SystemZMachineScheduler.cpp - SystemZ Scheduler Interface -*- C++ -*---==// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // -------------------------- Post RA scheduling ---------------------------- // 10*0b57cec5SDimitry Andric // SystemZPostRASchedStrategy is a scheduling strategy which is plugged into 11*0b57cec5SDimitry Andric // the MachineScheduler. It has a sorted Available set of SUs and a pickNode() 12*0b57cec5SDimitry Andric // implementation that looks to optimize decoder grouping and balance the 13*0b57cec5SDimitry Andric // usage of processor resources. Scheduler states are saved for the end 14*0b57cec5SDimitry Andric // region of each MBB, so that a successor block can learn from it. 15*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 16*0b57cec5SDimitry Andric 17*0b57cec5SDimitry Andric #include "SystemZMachineScheduler.h" 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric using namespace llvm; 20*0b57cec5SDimitry Andric 21*0b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler" 22*0b57cec5SDimitry Andric 23*0b57cec5SDimitry Andric #ifndef NDEBUG 24*0b57cec5SDimitry Andric // Print the set of SUs 25*0b57cec5SDimitry Andric void SystemZPostRASchedStrategy::SUSet:: 26*0b57cec5SDimitry Andric dump(SystemZHazardRecognizer &HazardRec) const { 27*0b57cec5SDimitry Andric dbgs() << "{"; 28*0b57cec5SDimitry Andric for (auto &SU : *this) { 29*0b57cec5SDimitry Andric HazardRec.dumpSU(SU, dbgs()); 30*0b57cec5SDimitry Andric if (SU != *rbegin()) 31*0b57cec5SDimitry Andric dbgs() << ", "; 32*0b57cec5SDimitry Andric } 33*0b57cec5SDimitry Andric dbgs() << "}\n"; 34*0b57cec5SDimitry Andric } 35*0b57cec5SDimitry Andric #endif 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric // Try to find a single predecessor that would be interesting for the 38*0b57cec5SDimitry Andric // scheduler in the top-most region of MBB. 39*0b57cec5SDimitry Andric static MachineBasicBlock *getSingleSchedPred(MachineBasicBlock *MBB, 40*0b57cec5SDimitry Andric const MachineLoop *Loop) { 41*0b57cec5SDimitry Andric MachineBasicBlock *PredMBB = nullptr; 42*0b57cec5SDimitry Andric if (MBB->pred_size() == 1) 43*0b57cec5SDimitry Andric PredMBB = *MBB->pred_begin(); 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric // The loop header has two predecessors, return the latch, but not for a 46*0b57cec5SDimitry Andric // single block loop. 47*0b57cec5SDimitry Andric if (MBB->pred_size() == 2 && Loop != nullptr && Loop->getHeader() == MBB) { 48*0b57cec5SDimitry Andric for (auto I = MBB->pred_begin(); I != MBB->pred_end(); ++I) 49*0b57cec5SDimitry Andric if (Loop->contains(*I)) 50*0b57cec5SDimitry Andric PredMBB = (*I == MBB ? nullptr : *I); 51*0b57cec5SDimitry Andric } 52*0b57cec5SDimitry Andric 53*0b57cec5SDimitry Andric assert ((PredMBB == nullptr || !Loop || Loop->contains(PredMBB)) 54*0b57cec5SDimitry Andric && "Loop MBB should not consider predecessor outside of loop."); 55*0b57cec5SDimitry Andric 56*0b57cec5SDimitry Andric return PredMBB; 57*0b57cec5SDimitry Andric } 58*0b57cec5SDimitry Andric 59*0b57cec5SDimitry Andric void SystemZPostRASchedStrategy:: 60*0b57cec5SDimitry Andric advanceTo(MachineBasicBlock::iterator NextBegin) { 61*0b57cec5SDimitry Andric MachineBasicBlock::iterator LastEmittedMI = HazardRec->getLastEmittedMI(); 62*0b57cec5SDimitry Andric MachineBasicBlock::iterator I = 63*0b57cec5SDimitry Andric ((LastEmittedMI != nullptr && LastEmittedMI->getParent() == MBB) ? 64*0b57cec5SDimitry Andric std::next(LastEmittedMI) : MBB->begin()); 65*0b57cec5SDimitry Andric 66*0b57cec5SDimitry Andric for (; I != NextBegin; ++I) { 67*0b57cec5SDimitry Andric if (I->isPosition() || I->isDebugInstr()) 68*0b57cec5SDimitry Andric continue; 69*0b57cec5SDimitry Andric HazardRec->emitInstruction(&*I); 70*0b57cec5SDimitry Andric } 71*0b57cec5SDimitry Andric } 72*0b57cec5SDimitry Andric 73*0b57cec5SDimitry Andric void SystemZPostRASchedStrategy::initialize(ScheduleDAGMI *dag) { 74*0b57cec5SDimitry Andric LLVM_DEBUG(HazardRec->dumpState();); 75*0b57cec5SDimitry Andric } 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) { 78*0b57cec5SDimitry Andric assert ((SchedStates.find(NextMBB) == SchedStates.end()) && 79*0b57cec5SDimitry Andric "Entering MBB twice?"); 80*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Entering " << printMBBReference(*NextMBB)); 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric MBB = NextMBB; 83*0b57cec5SDimitry Andric 84*0b57cec5SDimitry Andric /// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to 85*0b57cec5SDimitry Andric /// point to it. 86*0b57cec5SDimitry Andric HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel); 87*0b57cec5SDimitry Andric LLVM_DEBUG(const MachineLoop *Loop = MLI->getLoopFor(MBB); 88*0b57cec5SDimitry Andric if (Loop && Loop->getHeader() == MBB) dbgs() << " (Loop header)"; 89*0b57cec5SDimitry Andric dbgs() << ":\n";); 90*0b57cec5SDimitry Andric 91*0b57cec5SDimitry Andric // Try to take over the state from a single predecessor, if it has been 92*0b57cec5SDimitry Andric // scheduled. If this is not possible, we are done. 93*0b57cec5SDimitry Andric MachineBasicBlock *SinglePredMBB = 94*0b57cec5SDimitry Andric getSingleSchedPred(MBB, MLI->getLoopFor(MBB)); 95*0b57cec5SDimitry Andric if (SinglePredMBB == nullptr || 96*0b57cec5SDimitry Andric SchedStates.find(SinglePredMBB) == SchedStates.end()) 97*0b57cec5SDimitry Andric return; 98*0b57cec5SDimitry Andric 99*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Continued scheduling from " 100*0b57cec5SDimitry Andric << printMBBReference(*SinglePredMBB) << "\n";); 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric HazardRec->copyState(SchedStates[SinglePredMBB]); 103*0b57cec5SDimitry Andric LLVM_DEBUG(HazardRec->dumpState();); 104*0b57cec5SDimitry Andric 105*0b57cec5SDimitry Andric // Emit incoming terminator(s). Be optimistic and assume that branch 106*0b57cec5SDimitry Andric // prediction will generally do "the right thing". 107*0b57cec5SDimitry Andric for (MachineBasicBlock::iterator I = SinglePredMBB->getFirstTerminator(); 108*0b57cec5SDimitry Andric I != SinglePredMBB->end(); I++) { 109*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Emitting incoming branch: "; I->dump();); 110*0b57cec5SDimitry Andric bool TakenBranch = (I->isBranch() && 111*0b57cec5SDimitry Andric (TII->getBranchInfo(*I).isIndirect() || 112*0b57cec5SDimitry Andric TII->getBranchInfo(*I).getMBBTarget() == MBB)); 113*0b57cec5SDimitry Andric HazardRec->emitInstruction(&*I, TakenBranch); 114*0b57cec5SDimitry Andric if (TakenBranch) 115*0b57cec5SDimitry Andric break; 116*0b57cec5SDimitry Andric } 117*0b57cec5SDimitry Andric } 118*0b57cec5SDimitry Andric 119*0b57cec5SDimitry Andric void SystemZPostRASchedStrategy::leaveMBB() { 120*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Leaving " << printMBBReference(*MBB) << "\n";); 121*0b57cec5SDimitry Andric 122*0b57cec5SDimitry Andric // Advance to first terminator. The successor block will handle terminators 123*0b57cec5SDimitry Andric // dependent on CFG layout (T/NT branch etc). 124*0b57cec5SDimitry Andric advanceTo(MBB->getFirstTerminator()); 125*0b57cec5SDimitry Andric } 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric SystemZPostRASchedStrategy:: 128*0b57cec5SDimitry Andric SystemZPostRASchedStrategy(const MachineSchedContext *C) 129*0b57cec5SDimitry Andric : MLI(C->MLI), 130*0b57cec5SDimitry Andric TII(static_cast<const SystemZInstrInfo *> 131*0b57cec5SDimitry Andric (C->MF->getSubtarget().getInstrInfo())), 132*0b57cec5SDimitry Andric MBB(nullptr), HazardRec(nullptr) { 133*0b57cec5SDimitry Andric const TargetSubtargetInfo *ST = &C->MF->getSubtarget(); 134*0b57cec5SDimitry Andric SchedModel.init(ST); 135*0b57cec5SDimitry Andric } 136*0b57cec5SDimitry Andric 137*0b57cec5SDimitry Andric SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() { 138*0b57cec5SDimitry Andric // Delete hazard recognizers kept around for each MBB. 139*0b57cec5SDimitry Andric for (auto I : SchedStates) { 140*0b57cec5SDimitry Andric SystemZHazardRecognizer *hazrec = I.second; 141*0b57cec5SDimitry Andric delete hazrec; 142*0b57cec5SDimitry Andric } 143*0b57cec5SDimitry Andric } 144*0b57cec5SDimitry Andric 145*0b57cec5SDimitry Andric void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin, 146*0b57cec5SDimitry Andric MachineBasicBlock::iterator End, 147*0b57cec5SDimitry Andric unsigned NumRegionInstrs) { 148*0b57cec5SDimitry Andric // Don't emit the terminators. 149*0b57cec5SDimitry Andric if (Begin->isTerminator()) 150*0b57cec5SDimitry Andric return; 151*0b57cec5SDimitry Andric 152*0b57cec5SDimitry Andric // Emit any instructions before start of region. 153*0b57cec5SDimitry Andric advanceTo(Begin); 154*0b57cec5SDimitry Andric } 155*0b57cec5SDimitry Andric 156*0b57cec5SDimitry Andric // Pick the next node to schedule. 157*0b57cec5SDimitry Andric SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) { 158*0b57cec5SDimitry Andric // Only scheduling top-down. 159*0b57cec5SDimitry Andric IsTopNode = true; 160*0b57cec5SDimitry Andric 161*0b57cec5SDimitry Andric if (Available.empty()) 162*0b57cec5SDimitry Andric return nullptr; 163*0b57cec5SDimitry Andric 164*0b57cec5SDimitry Andric // If only one choice, return it. 165*0b57cec5SDimitry Andric if (Available.size() == 1) { 166*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Only one: "; 167*0b57cec5SDimitry Andric HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";); 168*0b57cec5SDimitry Andric return *Available.begin(); 169*0b57cec5SDimitry Andric } 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric // All nodes that are possible to schedule are stored in the Available set. 172*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Available: "; Available.dump(*HazardRec);); 173*0b57cec5SDimitry Andric 174*0b57cec5SDimitry Andric Candidate Best; 175*0b57cec5SDimitry Andric for (auto *SU : Available) { 176*0b57cec5SDimitry Andric 177*0b57cec5SDimitry Andric // SU is the next candidate to be compared against current Best. 178*0b57cec5SDimitry Andric Candidate c(SU, *HazardRec); 179*0b57cec5SDimitry Andric 180*0b57cec5SDimitry Andric // Remeber which SU is the best candidate. 181*0b57cec5SDimitry Andric if (Best.SU == nullptr || c < Best) { 182*0b57cec5SDimitry Andric Best = c; 183*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Best so far: ";); 184*0b57cec5SDimitry Andric } else 185*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Tried : ";); 186*0b57cec5SDimitry Andric LLVM_DEBUG(HazardRec->dumpSU(c.SU, dbgs()); c.dumpCosts(); 187*0b57cec5SDimitry Andric dbgs() << " Height:" << c.SU->getHeight(); dbgs() << "\n";); 188*0b57cec5SDimitry Andric 189*0b57cec5SDimitry Andric // Once we know we have seen all SUs that affect grouping or use unbuffered 190*0b57cec5SDimitry Andric // resources, we can stop iterating if Best looks good. 191*0b57cec5SDimitry Andric if (!SU->isScheduleHigh && Best.noCost()) 192*0b57cec5SDimitry Andric break; 193*0b57cec5SDimitry Andric } 194*0b57cec5SDimitry Andric 195*0b57cec5SDimitry Andric assert (Best.SU != nullptr); 196*0b57cec5SDimitry Andric return Best.SU; 197*0b57cec5SDimitry Andric } 198*0b57cec5SDimitry Andric 199*0b57cec5SDimitry Andric SystemZPostRASchedStrategy::Candidate:: 200*0b57cec5SDimitry Andric Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() { 201*0b57cec5SDimitry Andric SU = SU_; 202*0b57cec5SDimitry Andric 203*0b57cec5SDimitry Andric // Check the grouping cost. For a node that must begin / end a 204*0b57cec5SDimitry Andric // group, it is positive if it would do so prematurely, or negative 205*0b57cec5SDimitry Andric // if it would fit naturally into the schedule. 206*0b57cec5SDimitry Andric GroupingCost = HazardRec.groupingCost(SU); 207*0b57cec5SDimitry Andric 208*0b57cec5SDimitry Andric // Check the resources cost for this SU. 209*0b57cec5SDimitry Andric ResourcesCost = HazardRec.resourcesCost(SU); 210*0b57cec5SDimitry Andric } 211*0b57cec5SDimitry Andric 212*0b57cec5SDimitry Andric bool SystemZPostRASchedStrategy::Candidate:: 213*0b57cec5SDimitry Andric operator<(const Candidate &other) { 214*0b57cec5SDimitry Andric 215*0b57cec5SDimitry Andric // Check decoder grouping. 216*0b57cec5SDimitry Andric if (GroupingCost < other.GroupingCost) 217*0b57cec5SDimitry Andric return true; 218*0b57cec5SDimitry Andric if (GroupingCost > other.GroupingCost) 219*0b57cec5SDimitry Andric return false; 220*0b57cec5SDimitry Andric 221*0b57cec5SDimitry Andric // Compare the use of resources. 222*0b57cec5SDimitry Andric if (ResourcesCost < other.ResourcesCost) 223*0b57cec5SDimitry Andric return true; 224*0b57cec5SDimitry Andric if (ResourcesCost > other.ResourcesCost) 225*0b57cec5SDimitry Andric return false; 226*0b57cec5SDimitry Andric 227*0b57cec5SDimitry Andric // Higher SU is otherwise generally better. 228*0b57cec5SDimitry Andric if (SU->getHeight() > other.SU->getHeight()) 229*0b57cec5SDimitry Andric return true; 230*0b57cec5SDimitry Andric if (SU->getHeight() < other.SU->getHeight()) 231*0b57cec5SDimitry Andric return false; 232*0b57cec5SDimitry Andric 233*0b57cec5SDimitry Andric // If all same, fall back to original order. 234*0b57cec5SDimitry Andric if (SU->NodeNum < other.SU->NodeNum) 235*0b57cec5SDimitry Andric return true; 236*0b57cec5SDimitry Andric 237*0b57cec5SDimitry Andric return false; 238*0b57cec5SDimitry Andric } 239*0b57cec5SDimitry Andric 240*0b57cec5SDimitry Andric void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) { 241*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "** Scheduling SU(" << SU->NodeNum << ") "; 242*0b57cec5SDimitry Andric if (Available.size() == 1) dbgs() << "(only one) "; 243*0b57cec5SDimitry Andric Candidate c(SU, *HazardRec); c.dumpCosts(); dbgs() << "\n";); 244*0b57cec5SDimitry Andric 245*0b57cec5SDimitry Andric // Remove SU from Available set and update HazardRec. 246*0b57cec5SDimitry Andric Available.erase(SU); 247*0b57cec5SDimitry Andric HazardRec->EmitInstruction(SU); 248*0b57cec5SDimitry Andric } 249*0b57cec5SDimitry Andric 250*0b57cec5SDimitry Andric void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) { 251*0b57cec5SDimitry Andric // Set isScheduleHigh flag on all SUs that we want to consider first in 252*0b57cec5SDimitry Andric // pickNode(). 253*0b57cec5SDimitry Andric const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU); 254*0b57cec5SDimitry Andric bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup)); 255*0b57cec5SDimitry Andric SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered); 256*0b57cec5SDimitry Andric 257*0b57cec5SDimitry Andric // Put all released SUs in the Available set. 258*0b57cec5SDimitry Andric Available.insert(SU); 259*0b57cec5SDimitry Andric } 260