10b57cec5SDimitry Andric //===- ScoreboardHazardRecognizer.cpp - Scheduler Support -----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the ScoreboardHazardRecognizer class, which
100b57cec5SDimitry Andric // encapsultes hazard-avoidance heuristics for scheduling, based on the
110b57cec5SDimitry Andric // scheduling itineraries specified for the target.
120b57cec5SDimitry Andric //
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric
150b57cec5SDimitry Andric #include "llvm/CodeGen/ScoreboardHazardRecognizer.h"
160b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleDAG.h"
170b57cec5SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h"
180b57cec5SDimitry Andric #include "llvm/Config/llvm-config.h"
190b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h"
200b57cec5SDimitry Andric #include "llvm/MC/MCInstrItineraries.h"
210b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
220b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
230b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
240b57cec5SDimitry Andric #include <cassert>
250b57cec5SDimitry Andric
260b57cec5SDimitry Andric using namespace llvm;
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric #define DEBUG_TYPE DebugType
290b57cec5SDimitry Andric
ScoreboardHazardRecognizer(const InstrItineraryData * II,const ScheduleDAG * SchedDAG,const char * ParentDebugType)300b57cec5SDimitry Andric ScoreboardHazardRecognizer::ScoreboardHazardRecognizer(
310b57cec5SDimitry Andric const InstrItineraryData *II, const ScheduleDAG *SchedDAG,
320b57cec5SDimitry Andric const char *ParentDebugType)
3304eeddc0SDimitry Andric : DebugType(ParentDebugType), ItinData(II), DAG(SchedDAG) {
340b57cec5SDimitry Andric (void)DebugType;
350b57cec5SDimitry Andric // Determine the maximum depth of any itinerary. This determines the depth of
360b57cec5SDimitry Andric // the scoreboard. We always make the scoreboard at least 1 cycle deep to
370b57cec5SDimitry Andric // avoid dealing with the boundary condition.
380b57cec5SDimitry Andric unsigned ScoreboardDepth = 1;
390b57cec5SDimitry Andric if (ItinData && !ItinData->isEmpty()) {
400b57cec5SDimitry Andric for (unsigned idx = 0; ; ++idx) {
410b57cec5SDimitry Andric if (ItinData->isEndMarker(idx))
420b57cec5SDimitry Andric break;
430b57cec5SDimitry Andric
440b57cec5SDimitry Andric const InstrStage *IS = ItinData->beginStage(idx);
450b57cec5SDimitry Andric const InstrStage *E = ItinData->endStage(idx);
460b57cec5SDimitry Andric unsigned CurCycle = 0;
470b57cec5SDimitry Andric unsigned ItinDepth = 0;
480b57cec5SDimitry Andric for (; IS != E; ++IS) {
490b57cec5SDimitry Andric unsigned StageDepth = CurCycle + IS->getCycles();
500b57cec5SDimitry Andric if (ItinDepth < StageDepth) ItinDepth = StageDepth;
510b57cec5SDimitry Andric CurCycle += IS->getNextCycles();
520b57cec5SDimitry Andric }
530b57cec5SDimitry Andric
540b57cec5SDimitry Andric // Find the next power-of-2 >= ItinDepth
550b57cec5SDimitry Andric while (ItinDepth > ScoreboardDepth) {
560b57cec5SDimitry Andric ScoreboardDepth *= 2;
570b57cec5SDimitry Andric // Don't set MaxLookAhead until we find at least one nonzero stage.
580b57cec5SDimitry Andric // This way, an itinerary with no stages has MaxLookAhead==0, which
590b57cec5SDimitry Andric // completely bypasses the scoreboard hazard logic.
600b57cec5SDimitry Andric MaxLookAhead = ScoreboardDepth;
610b57cec5SDimitry Andric }
620b57cec5SDimitry Andric }
630b57cec5SDimitry Andric }
640b57cec5SDimitry Andric
650b57cec5SDimitry Andric ReservedScoreboard.reset(ScoreboardDepth);
660b57cec5SDimitry Andric RequiredScoreboard.reset(ScoreboardDepth);
670b57cec5SDimitry Andric
680b57cec5SDimitry Andric // If MaxLookAhead is not set above, then we are not enabled.
690b57cec5SDimitry Andric if (!isEnabled())
700b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Disabled scoreboard hazard recognizer\n");
710b57cec5SDimitry Andric else {
720b57cec5SDimitry Andric // A nonempty itinerary must have a SchedModel.
730b57cec5SDimitry Andric IssueWidth = ItinData->SchedModel.IssueWidth;
740b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "Using scoreboard hazard recognizer: Depth = "
750b57cec5SDimitry Andric << ScoreboardDepth << '\n');
760b57cec5SDimitry Andric }
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric
Reset()790b57cec5SDimitry Andric void ScoreboardHazardRecognizer::Reset() {
800b57cec5SDimitry Andric IssueCount = 0;
810b57cec5SDimitry Andric RequiredScoreboard.reset();
820b57cec5SDimitry Andric ReservedScoreboard.reset();
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric
850b57cec5SDimitry Andric #if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
dump() const860b57cec5SDimitry Andric LLVM_DUMP_METHOD void ScoreboardHazardRecognizer::Scoreboard::dump() const {
870b57cec5SDimitry Andric dbgs() << "Scoreboard:\n";
880b57cec5SDimitry Andric
890b57cec5SDimitry Andric unsigned last = Depth - 1;
900b57cec5SDimitry Andric while ((last > 0) && ((*this)[last] == 0))
910b57cec5SDimitry Andric last--;
920b57cec5SDimitry Andric
930b57cec5SDimitry Andric for (unsigned i = 0; i <= last; i++) {
945ffd83dbSDimitry Andric InstrStage::FuncUnits FUs = (*this)[i];
950b57cec5SDimitry Andric dbgs() << "\t";
965ffd83dbSDimitry Andric for (int j = std::numeric_limits<InstrStage::FuncUnits>::digits - 1;
975ffd83dbSDimitry Andric j >= 0; j--)
985ffd83dbSDimitry Andric dbgs() << ((FUs & (1ULL << j)) ? '1' : '0');
990b57cec5SDimitry Andric dbgs() << '\n';
1000b57cec5SDimitry Andric }
1010b57cec5SDimitry Andric }
1020b57cec5SDimitry Andric #endif
1030b57cec5SDimitry Andric
atIssueLimit() const1040b57cec5SDimitry Andric bool ScoreboardHazardRecognizer::atIssueLimit() const {
1050b57cec5SDimitry Andric if (IssueWidth == 0)
1060b57cec5SDimitry Andric return false;
1070b57cec5SDimitry Andric
1080b57cec5SDimitry Andric return IssueCount == IssueWidth;
1090b57cec5SDimitry Andric }
1100b57cec5SDimitry Andric
1110b57cec5SDimitry Andric ScheduleHazardRecognizer::HazardType
getHazardType(SUnit * SU,int Stalls)1120b57cec5SDimitry Andric ScoreboardHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
1130b57cec5SDimitry Andric if (!ItinData || ItinData->isEmpty())
1140b57cec5SDimitry Andric return NoHazard;
1150b57cec5SDimitry Andric
1160b57cec5SDimitry Andric // Note that stalls will be negative for bottom-up scheduling.
1170b57cec5SDimitry Andric int cycle = Stalls;
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric // Use the itinerary for the underlying instruction to check for
1200b57cec5SDimitry Andric // free FU's in the scoreboard at the appropriate future cycles.
1210b57cec5SDimitry Andric
1220b57cec5SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
1230b57cec5SDimitry Andric if (!MCID) {
1240b57cec5SDimitry Andric // Don't check hazards for non-machineinstr Nodes.
1250b57cec5SDimitry Andric return NoHazard;
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric unsigned idx = MCID->getSchedClass();
1280b57cec5SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx),
1290b57cec5SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) {
1300b57cec5SDimitry Andric // We must find one of the stage's units free for every cycle the
1310b57cec5SDimitry Andric // stage is occupied. FIXME it would be more accurate to find the
1320b57cec5SDimitry Andric // same unit free in all the cycles.
1330b57cec5SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) {
1340b57cec5SDimitry Andric int StageCycle = cycle + (int)i;
1350b57cec5SDimitry Andric if (StageCycle < 0)
1360b57cec5SDimitry Andric continue;
1370b57cec5SDimitry Andric
1380b57cec5SDimitry Andric if (StageCycle >= (int)RequiredScoreboard.getDepth()) {
1390b57cec5SDimitry Andric assert((StageCycle - Stalls) < (int)RequiredScoreboard.getDepth() &&
1400b57cec5SDimitry Andric "Scoreboard depth exceeded!");
1410b57cec5SDimitry Andric // This stage was stalled beyond pipeline depth, so cannot conflict.
1420b57cec5SDimitry Andric break;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric
1455ffd83dbSDimitry Andric InstrStage::FuncUnits freeUnits = IS->getUnits();
1460b57cec5SDimitry Andric switch (IS->getReservationKind()) {
1470b57cec5SDimitry Andric case InstrStage::Required:
1480b57cec5SDimitry Andric // Required FUs conflict with both reserved and required ones
1490b57cec5SDimitry Andric freeUnits &= ~ReservedScoreboard[StageCycle];
150*bdd1243dSDimitry Andric [[fallthrough]];
1510b57cec5SDimitry Andric case InstrStage::Reserved:
1520b57cec5SDimitry Andric // Reserved FUs can conflict only with required ones.
1530b57cec5SDimitry Andric freeUnits &= ~RequiredScoreboard[StageCycle];
1540b57cec5SDimitry Andric break;
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric
1570b57cec5SDimitry Andric if (!freeUnits) {
1580b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "*** Hazard in cycle +" << StageCycle << ", ");
1590b57cec5SDimitry Andric LLVM_DEBUG(DAG->dumpNode(*SU));
1600b57cec5SDimitry Andric return Hazard;
1610b57cec5SDimitry Andric }
1620b57cec5SDimitry Andric }
1630b57cec5SDimitry Andric
1640b57cec5SDimitry Andric // Advance the cycle to the next stage.
1650b57cec5SDimitry Andric cycle += IS->getNextCycles();
1660b57cec5SDimitry Andric }
1670b57cec5SDimitry Andric
1680b57cec5SDimitry Andric return NoHazard;
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric
EmitInstruction(SUnit * SU)1710b57cec5SDimitry Andric void ScoreboardHazardRecognizer::EmitInstruction(SUnit *SU) {
1720b57cec5SDimitry Andric if (!ItinData || ItinData->isEmpty())
1730b57cec5SDimitry Andric return;
1740b57cec5SDimitry Andric
1750b57cec5SDimitry Andric // Use the itinerary for the underlying instruction to reserve FU's
1760b57cec5SDimitry Andric // in the scoreboard at the appropriate future cycles.
1770b57cec5SDimitry Andric const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
1780b57cec5SDimitry Andric assert(MCID && "The scheduler must filter non-machineinstrs");
1790b57cec5SDimitry Andric if (DAG->TII->isZeroCost(MCID->Opcode))
1800b57cec5SDimitry Andric return;
1810b57cec5SDimitry Andric
1820b57cec5SDimitry Andric ++IssueCount;
1830b57cec5SDimitry Andric
1840b57cec5SDimitry Andric unsigned cycle = 0;
1850b57cec5SDimitry Andric
1860b57cec5SDimitry Andric unsigned idx = MCID->getSchedClass();
1870b57cec5SDimitry Andric for (const InstrStage *IS = ItinData->beginStage(idx),
1880b57cec5SDimitry Andric *E = ItinData->endStage(idx); IS != E; ++IS) {
1890b57cec5SDimitry Andric // We must reserve one of the stage's units for every cycle the
1900b57cec5SDimitry Andric // stage is occupied. FIXME it would be more accurate to reserve
1910b57cec5SDimitry Andric // the same unit free in all the cycles.
1920b57cec5SDimitry Andric for (unsigned int i = 0; i < IS->getCycles(); ++i) {
1930b57cec5SDimitry Andric assert(((cycle + i) < RequiredScoreboard.getDepth()) &&
1940b57cec5SDimitry Andric "Scoreboard depth exceeded!");
1950b57cec5SDimitry Andric
1965ffd83dbSDimitry Andric InstrStage::FuncUnits freeUnits = IS->getUnits();
1970b57cec5SDimitry Andric switch (IS->getReservationKind()) {
1980b57cec5SDimitry Andric case InstrStage::Required:
1990b57cec5SDimitry Andric // Required FUs conflict with both reserved and required ones
2000b57cec5SDimitry Andric freeUnits &= ~ReservedScoreboard[cycle + i];
201*bdd1243dSDimitry Andric [[fallthrough]];
2020b57cec5SDimitry Andric case InstrStage::Reserved:
2030b57cec5SDimitry Andric // Reserved FUs can conflict only with required ones.
2040b57cec5SDimitry Andric freeUnits &= ~RequiredScoreboard[cycle + i];
2050b57cec5SDimitry Andric break;
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric
2080b57cec5SDimitry Andric // reduce to a single unit
2095ffd83dbSDimitry Andric InstrStage::FuncUnits freeUnit = 0;
2100b57cec5SDimitry Andric do {
2110b57cec5SDimitry Andric freeUnit = freeUnits;
2120b57cec5SDimitry Andric freeUnits = freeUnit & (freeUnit - 1);
2130b57cec5SDimitry Andric } while (freeUnits);
2140b57cec5SDimitry Andric
2150b57cec5SDimitry Andric if (IS->getReservationKind() == InstrStage::Required)
2160b57cec5SDimitry Andric RequiredScoreboard[cycle + i] |= freeUnit;
2170b57cec5SDimitry Andric else
2180b57cec5SDimitry Andric ReservedScoreboard[cycle + i] |= freeUnit;
2190b57cec5SDimitry Andric }
2200b57cec5SDimitry Andric
2210b57cec5SDimitry Andric // Advance the cycle to the next stage.
2220b57cec5SDimitry Andric cycle += IS->getNextCycles();
2230b57cec5SDimitry Andric }
2240b57cec5SDimitry Andric
2250b57cec5SDimitry Andric LLVM_DEBUG(ReservedScoreboard.dump());
2260b57cec5SDimitry Andric LLVM_DEBUG(RequiredScoreboard.dump());
2270b57cec5SDimitry Andric }
2280b57cec5SDimitry Andric
AdvanceCycle()2290b57cec5SDimitry Andric void ScoreboardHazardRecognizer::AdvanceCycle() {
2300b57cec5SDimitry Andric IssueCount = 0;
2310b57cec5SDimitry Andric ReservedScoreboard[0] = 0; ReservedScoreboard.advance();
2320b57cec5SDimitry Andric RequiredScoreboard[0] = 0; RequiredScoreboard.advance();
2330b57cec5SDimitry Andric }
2340b57cec5SDimitry Andric
RecedeCycle()2350b57cec5SDimitry Andric void ScoreboardHazardRecognizer::RecedeCycle() {
2360b57cec5SDimitry Andric IssueCount = 0;
2370b57cec5SDimitry Andric ReservedScoreboard[ReservedScoreboard.getDepth()-1] = 0;
2380b57cec5SDimitry Andric ReservedScoreboard.recede();
2390b57cec5SDimitry Andric RequiredScoreboard[RequiredScoreboard.getDepth()-1] = 0;
2400b57cec5SDimitry Andric RequiredScoreboard.recede();
2410b57cec5SDimitry Andric }
242