VLIWMachineScheduler.h 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- VLIWMachineScheduler.h - VLIW-Focused Scheduling Pass ----*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. // //
  14. //===----------------------------------------------------------------------===//
  15. #ifndef LLVM_CODEGEN_VLIWMACHINESCHEDULER_H
  16. #define LLVM_CODEGEN_VLIWMACHINESCHEDULER_H
  17. #include "llvm/ADT/SmallVector.h"
  18. #include "llvm/ADT/Twine.h"
  19. #include "llvm/CodeGen/MachineScheduler.h"
  20. #include "llvm/CodeGen/TargetSchedule.h"
  21. #include <limits>
  22. #include <memory>
  23. #include <utility>
  24. namespace llvm {
  25. class DFAPacketizer;
  26. class RegisterClassInfo;
  27. class ScheduleHazardRecognizer;
  28. class SUnit;
  29. class TargetInstrInfo;
  30. class TargetSubtargetInfo;
  31. class VLIWResourceModel {
  32. protected:
  33. const TargetInstrInfo *TII;
  34. /// ResourcesModel - Represents VLIW state.
  35. /// Not limited to VLIW targets per se, but assumes definition of resource
  36. /// model by a target.
  37. DFAPacketizer *ResourcesModel;
  38. const TargetSchedModel *SchedModel;
  39. /// Local packet/bundle model. Purely
  40. /// internal to the MI scheduler at the time.
  41. SmallVector<SUnit *> Packet;
  42. /// Total packets created.
  43. unsigned TotalPackets = 0;
  44. public:
  45. VLIWResourceModel(const TargetSubtargetInfo &STI, const TargetSchedModel *SM);
  46. virtual ~VLIWResourceModel();
  47. virtual void reset();
  48. virtual bool hasDependence(const SUnit *SUd, const SUnit *SUu);
  49. virtual bool isResourceAvailable(SUnit *SU, bool IsTop);
  50. virtual bool reserveResources(SUnit *SU, bool IsTop);
  51. unsigned getTotalPackets() const { return TotalPackets; }
  52. size_t getPacketInstCount() const { return Packet.size(); }
  53. bool isInPacket(SUnit *SU) const { return is_contained(Packet, SU); }
  54. protected:
  55. virtual DFAPacketizer *createPacketizer(const TargetSubtargetInfo &STI) const;
  56. };
  57. /// Extend the standard ScheduleDAGMILive to provide more context and override
  58. /// the top-level schedule() driver.
  59. class VLIWMachineScheduler : public ScheduleDAGMILive {
  60. public:
  61. VLIWMachineScheduler(MachineSchedContext *C,
  62. std::unique_ptr<MachineSchedStrategy> S)
  63. : ScheduleDAGMILive(C, std::move(S)) {}
  64. /// Schedule - This is called back from ScheduleDAGInstrs::Run() when it's
  65. /// time to do some work.
  66. void schedule() override;
  67. RegisterClassInfo *getRegClassInfo() { return RegClassInfo; }
  68. int getBBSize() { return BB->size(); }
  69. };
  70. //===----------------------------------------------------------------------===//
  71. // ConvergingVLIWScheduler - Implementation of a VLIW-aware
  72. // MachineSchedStrategy.
  73. //===----------------------------------------------------------------------===//
  74. class ConvergingVLIWScheduler : public MachineSchedStrategy {
  75. protected:
  76. /// Store the state used by ConvergingVLIWScheduler heuristics, required
  77. /// for the lifetime of one invocation of pickNode().
  78. struct SchedCandidate {
  79. // The best SUnit candidate.
  80. SUnit *SU = nullptr;
  81. // Register pressure values for the best candidate.
  82. RegPressureDelta RPDelta;
  83. // Best scheduling cost.
  84. int SCost = 0;
  85. SchedCandidate() = default;
  86. };
  87. /// Represent the type of SchedCandidate found within a single queue.
  88. enum CandResult {
  89. NoCand,
  90. NodeOrder,
  91. SingleExcess,
  92. SingleCritical,
  93. SingleMax,
  94. MultiPressure,
  95. BestCost,
  96. Weak
  97. };
  98. // Constants used to denote relative importance of
  99. // heuristic components for cost computation.
  100. static constexpr unsigned PriorityOne = 200;
  101. static constexpr unsigned PriorityTwo = 50;
  102. static constexpr unsigned PriorityThree = 75;
  103. static constexpr unsigned ScaleTwo = 10;
  104. /// Each Scheduling boundary is associated with ready queues. It tracks the
  105. /// current cycle in whichever direction at has moved, and maintains the state
  106. /// of "hazards" and other interlocks at the current cycle.
  107. struct VLIWSchedBoundary {
  108. VLIWMachineScheduler *DAG = nullptr;
  109. const TargetSchedModel *SchedModel = nullptr;
  110. ReadyQueue Available;
  111. ReadyQueue Pending;
  112. bool CheckPending = false;
  113. ScheduleHazardRecognizer *HazardRec = nullptr;
  114. VLIWResourceModel *ResourceModel = nullptr;
  115. unsigned CurrCycle = 0;
  116. unsigned IssueCount = 0;
  117. unsigned CriticalPathLength = 0;
  118. /// MinReadyCycle - Cycle of the soonest available instruction.
  119. unsigned MinReadyCycle = std::numeric_limits<unsigned>::max();
  120. // Remember the greatest min operand latency.
  121. unsigned MaxMinLatency = 0;
  122. /// Pending queues extend the ready queues with the same ID and the
  123. /// PendingFlag set.
  124. VLIWSchedBoundary(unsigned ID, const Twine &Name)
  125. : Available(ID, Name + ".A"),
  126. Pending(ID << ConvergingVLIWScheduler::LogMaxQID, Name + ".P") {}
  127. ~VLIWSchedBoundary();
  128. void init(VLIWMachineScheduler *dag, const TargetSchedModel *smodel) {
  129. DAG = dag;
  130. SchedModel = smodel;
  131. CurrCycle = 0;
  132. IssueCount = 0;
  133. // Initialize the critical path length limit, which used by the scheduling
  134. // cost model to determine the value for scheduling an instruction. We use
  135. // a slightly different heuristic for small and large functions. For small
  136. // functions, it's important to use the height/depth of the instruction.
  137. // For large functions, prioritizing by height or depth increases spills.
  138. CriticalPathLength = DAG->getBBSize() / SchedModel->getIssueWidth();
  139. if (DAG->getBBSize() < 50)
  140. // We divide by two as a cheap and simple heuristic to reduce the
  141. // critcal path length, which increases the priority of using the graph
  142. // height/depth in the scheduler's cost computation.
  143. CriticalPathLength >>= 1;
  144. else {
  145. // For large basic blocks, we prefer a larger critical path length to
  146. // decrease the priority of using the graph height/depth.
  147. unsigned MaxPath = 0;
  148. for (auto &SU : DAG->SUnits)
  149. MaxPath = std::max(MaxPath, isTop() ? SU.getHeight() : SU.getDepth());
  150. CriticalPathLength = std::max(CriticalPathLength, MaxPath) + 1;
  151. }
  152. }
  153. bool isTop() const {
  154. return Available.getID() == ConvergingVLIWScheduler::TopQID;
  155. }
  156. bool checkHazard(SUnit *SU);
  157. void releaseNode(SUnit *SU, unsigned ReadyCycle);
  158. void bumpCycle();
  159. void bumpNode(SUnit *SU);
  160. void releasePending();
  161. void removeReady(SUnit *SU);
  162. SUnit *pickOnlyChoice();
  163. bool isLatencyBound(SUnit *SU) {
  164. if (CurrCycle >= CriticalPathLength)
  165. return true;
  166. unsigned PathLength = isTop() ? SU->getHeight() : SU->getDepth();
  167. return CriticalPathLength - CurrCycle <= PathLength;
  168. }
  169. };
  170. VLIWMachineScheduler *DAG = nullptr;
  171. const TargetSchedModel *SchedModel = nullptr;
  172. // State of the top and bottom scheduled instruction boundaries.
  173. VLIWSchedBoundary Top;
  174. VLIWSchedBoundary Bot;
  175. /// List of pressure sets that have a high pressure level in the region.
  176. SmallVector<bool> HighPressureSets;
  177. public:
  178. /// SUnit::NodeQueueId: 0 (none), 1 (top), 2 (bot), 3 (both)
  179. enum { TopQID = 1, BotQID = 2, LogMaxQID = 2 };
  180. ConvergingVLIWScheduler() : Top(TopQID, "TopQ"), Bot(BotQID, "BotQ") {}
  181. virtual ~ConvergingVLIWScheduler() = default;
  182. void initialize(ScheduleDAGMI *dag) override;
  183. SUnit *pickNode(bool &IsTopNode) override;
  184. void schedNode(SUnit *SU, bool IsTopNode) override;
  185. void releaseTopNode(SUnit *SU) override;
  186. void releaseBottomNode(SUnit *SU) override;
  187. unsigned reportPackets() {
  188. return Top.ResourceModel->getTotalPackets() +
  189. Bot.ResourceModel->getTotalPackets();
  190. }
  191. protected:
  192. virtual VLIWResourceModel *
  193. createVLIWResourceModel(const TargetSubtargetInfo &STI,
  194. const TargetSchedModel *SchedModel) const;
  195. SUnit *pickNodeBidrectional(bool &IsTopNode);
  196. int pressureChange(const SUnit *SU, bool isBotUp);
  197. virtual int SchedulingCost(ReadyQueue &Q, SUnit *SU,
  198. SchedCandidate &Candidate, RegPressureDelta &Delta,
  199. bool verbose);
  200. CandResult pickNodeFromQueue(VLIWSchedBoundary &Zone,
  201. const RegPressureTracker &RPTracker,
  202. SchedCandidate &Candidate);
  203. #ifndef NDEBUG
  204. void traceCandidate(const char *Label, const ReadyQueue &Q, SUnit *SU,
  205. int Cost, PressureChange P = PressureChange());
  206. void readyQueueVerboseDump(const RegPressureTracker &RPTracker,
  207. SchedCandidate &Candidate, ReadyQueue &Q);
  208. #endif
  209. };
  210. ScheduleDAGMILive *createVLIWSched(MachineSchedContext *C);
  211. } // end namespace llvm
  212. #endif // LLVM_CODEGEN_VLIWMACHINESCHEDULER_H
  213. #ifdef __GNUC__
  214. #pragma GCC diagnostic pop
  215. #endif