12754fe60SDimitry Andric //===----- ScoreboardHazardRecognizer.cpp - Scheduler Support -------------===// 22754fe60SDimitry Andric // 32754fe60SDimitry Andric // The LLVM Compiler Infrastructure 42754fe60SDimitry Andric // 52754fe60SDimitry Andric // This file is distributed under the University of Illinois Open Source 62754fe60SDimitry Andric // License. See LICENSE.TXT for details. 72754fe60SDimitry Andric // 82754fe60SDimitry Andric //===----------------------------------------------------------------------===// 92754fe60SDimitry Andric // 102754fe60SDimitry Andric // This file implements the ScoreboardHazardRecognizer class, which 112754fe60SDimitry Andric // encapsultes hazard-avoidance heuristics for scheduling, based on the 122754fe60SDimitry Andric // scheduling itineraries specified for the target. 132754fe60SDimitry Andric // 142754fe60SDimitry Andric //===----------------------------------------------------------------------===// 152754fe60SDimitry Andric 162754fe60SDimitry Andric #define DEBUG_TYPE ::llvm::ScoreboardHazardRecognizer::DebugType 172754fe60SDimitry Andric #include "llvm/CodeGen/ScoreboardHazardRecognizer.h" 182754fe60SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h" 1917a519f9SDimitry Andric #include "llvm/MC/MCInstrItineraries.h" 202754fe60SDimitry Andric #include "llvm/Support/Debug.h" 212754fe60SDimitry Andric #include "llvm/Support/ErrorHandling.h" 222754fe60SDimitry Andric #include "llvm/Support/raw_ostream.h" 232754fe60SDimitry Andric #include "llvm/Target/TargetInstrInfo.h" 242754fe60SDimitry Andric 252754fe60SDimitry Andric using namespace llvm; 262754fe60SDimitry Andric 272754fe60SDimitry Andric #ifndef NDEBUG 282754fe60SDimitry Andric const char *ScoreboardHazardRecognizer::DebugType = ""; 292754fe60SDimitry Andric #endif 302754fe60SDimitry Andric 312754fe60SDimitry Andric ScoreboardHazardRecognizer:: 322754fe60SDimitry Andric ScoreboardHazardRecognizer(const InstrItineraryData *II, 332754fe60SDimitry Andric const ScheduleDAG *SchedDAG, 342754fe60SDimitry Andric const char *ParentDebugType) : 352754fe60SDimitry Andric ScheduleHazardRecognizer(), ItinData(II), DAG(SchedDAG), IssueWidth(0), 362754fe60SDimitry Andric IssueCount(0) { 372754fe60SDimitry Andric 382754fe60SDimitry Andric #ifndef NDEBUG 392754fe60SDimitry Andric DebugType = ParentDebugType; 402754fe60SDimitry Andric #endif 412754fe60SDimitry Andric 427ae0e2c9SDimitry Andric // Determine the maximum depth of any itinerary. This determines the depth of 437ae0e2c9SDimitry Andric // the scoreboard. We always make the scoreboard at least 1 cycle deep to 447ae0e2c9SDimitry Andric // avoid dealing with the boundary condition. 452754fe60SDimitry Andric unsigned ScoreboardDepth = 1; 462754fe60SDimitry Andric if (ItinData && !ItinData->isEmpty()) { 472754fe60SDimitry Andric for (unsigned idx = 0; ; ++idx) { 482754fe60SDimitry Andric if (ItinData->isEndMarker(idx)) 492754fe60SDimitry Andric break; 502754fe60SDimitry Andric 512754fe60SDimitry Andric const InstrStage *IS = ItinData->beginStage(idx); 522754fe60SDimitry Andric const InstrStage *E = ItinData->endStage(idx); 532754fe60SDimitry Andric unsigned CurCycle = 0; 542754fe60SDimitry Andric unsigned ItinDepth = 0; 552754fe60SDimitry Andric for (; IS != E; ++IS) { 562754fe60SDimitry Andric unsigned StageDepth = CurCycle + IS->getCycles(); 572754fe60SDimitry Andric if (ItinDepth < StageDepth) ItinDepth = StageDepth; 582754fe60SDimitry Andric CurCycle += IS->getNextCycles(); 592754fe60SDimitry Andric } 602754fe60SDimitry Andric 612754fe60SDimitry Andric // Find the next power-of-2 >= ItinDepth 622754fe60SDimitry Andric while (ItinDepth > ScoreboardDepth) { 632754fe60SDimitry Andric ScoreboardDepth *= 2; 647ae0e2c9SDimitry Andric // Don't set MaxLookAhead until we find at least one nonzero stage. 657ae0e2c9SDimitry Andric // This way, an itinerary with no stages has MaxLookAhead==0, which 667ae0e2c9SDimitry Andric // completely bypasses the scoreboard hazard logic. 672754fe60SDimitry Andric MaxLookAhead = ScoreboardDepth; 682754fe60SDimitry Andric } 697ae0e2c9SDimitry Andric } 707ae0e2c9SDimitry Andric } 712754fe60SDimitry Andric 722754fe60SDimitry Andric ReservedScoreboard.reset(ScoreboardDepth); 732754fe60SDimitry Andric RequiredScoreboard.reset(ScoreboardDepth); 742754fe60SDimitry Andric 757ae0e2c9SDimitry Andric // If MaxLookAhead is not set above, then we are not enabled. 767ae0e2c9SDimitry Andric if (!isEnabled()) 777ae0e2c9SDimitry Andric DEBUG(dbgs() << "Disabled scoreboard hazard recognizer\n"); 787ae0e2c9SDimitry Andric else { 797ae0e2c9SDimitry Andric // A nonempty itinerary must have a SchedModel. 807ae0e2c9SDimitry Andric IssueWidth = ItinData->SchedModel->IssueWidth; 812754fe60SDimitry Andric DEBUG(dbgs() << "Using scoreboard hazard recognizer: Depth = " 822754fe60SDimitry Andric << ScoreboardDepth << '\n'); 832754fe60SDimitry Andric } 847ae0e2c9SDimitry Andric } 852754fe60SDimitry Andric 862754fe60SDimitry Andric void ScoreboardHazardRecognizer::Reset() { 872754fe60SDimitry Andric IssueCount = 0; 882754fe60SDimitry Andric RequiredScoreboard.reset(); 892754fe60SDimitry Andric ReservedScoreboard.reset(); 902754fe60SDimitry Andric } 912754fe60SDimitry Andric 922754fe60SDimitry Andric void ScoreboardHazardRecognizer::Scoreboard::dump() const { 932754fe60SDimitry Andric dbgs() << "Scoreboard:\n"; 942754fe60SDimitry Andric 952754fe60SDimitry Andric unsigned last = Depth - 1; 962754fe60SDimitry Andric while ((last > 0) && ((*this)[last] == 0)) 972754fe60SDimitry Andric last--; 982754fe60SDimitry Andric 992754fe60SDimitry Andric for (unsigned i = 0; i <= last; i++) { 1002754fe60SDimitry Andric unsigned FUs = (*this)[i]; 1012754fe60SDimitry Andric dbgs() << "\t"; 1022754fe60SDimitry Andric for (int j = 31; j >= 0; j--) 1032754fe60SDimitry Andric dbgs() << ((FUs & (1 << j)) ? '1' : '0'); 1042754fe60SDimitry Andric dbgs() << '\n'; 1052754fe60SDimitry Andric } 1062754fe60SDimitry Andric } 1072754fe60SDimitry Andric 1082754fe60SDimitry Andric bool ScoreboardHazardRecognizer::atIssueLimit() const { 1092754fe60SDimitry Andric if (IssueWidth == 0) 1102754fe60SDimitry Andric return false; 1112754fe60SDimitry Andric 1122754fe60SDimitry Andric return IssueCount == IssueWidth; 1132754fe60SDimitry Andric } 1142754fe60SDimitry Andric 1152754fe60SDimitry Andric ScheduleHazardRecognizer::HazardType 1162754fe60SDimitry Andric ScoreboardHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { 1172754fe60SDimitry Andric if (!ItinData || ItinData->isEmpty()) 1182754fe60SDimitry Andric return NoHazard; 1192754fe60SDimitry Andric 1202754fe60SDimitry Andric // Note that stalls will be negative for bottom-up scheduling. 1212754fe60SDimitry Andric int cycle = Stalls; 1222754fe60SDimitry Andric 1232754fe60SDimitry Andric // Use the itinerary for the underlying instruction to check for 1242754fe60SDimitry Andric // free FU's in the scoreboard at the appropriate future cycles. 1252754fe60SDimitry Andric 12617a519f9SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU); 12717a519f9SDimitry Andric if (MCID == NULL) { 1282754fe60SDimitry Andric // Don't check hazards for non-machineinstr Nodes. 1292754fe60SDimitry Andric return NoHazard; 1302754fe60SDimitry Andric } 13117a519f9SDimitry Andric unsigned idx = MCID->getSchedClass(); 1322754fe60SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx), 1332754fe60SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) { 1342754fe60SDimitry Andric // We must find one of the stage's units free for every cycle the 1352754fe60SDimitry Andric // stage is occupied. FIXME it would be more accurate to find the 1362754fe60SDimitry Andric // same unit free in all the cycles. 1372754fe60SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) { 1382754fe60SDimitry Andric int StageCycle = cycle + (int)i; 1392754fe60SDimitry Andric if (StageCycle < 0) 1402754fe60SDimitry Andric continue; 1412754fe60SDimitry Andric 1422754fe60SDimitry Andric if (StageCycle >= (int)RequiredScoreboard.getDepth()) { 1432754fe60SDimitry Andric assert((StageCycle - Stalls) < (int)RequiredScoreboard.getDepth() && 1442754fe60SDimitry Andric "Scoreboard depth exceeded!"); 1452754fe60SDimitry Andric // This stage was stalled beyond pipeline depth, so cannot conflict. 1462754fe60SDimitry Andric break; 1472754fe60SDimitry Andric } 1482754fe60SDimitry Andric 1492754fe60SDimitry Andric unsigned freeUnits = IS->getUnits(); 1502754fe60SDimitry Andric switch (IS->getReservationKind()) { 1512754fe60SDimitry Andric case InstrStage::Required: 1522754fe60SDimitry Andric // Required FUs conflict with both reserved and required ones 1532754fe60SDimitry Andric freeUnits &= ~ReservedScoreboard[StageCycle]; 1542754fe60SDimitry Andric // FALLTHROUGH 1552754fe60SDimitry Andric case InstrStage::Reserved: 1562754fe60SDimitry Andric // Reserved FUs can conflict only with required ones. 1572754fe60SDimitry Andric freeUnits &= ~RequiredScoreboard[StageCycle]; 1582754fe60SDimitry Andric break; 1592754fe60SDimitry Andric } 1602754fe60SDimitry Andric 1612754fe60SDimitry Andric if (!freeUnits) { 1627ae0e2c9SDimitry Andric DEBUG(dbgs() << "*** Hazard in cycle +" << StageCycle << ", "); 1632754fe60SDimitry Andric DEBUG(dbgs() << "SU(" << SU->NodeNum << "): "); 1642754fe60SDimitry Andric DEBUG(DAG->dumpNode(SU)); 1652754fe60SDimitry Andric return Hazard; 1662754fe60SDimitry Andric } 1672754fe60SDimitry Andric } 1682754fe60SDimitry Andric 1692754fe60SDimitry Andric // Advance the cycle to the next stage. 1702754fe60SDimitry Andric cycle += IS->getNextCycles(); 1712754fe60SDimitry Andric } 1722754fe60SDimitry Andric 1732754fe60SDimitry Andric return NoHazard; 1742754fe60SDimitry Andric } 1752754fe60SDimitry Andric 1762754fe60SDimitry Andric void ScoreboardHazardRecognizer::EmitInstruction(SUnit *SU) { 1772754fe60SDimitry Andric if (!ItinData || ItinData->isEmpty()) 1782754fe60SDimitry Andric return; 1792754fe60SDimitry Andric 1802754fe60SDimitry Andric // Use the itinerary for the underlying instruction to reserve FU's 1812754fe60SDimitry Andric // in the scoreboard at the appropriate future cycles. 18217a519f9SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU); 18317a519f9SDimitry Andric assert(MCID && "The scheduler must filter non-machineinstrs"); 18417a519f9SDimitry Andric if (DAG->TII->isZeroCost(MCID->Opcode)) 1852754fe60SDimitry Andric return; 1862754fe60SDimitry Andric 1872754fe60SDimitry Andric ++IssueCount; 1882754fe60SDimitry Andric 1892754fe60SDimitry Andric unsigned cycle = 0; 1902754fe60SDimitry Andric 19117a519f9SDimitry Andric unsigned idx = MCID->getSchedClass(); 1922754fe60SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx), 1932754fe60SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) { 1942754fe60SDimitry Andric // We must reserve one of the stage's units for every cycle the 1952754fe60SDimitry Andric // stage is occupied. FIXME it would be more accurate to reserve 1962754fe60SDimitry Andric // the same unit free in all the cycles. 1972754fe60SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) { 1982754fe60SDimitry Andric assert(((cycle + i) < RequiredScoreboard.getDepth()) && 1992754fe60SDimitry Andric "Scoreboard depth exceeded!"); 2002754fe60SDimitry Andric 2012754fe60SDimitry Andric unsigned freeUnits = IS->getUnits(); 2022754fe60SDimitry Andric switch (IS->getReservationKind()) { 2032754fe60SDimitry Andric case InstrStage::Required: 2042754fe60SDimitry Andric // Required FUs conflict with both reserved and required ones 2052754fe60SDimitry Andric freeUnits &= ~ReservedScoreboard[cycle + i]; 2062754fe60SDimitry Andric // FALLTHROUGH 2072754fe60SDimitry Andric case InstrStage::Reserved: 2082754fe60SDimitry Andric // Reserved FUs can conflict only with required ones. 2092754fe60SDimitry Andric freeUnits &= ~RequiredScoreboard[cycle + i]; 2102754fe60SDimitry Andric break; 2112754fe60SDimitry Andric } 2122754fe60SDimitry Andric 2132754fe60SDimitry Andric // reduce to a single unit 2142754fe60SDimitry Andric unsigned freeUnit = 0; 2152754fe60SDimitry Andric do { 2162754fe60SDimitry Andric freeUnit = freeUnits; 2172754fe60SDimitry Andric freeUnits = freeUnit & (freeUnit - 1); 2182754fe60SDimitry Andric } while (freeUnits); 2192754fe60SDimitry Andric 2202754fe60SDimitry Andric if (IS->getReservationKind() == InstrStage::Required) 2212754fe60SDimitry Andric RequiredScoreboard[cycle + i] |= freeUnit; 2222754fe60SDimitry Andric else 2232754fe60SDimitry Andric ReservedScoreboard[cycle + i] |= freeUnit; 2242754fe60SDimitry Andric } 2252754fe60SDimitry Andric 2262754fe60SDimitry Andric // Advance the cycle to the next stage. 2272754fe60SDimitry Andric cycle += IS->getNextCycles(); 2282754fe60SDimitry Andric } 2292754fe60SDimitry Andric 2302754fe60SDimitry Andric DEBUG(ReservedScoreboard.dump()); 2312754fe60SDimitry Andric DEBUG(RequiredScoreboard.dump()); 2322754fe60SDimitry Andric } 2332754fe60SDimitry Andric 2342754fe60SDimitry Andric void ScoreboardHazardRecognizer::AdvanceCycle() { 2352754fe60SDimitry Andric IssueCount = 0; 2362754fe60SDimitry Andric ReservedScoreboard[0] = 0; ReservedScoreboard.advance(); 2372754fe60SDimitry Andric RequiredScoreboard[0] = 0; RequiredScoreboard.advance(); 2382754fe60SDimitry Andric } 2392754fe60SDimitry Andric 2402754fe60SDimitry Andric void ScoreboardHazardRecognizer::RecedeCycle() { 2412754fe60SDimitry Andric IssueCount = 0; 2422754fe60SDimitry Andric ReservedScoreboard[ReservedScoreboard.getDepth()-1] = 0; 2432754fe60SDimitry Andric ReservedScoreboard.recede(); 2442754fe60SDimitry Andric RequiredScoreboard[RequiredScoreboard.getDepth()-1] = 0; 2452754fe60SDimitry Andric RequiredScoreboard.recede(); 2462754fe60SDimitry Andric } 247