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