1 //===----- ScoreboardHazardRecognizer.cpp - Scheduler Support -------------===// 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 // This file implements the ScoreboardHazardRecognizer class, which 11 // encapsultes hazard-avoidance heuristics for scheduling, based on the 12 // scheduling itineraries specified for the target. 13 // 14 //===----------------------------------------------------------------------===// 15 16 #include "llvm/CodeGen/ScoreboardHazardRecognizer.h" 17 #include "llvm/CodeGen/ScheduleDAG.h" 18 #include "llvm/MC/MCInstrItineraries.h" 19 #include "llvm/Support/Debug.h" 20 #include "llvm/Support/ErrorHandling.h" 21 #include "llvm/Support/raw_ostream.h" 22 #include "llvm/Target/TargetInstrInfo.h" 23 24 using namespace llvm; 25 26 #define DEBUG_TYPE ::llvm::ScoreboardHazardRecognizer::DebugType 27 28 #ifndef NDEBUG 29 const char *ScoreboardHazardRecognizer::DebugType = ""; 30 #endif 31 32 ScoreboardHazardRecognizer:: 33 ScoreboardHazardRecognizer(const InstrItineraryData *II, 34 const ScheduleDAG *SchedDAG, 35 const char *ParentDebugType) : 36 ScheduleHazardRecognizer(), ItinData(II), DAG(SchedDAG), IssueWidth(0), 37 IssueCount(0) { 38 39 #ifndef NDEBUG 40 DebugType = ParentDebugType; 41 #endif 42 43 // Determine the maximum depth of any itinerary. This determines the depth of 44 // the scoreboard. We always make the scoreboard at least 1 cycle deep to 45 // avoid dealing with the boundary condition. 46 unsigned ScoreboardDepth = 1; 47 if (ItinData && !ItinData->isEmpty()) { 48 for (unsigned idx = 0; ; ++idx) { 49 if (ItinData->isEndMarker(idx)) 50 break; 51 52 const InstrStage *IS = ItinData->beginStage(idx); 53 const InstrStage *E = ItinData->endStage(idx); 54 unsigned CurCycle = 0; 55 unsigned ItinDepth = 0; 56 for (; IS != E; ++IS) { 57 unsigned StageDepth = CurCycle + IS->getCycles(); 58 if (ItinDepth < StageDepth) ItinDepth = StageDepth; 59 CurCycle += IS->getNextCycles(); 60 } 61 62 // Find the next power-of-2 >= ItinDepth 63 while (ItinDepth > ScoreboardDepth) { 64 ScoreboardDepth *= 2; 65 // Don't set MaxLookAhead until we find at least one nonzero stage. 66 // This way, an itinerary with no stages has MaxLookAhead==0, which 67 // completely bypasses the scoreboard hazard logic. 68 MaxLookAhead = ScoreboardDepth; 69 } 70 } 71 } 72 73 ReservedScoreboard.reset(ScoreboardDepth); 74 RequiredScoreboard.reset(ScoreboardDepth); 75 76 // If MaxLookAhead is not set above, then we are not enabled. 77 if (!isEnabled()) 78 DEBUG(dbgs() << "Disabled scoreboard hazard recognizer\n"); 79 else { 80 // A nonempty itinerary must have a SchedModel. 81 IssueWidth = ItinData->SchedModel.IssueWidth; 82 DEBUG(dbgs() << "Using scoreboard hazard recognizer: Depth = " 83 << ScoreboardDepth << '\n'); 84 } 85 } 86 87 void ScoreboardHazardRecognizer::Reset() { 88 IssueCount = 0; 89 RequiredScoreboard.reset(); 90 ReservedScoreboard.reset(); 91 } 92 93 #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 94 void ScoreboardHazardRecognizer::Scoreboard::dump() const { 95 dbgs() << "Scoreboard:\n"; 96 97 unsigned last = Depth - 1; 98 while ((last > 0) && ((*this)[last] == 0)) 99 last--; 100 101 for (unsigned i = 0; i <= last; i++) { 102 unsigned FUs = (*this)[i]; 103 dbgs() << "\t"; 104 for (int j = 31; j >= 0; j--) 105 dbgs() << ((FUs & (1 << j)) ? '1' : '0'); 106 dbgs() << '\n'; 107 } 108 } 109 #endif 110 111 bool ScoreboardHazardRecognizer::atIssueLimit() const { 112 if (IssueWidth == 0) 113 return false; 114 115 return IssueCount == IssueWidth; 116 } 117 118 ScheduleHazardRecognizer::HazardType 119 ScoreboardHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { 120 if (!ItinData || ItinData->isEmpty()) 121 return NoHazard; 122 123 // Note that stalls will be negative for bottom-up scheduling. 124 int cycle = Stalls; 125 126 // Use the itinerary for the underlying instruction to check for 127 // free FU's in the scoreboard at the appropriate future cycles. 128 129 const MCInstrDesc *MCID = DAG->getInstrDesc(SU); 130 if (!MCID) { 131 // Don't check hazards for non-machineinstr Nodes. 132 return NoHazard; 133 } 134 unsigned idx = MCID->getSchedClass(); 135 for (const InstrStage *IS = ItinData->beginStage(idx), 136 *E = ItinData->endStage(idx); IS != E; ++IS) { 137 // We must find one of the stage's units free for every cycle the 138 // stage is occupied. FIXME it would be more accurate to find the 139 // same unit free in all the cycles. 140 for (unsigned int i = 0; i < IS->getCycles(); ++i) { 141 int StageCycle = cycle + (int)i; 142 if (StageCycle < 0) 143 continue; 144 145 if (StageCycle >= (int)RequiredScoreboard.getDepth()) { 146 assert((StageCycle - Stalls) < (int)RequiredScoreboard.getDepth() && 147 "Scoreboard depth exceeded!"); 148 // This stage was stalled beyond pipeline depth, so cannot conflict. 149 break; 150 } 151 152 unsigned freeUnits = IS->getUnits(); 153 switch (IS->getReservationKind()) { 154 case InstrStage::Required: 155 // Required FUs conflict with both reserved and required ones 156 freeUnits &= ~ReservedScoreboard[StageCycle]; 157 // FALLTHROUGH 158 case InstrStage::Reserved: 159 // Reserved FUs can conflict only with required ones. 160 freeUnits &= ~RequiredScoreboard[StageCycle]; 161 break; 162 } 163 164 if (!freeUnits) { 165 DEBUG(dbgs() << "*** Hazard in cycle +" << StageCycle << ", "); 166 DEBUG(dbgs() << "SU(" << SU->NodeNum << "): "); 167 DEBUG(DAG->dumpNode(SU)); 168 return Hazard; 169 } 170 } 171 172 // Advance the cycle to the next stage. 173 cycle += IS->getNextCycles(); 174 } 175 176 return NoHazard; 177 } 178 179 void ScoreboardHazardRecognizer::EmitInstruction(SUnit *SU) { 180 if (!ItinData || ItinData->isEmpty()) 181 return; 182 183 // Use the itinerary for the underlying instruction to reserve FU's 184 // in the scoreboard at the appropriate future cycles. 185 const MCInstrDesc *MCID = DAG->getInstrDesc(SU); 186 assert(MCID && "The scheduler must filter non-machineinstrs"); 187 if (DAG->TII->isZeroCost(MCID->Opcode)) 188 return; 189 190 ++IssueCount; 191 192 unsigned cycle = 0; 193 194 unsigned idx = MCID->getSchedClass(); 195 for (const InstrStage *IS = ItinData->beginStage(idx), 196 *E = ItinData->endStage(idx); IS != E; ++IS) { 197 // We must reserve one of the stage's units for every cycle the 198 // stage is occupied. FIXME it would be more accurate to reserve 199 // the same unit free in all the cycles. 200 for (unsigned int i = 0; i < IS->getCycles(); ++i) { 201 assert(((cycle + i) < RequiredScoreboard.getDepth()) && 202 "Scoreboard depth exceeded!"); 203 204 unsigned freeUnits = IS->getUnits(); 205 switch (IS->getReservationKind()) { 206 case InstrStage::Required: 207 // Required FUs conflict with both reserved and required ones 208 freeUnits &= ~ReservedScoreboard[cycle + i]; 209 // FALLTHROUGH 210 case InstrStage::Reserved: 211 // Reserved FUs can conflict only with required ones. 212 freeUnits &= ~RequiredScoreboard[cycle + i]; 213 break; 214 } 215 216 // reduce to a single unit 217 unsigned freeUnit = 0; 218 do { 219 freeUnit = freeUnits; 220 freeUnits = freeUnit & (freeUnit - 1); 221 } while (freeUnits); 222 223 if (IS->getReservationKind() == InstrStage::Required) 224 RequiredScoreboard[cycle + i] |= freeUnit; 225 else 226 ReservedScoreboard[cycle + i] |= freeUnit; 227 } 228 229 // Advance the cycle to the next stage. 230 cycle += IS->getNextCycles(); 231 } 232 233 DEBUG(ReservedScoreboard.dump()); 234 DEBUG(RequiredScoreboard.dump()); 235 } 236 237 void ScoreboardHazardRecognizer::AdvanceCycle() { 238 IssueCount = 0; 239 ReservedScoreboard[0] = 0; ReservedScoreboard.advance(); 240 RequiredScoreboard[0] = 0; RequiredScoreboard.advance(); 241 } 242 243 void ScoreboardHazardRecognizer::RecedeCycle() { 244 IssueCount = 0; 245 ReservedScoreboard[ReservedScoreboard.getDepth()-1] = 0; 246 ReservedScoreboard.recede(); 247 RequiredScoreboard[RequiredScoreboard.getDepth()-1] = 0; 248 RequiredScoreboard.recede(); 249 } 250