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