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 #include "llvm/CodeGen/ScoreboardHazardRecognizer.h" 172754fe60SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h" 1817a519f9SDimitry Andric #include "llvm/MC/MCInstrItineraries.h" 192754fe60SDimitry Andric #include "llvm/Support/Debug.h" 202754fe60SDimitry Andric #include "llvm/Support/ErrorHandling.h" 212754fe60SDimitry Andric #include "llvm/Support/raw_ostream.h" 222754fe60SDimitry Andric #include "llvm/Target/TargetInstrInfo.h" 232754fe60SDimitry Andric 242754fe60SDimitry Andric using namespace llvm; 252754fe60SDimitry Andric 2691bc56edSDimitry Andric #define DEBUG_TYPE ::llvm::ScoreboardHazardRecognizer::DebugType 2791bc56edSDimitry Andric 282754fe60SDimitry Andric #ifndef NDEBUG 292754fe60SDimitry Andric const char *ScoreboardHazardRecognizer::DebugType = ""; 302754fe60SDimitry Andric #endif 312754fe60SDimitry Andric 322754fe60SDimitry Andric ScoreboardHazardRecognizer:: 332754fe60SDimitry Andric ScoreboardHazardRecognizer(const InstrItineraryData *II, 342754fe60SDimitry Andric const ScheduleDAG *SchedDAG, 352754fe60SDimitry Andric const char *ParentDebugType) : 362754fe60SDimitry Andric ScheduleHazardRecognizer(), ItinData(II), DAG(SchedDAG), IssueWidth(0), 372754fe60SDimitry Andric IssueCount(0) { 382754fe60SDimitry Andric 392754fe60SDimitry Andric #ifndef NDEBUG 402754fe60SDimitry Andric DebugType = ParentDebugType; 412754fe60SDimitry Andric #endif 422754fe60SDimitry Andric 437ae0e2c9SDimitry Andric // Determine the maximum depth of any itinerary. This determines the depth of 447ae0e2c9SDimitry Andric // the scoreboard. We always make the scoreboard at least 1 cycle deep to 457ae0e2c9SDimitry Andric // avoid dealing with the boundary condition. 462754fe60SDimitry Andric unsigned ScoreboardDepth = 1; 472754fe60SDimitry Andric if (ItinData && !ItinData->isEmpty()) { 482754fe60SDimitry Andric for (unsigned idx = 0; ; ++idx) { 492754fe60SDimitry Andric if (ItinData->isEndMarker(idx)) 502754fe60SDimitry Andric break; 512754fe60SDimitry Andric 522754fe60SDimitry Andric const InstrStage *IS = ItinData->beginStage(idx); 532754fe60SDimitry Andric const InstrStage *E = ItinData->endStage(idx); 542754fe60SDimitry Andric unsigned CurCycle = 0; 552754fe60SDimitry Andric unsigned ItinDepth = 0; 562754fe60SDimitry Andric for (; IS != E; ++IS) { 572754fe60SDimitry Andric unsigned StageDepth = CurCycle + IS->getCycles(); 582754fe60SDimitry Andric if (ItinDepth < StageDepth) ItinDepth = StageDepth; 592754fe60SDimitry Andric CurCycle += IS->getNextCycles(); 602754fe60SDimitry Andric } 612754fe60SDimitry Andric 622754fe60SDimitry Andric // Find the next power-of-2 >= ItinDepth 632754fe60SDimitry Andric while (ItinDepth > ScoreboardDepth) { 642754fe60SDimitry Andric ScoreboardDepth *= 2; 657ae0e2c9SDimitry Andric // Don't set MaxLookAhead until we find at least one nonzero stage. 667ae0e2c9SDimitry Andric // This way, an itinerary with no stages has MaxLookAhead==0, which 677ae0e2c9SDimitry Andric // completely bypasses the scoreboard hazard logic. 682754fe60SDimitry Andric MaxLookAhead = ScoreboardDepth; 692754fe60SDimitry Andric } 707ae0e2c9SDimitry Andric } 717ae0e2c9SDimitry Andric } 722754fe60SDimitry Andric 732754fe60SDimitry Andric ReservedScoreboard.reset(ScoreboardDepth); 742754fe60SDimitry Andric RequiredScoreboard.reset(ScoreboardDepth); 752754fe60SDimitry Andric 767ae0e2c9SDimitry Andric // If MaxLookAhead is not set above, then we are not enabled. 777ae0e2c9SDimitry Andric if (!isEnabled()) 787ae0e2c9SDimitry Andric DEBUG(dbgs() << "Disabled scoreboard hazard recognizer\n"); 797ae0e2c9SDimitry Andric else { 807ae0e2c9SDimitry Andric // A nonempty itinerary must have a SchedModel. 8139d628a0SDimitry Andric IssueWidth = ItinData->SchedModel.IssueWidth; 822754fe60SDimitry Andric DEBUG(dbgs() << "Using scoreboard hazard recognizer: Depth = " 832754fe60SDimitry Andric << ScoreboardDepth << '\n'); 842754fe60SDimitry Andric } 857ae0e2c9SDimitry Andric } 862754fe60SDimitry Andric 872754fe60SDimitry Andric void ScoreboardHazardRecognizer::Reset() { 882754fe60SDimitry Andric IssueCount = 0; 892754fe60SDimitry Andric RequiredScoreboard.reset(); 902754fe60SDimitry Andric ReservedScoreboard.reset(); 912754fe60SDimitry Andric } 922754fe60SDimitry Andric 933861d79fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 942754fe60SDimitry Andric void ScoreboardHazardRecognizer::Scoreboard::dump() const { 952754fe60SDimitry Andric dbgs() << "Scoreboard:\n"; 962754fe60SDimitry Andric 972754fe60SDimitry Andric unsigned last = Depth - 1; 982754fe60SDimitry Andric while ((last > 0) && ((*this)[last] == 0)) 992754fe60SDimitry Andric last--; 1002754fe60SDimitry Andric 1012754fe60SDimitry Andric for (unsigned i = 0; i <= last; i++) { 1022754fe60SDimitry Andric unsigned FUs = (*this)[i]; 1032754fe60SDimitry Andric dbgs() << "\t"; 1042754fe60SDimitry Andric for (int j = 31; j >= 0; j--) 1052754fe60SDimitry Andric dbgs() << ((FUs & (1 << j)) ? '1' : '0'); 1062754fe60SDimitry Andric dbgs() << '\n'; 1072754fe60SDimitry Andric } 1082754fe60SDimitry Andric } 1093861d79fSDimitry Andric #endif 1102754fe60SDimitry Andric 1112754fe60SDimitry Andric bool ScoreboardHazardRecognizer::atIssueLimit() const { 1122754fe60SDimitry Andric if (IssueWidth == 0) 1132754fe60SDimitry Andric return false; 1142754fe60SDimitry Andric 1152754fe60SDimitry Andric return IssueCount == IssueWidth; 1162754fe60SDimitry Andric } 1172754fe60SDimitry Andric 1182754fe60SDimitry Andric ScheduleHazardRecognizer::HazardType 1192754fe60SDimitry Andric ScoreboardHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { 1202754fe60SDimitry Andric if (!ItinData || ItinData->isEmpty()) 1212754fe60SDimitry Andric return NoHazard; 1222754fe60SDimitry Andric 1232754fe60SDimitry Andric // Note that stalls will be negative for bottom-up scheduling. 1242754fe60SDimitry Andric int cycle = Stalls; 1252754fe60SDimitry Andric 1262754fe60SDimitry Andric // Use the itinerary for the underlying instruction to check for 1272754fe60SDimitry Andric // free FU's in the scoreboard at the appropriate future cycles. 1282754fe60SDimitry Andric 12917a519f9SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU); 13091bc56edSDimitry Andric if (!MCID) { 1312754fe60SDimitry Andric // Don't check hazards for non-machineinstr Nodes. 1322754fe60SDimitry Andric return NoHazard; 1332754fe60SDimitry Andric } 13417a519f9SDimitry Andric unsigned idx = MCID->getSchedClass(); 1352754fe60SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx), 1362754fe60SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) { 1372754fe60SDimitry Andric // We must find one of the stage's units free for every cycle the 1382754fe60SDimitry Andric // stage is occupied. FIXME it would be more accurate to find the 1392754fe60SDimitry Andric // same unit free in all the cycles. 1402754fe60SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) { 1412754fe60SDimitry Andric int StageCycle = cycle + (int)i; 1422754fe60SDimitry Andric if (StageCycle < 0) 1432754fe60SDimitry Andric continue; 1442754fe60SDimitry Andric 1452754fe60SDimitry Andric if (StageCycle >= (int)RequiredScoreboard.getDepth()) { 1462754fe60SDimitry Andric assert((StageCycle - Stalls) < (int)RequiredScoreboard.getDepth() && 1472754fe60SDimitry Andric "Scoreboard depth exceeded!"); 1482754fe60SDimitry Andric // This stage was stalled beyond pipeline depth, so cannot conflict. 1492754fe60SDimitry Andric break; 1502754fe60SDimitry Andric } 1512754fe60SDimitry Andric 1522754fe60SDimitry Andric unsigned freeUnits = IS->getUnits(); 1532754fe60SDimitry Andric switch (IS->getReservationKind()) { 1542754fe60SDimitry Andric case InstrStage::Required: 1552754fe60SDimitry Andric // Required FUs conflict with both reserved and required ones 1562754fe60SDimitry Andric freeUnits &= ~ReservedScoreboard[StageCycle]; 1572754fe60SDimitry Andric // FALLTHROUGH 1582754fe60SDimitry Andric case InstrStage::Reserved: 1592754fe60SDimitry Andric // Reserved FUs can conflict only with required ones. 1602754fe60SDimitry Andric freeUnits &= ~RequiredScoreboard[StageCycle]; 1612754fe60SDimitry Andric break; 1622754fe60SDimitry Andric } 1632754fe60SDimitry Andric 1642754fe60SDimitry Andric if (!freeUnits) { 1657ae0e2c9SDimitry Andric DEBUG(dbgs() << "*** Hazard in cycle +" << StageCycle << ", "); 1662754fe60SDimitry Andric DEBUG(dbgs() << "SU(" << SU->NodeNum << "): "); 1672754fe60SDimitry Andric DEBUG(DAG->dumpNode(SU)); 1682754fe60SDimitry Andric return Hazard; 1692754fe60SDimitry Andric } 1702754fe60SDimitry Andric } 1712754fe60SDimitry Andric 1722754fe60SDimitry Andric // Advance the cycle to the next stage. 1732754fe60SDimitry Andric cycle += IS->getNextCycles(); 1742754fe60SDimitry Andric } 1752754fe60SDimitry Andric 1762754fe60SDimitry Andric return NoHazard; 1772754fe60SDimitry Andric } 1782754fe60SDimitry Andric 1792754fe60SDimitry Andric void ScoreboardHazardRecognizer::EmitInstruction(SUnit *SU) { 1802754fe60SDimitry Andric if (!ItinData || ItinData->isEmpty()) 1812754fe60SDimitry Andric return; 1822754fe60SDimitry Andric 1832754fe60SDimitry Andric // Use the itinerary for the underlying instruction to reserve FU's 1842754fe60SDimitry Andric // in the scoreboard at the appropriate future cycles. 18517a519f9SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU); 18617a519f9SDimitry Andric assert(MCID && "The scheduler must filter non-machineinstrs"); 18717a519f9SDimitry Andric if (DAG->TII->isZeroCost(MCID->Opcode)) 1882754fe60SDimitry Andric return; 1892754fe60SDimitry Andric 1902754fe60SDimitry Andric ++IssueCount; 1912754fe60SDimitry Andric 1922754fe60SDimitry Andric unsigned cycle = 0; 1932754fe60SDimitry Andric 19417a519f9SDimitry Andric unsigned idx = MCID->getSchedClass(); 1952754fe60SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx), 1962754fe60SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) { 1972754fe60SDimitry Andric // We must reserve one of the stage's units for every cycle the 1982754fe60SDimitry Andric // stage is occupied. FIXME it would be more accurate to reserve 1992754fe60SDimitry Andric // the same unit free in all the cycles. 2002754fe60SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) { 2012754fe60SDimitry Andric assert(((cycle + i) < RequiredScoreboard.getDepth()) && 2022754fe60SDimitry Andric "Scoreboard depth exceeded!"); 2032754fe60SDimitry Andric 2042754fe60SDimitry Andric unsigned freeUnits = IS->getUnits(); 2052754fe60SDimitry Andric switch (IS->getReservationKind()) { 2062754fe60SDimitry Andric case InstrStage::Required: 2072754fe60SDimitry Andric // Required FUs conflict with both reserved and required ones 2082754fe60SDimitry Andric freeUnits &= ~ReservedScoreboard[cycle + i]; 2092754fe60SDimitry Andric // FALLTHROUGH 2102754fe60SDimitry Andric case InstrStage::Reserved: 2112754fe60SDimitry Andric // Reserved FUs can conflict only with required ones. 2122754fe60SDimitry Andric freeUnits &= ~RequiredScoreboard[cycle + i]; 2132754fe60SDimitry Andric break; 2142754fe60SDimitry Andric } 2152754fe60SDimitry Andric 2162754fe60SDimitry Andric // reduce to a single unit 2172754fe60SDimitry Andric unsigned freeUnit = 0; 2182754fe60SDimitry Andric do { 2192754fe60SDimitry Andric freeUnit = freeUnits; 2202754fe60SDimitry Andric freeUnits = freeUnit & (freeUnit - 1); 2212754fe60SDimitry Andric } while (freeUnits); 2222754fe60SDimitry Andric 2232754fe60SDimitry Andric if (IS->getReservationKind() == InstrStage::Required) 2242754fe60SDimitry Andric RequiredScoreboard[cycle + i] |= freeUnit; 2252754fe60SDimitry Andric else 2262754fe60SDimitry Andric ReservedScoreboard[cycle + i] |= freeUnit; 2272754fe60SDimitry Andric } 2282754fe60SDimitry Andric 2292754fe60SDimitry Andric // Advance the cycle to the next stage. 2302754fe60SDimitry Andric cycle += IS->getNextCycles(); 2312754fe60SDimitry Andric } 2322754fe60SDimitry Andric 2332754fe60SDimitry Andric DEBUG(ReservedScoreboard.dump()); 2342754fe60SDimitry Andric DEBUG(RequiredScoreboard.dump()); 2352754fe60SDimitry Andric } 2362754fe60SDimitry Andric 2372754fe60SDimitry Andric void ScoreboardHazardRecognizer::AdvanceCycle() { 2382754fe60SDimitry Andric IssueCount = 0; 2392754fe60SDimitry Andric ReservedScoreboard[0] = 0; ReservedScoreboard.advance(); 2402754fe60SDimitry Andric RequiredScoreboard[0] = 0; RequiredScoreboard.advance(); 2412754fe60SDimitry Andric } 2422754fe60SDimitry Andric 2432754fe60SDimitry Andric void ScoreboardHazardRecognizer::RecedeCycle() { 2442754fe60SDimitry Andric IssueCount = 0; 2452754fe60SDimitry Andric ReservedScoreboard[ReservedScoreboard.getDepth()-1] = 0; 2462754fe60SDimitry Andric ReservedScoreboard.recede(); 2472754fe60SDimitry Andric RequiredScoreboard[RequiredScoreboard.getDepth()-1] = 0; 2482754fe60SDimitry Andric RequiredScoreboard.recede(); 2492754fe60SDimitry Andric } 250