ScoreboardHazardRecognizer.cpp 7.9 KB

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