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 263ca95b02SDimitry Andric #define DEBUG_TYPE DebugType 2791bc56edSDimitry Andric 283ca95b02SDimitry Andric ScoreboardHazardRecognizer::ScoreboardHazardRecognizer( 293ca95b02SDimitry Andric const InstrItineraryData *II, const ScheduleDAG *SchedDAG, 303ca95b02SDimitry Andric const char *ParentDebugType) 313ca95b02SDimitry Andric : ScheduleHazardRecognizer(), DebugType(ParentDebugType), ItinData(II), 323ca95b02SDimitry Andric DAG(SchedDAG), IssueWidth(0), IssueCount(0) { 332754fe60SDimitry Andric 347ae0e2c9SDimitry Andric // Determine the maximum depth of any itinerary. This determines the depth of 357ae0e2c9SDimitry Andric // the scoreboard. We always make the scoreboard at least 1 cycle deep to 367ae0e2c9SDimitry Andric // avoid dealing with the boundary condition. 372754fe60SDimitry Andric unsigned ScoreboardDepth = 1; 382754fe60SDimitry Andric if (ItinData && !ItinData->isEmpty()) { 392754fe60SDimitry Andric for (unsigned idx = 0; ; ++idx) { 402754fe60SDimitry Andric if (ItinData->isEndMarker(idx)) 412754fe60SDimitry Andric break; 422754fe60SDimitry Andric 432754fe60SDimitry Andric const InstrStage *IS = ItinData->beginStage(idx); 442754fe60SDimitry Andric const InstrStage *E = ItinData->endStage(idx); 452754fe60SDimitry Andric unsigned CurCycle = 0; 462754fe60SDimitry Andric unsigned ItinDepth = 0; 472754fe60SDimitry Andric for (; IS != E; ++IS) { 482754fe60SDimitry Andric unsigned StageDepth = CurCycle + IS->getCycles(); 492754fe60SDimitry Andric if (ItinDepth < StageDepth) ItinDepth = StageDepth; 502754fe60SDimitry Andric CurCycle += IS->getNextCycles(); 512754fe60SDimitry Andric } 522754fe60SDimitry Andric 532754fe60SDimitry Andric // Find the next power-of-2 >= ItinDepth 542754fe60SDimitry Andric while (ItinDepth > ScoreboardDepth) { 552754fe60SDimitry Andric ScoreboardDepth *= 2; 567ae0e2c9SDimitry Andric // Don't set MaxLookAhead until we find at least one nonzero stage. 577ae0e2c9SDimitry Andric // This way, an itinerary with no stages has MaxLookAhead==0, which 587ae0e2c9SDimitry Andric // completely bypasses the scoreboard hazard logic. 592754fe60SDimitry Andric MaxLookAhead = ScoreboardDepth; 602754fe60SDimitry Andric } 617ae0e2c9SDimitry Andric } 627ae0e2c9SDimitry Andric } 632754fe60SDimitry Andric 642754fe60SDimitry Andric ReservedScoreboard.reset(ScoreboardDepth); 652754fe60SDimitry Andric RequiredScoreboard.reset(ScoreboardDepth); 662754fe60SDimitry Andric 677ae0e2c9SDimitry Andric // If MaxLookAhead is not set above, then we are not enabled. 687ae0e2c9SDimitry Andric if (!isEnabled()) 697ae0e2c9SDimitry Andric DEBUG(dbgs() << "Disabled scoreboard hazard recognizer\n"); 707ae0e2c9SDimitry Andric else { 717ae0e2c9SDimitry Andric // A nonempty itinerary must have a SchedModel. 7239d628a0SDimitry Andric IssueWidth = ItinData->SchedModel.IssueWidth; 732754fe60SDimitry Andric DEBUG(dbgs() << "Using scoreboard hazard recognizer: Depth = " 742754fe60SDimitry Andric << ScoreboardDepth << '\n'); 752754fe60SDimitry Andric } 767ae0e2c9SDimitry Andric } 772754fe60SDimitry Andric 782754fe60SDimitry Andric void ScoreboardHazardRecognizer::Reset() { 792754fe60SDimitry Andric IssueCount = 0; 802754fe60SDimitry Andric RequiredScoreboard.reset(); 812754fe60SDimitry Andric ReservedScoreboard.reset(); 822754fe60SDimitry Andric } 832754fe60SDimitry Andric 843861d79fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 853ca95b02SDimitry Andric LLVM_DUMP_METHOD void ScoreboardHazardRecognizer::Scoreboard::dump() const { 862754fe60SDimitry Andric dbgs() << "Scoreboard:\n"; 872754fe60SDimitry Andric 882754fe60SDimitry Andric unsigned last = Depth - 1; 892754fe60SDimitry Andric while ((last > 0) && ((*this)[last] == 0)) 902754fe60SDimitry Andric last--; 912754fe60SDimitry Andric 922754fe60SDimitry Andric for (unsigned i = 0; i <= last; i++) { 932754fe60SDimitry Andric unsigned FUs = (*this)[i]; 942754fe60SDimitry Andric dbgs() << "\t"; 952754fe60SDimitry Andric for (int j = 31; j >= 0; j--) 962754fe60SDimitry Andric dbgs() << ((FUs & (1 << j)) ? '1' : '0'); 972754fe60SDimitry Andric dbgs() << '\n'; 982754fe60SDimitry Andric } 992754fe60SDimitry Andric } 1003861d79fSDimitry Andric #endif 1012754fe60SDimitry Andric 1022754fe60SDimitry Andric bool ScoreboardHazardRecognizer::atIssueLimit() const { 1032754fe60SDimitry Andric if (IssueWidth == 0) 1042754fe60SDimitry Andric return false; 1052754fe60SDimitry Andric 1062754fe60SDimitry Andric return IssueCount == IssueWidth; 1072754fe60SDimitry Andric } 1082754fe60SDimitry Andric 1092754fe60SDimitry Andric ScheduleHazardRecognizer::HazardType 1102754fe60SDimitry Andric ScoreboardHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { 1112754fe60SDimitry Andric if (!ItinData || ItinData->isEmpty()) 1122754fe60SDimitry Andric return NoHazard; 1132754fe60SDimitry Andric 1142754fe60SDimitry Andric // Note that stalls will be negative for bottom-up scheduling. 1152754fe60SDimitry Andric int cycle = Stalls; 1162754fe60SDimitry Andric 1172754fe60SDimitry Andric // Use the itinerary for the underlying instruction to check for 1182754fe60SDimitry Andric // free FU's in the scoreboard at the appropriate future cycles. 1192754fe60SDimitry Andric 12017a519f9SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU); 12191bc56edSDimitry Andric if (!MCID) { 1222754fe60SDimitry Andric // Don't check hazards for non-machineinstr Nodes. 1232754fe60SDimitry Andric return NoHazard; 1242754fe60SDimitry Andric } 12517a519f9SDimitry Andric unsigned idx = MCID->getSchedClass(); 1262754fe60SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx), 1272754fe60SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) { 1282754fe60SDimitry Andric // We must find one of the stage's units free for every cycle the 1292754fe60SDimitry Andric // stage is occupied. FIXME it would be more accurate to find the 1302754fe60SDimitry Andric // same unit free in all the cycles. 1312754fe60SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) { 1322754fe60SDimitry Andric int StageCycle = cycle + (int)i; 1332754fe60SDimitry Andric if (StageCycle < 0) 1342754fe60SDimitry Andric continue; 1352754fe60SDimitry Andric 1362754fe60SDimitry Andric if (StageCycle >= (int)RequiredScoreboard.getDepth()) { 1372754fe60SDimitry Andric assert((StageCycle - Stalls) < (int)RequiredScoreboard.getDepth() && 1382754fe60SDimitry Andric "Scoreboard depth exceeded!"); 1392754fe60SDimitry Andric // This stage was stalled beyond pipeline depth, so cannot conflict. 1402754fe60SDimitry Andric break; 1412754fe60SDimitry Andric } 1422754fe60SDimitry Andric 1432754fe60SDimitry Andric unsigned freeUnits = IS->getUnits(); 1442754fe60SDimitry Andric switch (IS->getReservationKind()) { 1452754fe60SDimitry Andric case InstrStage::Required: 1462754fe60SDimitry Andric // Required FUs conflict with both reserved and required ones 1472754fe60SDimitry Andric freeUnits &= ~ReservedScoreboard[StageCycle]; 1482754fe60SDimitry Andric // FALLTHROUGH 1492754fe60SDimitry Andric case InstrStage::Reserved: 1502754fe60SDimitry Andric // Reserved FUs can conflict only with required ones. 1512754fe60SDimitry Andric freeUnits &= ~RequiredScoreboard[StageCycle]; 1522754fe60SDimitry Andric break; 1532754fe60SDimitry Andric } 1542754fe60SDimitry Andric 1552754fe60SDimitry Andric if (!freeUnits) { 1567ae0e2c9SDimitry Andric DEBUG(dbgs() << "*** Hazard in cycle +" << StageCycle << ", "); 1572754fe60SDimitry Andric DEBUG(dbgs() << "SU(" << SU->NodeNum << "): "); 1582754fe60SDimitry Andric DEBUG(DAG->dumpNode(SU)); 1592754fe60SDimitry Andric return Hazard; 1602754fe60SDimitry Andric } 1612754fe60SDimitry Andric } 1622754fe60SDimitry Andric 1632754fe60SDimitry Andric // Advance the cycle to the next stage. 1642754fe60SDimitry Andric cycle += IS->getNextCycles(); 1652754fe60SDimitry Andric } 1662754fe60SDimitry Andric 1672754fe60SDimitry Andric return NoHazard; 1682754fe60SDimitry Andric } 1692754fe60SDimitry Andric 1702754fe60SDimitry Andric void ScoreboardHazardRecognizer::EmitInstruction(SUnit *SU) { 1712754fe60SDimitry Andric if (!ItinData || ItinData->isEmpty()) 1722754fe60SDimitry Andric return; 1732754fe60SDimitry Andric 1742754fe60SDimitry Andric // Use the itinerary for the underlying instruction to reserve FU's 1752754fe60SDimitry Andric // in the scoreboard at the appropriate future cycles. 17617a519f9SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU); 17717a519f9SDimitry Andric assert(MCID && "The scheduler must filter non-machineinstrs"); 17817a519f9SDimitry Andric if (DAG->TII->isZeroCost(MCID->Opcode)) 1792754fe60SDimitry Andric return; 1802754fe60SDimitry Andric 1812754fe60SDimitry Andric ++IssueCount; 1822754fe60SDimitry Andric 1832754fe60SDimitry Andric unsigned cycle = 0; 1842754fe60SDimitry Andric 18517a519f9SDimitry Andric unsigned idx = MCID->getSchedClass(); 1862754fe60SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx), 1872754fe60SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) { 1882754fe60SDimitry Andric // We must reserve one of the stage's units for every cycle the 1892754fe60SDimitry Andric // stage is occupied. FIXME it would be more accurate to reserve 1902754fe60SDimitry Andric // the same unit free in all the cycles. 1912754fe60SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) { 1922754fe60SDimitry Andric assert(((cycle + i) < RequiredScoreboard.getDepth()) && 1932754fe60SDimitry Andric "Scoreboard depth exceeded!"); 1942754fe60SDimitry Andric 1952754fe60SDimitry Andric unsigned freeUnits = IS->getUnits(); 1962754fe60SDimitry Andric switch (IS->getReservationKind()) { 1972754fe60SDimitry Andric case InstrStage::Required: 1982754fe60SDimitry Andric // Required FUs conflict with both reserved and required ones 1992754fe60SDimitry Andric freeUnits &= ~ReservedScoreboard[cycle + i]; 2002754fe60SDimitry Andric // FALLTHROUGH 2012754fe60SDimitry Andric case InstrStage::Reserved: 2022754fe60SDimitry Andric // Reserved FUs can conflict only with required ones. 2032754fe60SDimitry Andric freeUnits &= ~RequiredScoreboard[cycle + i]; 2042754fe60SDimitry Andric break; 2052754fe60SDimitry Andric } 2062754fe60SDimitry Andric 2072754fe60SDimitry Andric // reduce to a single unit 2082754fe60SDimitry Andric unsigned freeUnit = 0; 2092754fe60SDimitry Andric do { 2102754fe60SDimitry Andric freeUnit = freeUnits; 2112754fe60SDimitry Andric freeUnits = freeUnit & (freeUnit - 1); 2122754fe60SDimitry Andric } while (freeUnits); 2132754fe60SDimitry Andric 2142754fe60SDimitry Andric if (IS->getReservationKind() == InstrStage::Required) 2152754fe60SDimitry Andric RequiredScoreboard[cycle + i] |= freeUnit; 2162754fe60SDimitry Andric else 2172754fe60SDimitry Andric ReservedScoreboard[cycle + i] |= freeUnit; 2182754fe60SDimitry Andric } 2192754fe60SDimitry Andric 2202754fe60SDimitry Andric // Advance the cycle to the next stage. 2212754fe60SDimitry Andric cycle += IS->getNextCycles(); 2222754fe60SDimitry Andric } 2232754fe60SDimitry Andric 2242754fe60SDimitry Andric DEBUG(ReservedScoreboard.dump()); 2252754fe60SDimitry Andric DEBUG(RequiredScoreboard.dump()); 2262754fe60SDimitry Andric } 2272754fe60SDimitry Andric 2282754fe60SDimitry Andric void ScoreboardHazardRecognizer::AdvanceCycle() { 2292754fe60SDimitry Andric IssueCount = 0; 2302754fe60SDimitry Andric ReservedScoreboard[0] = 0; ReservedScoreboard.advance(); 2312754fe60SDimitry Andric RequiredScoreboard[0] = 0; RequiredScoreboard.advance(); 2322754fe60SDimitry Andric } 2332754fe60SDimitry Andric 2342754fe60SDimitry Andric void ScoreboardHazardRecognizer::RecedeCycle() { 2352754fe60SDimitry Andric IssueCount = 0; 2362754fe60SDimitry Andric ReservedScoreboard[ReservedScoreboard.getDepth()-1] = 0; 2372754fe60SDimitry Andric ReservedScoreboard.recede(); 2382754fe60SDimitry Andric RequiredScoreboard[RequiredScoreboard.getDepth()-1] = 0; 2392754fe60SDimitry Andric RequiredScoreboard.recede(); 2402754fe60SDimitry Andric } 241