1//===----- ScoreboardHazardRecognizer.cpp - Scheduler Support -------------===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file implements the ScoreboardHazardRecognizer class, which
11// encapsultes hazard-avoidance heuristics for scheduling, based on the
12// scheduling itineraries specified for the target.
13//
14//===----------------------------------------------------------------------===//
15
16#define DEBUG_TYPE ::llvm::ScoreboardHazardRecognizer::DebugType
17#include "llvm/CodeGen/ScoreboardHazardRecognizer.h"
18#include "llvm/CodeGen/ScheduleDAG.h"
19#include "llvm/MC/MCInstrItineraries.h"
20#include "llvm/Support/Debug.h"
21#include "llvm/Support/ErrorHandling.h"
22#include "llvm/Support/raw_ostream.h"
23#include "llvm/Target/TargetInstrInfo.h"
24
25using namespace llvm;
26
27#ifndef NDEBUG
28const char *ScoreboardHazardRecognizer::DebugType = "";
29#endif
30
31ScoreboardHazardRecognizer::
32ScoreboardHazardRecognizer(const InstrItineraryData *II,
33                           const ScheduleDAG *SchedDAG,
34                           const char *ParentDebugType) :
35  ScheduleHazardRecognizer(), ItinData(II), DAG(SchedDAG), IssueWidth(0),
36  IssueCount(0) {
37
38#ifndef NDEBUG
39  DebugType = ParentDebugType;
40#endif
41
42  // Determine the maximum depth of any itinerary. This determines the depth of
43  // the scoreboard. We always make the scoreboard at least 1 cycle deep to
44  // avoid dealing with the boundary condition.
45  unsigned ScoreboardDepth = 1;
46  if (ItinData && !ItinData->isEmpty()) {
47    for (unsigned idx = 0; ; ++idx) {
48      if (ItinData->isEndMarker(idx))
49        break;
50
51      const InstrStage *IS = ItinData->beginStage(idx);
52      const InstrStage *E = ItinData->endStage(idx);
53      unsigned CurCycle = 0;
54      unsigned ItinDepth = 0;
55      for (; IS != E; ++IS) {
56        unsigned StageDepth = CurCycle + IS->getCycles();
57        if (ItinDepth < StageDepth) ItinDepth = StageDepth;
58        CurCycle += IS->getNextCycles();
59      }
60
61      // Find the next power-of-2 >= ItinDepth
62      while (ItinDepth > ScoreboardDepth) {
63        ScoreboardDepth *= 2;
64        // Don't set MaxLookAhead until we find at least one nonzero stage.
65        // This way, an itinerary with no stages has MaxLookAhead==0, which
66        // completely bypasses the scoreboard hazard logic.
67        MaxLookAhead = ScoreboardDepth;
68      }
69    }
70  }
71
72  ReservedScoreboard.reset(ScoreboardDepth);
73  RequiredScoreboard.reset(ScoreboardDepth);
74
75  // If MaxLookAhead is not set above, then we are not enabled.
76  if (!isEnabled())
77    DEBUG(dbgs() << "Disabled scoreboard hazard recognizer\n");
78  else {
79    // A nonempty itinerary must have a SchedModel.
80    IssueWidth = ItinData->SchedModel->IssueWidth;
81    DEBUG(dbgs() << "Using scoreboard hazard recognizer: Depth = "
82          << ScoreboardDepth << '\n');
83  }
84}
85
86void ScoreboardHazardRecognizer::Reset() {
87  IssueCount = 0;
88  RequiredScoreboard.reset();
89  ReservedScoreboard.reset();
90}
91
92#ifndef NDEBUG
93void ScoreboardHazardRecognizer::Scoreboard::dump() const {
94  dbgs() << "Scoreboard:\n";
95
96  unsigned last = Depth - 1;
97  while ((last > 0) && ((*this)[last] == 0))
98    last--;
99
100  for (unsigned i = 0; i <= last; i++) {
101    unsigned FUs = (*this)[i];
102    dbgs() << "\t";
103    for (int j = 31; j >= 0; j--)
104      dbgs() << ((FUs & (1 << j)) ? '1' : '0');
105    dbgs() << '\n';
106  }
107}
108#endif
109
110bool ScoreboardHazardRecognizer::atIssueLimit() const {
111  if (IssueWidth == 0)
112    return false;
113
114  return IssueCount == IssueWidth;
115}
116
117ScheduleHazardRecognizer::HazardType
118ScoreboardHazardRecognizer::getHazardType(SUnit *SU, int Stalls) {
119  if (!ItinData || ItinData->isEmpty())
120    return NoHazard;
121
122  // Note that stalls will be negative for bottom-up scheduling.
123  int cycle = Stalls;
124
125  // Use the itinerary for the underlying instruction to check for
126  // free FU's in the scoreboard at the appropriate future cycles.
127
128  const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
129  if (MCID == NULL) {
130    // Don't check hazards for non-machineinstr Nodes.
131    return NoHazard;
132  }
133  unsigned idx = MCID->getSchedClass();
134  for (const InstrStage *IS = ItinData->beginStage(idx),
135         *E = ItinData->endStage(idx); IS != E; ++IS) {
136    // We must find one of the stage's units free for every cycle the
137    // stage is occupied. FIXME it would be more accurate to find the
138    // same unit free in all the cycles.
139    for (unsigned int i = 0; i < IS->getCycles(); ++i) {
140      int StageCycle = cycle + (int)i;
141      if (StageCycle < 0)
142        continue;
143
144      if (StageCycle >= (int)RequiredScoreboard.getDepth()) {
145        assert((StageCycle - Stalls) < (int)RequiredScoreboard.getDepth() &&
146               "Scoreboard depth exceeded!");
147        // This stage was stalled beyond pipeline depth, so cannot conflict.
148        break;
149      }
150
151      unsigned freeUnits = IS->getUnits();
152      switch (IS->getReservationKind()) {
153      case InstrStage::Required:
154        // Required FUs conflict with both reserved and required ones
155        freeUnits &= ~ReservedScoreboard[StageCycle];
156        // FALLTHROUGH
157      case InstrStage::Reserved:
158        // Reserved FUs can conflict only with required ones.
159        freeUnits &= ~RequiredScoreboard[StageCycle];
160        break;
161      }
162
163      if (!freeUnits) {
164        DEBUG(dbgs() << "*** Hazard in cycle +" << StageCycle << ", ");
165        DEBUG(dbgs() << "SU(" << SU->NodeNum << "): ");
166        DEBUG(DAG->dumpNode(SU));
167        return Hazard;
168      }
169    }
170
171    // Advance the cycle to the next stage.
172    cycle += IS->getNextCycles();
173  }
174
175  return NoHazard;
176}
177
178void ScoreboardHazardRecognizer::EmitInstruction(SUnit *SU) {
179  if (!ItinData || ItinData->isEmpty())
180    return;
181
182  // Use the itinerary for the underlying instruction to reserve FU's
183  // in the scoreboard at the appropriate future cycles.
184  const MCInstrDesc *MCID = DAG->getInstrDesc(SU);
185  assert(MCID && "The scheduler must filter non-machineinstrs");
186  if (DAG->TII->isZeroCost(MCID->Opcode))
187    return;
188
189  ++IssueCount;
190
191  unsigned cycle = 0;
192
193  unsigned idx = MCID->getSchedClass();
194  for (const InstrStage *IS = ItinData->beginStage(idx),
195         *E = ItinData->endStage(idx); IS != E; ++IS) {
196    // We must reserve one of the stage's units for every cycle the
197    // stage is occupied. FIXME it would be more accurate to reserve
198    // the same unit free in all the cycles.
199    for (unsigned int i = 0; i < IS->getCycles(); ++i) {
200      assert(((cycle + i) < RequiredScoreboard.getDepth()) &&
201             "Scoreboard depth exceeded!");
202
203      unsigned freeUnits = IS->getUnits();
204      switch (IS->getReservationKind()) {
205      case InstrStage::Required:
206        // Required FUs conflict with both reserved and required ones
207        freeUnits &= ~ReservedScoreboard[cycle + i];
208        // FALLTHROUGH
209      case InstrStage::Reserved:
210        // Reserved FUs can conflict only with required ones.
211        freeUnits &= ~RequiredScoreboard[cycle + i];
212        break;
213      }
214
215      // reduce to a single unit
216      unsigned freeUnit = 0;
217      do {
218        freeUnit = freeUnits;
219        freeUnits = freeUnit & (freeUnit - 1);
220      } while (freeUnits);
221
222      if (IS->getReservationKind() == InstrStage::Required)
223        RequiredScoreboard[cycle + i] |= freeUnit;
224      else
225        ReservedScoreboard[cycle + i] |= freeUnit;
226    }
227
228    // Advance the cycle to the next stage.
229    cycle += IS->getNextCycles();
230  }
231
232  DEBUG(ReservedScoreboard.dump());
233  DEBUG(RequiredScoreboard.dump());
234}
235
236void ScoreboardHazardRecognizer::AdvanceCycle() {
237  IssueCount = 0;
238  ReservedScoreboard[0] = 0; ReservedScoreboard.advance();
239  RequiredScoreboard[0] = 0; RequiredScoreboard.advance();
240}
241
242void ScoreboardHazardRecognizer::RecedeCycle() {
243  IssueCount = 0;
244  ReservedScoreboard[ReservedScoreboard.getDepth()-1] = 0;
245  ReservedScoreboard.recede();
246  RequiredScoreboard[RequiredScoreboard.getDepth()-1] = 0;
247  RequiredScoreboard.recede();
248}
249