17a7e6055SDimitry 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" 182cab237bSDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 197a7e6055SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 2017a519f9SDimitry Andric #include "llvm/MC/MCInstrItineraries.h" 217a7e6055SDimitry Andric #include "llvm/Support/Compiler.h" 222754fe60SDimitry Andric #include "llvm/Support/Debug.h" 232754fe60SDimitry Andric #include "llvm/Support/raw_ostream.h" 247a7e6055SDimitry Andric #include <cassert> 252754fe60SDimitry Andric 262754fe60SDimitry Andric using namespace llvm; 272754fe60SDimitry Andric 283ca95b02SDimitry Andric #define DEBUG_TYPE DebugType 2991bc56edSDimitry Andric 303ca95b02SDimitry Andric ScoreboardHazardRecognizer::ScoreboardHazardRecognizer( 313ca95b02SDimitry Andric const InstrItineraryData *II, const ScheduleDAG *SchedDAG, 323ca95b02SDimitry Andric const char *ParentDebugType) 333ca95b02SDimitry Andric : ScheduleHazardRecognizer(), DebugType(ParentDebugType), ItinData(II), 347a7e6055SDimitry Andric DAG(SchedDAG) { 352cab237bSDimitry Andric (void)DebugType; 367ae0e2c9SDimitry Andric // Determine the maximum depth of any itinerary. This determines the depth of 377ae0e2c9SDimitry Andric // the scoreboard. We always make the scoreboard at least 1 cycle deep to 387ae0e2c9SDimitry Andric // avoid dealing with the boundary condition. 392754fe60SDimitry Andric unsigned ScoreboardDepth = 1; 402754fe60SDimitry Andric if (ItinData && !ItinData->isEmpty()) { 412754fe60SDimitry Andric for (unsigned idx = 0; ; ++idx) { 422754fe60SDimitry Andric if (ItinData->isEndMarker(idx)) 432754fe60SDimitry Andric break; 442754fe60SDimitry Andric 452754fe60SDimitry Andric const InstrStage *IS = ItinData->beginStage(idx); 462754fe60SDimitry Andric const InstrStage *E = ItinData->endStage(idx); 472754fe60SDimitry Andric unsigned CurCycle = 0; 482754fe60SDimitry Andric unsigned ItinDepth = 0; 492754fe60SDimitry Andric for (; IS != E; ++IS) { 502754fe60SDimitry Andric unsigned StageDepth = CurCycle + IS->getCycles(); 512754fe60SDimitry Andric if (ItinDepth < StageDepth) ItinDepth = StageDepth; 522754fe60SDimitry Andric CurCycle += IS->getNextCycles(); 532754fe60SDimitry Andric } 542754fe60SDimitry Andric 552754fe60SDimitry Andric // Find the next power-of-2 >= ItinDepth 562754fe60SDimitry Andric while (ItinDepth > ScoreboardDepth) { 572754fe60SDimitry Andric ScoreboardDepth *= 2; 587ae0e2c9SDimitry Andric // Don't set MaxLookAhead until we find at least one nonzero stage. 597ae0e2c9SDimitry Andric // This way, an itinerary with no stages has MaxLookAhead==0, which 607ae0e2c9SDimitry Andric // completely bypasses the scoreboard hazard logic. 612754fe60SDimitry Andric MaxLookAhead = ScoreboardDepth; 622754fe60SDimitry Andric } 637ae0e2c9SDimitry Andric } 647ae0e2c9SDimitry Andric } 652754fe60SDimitry Andric 662754fe60SDimitry Andric ReservedScoreboard.reset(ScoreboardDepth); 672754fe60SDimitry Andric RequiredScoreboard.reset(ScoreboardDepth); 682754fe60SDimitry Andric 697ae0e2c9SDimitry Andric // If MaxLookAhead is not set above, then we are not enabled. 707ae0e2c9SDimitry Andric if (!isEnabled()) 717ae0e2c9SDimitry Andric DEBUG(dbgs() << "Disabled scoreboard hazard recognizer\n"); 727ae0e2c9SDimitry Andric else { 737ae0e2c9SDimitry Andric // A nonempty itinerary must have a SchedModel. 7439d628a0SDimitry Andric IssueWidth = ItinData->SchedModel.IssueWidth; 752754fe60SDimitry Andric DEBUG(dbgs() << "Using scoreboard hazard recognizer: Depth = " 762754fe60SDimitry Andric << ScoreboardDepth << '\n'); 772754fe60SDimitry Andric } 787ae0e2c9SDimitry Andric } 792754fe60SDimitry Andric 802754fe60SDimitry Andric void ScoreboardHazardRecognizer::Reset() { 812754fe60SDimitry Andric IssueCount = 0; 822754fe60SDimitry Andric RequiredScoreboard.reset(); 832754fe60SDimitry Andric ReservedScoreboard.reset(); 842754fe60SDimitry Andric } 852754fe60SDimitry Andric 863861d79fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP) 873ca95b02SDimitry Andric LLVM_DUMP_METHOD void ScoreboardHazardRecognizer::Scoreboard::dump() const { 882754fe60SDimitry Andric dbgs() << "Scoreboard:\n"; 892754fe60SDimitry Andric 902754fe60SDimitry Andric unsigned last = Depth - 1; 912754fe60SDimitry Andric while ((last > 0) && ((*this)[last] == 0)) 922754fe60SDimitry Andric last--; 932754fe60SDimitry Andric 942754fe60SDimitry Andric for (unsigned i = 0; i <= last; i++) { 952754fe60SDimitry Andric unsigned FUs = (*this)[i]; 962754fe60SDimitry Andric dbgs() << "\t"; 972754fe60SDimitry Andric for (int j = 31; j >= 0; j--) 982754fe60SDimitry Andric dbgs() << ((FUs & (1 << j)) ? '1' : '0'); 992754fe60SDimitry Andric dbgs() << '\n'; 1002754fe60SDimitry Andric } 1012754fe60SDimitry Andric } 1023861d79fSDimitry Andric #endif 1032754fe60SDimitry Andric 1042754fe60SDimitry Andric bool ScoreboardHazardRecognizer::atIssueLimit() const { 1052754fe60SDimitry Andric if (IssueWidth == 0) 1062754fe60SDimitry Andric return false; 1072754fe60SDimitry Andric 1082754fe60SDimitry Andric return IssueCount == IssueWidth; 1092754fe60SDimitry Andric } 1102754fe60SDimitry Andric 1112754fe60SDimitry Andric ScheduleHazardRecognizer::HazardType 1122754fe60SDimitry Andric ScoreboardHazardRecognizer::getHazardType(SUnit *SU, int Stalls) { 1132754fe60SDimitry Andric if (!ItinData || ItinData->isEmpty()) 1142754fe60SDimitry Andric return NoHazard; 1152754fe60SDimitry Andric 1162754fe60SDimitry Andric // Note that stalls will be negative for bottom-up scheduling. 1172754fe60SDimitry Andric int cycle = Stalls; 1182754fe60SDimitry Andric 1192754fe60SDimitry Andric // Use the itinerary for the underlying instruction to check for 1202754fe60SDimitry Andric // free FU's in the scoreboard at the appropriate future cycles. 1212754fe60SDimitry Andric 12217a519f9SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU); 12391bc56edSDimitry Andric if (!MCID) { 1242754fe60SDimitry Andric // Don't check hazards for non-machineinstr Nodes. 1252754fe60SDimitry Andric return NoHazard; 1262754fe60SDimitry Andric } 12717a519f9SDimitry Andric unsigned idx = MCID->getSchedClass(); 1282754fe60SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx), 1292754fe60SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) { 1302754fe60SDimitry Andric // We must find one of the stage's units free for every cycle the 1312754fe60SDimitry Andric // stage is occupied. FIXME it would be more accurate to find the 1322754fe60SDimitry Andric // same unit free in all the cycles. 1332754fe60SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) { 1342754fe60SDimitry Andric int StageCycle = cycle + (int)i; 1352754fe60SDimitry Andric if (StageCycle < 0) 1362754fe60SDimitry Andric continue; 1372754fe60SDimitry Andric 1382754fe60SDimitry Andric if (StageCycle >= (int)RequiredScoreboard.getDepth()) { 1392754fe60SDimitry Andric assert((StageCycle - Stalls) < (int)RequiredScoreboard.getDepth() && 1402754fe60SDimitry Andric "Scoreboard depth exceeded!"); 1412754fe60SDimitry Andric // This stage was stalled beyond pipeline depth, so cannot conflict. 1422754fe60SDimitry Andric break; 1432754fe60SDimitry Andric } 1442754fe60SDimitry Andric 1452754fe60SDimitry Andric unsigned freeUnits = IS->getUnits(); 1462754fe60SDimitry Andric switch (IS->getReservationKind()) { 1472754fe60SDimitry Andric case InstrStage::Required: 1482754fe60SDimitry Andric // Required FUs conflict with both reserved and required ones 1492754fe60SDimitry Andric freeUnits &= ~ReservedScoreboard[StageCycle]; 150d88c1a5aSDimitry Andric LLVM_FALLTHROUGH; 1512754fe60SDimitry Andric case InstrStage::Reserved: 1522754fe60SDimitry Andric // Reserved FUs can conflict only with required ones. 1532754fe60SDimitry Andric freeUnits &= ~RequiredScoreboard[StageCycle]; 1542754fe60SDimitry Andric break; 1552754fe60SDimitry Andric } 1562754fe60SDimitry Andric 1572754fe60SDimitry Andric if (!freeUnits) { 1587ae0e2c9SDimitry Andric DEBUG(dbgs() << "*** Hazard in cycle +" << StageCycle << ", "); 1592754fe60SDimitry Andric DEBUG(dbgs() << "SU(" << SU->NodeNum << "): "); 1602754fe60SDimitry Andric DEBUG(DAG->dumpNode(SU)); 1612754fe60SDimitry Andric return Hazard; 1622754fe60SDimitry Andric } 1632754fe60SDimitry Andric } 1642754fe60SDimitry Andric 1652754fe60SDimitry Andric // Advance the cycle to the next stage. 1662754fe60SDimitry Andric cycle += IS->getNextCycles(); 1672754fe60SDimitry Andric } 1682754fe60SDimitry Andric 1692754fe60SDimitry Andric return NoHazard; 1702754fe60SDimitry Andric } 1712754fe60SDimitry Andric 1722754fe60SDimitry Andric void ScoreboardHazardRecognizer::EmitInstruction(SUnit *SU) { 1732754fe60SDimitry Andric if (!ItinData || ItinData->isEmpty()) 1742754fe60SDimitry Andric return; 1752754fe60SDimitry Andric 1762754fe60SDimitry Andric // Use the itinerary for the underlying instruction to reserve FU's 1772754fe60SDimitry Andric // in the scoreboard at the appropriate future cycles. 17817a519f9SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU); 17917a519f9SDimitry Andric assert(MCID && "The scheduler must filter non-machineinstrs"); 18017a519f9SDimitry Andric if (DAG->TII->isZeroCost(MCID->Opcode)) 1812754fe60SDimitry Andric return; 1822754fe60SDimitry Andric 1832754fe60SDimitry Andric ++IssueCount; 1842754fe60SDimitry Andric 1852754fe60SDimitry Andric unsigned cycle = 0; 1862754fe60SDimitry Andric 18717a519f9SDimitry Andric unsigned idx = MCID->getSchedClass(); 1882754fe60SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx), 1892754fe60SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) { 1902754fe60SDimitry Andric // We must reserve one of the stage's units for every cycle the 1912754fe60SDimitry Andric // stage is occupied. FIXME it would be more accurate to reserve 1922754fe60SDimitry Andric // the same unit free in all the cycles. 1932754fe60SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) { 1942754fe60SDimitry Andric assert(((cycle + i) < RequiredScoreboard.getDepth()) && 1952754fe60SDimitry Andric "Scoreboard depth exceeded!"); 1962754fe60SDimitry Andric 1972754fe60SDimitry Andric unsigned freeUnits = IS->getUnits(); 1982754fe60SDimitry Andric switch (IS->getReservationKind()) { 1992754fe60SDimitry Andric case InstrStage::Required: 2002754fe60SDimitry Andric // Required FUs conflict with both reserved and required ones 2012754fe60SDimitry Andric freeUnits &= ~ReservedScoreboard[cycle + i]; 202d88c1a5aSDimitry Andric LLVM_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 if (IS->getReservationKind() == InstrStage::Required) 2172754fe60SDimitry Andric RequiredScoreboard[cycle + i] |= freeUnit; 2182754fe60SDimitry Andric else 2192754fe60SDimitry Andric ReservedScoreboard[cycle + i] |= freeUnit; 2202754fe60SDimitry Andric } 2212754fe60SDimitry Andric 2222754fe60SDimitry Andric // Advance the cycle to the next stage. 2232754fe60SDimitry Andric cycle += IS->getNextCycles(); 2242754fe60SDimitry Andric } 2252754fe60SDimitry Andric 2262754fe60SDimitry Andric DEBUG(ReservedScoreboard.dump()); 2272754fe60SDimitry Andric DEBUG(RequiredScoreboard.dump()); 2282754fe60SDimitry Andric } 2292754fe60SDimitry Andric 2302754fe60SDimitry Andric void ScoreboardHazardRecognizer::AdvanceCycle() { 2312754fe60SDimitry Andric IssueCount = 0; 2322754fe60SDimitry Andric ReservedScoreboard[0] = 0; ReservedScoreboard.advance(); 2332754fe60SDimitry Andric RequiredScoreboard[0] = 0; RequiredScoreboard.advance(); 2342754fe60SDimitry Andric } 2352754fe60SDimitry Andric 2362754fe60SDimitry Andric void ScoreboardHazardRecognizer::RecedeCycle() { 2372754fe60SDimitry Andric IssueCount = 0; 2382754fe60SDimitry Andric ReservedScoreboard[ReservedScoreboard.getDepth()-1] = 0; 2392754fe60SDimitry Andric ReservedScoreboard.recede(); 2402754fe60SDimitry Andric RequiredScoreboard[RequiredScoreboard.getDepth()-1] = 0; 2412754fe60SDimitry Andric RequiredScoreboard.recede(); 2422754fe60SDimitry Andric } 243