ScoreboardHazardRecognizer.cpp 8.0 KB

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