• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- HexagonMachineScheduler.h - Custom Hexagon MI scheduler.      ----===//
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 // Custom Hexagon MI scheduler.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef HEXAGONASMPRINTER_H
15 #define HEXAGONASMPRINTER_H
16 
17 #include "llvm/CodeGen/LiveIntervalAnalysis.h"
18 #include "llvm/CodeGen/MachineScheduler.h"
19 #include "llvm/CodeGen/Passes.h"
20 #include "llvm/CodeGen/RegisterClassInfo.h"
21 #include "llvm/CodeGen/RegisterPressure.h"
22 #include "llvm/CodeGen/ResourcePriorityQueue.h"
23 #include "llvm/CodeGen/ScheduleDAGInstrs.h"
24 #include "llvm/CodeGen/ScheduleHazardRecognizer.h"
25 #include "llvm/Analysis/AliasAnalysis.h"
26 #include "llvm/Target/TargetInstrInfo.h"
27 #include "llvm/Support/CommandLine.h"
28 #include "llvm/Support/Debug.h"
29 #include "llvm/Support/ErrorHandling.h"
30 #include "llvm/Support/raw_ostream.h"
31 #include "llvm/ADT/OwningPtr.h"
32 #include "llvm/ADT/PriorityQueue.h"
33 
34 using namespace llvm;
35 
36 //===----------------------------------------------------------------------===//
37 // MachineSchedStrategy - Interface to a machine scheduling algorithm.
38 //===----------------------------------------------------------------------===//
39 
40 namespace llvm {
41 class VLIWMachineScheduler;
42 
43 /// MachineSchedStrategy - Interface used by VLIWMachineScheduler to drive
44 /// the selected scheduling algorithm.
45 ///
46 /// TODO: Move this to ScheduleDAGInstrs.h
47 class MachineSchedStrategy {
48 public:
~MachineSchedStrategy()49   virtual ~MachineSchedStrategy() {}
50 
51   /// Initialize the strategy after building the DAG for a new region.
52   virtual void initialize(VLIWMachineScheduler *DAG) = 0;
53 
54   /// Pick the next node to schedule, or return NULL. Set IsTopNode to true to
55   /// schedule the node at the top of the unscheduled region. Otherwise it will
56   /// be scheduled at the bottom.
57   virtual SUnit *pickNode(bool &IsTopNode) = 0;
58 
59   /// Notify MachineSchedStrategy that VLIWMachineScheduler has
60   /// scheduled a node.
61   virtual void schedNode(SUnit *SU, bool IsTopNode) = 0;
62 
63   /// When all predecessor dependencies have been resolved, free this node for
64   /// top-down scheduling.
65   virtual void releaseTopNode(SUnit *SU) = 0;
66   /// When all successor dependencies have been resolved, free this node for
67   /// bottom-up scheduling.
68   virtual void releaseBottomNode(SUnit *SU) = 0;
69 };
70 
71 //===----------------------------------------------------------------------===//
72 // ConvergingVLIWScheduler - Implementation of the standard
73 // MachineSchedStrategy.
74 //===----------------------------------------------------------------------===//
75 
76 /// ReadyQueue encapsulates vector of "ready" SUnits with basic convenience
77 /// methods for pushing and removing nodes. ReadyQueue's are uniquely identified
78 /// by an ID. SUnit::NodeQueueId is a mask of the ReadyQueues the SUnit is in.
79 class ReadyQueue {
80   unsigned ID;
81   std::string Name;
82   std::vector<SUnit*> Queue;
83 
84 public:
ReadyQueue(unsigned id,const Twine & name)85   ReadyQueue(unsigned id, const Twine &name): ID(id), Name(name.str()) {}
86 
getID()87   unsigned getID() const { return ID; }
88 
getName()89   StringRef getName() const { return Name; }
90 
91   // SU is in this queue if it's NodeQueueID is a superset of this ID.
isInQueue(SUnit * SU)92   bool isInQueue(SUnit *SU) const { return (SU->NodeQueueId & ID); }
93 
empty()94   bool empty() const { return Queue.empty(); }
95 
size()96   unsigned size() const { return Queue.size(); }
97 
98   typedef std::vector<SUnit*>::iterator iterator;
99 
begin()100   iterator begin() { return Queue.begin(); }
101 
end()102   iterator end() { return Queue.end(); }
103 
find(SUnit * SU)104   iterator find(SUnit *SU) {
105     return std::find(Queue.begin(), Queue.end(), SU);
106   }
107 
push(SUnit * SU)108   void push(SUnit *SU) {
109     Queue.push_back(SU);
110     SU->NodeQueueId |= ID;
111   }
112 
remove(iterator I)113   void remove(iterator I) {
114     (*I)->NodeQueueId &= ~ID;
115     *I = Queue.back();
116     Queue.pop_back();
117   }
118 
dump()119   void dump() {
120     dbgs() << Name << ": ";
121     for (unsigned i = 0, e = Queue.size(); i < e; ++i)
122       dbgs() << Queue[i]->NodeNum << " ";
123     dbgs() << "\n";
124   }
125 };
126 
127 class VLIWResourceModel {
128   /// ResourcesModel - Represents VLIW state.
129   /// Not limited to VLIW targets per say, but assumes
130   /// definition of DFA by a target.
131   DFAPacketizer *ResourcesModel;
132 
133   const InstrItineraryData *InstrItins;
134 
135   /// Local packet/bundle model. Purely
136   /// internal to the MI schedulre at the time.
137   std::vector<SUnit*> Packet;
138 
139   /// Total packets created.
140   unsigned TotalPackets;
141 
142 public:
VLIWResourceModel(MachineSchedContext * C,const InstrItineraryData * IID)143   VLIWResourceModel(MachineSchedContext *C, const InstrItineraryData *IID) :
144     InstrItins(IID), TotalPackets(0) {
145     const TargetMachine &TM = C->MF->getTarget();
146     ResourcesModel = TM.getInstrInfo()->CreateTargetScheduleState(&TM,NULL);
147 
148     // This hard requirement could be relaxed,
149     // but for now do not let it proceed.
150     assert(ResourcesModel && "Unimplemented CreateTargetScheduleState.");
151 
152     Packet.resize(InstrItins->SchedModel->IssueWidth);
153     Packet.clear();
154     ResourcesModel->clearResources();
155   }
156 
VLIWResourceModel(const TargetMachine & TM)157   VLIWResourceModel(const TargetMachine &TM) :
158     InstrItins(TM.getInstrItineraryData()), TotalPackets(0) {
159     ResourcesModel = TM.getInstrInfo()->CreateTargetScheduleState(&TM,NULL);
160 
161     // This hard requirement could be relaxed,
162     // but for now do not let it proceed.
163     assert(ResourcesModel && "Unimplemented CreateTargetScheduleState.");
164 
165     Packet.resize(InstrItins->SchedModel->IssueWidth);
166     Packet.clear();
167     ResourcesModel->clearResources();
168   }
169 
~VLIWResourceModel()170   ~VLIWResourceModel() {
171     delete ResourcesModel;
172   }
173 
resetPacketState()174   void resetPacketState() {
175     Packet.clear();
176   }
177 
resetDFA()178   void resetDFA() {
179     ResourcesModel->clearResources();
180   }
181 
reset()182   void reset() {
183     Packet.clear();
184     ResourcesModel->clearResources();
185   }
186 
187   bool isResourceAvailable(SUnit *SU);
188   bool reserveResources(SUnit *SU);
getTotalPackets()189   unsigned getTotalPackets() const { return TotalPackets; }
190 };
191 
192 class VLIWMachineScheduler : public ScheduleDAGInstrs {
193   /// AA - AliasAnalysis for making memory reference queries.
194   AliasAnalysis *AA;
195 
196   RegisterClassInfo *RegClassInfo;
197   MachineSchedStrategy *SchedImpl;
198 
199   MachineBasicBlock::iterator LiveRegionEnd;
200 
201   /// Register pressure in this region computed by buildSchedGraph.
202   IntervalPressure RegPressure;
203   RegPressureTracker RPTracker;
204 
205   /// List of pressure sets that exceed the target's pressure limit before
206   /// scheduling, listed in increasing set ID order. Each pressure set is paired
207   /// with its max pressure in the currently scheduled regions.
208   std::vector<PressureElement> RegionCriticalPSets;
209 
210   /// The top of the unscheduled zone.
211   MachineBasicBlock::iterator CurrentTop;
212   IntervalPressure TopPressure;
213   RegPressureTracker TopRPTracker;
214 
215   /// The bottom of the unscheduled zone.
216   MachineBasicBlock::iterator CurrentBottom;
217   IntervalPressure BotPressure;
218   RegPressureTracker BotRPTracker;
219 
220 #ifndef NDEBUG
221   /// The number of instructions scheduled so far. Used to cut off the
222   /// scheduler at the point determined by misched-cutoff.
223   unsigned NumInstrsScheduled;
224 #endif
225 
226   /// Total packets in the region.
227   unsigned TotalPackets;
228 
229   const MachineLoopInfo *MLI;
230 public:
VLIWMachineScheduler(MachineSchedContext * C,MachineSchedStrategy * S)231   VLIWMachineScheduler(MachineSchedContext *C, MachineSchedStrategy *S):
232     ScheduleDAGInstrs(*C->MF, *C->MLI, *C->MDT, /*IsPostRA=*/false, C->LIS),
233     AA(C->AA), RegClassInfo(C->RegClassInfo), SchedImpl(S),
234     RPTracker(RegPressure), CurrentTop(), TopRPTracker(TopPressure),
235     CurrentBottom(), BotRPTracker(BotPressure), MLI(C->MLI) {
236 #ifndef NDEBUG
237     NumInstrsScheduled = 0;
238 #endif
239     TotalPackets = 0;
240   }
241 
~VLIWMachineScheduler()242   virtual ~VLIWMachineScheduler() {
243     delete SchedImpl;
244   }
245 
top()246   MachineBasicBlock::iterator top() const { return CurrentTop; }
bottom()247   MachineBasicBlock::iterator bottom() const { return CurrentBottom; }
248 
249   /// Implement the ScheduleDAGInstrs interface for handling the next scheduling
250   /// region. This covers all instructions in a block, while schedule() may only
251   /// cover a subset.
252   void enterRegion(MachineBasicBlock *bb,
253                    MachineBasicBlock::iterator begin,
254                    MachineBasicBlock::iterator end,
255                    unsigned endcount);
256 
257   /// Schedule - This is called back from ScheduleDAGInstrs::Run() when it's
258   /// time to do some work.
259   void schedule();
260 
261   unsigned CurCycle;
262 
263   /// Get current register pressure for the top scheduled instructions.
getTopPressure()264   const IntervalPressure &getTopPressure() const { return TopPressure; }
getTopRPTracker()265   const RegPressureTracker &getTopRPTracker() const { return TopRPTracker; }
266 
267   /// Get current register pressure for the bottom scheduled instructions.
getBotPressure()268   const IntervalPressure &getBotPressure() const { return BotPressure; }
getBotRPTracker()269   const RegPressureTracker &getBotRPTracker() const { return BotRPTracker; }
270 
271   /// Get register pressure for the entire scheduling region before scheduling.
getRegPressure()272   const IntervalPressure &getRegPressure() const { return RegPressure; }
273 
getRegionCriticalPSets()274   const std::vector<PressureElement> &getRegionCriticalPSets() const {
275     return RegionCriticalPSets;
276   }
277 
278   /// getIssueWidth - Return the max instructions per scheduling group.
getIssueWidth()279   unsigned getIssueWidth() const {
280     return (InstrItins && InstrItins->SchedModel)
281       ? InstrItins->SchedModel->IssueWidth : 1;
282   }
283 
284   /// getNumMicroOps - Return the number of issue slots required for this MI.
getNumMicroOps(MachineInstr * MI)285   unsigned getNumMicroOps(MachineInstr *MI) const {
286     return 1;
287     //if (!InstrItins) return 1;
288     //int UOps = InstrItins->getNumMicroOps(MI->getDesc().getSchedClass());
289     //return (UOps >= 0) ? UOps : TII->getNumMicroOps(InstrItins, MI);
290   }
291 
292 private:
293   void scheduleNodeTopDown(SUnit *SU);
294   void listScheduleTopDown();
295 
296   void initRegPressure();
297   void updateScheduledPressure(std::vector<unsigned> NewMaxPressure);
298 
299   void moveInstruction(MachineInstr *MI, MachineBasicBlock::iterator InsertPos);
300   bool checkSchedLimit();
301 
302   void releaseRoots();
303 
304   void releaseSucc(SUnit *SU, SDep *SuccEdge);
305   void releaseSuccessors(SUnit *SU);
306   void releasePred(SUnit *SU, SDep *PredEdge);
307   void releasePredecessors(SUnit *SU);
308 
309   void placeDebugValues();
310 };
311 
312 /// ConvergingVLIWScheduler shrinks the unscheduled zone using heuristics
313 /// to balance the schedule.
314 class ConvergingVLIWScheduler : public MachineSchedStrategy {
315 
316   /// Store the state used by ConvergingVLIWScheduler heuristics, required
317   ///  for the lifetime of one invocation of pickNode().
318   struct SchedCandidate {
319     // The best SUnit candidate.
320     SUnit *SU;
321 
322     // Register pressure values for the best candidate.
323     RegPressureDelta RPDelta;
324 
325     // Best scheduling cost.
326     int SCost;
327 
SchedCandidateSchedCandidate328     SchedCandidate(): SU(NULL), SCost(0) {}
329   };
330   /// Represent the type of SchedCandidate found within a single queue.
331   enum CandResult {
332     NoCand, NodeOrder, SingleExcess, SingleCritical, SingleMax, MultiPressure,
333     BestCost};
334 
335   /// Each Scheduling boundary is associated with ready queues. It tracks the
336   /// current cycle in whichever direction at has moved, and maintains the state
337   /// of "hazards" and other interlocks at the current cycle.
338   struct SchedBoundary {
339     VLIWMachineScheduler *DAG;
340 
341     ReadyQueue Available;
342     ReadyQueue Pending;
343     bool CheckPending;
344 
345     ScheduleHazardRecognizer *HazardRec;
346     VLIWResourceModel *ResourceModel;
347 
348     unsigned CurrCycle;
349     unsigned IssueCount;
350 
351     /// MinReadyCycle - Cycle of the soonest available instruction.
352     unsigned MinReadyCycle;
353 
354     // Remember the greatest min operand latency.
355     unsigned MaxMinLatency;
356 
357     /// Pending queues extend the ready queues with the same ID and the
358     /// PendingFlag set.
SchedBoundarySchedBoundary359     SchedBoundary(unsigned ID, const Twine &Name):
360       DAG(0), Available(ID, Name+".A"),
361       Pending(ID << ConvergingVLIWScheduler::LogMaxQID, Name+".P"),
362       CheckPending(false), HazardRec(0), ResourceModel(0),
363       CurrCycle(0), IssueCount(0),
364       MinReadyCycle(UINT_MAX), MaxMinLatency(0) {}
365 
~SchedBoundarySchedBoundary366     ~SchedBoundary() {
367       delete ResourceModel;
368       delete HazardRec;
369     }
370 
isTopSchedBoundary371     bool isTop() const {
372       return Available.getID() == ConvergingVLIWScheduler::TopQID;
373     }
374 
375     bool checkHazard(SUnit *SU);
376 
377     void releaseNode(SUnit *SU, unsigned ReadyCycle);
378 
379     void bumpCycle();
380 
381     void bumpNode(SUnit *SU);
382 
383     void releasePending();
384 
385     void removeReady(SUnit *SU);
386 
387     SUnit *pickOnlyChoice();
388   };
389 
390   VLIWMachineScheduler *DAG;
391   const TargetRegisterInfo *TRI;
392 
393   // State of the top and bottom scheduled instruction boundaries.
394   SchedBoundary Top;
395   SchedBoundary Bot;
396 
397 public:
398   /// SUnit::NodeQueueId: 0 (none), 1 (top), 2 (bot), 3 (both)
399   enum {
400     TopQID = 1,
401     BotQID = 2,
402     LogMaxQID = 2
403   };
404 
ConvergingVLIWScheduler()405   ConvergingVLIWScheduler():
406     DAG(0), TRI(0), Top(TopQID, "TopQ"), Bot(BotQID, "BotQ") {}
407 
408   virtual void initialize(VLIWMachineScheduler *dag);
409 
410   virtual SUnit *pickNode(bool &IsTopNode);
411 
412   virtual void schedNode(SUnit *SU, bool IsTopNode);
413 
414   virtual void releaseTopNode(SUnit *SU);
415 
416   virtual void releaseBottomNode(SUnit *SU);
417 
418 protected:
419   SUnit *pickNodeBidrectional(bool &IsTopNode);
420 
421   int SchedulingCost(ReadyQueue &Q,
422                      SUnit *SU, SchedCandidate &Candidate,
423                      RegPressureDelta &Delta, bool verbose);
424 
425   CandResult pickNodeFromQueue(ReadyQueue &Q,
426                                const RegPressureTracker &RPTracker,
427                                SchedCandidate &Candidate);
428 #ifndef NDEBUG
429   void traceCandidate(const char *Label, const ReadyQueue &Q, SUnit *SU,
430                       PressureElement P = PressureElement());
431 #endif
432 };
433 
434 } // namespace
435 
436 
437 #endif
438