1 //-- SystemZMachineScheduler.cpp - SystemZ Scheduler Interface -*- C++ -*---==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // -------------------------- Post RA scheduling ---------------------------- // 11 // SystemZPostRASchedStrategy is a scheduling strategy which is plugged into 12 // the MachineScheduler. It has a sorted Available set of SUs and a pickNode() 13 // implementation that looks to optimize decoder grouping and balance the 14 // usage of processor resources. Scheduler states are saved for the end 15 // region of each MBB, so that a successor block can learn from it. 16 //===----------------------------------------------------------------------===// 17 18 #include "SystemZMachineScheduler.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->isDebugValue()) 69 continue; 70 HazardRec->emitInstruction(&*I); 71 } 72 } 73 74 void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) { 75 assert ((SchedStates.find(NextMBB) == SchedStates.end()) && 76 "Entering MBB twice?"); 77 DEBUG(dbgs() << "+++ Entering " << printMBBReference(*NextMBB)); 78 79 MBB = NextMBB; 80 /// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to 81 /// point to it. 82 HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel); 83 DEBUG (const MachineLoop *Loop = MLI->getLoopFor(MBB); 84 if(Loop && Loop->getHeader() == MBB) 85 dbgs() << " (Loop header)"; 86 dbgs() << ":\n";); 87 88 // Try to take over the state from a single predecessor, if it has been 89 // scheduled. If this is not possible, we are done. 90 MachineBasicBlock *SinglePredMBB = 91 getSingleSchedPred(MBB, MLI->getLoopFor(MBB)); 92 if (SinglePredMBB == nullptr || 93 SchedStates.find(SinglePredMBB) == SchedStates.end()) 94 return; 95 96 DEBUG(dbgs() << "+++ Continued scheduling from " 97 << printMBBReference(*SinglePredMBB) << "\n";); 98 99 HazardRec->copyState(SchedStates[SinglePredMBB]); 100 101 // Emit incoming terminator(s). Be optimistic and assume that branch 102 // prediction will generally do "the right thing". 103 for (MachineBasicBlock::iterator I = SinglePredMBB->getFirstTerminator(); 104 I != SinglePredMBB->end(); I++) { 105 DEBUG (dbgs() << "+++ Emitting incoming branch: "; I->dump();); 106 bool TakenBranch = (I->isBranch() && 107 (TII->getBranchInfo(*I).Target->isReg() || // Relative branch 108 TII->getBranchInfo(*I).Target->getMBB() == MBB)); 109 HazardRec->emitInstruction(&*I, TakenBranch); 110 if (TakenBranch) 111 break; 112 } 113 } 114 115 void SystemZPostRASchedStrategy::leaveMBB() { 116 DEBUG(dbgs() << "+++ Leaving " << printMBBReference(*MBB) << "\n";); 117 118 // Advance to first terminator. The successor block will handle terminators 119 // dependent on CFG layout (T/NT branch etc). 120 advanceTo(MBB->getFirstTerminator()); 121 } 122 123 SystemZPostRASchedStrategy:: 124 SystemZPostRASchedStrategy(const MachineSchedContext *C) 125 : MLI(C->MLI), 126 TII(static_cast<const SystemZInstrInfo *> 127 (C->MF->getSubtarget().getInstrInfo())), 128 MBB(nullptr), HazardRec(nullptr) { 129 const TargetSubtargetInfo *ST = &C->MF->getSubtarget(); 130 SchedModel.init(ST->getSchedModel(), ST, TII); 131 } 132 133 SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() { 134 // Delete hazard recognizers kept around for each MBB. 135 for (auto I : SchedStates) { 136 SystemZHazardRecognizer *hazrec = I.second; 137 delete hazrec; 138 } 139 } 140 141 void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin, 142 MachineBasicBlock::iterator End, 143 unsigned NumRegionInstrs) { 144 // Don't emit the terminators. 145 if (Begin->isTerminator()) 146 return; 147 148 // Emit any instructions before start of region. 149 advanceTo(Begin); 150 } 151 152 // Pick the next node to schedule. 153 SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) { 154 // Only scheduling top-down. 155 IsTopNode = true; 156 157 if (Available.empty()) 158 return nullptr; 159 160 // If only one choice, return it. 161 if (Available.size() == 1) { 162 DEBUG (dbgs() << "+++ Only one: "; 163 HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";); 164 return *Available.begin(); 165 } 166 167 // All nodes that are possible to schedule are stored by in the 168 // Available set. 169 DEBUG(dbgs() << "+++ Available: "; Available.dump(*HazardRec);); 170 171 Candidate Best; 172 for (auto *SU : Available) { 173 174 // SU is the next candidate to be compared against current Best. 175 Candidate c(SU, *HazardRec); 176 177 // Remeber which SU is the best candidate. 178 if (Best.SU == nullptr || c < Best) { 179 Best = c; 180 DEBUG(dbgs() << "+++ Best sofar: "; 181 HazardRec->dumpSU(Best.SU, dbgs()); 182 if (Best.GroupingCost != 0) 183 dbgs() << "\tGrouping cost:" << Best.GroupingCost; 184 if (Best.ResourcesCost != 0) 185 dbgs() << " Resource cost:" << Best.ResourcesCost; 186 dbgs() << " Height:" << Best.SU->getHeight(); 187 dbgs() << "\n";); 188 } 189 190 // Once we know we have seen all SUs that affect grouping or use unbuffered 191 // resources, we can stop iterating if Best looks good. 192 if (!SU->isScheduleHigh && Best.noCost()) 193 break; 194 } 195 196 assert (Best.SU != nullptr); 197 return Best.SU; 198 } 199 200 SystemZPostRASchedStrategy::Candidate:: 201 Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() { 202 SU = SU_; 203 204 // Check the grouping cost. For a node that must begin / end a 205 // group, it is positive if it would do so prematurely, or negative 206 // if it would fit naturally into the schedule. 207 GroupingCost = HazardRec.groupingCost(SU); 208 209 // Check the resources cost for this SU. 210 ResourcesCost = HazardRec.resourcesCost(SU); 211 } 212 213 bool SystemZPostRASchedStrategy::Candidate:: 214 operator<(const Candidate &other) { 215 216 // Check decoder grouping. 217 if (GroupingCost < other.GroupingCost) 218 return true; 219 if (GroupingCost > other.GroupingCost) 220 return false; 221 222 // Compare the use of resources. 223 if (ResourcesCost < other.ResourcesCost) 224 return true; 225 if (ResourcesCost > other.ResourcesCost) 226 return false; 227 228 // Higher SU is otherwise generally better. 229 if (SU->getHeight() > other.SU->getHeight()) 230 return true; 231 if (SU->getHeight() < other.SU->getHeight()) 232 return false; 233 234 // If all same, fall back to original order. 235 if (SU->NodeNum < other.SU->NodeNum) 236 return true; 237 238 return false; 239 } 240 241 void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) { 242 DEBUG(dbgs() << "+++ Scheduling SU(" << SU->NodeNum << ")\n";); 243 244 // Remove SU from Available set and update HazardRec. 245 Available.erase(SU); 246 HazardRec->EmitInstruction(SU); 247 } 248 249 void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) { 250 // Set isScheduleHigh flag on all SUs that we want to consider first in 251 // pickNode(). 252 const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU); 253 bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup)); 254 SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered); 255 256 // Put all released SUs in the Available set. 257 Available.insert(SU); 258 } 259