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"
194ba319b5SDimitry Andric #include "llvm/Config/llvm-config.h"
207a7e6055SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
2117a519f9SDimitry Andric #include "llvm/MC/MCInstrItineraries.h"
227a7e6055SDimitry Andric #include "llvm/Support/Compiler.h"
232754fe60SDimitry Andric #include "llvm/Support/Debug.h"
242754fe60SDimitry Andric #include "llvm/Support/raw_ostream.h"
257a7e6055SDimitry Andric #include <cassert>
262754fe60SDimitry Andric
272754fe60SDimitry Andric using namespace llvm;
282754fe60SDimitry Andric
293ca95b02SDimitry Andric #define DEBUG_TYPE DebugType
3091bc56edSDimitry Andric
ScoreboardHazardRecognizer(const InstrItineraryData * II,const ScheduleDAG * SchedDAG,const char * ParentDebugType)313ca95b02SDimitry Andric ScoreboardHazardRecognizer::ScoreboardHazardRecognizer(
323ca95b02SDimitry Andric const InstrItineraryData *II, const ScheduleDAG *SchedDAG,
333ca95b02SDimitry Andric const char *ParentDebugType)
343ca95b02SDimitry Andric : ScheduleHazardRecognizer(), DebugType(ParentDebugType), ItinData(II),
357a7e6055SDimitry Andric DAG(SchedDAG) {
362cab237bSDimitry Andric (void)DebugType;
377ae0e2c9SDimitry Andric // Determine the maximum depth of any itinerary. This determines the depth of
387ae0e2c9SDimitry Andric // the scoreboard. We always make the scoreboard at least 1 cycle deep to
397ae0e2c9SDimitry Andric // avoid dealing with the boundary condition.
402754fe60SDimitry Andric unsigned ScoreboardDepth = 1;
412754fe60SDimitry Andric if (ItinData && !ItinData->isEmpty()) {
422754fe60SDimitry Andric for (unsigned idx = 0; ; ++idx) {
432754fe60SDimitry Andric if (ItinData->isEndMarker(idx))
442754fe60SDimitry Andric break;
452754fe60SDimitry Andric
462754fe60SDimitry Andric const InstrStage *IS = ItinData->beginStage(idx);
472754fe60SDimitry Andric const InstrStage *E = ItinData->endStage(idx);
482754fe60SDimitry Andric unsigned CurCycle = 0;
492754fe60SDimitry Andric unsigned ItinDepth = 0;
502754fe60SDimitry Andric for (; IS != E; ++IS) {
512754fe60SDimitry Andric unsigned StageDepth = CurCycle + IS->getCycles();
522754fe60SDimitry Andric if (ItinDepth < StageDepth) ItinDepth = StageDepth;
532754fe60SDimitry Andric CurCycle += IS->getNextCycles();
542754fe60SDimitry Andric }
552754fe60SDimitry Andric
562754fe60SDimitry Andric // Find the next power-of-2 >= ItinDepth
572754fe60SDimitry Andric while (ItinDepth > ScoreboardDepth) {
582754fe60SDimitry Andric ScoreboardDepth *= 2;
597ae0e2c9SDimitry Andric // Don't set MaxLookAhead until we find at least one nonzero stage.
607ae0e2c9SDimitry Andric // This way, an itinerary with no stages has MaxLookAhead==0, which
617ae0e2c9SDimitry Andric // completely bypasses the scoreboard hazard logic.
622754fe60SDimitry Andric MaxLookAhead = ScoreboardDepth;
632754fe60SDimitry Andric }
647ae0e2c9SDimitry Andric }
657ae0e2c9SDimitry Andric }
662754fe60SDimitry Andric
672754fe60SDimitry Andric ReservedScoreboard.reset(ScoreboardDepth);
682754fe60SDimitry Andric RequiredScoreboard.reset(ScoreboardDepth);
692754fe60SDimitry Andric
707ae0e2c9SDimitry Andric // If MaxLookAhead is not set above, then we are not enabled.
717ae0e2c9SDimitry Andric if (!isEnabled())
724ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << "Disabled scoreboard hazard recognizer\n");
737ae0e2c9SDimitry Andric else {
747ae0e2c9SDimitry Andric // A nonempty itinerary must have a SchedModel.
7539d628a0SDimitry Andric IssueWidth = ItinData->SchedModel.IssueWidth;
764ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << "Using scoreboard hazard recognizer: Depth = "
772754fe60SDimitry Andric << ScoreboardDepth << '\n');
782754fe60SDimitry Andric }
797ae0e2c9SDimitry Andric }
802754fe60SDimitry Andric
Reset()812754fe60SDimitry Andric void ScoreboardHazardRecognizer::Reset() {
822754fe60SDimitry Andric IssueCount = 0;
832754fe60SDimitry Andric RequiredScoreboard.reset();
842754fe60SDimitry Andric ReservedScoreboard.reset();
852754fe60SDimitry Andric }
862754fe60SDimitry Andric
873861d79fSDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const883ca95b02SDimitry Andric LLVM_DUMP_METHOD void ScoreboardHazardRecognizer::Scoreboard::dump() const {
892754fe60SDimitry Andric dbgs() << "Scoreboard:\n";
902754fe60SDimitry Andric
912754fe60SDimitry Andric unsigned last = Depth - 1;
922754fe60SDimitry Andric while ((last > 0) && ((*this)[last] == 0))
932754fe60SDimitry Andric last--;
942754fe60SDimitry Andric
952754fe60SDimitry Andric for (unsigned i = 0; i <= last; i++) {
962754fe60SDimitry Andric unsigned FUs = (*this)[i];
972754fe60SDimitry Andric dbgs() << "\t";
982754fe60SDimitry Andric for (int j = 31; j >= 0; j--)
992754fe60SDimitry Andric dbgs() << ((FUs & (1 << j)) ? '1' : '0');
1002754fe60SDimitry Andric dbgs() << '\n';
1012754fe60SDimitry Andric }
1022754fe60SDimitry Andric }
1033861d79fSDimitry Andric #endif
1042754fe60SDimitry Andric
atIssueLimit() const1052754fe60SDimitry Andric bool ScoreboardHazardRecognizer::atIssueLimit() const {
1062754fe60SDimitry Andric if (IssueWidth == 0)
1072754fe60SDimitry Andric return false;
1082754fe60SDimitry Andric
1092754fe60SDimitry Andric return IssueCount == IssueWidth;
1102754fe60SDimitry Andric }
1112754fe60SDimitry Andric
1122754fe60SDimitry Andric ScheduleHazardRecognizer::HazardType
getHazardType(SUnit * SU,int Stalls)1132754fe60SDimitry Andric ScoreboardHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
1142754fe60SDimitry Andric if (!ItinData || ItinData->isEmpty())
1152754fe60SDimitry Andric return NoHazard;
1162754fe60SDimitry Andric
1172754fe60SDimitry Andric // Note that stalls will be negative for bottom-up scheduling.
1182754fe60SDimitry Andric int cycle = Stalls;
1192754fe60SDimitry Andric
1202754fe60SDimitry Andric // Use the itinerary for the underlying instruction to check for
1212754fe60SDimitry Andric // free FU's in the scoreboard at the appropriate future cycles.
1222754fe60SDimitry Andric
12317a519f9SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
12491bc56edSDimitry Andric if (!MCID) {
1252754fe60SDimitry Andric // Don't check hazards for non-machineinstr Nodes.
1262754fe60SDimitry Andric return NoHazard;
1272754fe60SDimitry Andric }
12817a519f9SDimitry Andric unsigned idx = MCID->getSchedClass();
1292754fe60SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx),
1302754fe60SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) {
1312754fe60SDimitry Andric // We must find one of the stage's units free for every cycle the
1322754fe60SDimitry Andric // stage is occupied. FIXME it would be more accurate to find the
1332754fe60SDimitry Andric // same unit free in all the cycles.
1342754fe60SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) {
1352754fe60SDimitry Andric int StageCycle = cycle + (int)i;
1362754fe60SDimitry Andric if (StageCycle < 0)
1372754fe60SDimitry Andric continue;
1382754fe60SDimitry Andric
1392754fe60SDimitry Andric if (StageCycle >= (int)RequiredScoreboard.getDepth()) {
1402754fe60SDimitry Andric assert((StageCycle - Stalls) < (int)RequiredScoreboard.getDepth() &&
1412754fe60SDimitry Andric "Scoreboard depth exceeded!");
1422754fe60SDimitry Andric // This stage was stalled beyond pipeline depth, so cannot conflict.
1432754fe60SDimitry Andric break;
1442754fe60SDimitry Andric }
1452754fe60SDimitry Andric
1462754fe60SDimitry Andric unsigned freeUnits = IS->getUnits();
1472754fe60SDimitry Andric switch (IS->getReservationKind()) {
1482754fe60SDimitry Andric case InstrStage::Required:
1492754fe60SDimitry Andric // Required FUs conflict with both reserved and required ones
1502754fe60SDimitry Andric freeUnits &= ~ReservedScoreboard[StageCycle];
151d88c1a5aSDimitry Andric LLVM_FALLTHROUGH;
1522754fe60SDimitry Andric case InstrStage::Reserved:
1532754fe60SDimitry Andric // Reserved FUs can conflict only with required ones.
1542754fe60SDimitry Andric freeUnits &= ~RequiredScoreboard[StageCycle];
1552754fe60SDimitry Andric break;
1562754fe60SDimitry Andric }
1572754fe60SDimitry Andric
1582754fe60SDimitry Andric if (!freeUnits) {
1594ba319b5SDimitry Andric LLVM_DEBUG(dbgs() << "*** Hazard in cycle +" << StageCycle << ", ");
160*b5893f02SDimitry Andric LLVM_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
EmitInstruction(SUnit * SU)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
2264ba319b5SDimitry Andric LLVM_DEBUG(ReservedScoreboard.dump());
2274ba319b5SDimitry Andric LLVM_DEBUG(RequiredScoreboard.dump());
2282754fe60SDimitry Andric }
2292754fe60SDimitry Andric
AdvanceCycle()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
RecedeCycle()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