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 422754fe60SDimitry Andric // Determine the maximum depth of any itinerary. This determines the 432754fe60SDimitry Andric // depth of the scoreboard. We always make the scoreboard at least 1 442754fe60SDimitry Andric // cycle deep to avoid dealing with the boundary condition. 452754fe60SDimitry Andric unsigned ScoreboardDepth = 1; 462754fe60SDimitry Andric if (ItinData && !ItinData->isEmpty()) { 472754fe60SDimitry Andric IssueWidth = ItinData->IssueWidth; 482754fe60SDimitry Andric 492754fe60SDimitry Andric for (unsigned idx = 0; ; ++idx) { 502754fe60SDimitry Andric if (ItinData->isEndMarker(idx)) 512754fe60SDimitry Andric break; 522754fe60SDimitry Andric 532754fe60SDimitry Andric const InstrStage *IS = ItinData->beginStage(idx); 542754fe60SDimitry Andric const InstrStage *E = ItinData->endStage(idx); 552754fe60SDimitry Andric unsigned CurCycle = 0; 562754fe60SDimitry Andric unsigned ItinDepth = 0; 572754fe60SDimitry Andric for (; IS != E; ++IS) { 582754fe60SDimitry Andric unsigned StageDepth = CurCycle + IS->getCycles(); 592754fe60SDimitry Andric if (ItinDepth < StageDepth) ItinDepth = StageDepth; 602754fe60SDimitry Andric CurCycle += IS->getNextCycles(); 612754fe60SDimitry Andric } 622754fe60SDimitry Andric 632754fe60SDimitry Andric // Find the next power-of-2 >= ItinDepth 642754fe60SDimitry Andric while (ItinDepth > ScoreboardDepth) { 652754fe60SDimitry Andric ScoreboardDepth *= 2; 662754fe60SDimitry Andric } 672754fe60SDimitry Andric } 682754fe60SDimitry Andric MaxLookAhead = ScoreboardDepth; 692754fe60SDimitry Andric } 702754fe60SDimitry Andric 712754fe60SDimitry Andric ReservedScoreboard.reset(ScoreboardDepth); 722754fe60SDimitry Andric RequiredScoreboard.reset(ScoreboardDepth); 732754fe60SDimitry Andric 742754fe60SDimitry Andric DEBUG(dbgs() << "Using scoreboard hazard recognizer: Depth = " 752754fe60SDimitry Andric << ScoreboardDepth << '\n'); 762754fe60SDimitry Andric } 772754fe60SDimitry Andric 782754fe60SDimitry Andric void ScoreboardHazardRecognizer::Reset() { 792754fe60SDimitry Andric IssueCount = 0; 802754fe60SDimitry Andric RequiredScoreboard.reset(); 812754fe60SDimitry Andric ReservedScoreboard.reset(); 822754fe60SDimitry Andric } 832754fe60SDimitry Andric 842754fe60SDimitry Andric void ScoreboardHazardRecognizer::Scoreboard::dump() const { 852754fe60SDimitry Andric dbgs() << "Scoreboard:\n"; 862754fe60SDimitry Andric 872754fe60SDimitry Andric unsigned last = Depth - 1; 882754fe60SDimitry Andric while ((last > 0) && ((*this)[last] == 0)) 892754fe60SDimitry Andric last--; 902754fe60SDimitry Andric 912754fe60SDimitry Andric for (unsigned i = 0; i <= last; i++) { 922754fe60SDimitry Andric unsigned FUs = (*this)[i]; 932754fe60SDimitry Andric dbgs() << "\t"; 942754fe60SDimitry Andric for (int j = 31; j >= 0; j--) 952754fe60SDimitry Andric dbgs() << ((FUs & (1 << j)) ? '1' : '0'); 962754fe60SDimitry Andric dbgs() << '\n'; 972754fe60SDimitry Andric } 982754fe60SDimitry Andric } 992754fe60SDimitry Andric 1002754fe60SDimitry Andric bool ScoreboardHazardRecognizer::atIssueLimit() const { 1012754fe60SDimitry Andric if (IssueWidth == 0) 1022754fe60SDimitry Andric return false; 1032754fe60SDimitry Andric 1042754fe60SDimitry Andric return IssueCount == IssueWidth; 1052754fe60SDimitry Andric } 1062754fe60SDimitry Andric 1072754fe60SDimitry Andric ScheduleHazardRecognizer::HazardType 1082754fe60SDimitry Andric ScoreboardHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { 1092754fe60SDimitry Andric if (!ItinData || ItinData->isEmpty()) 1102754fe60SDimitry Andric return NoHazard; 1112754fe60SDimitry Andric 1122754fe60SDimitry Andric // Note that stalls will be negative for bottom-up scheduling. 1132754fe60SDimitry Andric int cycle = Stalls; 1142754fe60SDimitry Andric 1152754fe60SDimitry Andric // Use the itinerary for the underlying instruction to check for 1162754fe60SDimitry Andric // free FU's in the scoreboard at the appropriate future cycles. 1172754fe60SDimitry Andric 11817a519f9SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU); 11917a519f9SDimitry Andric if (MCID == NULL) { 1202754fe60SDimitry Andric // Don't check hazards for non-machineinstr Nodes. 1212754fe60SDimitry Andric return NoHazard; 1222754fe60SDimitry Andric } 12317a519f9SDimitry Andric unsigned idx = MCID->getSchedClass(); 1242754fe60SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx), 1252754fe60SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) { 1262754fe60SDimitry Andric // We must find one of the stage's units free for every cycle the 1272754fe60SDimitry Andric // stage is occupied. FIXME it would be more accurate to find the 1282754fe60SDimitry Andric // same unit free in all the cycles. 1292754fe60SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) { 1302754fe60SDimitry Andric int StageCycle = cycle + (int)i; 1312754fe60SDimitry Andric if (StageCycle < 0) 1322754fe60SDimitry Andric continue; 1332754fe60SDimitry Andric 1342754fe60SDimitry Andric if (StageCycle >= (int)RequiredScoreboard.getDepth()) { 1352754fe60SDimitry Andric assert((StageCycle - Stalls) < (int)RequiredScoreboard.getDepth() && 1362754fe60SDimitry Andric "Scoreboard depth exceeded!"); 1372754fe60SDimitry Andric // This stage was stalled beyond pipeline depth, so cannot conflict. 1382754fe60SDimitry Andric break; 1392754fe60SDimitry Andric } 1402754fe60SDimitry Andric 1412754fe60SDimitry Andric unsigned freeUnits = IS->getUnits(); 1422754fe60SDimitry Andric switch (IS->getReservationKind()) { 1432754fe60SDimitry Andric default: 1442754fe60SDimitry Andric assert(0 && "Invalid FU reservation"); 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) { 1562754fe60SDimitry Andric DEBUG(dbgs() << "*** Hazard in cycle " << (cycle + i) << ", "); 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 default: 1982754fe60SDimitry Andric assert(0 && "Invalid FU reservation"); 1992754fe60SDimitry Andric case InstrStage::Required: 2002754fe60SDimitry Andric // Required FUs conflict with both reserved and required ones 2012754fe60SDimitry Andric freeUnits &= ~ReservedScoreboard[cycle + i]; 2022754fe60SDimitry Andric // FALLTHROUGH 2032754fe60SDimitry Andric case InstrStage::Reserved: 2042754fe60SDimitry Andric // Reserved FUs can conflict only with required ones. 2052754fe60SDimitry Andric freeUnits &= ~RequiredScoreboard[cycle + i]; 2062754fe60SDimitry Andric break; 2072754fe60SDimitry Andric } 2082754fe60SDimitry Andric 2092754fe60SDimitry Andric // reduce to a single unit 2102754fe60SDimitry Andric unsigned freeUnit = 0; 2112754fe60SDimitry Andric do { 2122754fe60SDimitry Andric freeUnit = freeUnits; 2132754fe60SDimitry Andric freeUnits = freeUnit & (freeUnit - 1); 2142754fe60SDimitry Andric } while (freeUnits); 2152754fe60SDimitry Andric 2162754fe60SDimitry Andric assert(freeUnit && "No function unit available!"); 2172754fe60SDimitry Andric if (IS->getReservationKind() == InstrStage::Required) 2182754fe60SDimitry Andric RequiredScoreboard[cycle + i] |= freeUnit; 2192754fe60SDimitry Andric else 2202754fe60SDimitry Andric ReservedScoreboard[cycle + i] |= freeUnit; 2212754fe60SDimitry Andric } 2222754fe60SDimitry Andric 2232754fe60SDimitry Andric // Advance the cycle to the next stage. 2242754fe60SDimitry Andric cycle += IS->getNextCycles(); 2252754fe60SDimitry Andric } 2262754fe60SDimitry Andric 2272754fe60SDimitry Andric DEBUG(ReservedScoreboard.dump()); 2282754fe60SDimitry Andric DEBUG(RequiredScoreboard.dump()); 2292754fe60SDimitry Andric } 2302754fe60SDimitry Andric 2312754fe60SDimitry Andric void ScoreboardHazardRecognizer::AdvanceCycle() { 2322754fe60SDimitry Andric IssueCount = 0; 2332754fe60SDimitry Andric ReservedScoreboard[0] = 0; ReservedScoreboard.advance(); 2342754fe60SDimitry Andric RequiredScoreboard[0] = 0; RequiredScoreboard.advance(); 2352754fe60SDimitry Andric } 2362754fe60SDimitry Andric 2372754fe60SDimitry Andric void ScoreboardHazardRecognizer::RecedeCycle() { 2382754fe60SDimitry Andric IssueCount = 0; 2392754fe60SDimitry Andric ReservedScoreboard[ReservedScoreboard.getDepth()-1] = 0; 2402754fe60SDimitry Andric ReservedScoreboard.recede(); 2412754fe60SDimitry Andric RequiredScoreboard[RequiredScoreboard.getDepth()-1] = 0; 2422754fe60SDimitry Andric RequiredScoreboard.recede(); 2432754fe60SDimitry Andric } 244