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