blob: ad8ed5aaf978e7704f5516f2f3a087858df141d6 [file] [log] [blame]
Evan Chengab495562006-01-25 09:14:32 +00001//===---- ScheduleDAGList.cpp - Implement a list scheduler for isel DAG ---===//
Evan Cheng31272342006-01-23 08:26:10 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by Evan Cheng and is distributed under the
6// University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
Evan Chengd38c22b2006-05-11 23:55:42 +000010// This implements a top-down list scheduler, using standard algorithms.
11// The basic approach uses a priority queue of available nodes to schedule.
12// One at a time, nodes are taken from the priority queue (thus in priority
13// order), checked for legality to schedule, and emitted if legal.
Chris Lattner01aa7522006-03-06 17:58:04 +000014//
15// Nodes may not be legal to schedule either due to structural hazards (e.g.
16// pipeline or resource constraints) or because an input to the instruction has
17// not completed execution.
Evan Cheng31272342006-01-23 08:26:10 +000018//
19//===----------------------------------------------------------------------===//
20
21#define DEBUG_TYPE "sched"
22#include "llvm/CodeGen/ScheduleDAG.h"
Evan Cheng9add8802006-05-04 19:16:39 +000023#include "llvm/CodeGen/SSARegMap.h"
24#include "llvm/Target/MRegisterInfo.h"
Owen Anderson8c2c1e92006-05-12 06:33:49 +000025#include "llvm/Target/TargetData.h"
Evan Cheng31272342006-01-23 08:26:10 +000026#include "llvm/Target/TargetMachine.h"
27#include "llvm/Target/TargetInstrInfo.h"
Evan Chengab495562006-01-25 09:14:32 +000028#include "llvm/Support/Debug.h"
Chris Lattnerfa5e1c92006-03-05 23:13:56 +000029#include "llvm/ADT/Statistic.h"
Evan Chengab495562006-01-25 09:14:32 +000030#include <climits>
31#include <iostream>
Evan Cheng31272342006-01-23 08:26:10 +000032#include <queue>
33using namespace llvm;
34
Evan Chengab495562006-01-25 09:14:32 +000035namespace {
Chris Lattnerfa5e1c92006-03-05 23:13:56 +000036 Statistic<> NumNoops ("scheduler", "Number of noops inserted");
37 Statistic<> NumStalls("scheduler", "Number of pipeline stalls");
Chris Lattneraf5e26c2006-03-08 04:37:58 +000038}
Evan Chengab495562006-01-25 09:14:32 +000039
Chris Lattneraf5e26c2006-03-08 04:37:58 +000040namespace {
Chris Lattner9e95acc2006-03-09 06:37:29 +000041//===----------------------------------------------------------------------===//
42/// ScheduleDAGList - The actual list scheduler implementation. This supports
Evan Chengd38c22b2006-05-11 23:55:42 +000043/// top-down scheduling.
Chris Lattner9e95acc2006-03-09 06:37:29 +000044///
Evan Cheng31272342006-01-23 08:26:10 +000045class ScheduleDAGList : public ScheduleDAG {
46private:
Chris Lattner356183d2006-03-11 22:44:37 +000047 /// AvailableQueue - The priority queue to use for the available SUnits.
48 ///
49 SchedulingPriorityQueue *AvailableQueue;
Chris Lattner9df64752006-03-09 06:35:14 +000050
Chris Lattner572003c2006-03-12 00:38:57 +000051 /// PendingQueue - This contains all of the instructions whose operands have
52 /// been issued, but their results are not ready yet (due to the latency of
53 /// the operation). Once the operands becomes available, the instruction is
54 /// added to the AvailableQueue. This keeps track of each SUnit and the
55 /// number of cycles left to execute before the operation is available.
56 std::vector<std::pair<unsigned, SUnit*> > PendingQueue;
Evan Cheng9add8802006-05-04 19:16:39 +000057
Chris Lattnere50c0922006-03-05 22:45:01 +000058 /// HazardRec - The hazard recognizer to use.
Chris Lattner543832d2006-03-08 04:25:59 +000059 HazardRecognizer *HazardRec;
Evan Cheng9add8802006-05-04 19:16:39 +000060
Evan Cheng31272342006-01-23 08:26:10 +000061public:
62 ScheduleDAGList(SelectionDAG &dag, MachineBasicBlock *bb,
Evan Chengd38c22b2006-05-11 23:55:42 +000063 const TargetMachine &tm,
Chris Lattner356183d2006-03-11 22:44:37 +000064 SchedulingPriorityQueue *availqueue,
Chris Lattner543832d2006-03-08 04:25:59 +000065 HazardRecognizer *HR)
Evan Chengd38c22b2006-05-11 23:55:42 +000066 : ScheduleDAG(dag, bb, tm),
Chris Lattner356183d2006-03-11 22:44:37 +000067 AvailableQueue(availqueue), HazardRec(HR) {
Chris Lattnere50c0922006-03-05 22:45:01 +000068 }
Evan Chengab495562006-01-25 09:14:32 +000069
70 ~ScheduleDAGList() {
Chris Lattner543832d2006-03-08 04:25:59 +000071 delete HazardRec;
Chris Lattner356183d2006-03-11 22:44:37 +000072 delete AvailableQueue;
Evan Chengab495562006-01-25 09:14:32 +000073 }
Evan Cheng31272342006-01-23 08:26:10 +000074
75 void Schedule();
Evan Cheng31272342006-01-23 08:26:10 +000076
Evan Chengab495562006-01-25 09:14:32 +000077private:
Chris Lattner572003c2006-03-12 00:38:57 +000078 void ReleaseSucc(SUnit *SuccSU, bool isChain);
Chris Lattner063086b2006-03-11 22:34:41 +000079 void ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle);
Chris Lattner399bee22006-03-09 06:48:37 +000080 void ListScheduleTopDown();
Evan Chengab495562006-01-25 09:14:32 +000081};
Chris Lattneraf5e26c2006-03-08 04:37:58 +000082} // end anonymous namespace
Evan Chengab495562006-01-25 09:14:32 +000083
Chris Lattner47639db2006-03-06 00:22:00 +000084HazardRecognizer::~HazardRecognizer() {}
85
Evan Chengc4c339c2006-01-26 00:30:29 +000086
Chris Lattner9995a0c2006-03-11 22:28:35 +000087/// Schedule - Schedule the DAG using list scheduling.
Chris Lattner9995a0c2006-03-11 22:28:35 +000088void ScheduleDAGList::Schedule() {
89 DEBUG(std::cerr << "********** List Scheduling **********\n");
90
91 // Build scheduling units.
92 BuildSchedUnits();
Evan Cheng7d693892006-05-09 07:13:34 +000093
Chris Lattner356183d2006-03-11 22:44:37 +000094 AvailableQueue->initNodes(SUnits);
Chris Lattner9995a0c2006-03-11 22:28:35 +000095
Evan Chengd38c22b2006-05-11 23:55:42 +000096 ListScheduleTopDown();
Chris Lattner9995a0c2006-03-11 22:28:35 +000097
Chris Lattner356183d2006-03-11 22:44:37 +000098 AvailableQueue->releaseState();
Chris Lattner9995a0c2006-03-11 22:28:35 +000099
100 DEBUG(std::cerr << "*** Final schedule ***\n");
101 DEBUG(dumpSchedule());
102 DEBUG(std::cerr << "\n");
103
104 // Emit in scheduled order
105 EmitSchedule();
106}
107
108//===----------------------------------------------------------------------===//
Chris Lattner9995a0c2006-03-11 22:28:35 +0000109// Top-Down Scheduling
110//===----------------------------------------------------------------------===//
111
112/// ReleaseSucc - Decrement the NumPredsLeft count of a successor. Add it to
Chris Lattner572003c2006-03-12 00:38:57 +0000113/// the PendingQueue if the count reaches zero.
114void ScheduleDAGList::ReleaseSucc(SUnit *SuccSU, bool isChain) {
Chris Lattner9995a0c2006-03-11 22:28:35 +0000115 if (!isChain)
116 SuccSU->NumPredsLeft--;
117 else
118 SuccSU->NumChainPredsLeft--;
119
Chris Lattner572003c2006-03-12 00:38:57 +0000120 assert(SuccSU->NumPredsLeft >= 0 && SuccSU->NumChainPredsLeft >= 0 &&
121 "List scheduling internal error");
Chris Lattner9995a0c2006-03-11 22:28:35 +0000122
123 if ((SuccSU->NumPredsLeft + SuccSU->NumChainPredsLeft) == 0) {
Chris Lattner572003c2006-03-12 00:38:57 +0000124 // Compute how many cycles it will be before this actually becomes
125 // available. This is the max of the start time of all predecessors plus
126 // their latencies.
127 unsigned AvailableCycle = 0;
128 for (std::set<std::pair<SUnit*, bool> >::iterator I = SuccSU->Preds.begin(),
129 E = SuccSU->Preds.end(); I != E; ++I) {
Chris Lattnera767dbf2006-03-12 09:01:41 +0000130 // If this is a token edge, we don't need to wait for the latency of the
131 // preceeding instruction (e.g. a long-latency load) unless there is also
132 // some other data dependence.
Chris Lattner86a9b602006-03-12 03:52:09 +0000133 unsigned PredDoneCycle = I->first->Cycle;
134 if (!I->second)
135 PredDoneCycle += I->first->Latency;
Chris Lattnera767dbf2006-03-12 09:01:41 +0000136 else if (I->first->Latency)
137 PredDoneCycle += 1;
Chris Lattner86a9b602006-03-12 03:52:09 +0000138
139 AvailableCycle = std::max(AvailableCycle, PredDoneCycle);
Chris Lattner572003c2006-03-12 00:38:57 +0000140 }
141
142 PendingQueue.push_back(std::make_pair(AvailableCycle, SuccSU));
Chris Lattner9995a0c2006-03-11 22:28:35 +0000143 }
144}
145
146/// ScheduleNodeTopDown - Add the node to the schedule. Decrement the pending
147/// count of its successors. If a successor pending count is zero, add it to
148/// the Available queue.
Chris Lattner356183d2006-03-11 22:44:37 +0000149void ScheduleDAGList::ScheduleNodeTopDown(SUnit *SU, unsigned CurCycle) {
Chris Lattner572003c2006-03-12 00:38:57 +0000150 DEBUG(std::cerr << "*** Scheduling [" << CurCycle << "]: ");
Chris Lattner9995a0c2006-03-11 22:28:35 +0000151 DEBUG(SU->dump(&DAG));
152
153 Sequence.push_back(SU);
Chris Lattner356183d2006-03-11 22:44:37 +0000154 SU->Cycle = CurCycle;
Chris Lattner9995a0c2006-03-11 22:28:35 +0000155
156 // Bottom up: release successors.
157 for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Succs.begin(),
Chris Lattner356183d2006-03-11 22:44:37 +0000158 E = SU->Succs.end(); I != E; ++I)
Chris Lattner572003c2006-03-12 00:38:57 +0000159 ReleaseSucc(I->first, I->second);
Chris Lattner9995a0c2006-03-11 22:28:35 +0000160}
161
Chris Lattner98ecb8e2006-03-05 21:10:33 +0000162/// ListScheduleTopDown - The main loop of list scheduling for top-down
163/// schedulers.
Chris Lattner399bee22006-03-09 06:48:37 +0000164void ScheduleDAGList::ListScheduleTopDown() {
Chris Lattner572003c2006-03-12 00:38:57 +0000165 unsigned CurCycle = 0;
Chris Lattner98ecb8e2006-03-05 21:10:33 +0000166 SUnit *Entry = SUnitMap[DAG.getEntryNode().Val];
Chris Lattner572003c2006-03-12 00:38:57 +0000167
Chris Lattner98ecb8e2006-03-05 21:10:33 +0000168 // All leaves to Available queue.
Chris Lattner42e20262006-03-08 04:54:34 +0000169 for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
Chris Lattner98ecb8e2006-03-05 21:10:33 +0000170 // It is available if it has no predecessors.
Chris Lattner572003c2006-03-12 00:38:57 +0000171 if (SUnits[i].Preds.size() == 0 && &SUnits[i] != Entry) {
Chris Lattner356183d2006-03-11 22:44:37 +0000172 AvailableQueue->push(&SUnits[i]);
Chris Lattner572003c2006-03-12 00:38:57 +0000173 SUnits[i].isAvailable = SUnits[i].isPending = true;
174 }
Chris Lattner98ecb8e2006-03-05 21:10:33 +0000175 }
176
Chris Lattner572003c2006-03-12 00:38:57 +0000177 // Emit the entry node first.
178 ScheduleNodeTopDown(Entry, CurCycle);
179 HazardRec->EmitInstruction(Entry->Node);
180
Chris Lattner98ecb8e2006-03-05 21:10:33 +0000181 // While Available queue is not empty, grab the node with the highest
182 // priority. If it is not ready put it back. Schedule the node.
183 std::vector<SUnit*> NotReady;
Chris Lattner572003c2006-03-12 00:38:57 +0000184 while (!AvailableQueue->empty() || !PendingQueue.empty()) {
185 // Check to see if any of the pending instructions are ready to issue. If
186 // so, add them to the available queue.
Chris Lattnera767dbf2006-03-12 09:01:41 +0000187 for (unsigned i = 0, e = PendingQueue.size(); i != e; ++i) {
Chris Lattner572003c2006-03-12 00:38:57 +0000188 if (PendingQueue[i].first == CurCycle) {
189 AvailableQueue->push(PendingQueue[i].second);
190 PendingQueue[i].second->isAvailable = true;
191 PendingQueue[i] = PendingQueue.back();
192 PendingQueue.pop_back();
193 --i; --e;
194 } else {
195 assert(PendingQueue[i].first > CurCycle && "Negative latency?");
196 }
Chris Lattnera767dbf2006-03-12 09:01:41 +0000197 }
Chris Lattner572003c2006-03-12 00:38:57 +0000198
Chris Lattnera767dbf2006-03-12 09:01:41 +0000199 // If there are no instructions available, don't try to issue anything, and
200 // don't advance the hazard recognizer.
201 if (AvailableQueue->empty()) {
202 ++CurCycle;
203 continue;
204 }
Chris Lattner98ecb8e2006-03-05 21:10:33 +0000205
Chris Lattnera767dbf2006-03-12 09:01:41 +0000206 SUnit *FoundSUnit = 0;
207 SDNode *FoundNode = 0;
208
Chris Lattnere50c0922006-03-05 22:45:01 +0000209 bool HasNoopHazards = false;
Chris Lattner572003c2006-03-12 00:38:57 +0000210 while (!AvailableQueue->empty()) {
Chris Lattnera767dbf2006-03-12 09:01:41 +0000211 SUnit *CurSUnit = AvailableQueue->pop();
Chris Lattner0c801bd2006-03-07 05:40:43 +0000212
213 // Get the node represented by this SUnit.
Chris Lattnera767dbf2006-03-12 09:01:41 +0000214 FoundNode = CurSUnit->Node;
215
Chris Lattner0c801bd2006-03-07 05:40:43 +0000216 // If this is a pseudo op, like copyfromreg, look to see if there is a
217 // real target node flagged to it. If so, use the target node.
Chris Lattnera767dbf2006-03-12 09:01:41 +0000218 for (unsigned i = 0, e = CurSUnit->FlaggedNodes.size();
219 FoundNode->getOpcode() < ISD::BUILTIN_OP_END && i != e; ++i)
220 FoundNode = CurSUnit->FlaggedNodes[i];
Chris Lattner0c801bd2006-03-07 05:40:43 +0000221
Chris Lattnera767dbf2006-03-12 09:01:41 +0000222 HazardRecognizer::HazardType HT = HazardRec->getHazardType(FoundNode);
Chris Lattnere50c0922006-03-05 22:45:01 +0000223 if (HT == HazardRecognizer::NoHazard) {
Chris Lattnera767dbf2006-03-12 09:01:41 +0000224 FoundSUnit = CurSUnit;
Chris Lattnere50c0922006-03-05 22:45:01 +0000225 break;
226 }
227
228 // Remember if this is a noop hazard.
229 HasNoopHazards |= HT == HazardRecognizer::NoopHazard;
230
Chris Lattnera767dbf2006-03-12 09:01:41 +0000231 NotReady.push_back(CurSUnit);
Chris Lattner572003c2006-03-12 00:38:57 +0000232 }
Chris Lattnere50c0922006-03-05 22:45:01 +0000233
Chris Lattner98ecb8e2006-03-05 21:10:33 +0000234 // Add the nodes that aren't ready back onto the available list.
Chris Lattnera767dbf2006-03-12 09:01:41 +0000235 if (!NotReady.empty()) {
236 AvailableQueue->push_all(NotReady);
237 NotReady.clear();
238 }
Chris Lattnere50c0922006-03-05 22:45:01 +0000239
240 // If we found a node to schedule, do it now.
Chris Lattnera767dbf2006-03-12 09:01:41 +0000241 if (FoundSUnit) {
242 ScheduleNodeTopDown(FoundSUnit, CurCycle);
243 HazardRec->EmitInstruction(FoundNode);
244 FoundSUnit->isScheduled = true;
245 AvailableQueue->ScheduledNode(FoundSUnit);
Chris Lattner572003c2006-03-12 00:38:57 +0000246
247 // If this is a pseudo-op node, we don't want to increment the current
248 // cycle.
Chris Lattnera767dbf2006-03-12 09:01:41 +0000249 if (FoundSUnit->Latency) // Don't increment CurCycle for pseudo-ops!
250 ++CurCycle;
Chris Lattnere50c0922006-03-05 22:45:01 +0000251 } else if (!HasNoopHazards) {
252 // Otherwise, we have a pipeline stall, but no other problem, just advance
253 // the current cycle and try again.
Chris Lattner0c801bd2006-03-07 05:40:43 +0000254 DEBUG(std::cerr << "*** Advancing cycle, no work to do\n");
Chris Lattner543832d2006-03-08 04:25:59 +0000255 HazardRec->AdvanceCycle();
Chris Lattnerfa5e1c92006-03-05 23:13:56 +0000256 ++NumStalls;
Chris Lattnera767dbf2006-03-12 09:01:41 +0000257 ++CurCycle;
Chris Lattnere50c0922006-03-05 22:45:01 +0000258 } else {
259 // Otherwise, we have no instructions to issue and we have instructions
260 // that will fault if we don't do this right. This is the case for
261 // processors without pipeline interlocks and other cases.
Chris Lattner0c801bd2006-03-07 05:40:43 +0000262 DEBUG(std::cerr << "*** Emitting noop\n");
Chris Lattner543832d2006-03-08 04:25:59 +0000263 HazardRec->EmitNoop();
Chris Lattner00b52ea2006-03-05 23:59:20 +0000264 Sequence.push_back(0); // NULL SUnit* -> noop
Chris Lattnerfa5e1c92006-03-05 23:13:56 +0000265 ++NumNoops;
Chris Lattnera767dbf2006-03-12 09:01:41 +0000266 ++CurCycle;
Chris Lattnere50c0922006-03-05 22:45:01 +0000267 }
Chris Lattner98ecb8e2006-03-05 21:10:33 +0000268 }
269
270#ifndef NDEBUG
271 // Verify that all SUnits were scheduled.
272 bool AnyNotSched = false;
Chris Lattner42e20262006-03-08 04:54:34 +0000273 for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
274 if (SUnits[i].NumPredsLeft != 0 || SUnits[i].NumChainPredsLeft != 0) {
Chris Lattner98ecb8e2006-03-05 21:10:33 +0000275 if (!AnyNotSched)
276 std::cerr << "*** List scheduling failed! ***\n";
Chris Lattner42e20262006-03-08 04:54:34 +0000277 SUnits[i].dump(&DAG);
Chris Lattner98ecb8e2006-03-05 21:10:33 +0000278 std::cerr << "has not been scheduled!\n";
279 AnyNotSched = true;
280 }
281 }
282 assert(!AnyNotSched);
283#endif
284}
285
Chris Lattner9df64752006-03-09 06:35:14 +0000286//===----------------------------------------------------------------------===//
Chris Lattner6398c132006-03-09 07:38:27 +0000287// LatencyPriorityQueue Implementation
288//===----------------------------------------------------------------------===//
289//
290// This is a SchedulingPriorityQueue that schedules using latency information to
291// reduce the length of the critical path through the basic block.
292//
293namespace {
294 class LatencyPriorityQueue;
295
296 /// Sorting functions for the Available queue.
297 struct latency_sort : public std::binary_function<SUnit*, SUnit*, bool> {
298 LatencyPriorityQueue *PQ;
299 latency_sort(LatencyPriorityQueue *pq) : PQ(pq) {}
300 latency_sort(const latency_sort &RHS) : PQ(RHS.PQ) {}
301
302 bool operator()(const SUnit* left, const SUnit* right) const;
303 };
304} // end anonymous namespace
305
306namespace {
307 class LatencyPriorityQueue : public SchedulingPriorityQueue {
308 // SUnits - The SUnits for the current graph.
309 const std::vector<SUnit> *SUnits;
310
311 // Latencies - The latency (max of latency from this node to the bb exit)
312 // for each node.
313 std::vector<int> Latencies;
Chris Lattner349e9dd2006-03-10 05:51:05 +0000314
315 /// NumNodesSolelyBlocking - This vector contains, for every node in the
316 /// Queue, the number of nodes that the node is the sole unscheduled
317 /// predecessor for. This is used as a tie-breaker heuristic for better
318 /// mobility.
319 std::vector<unsigned> NumNodesSolelyBlocking;
320
Chris Lattner6398c132006-03-09 07:38:27 +0000321 std::priority_queue<SUnit*, std::vector<SUnit*>, latency_sort> Queue;
322public:
323 LatencyPriorityQueue() : Queue(latency_sort(this)) {
324 }
325
326 void initNodes(const std::vector<SUnit> &sunits) {
327 SUnits = &sunits;
328 // Calculate node priorities.
329 CalculatePriorities();
330 }
331 void releaseState() {
332 SUnits = 0;
333 Latencies.clear();
334 }
335
336 unsigned getLatency(unsigned NodeNum) const {
337 assert(NodeNum < Latencies.size());
338 return Latencies[NodeNum];
339 }
340
Chris Lattner349e9dd2006-03-10 05:51:05 +0000341 unsigned getNumSolelyBlockNodes(unsigned NodeNum) const {
342 assert(NodeNum < NumNodesSolelyBlocking.size());
343 return NumNodesSolelyBlocking[NodeNum];
344 }
345
Chris Lattner6398c132006-03-09 07:38:27 +0000346 bool empty() const { return Queue.empty(); }
347
Chris Lattner349e9dd2006-03-10 05:51:05 +0000348 virtual void push(SUnit *U) {
349 push_impl(U);
Chris Lattner6398c132006-03-09 07:38:27 +0000350 }
Chris Lattner349e9dd2006-03-10 05:51:05 +0000351 void push_impl(SUnit *U);
352
Chris Lattner25e25562006-03-10 04:32:49 +0000353 void push_all(const std::vector<SUnit *> &Nodes) {
354 for (unsigned i = 0, e = Nodes.size(); i != e; ++i)
Chris Lattner349e9dd2006-03-10 05:51:05 +0000355 push_impl(Nodes[i]);
Chris Lattner25e25562006-03-10 04:32:49 +0000356 }
357
Chris Lattner6398c132006-03-09 07:38:27 +0000358 SUnit *pop() {
Evan Cheng61e9f0d2006-05-30 18:04:34 +0000359 if (empty()) return NULL;
Chris Lattner6398c132006-03-09 07:38:27 +0000360 SUnit *V = Queue.top();
361 Queue.pop();
Chris Lattner6398c132006-03-09 07:38:27 +0000362 return V;
363 }
Evan Cheng7d693892006-05-09 07:13:34 +0000364
Evan Chengd38c22b2006-05-11 23:55:42 +0000365 // ScheduledNode - As nodes are scheduled, we look to see if there are any
366 // successor nodes that have a single unscheduled predecessor. If so, that
367 // single predecessor has a higher priority, since scheduling it will make
368 // the node available.
369 void ScheduledNode(SUnit *Node);
370
371private:
372 void CalculatePriorities();
373 int CalcLatency(const SUnit &SU);
374 void AdjustPriorityOfUnscheduledPreds(SUnit *SU);
375
Chris Lattner349e9dd2006-03-10 05:51:05 +0000376 /// RemoveFromPriorityQueue - This is a really inefficient way to remove a
377 /// node from a priority queue. We should roll our own heap to make this
378 /// better or something.
379 void RemoveFromPriorityQueue(SUnit *SU) {
380 std::vector<SUnit*> Temp;
381
382 assert(!Queue.empty() && "Not in queue!");
383 while (Queue.top() != SU) {
384 Temp.push_back(Queue.top());
385 Queue.pop();
386 assert(!Queue.empty() && "Not in queue!");
387 }
388
389 // Remove the node from the PQ.
390 Queue.pop();
391
392 // Add all the other nodes back.
393 for (unsigned i = 0, e = Temp.size(); i != e; ++i)
394 Queue.push(Temp[i]);
395 }
Chris Lattner6398c132006-03-09 07:38:27 +0000396 };
397}
398
399bool latency_sort::operator()(const SUnit *LHS, const SUnit *RHS) const {
400 unsigned LHSNum = LHS->NodeNum;
401 unsigned RHSNum = RHS->NodeNum;
Chris Lattner349e9dd2006-03-10 05:51:05 +0000402
403 // The most important heuristic is scheduling the critical path.
404 unsigned LHSLatency = PQ->getLatency(LHSNum);
405 unsigned RHSLatency = PQ->getLatency(RHSNum);
406 if (LHSLatency < RHSLatency) return true;
407 if (LHSLatency > RHSLatency) return false;
Chris Lattner6398c132006-03-09 07:38:27 +0000408
Chris Lattner349e9dd2006-03-10 05:51:05 +0000409 // After that, if two nodes have identical latencies, look to see if one will
410 // unblock more other nodes than the other.
411 unsigned LHSBlocked = PQ->getNumSolelyBlockNodes(LHSNum);
412 unsigned RHSBlocked = PQ->getNumSolelyBlockNodes(RHSNum);
413 if (LHSBlocked < RHSBlocked) return true;
414 if (LHSBlocked > RHSBlocked) return false;
415
416 // Finally, just to provide a stable ordering, use the node number as a
417 // deciding factor.
418 return LHSNum < RHSNum;
Chris Lattner6398c132006-03-09 07:38:27 +0000419}
420
421
422/// CalcNodePriority - Calculate the maximal path from the node to the exit.
423///
424int LatencyPriorityQueue::CalcLatency(const SUnit &SU) {
425 int &Latency = Latencies[SU.NodeNum];
426 if (Latency != -1)
427 return Latency;
428
429 int MaxSuccLatency = 0;
Chris Lattner578d8fc2006-03-11 22:24:20 +0000430 for (std::set<std::pair<SUnit*, bool> >::const_iterator I = SU.Succs.begin(),
Chris Lattner6398c132006-03-09 07:38:27 +0000431 E = SU.Succs.end(); I != E; ++I)
Chris Lattner578d8fc2006-03-11 22:24:20 +0000432 MaxSuccLatency = std::max(MaxSuccLatency, CalcLatency(*I->first));
Chris Lattner6398c132006-03-09 07:38:27 +0000433
434 return Latency = MaxSuccLatency + SU.Latency;
435}
436
437/// CalculatePriorities - Calculate priorities of all scheduling units.
438void LatencyPriorityQueue::CalculatePriorities() {
439 Latencies.assign(SUnits->size(), -1);
Chris Lattner349e9dd2006-03-10 05:51:05 +0000440 NumNodesSolelyBlocking.assign(SUnits->size(), 0);
Chris Lattner6398c132006-03-09 07:38:27 +0000441
442 for (unsigned i = 0, e = SUnits->size(); i != e; ++i)
443 CalcLatency((*SUnits)[i]);
444}
445
Chris Lattner349e9dd2006-03-10 05:51:05 +0000446/// getSingleUnscheduledPred - If there is exactly one unscheduled predecessor
447/// of SU, return it, otherwise return null.
448static SUnit *getSingleUnscheduledPred(SUnit *SU) {
449 SUnit *OnlyAvailablePred = 0;
Chris Lattner578d8fc2006-03-11 22:24:20 +0000450 for (std::set<std::pair<SUnit*, bool> >::const_iterator I = SU->Preds.begin(),
Chris Lattner349e9dd2006-03-10 05:51:05 +0000451 E = SU->Preds.end(); I != E; ++I)
Chris Lattner578d8fc2006-03-11 22:24:20 +0000452 if (!I->first->isScheduled) {
Chris Lattner349e9dd2006-03-10 05:51:05 +0000453 // We found an available, but not scheduled, predecessor. If it's the
454 // only one we have found, keep track of it... otherwise give up.
Chris Lattner578d8fc2006-03-11 22:24:20 +0000455 if (OnlyAvailablePred && OnlyAvailablePred != I->first)
Chris Lattner349e9dd2006-03-10 05:51:05 +0000456 return 0;
Chris Lattner578d8fc2006-03-11 22:24:20 +0000457 OnlyAvailablePred = I->first;
Chris Lattner349e9dd2006-03-10 05:51:05 +0000458 }
459
460 return OnlyAvailablePred;
461}
462
463void LatencyPriorityQueue::push_impl(SUnit *SU) {
464 // Look at all of the successors of this node. Count the number of nodes that
465 // this node is the sole unscheduled node for.
466 unsigned NumNodesBlocking = 0;
Chris Lattner578d8fc2006-03-11 22:24:20 +0000467 for (std::set<std::pair<SUnit*, bool> >::const_iterator I = SU->Succs.begin(),
Chris Lattner349e9dd2006-03-10 05:51:05 +0000468 E = SU->Succs.end(); I != E; ++I)
Chris Lattner578d8fc2006-03-11 22:24:20 +0000469 if (getSingleUnscheduledPred(I->first) == SU)
Chris Lattner349e9dd2006-03-10 05:51:05 +0000470 ++NumNodesBlocking;
Chris Lattner578d8fc2006-03-11 22:24:20 +0000471 NumNodesSolelyBlocking[SU->NodeNum] = NumNodesBlocking;
Chris Lattner349e9dd2006-03-10 05:51:05 +0000472
473 Queue.push(SU);
474}
475
476
477// ScheduledNode - As nodes are scheduled, we look to see if there are any
478// successor nodes that have a single unscheduled predecessor. If so, that
479// single predecessor has a higher priority, since scheduling it will make
480// the node available.
481void LatencyPriorityQueue::ScheduledNode(SUnit *SU) {
Chris Lattner578d8fc2006-03-11 22:24:20 +0000482 for (std::set<std::pair<SUnit*, bool> >::const_iterator I = SU->Succs.begin(),
Chris Lattner349e9dd2006-03-10 05:51:05 +0000483 E = SU->Succs.end(); I != E; ++I)
Chris Lattner578d8fc2006-03-11 22:24:20 +0000484 AdjustPriorityOfUnscheduledPreds(I->first);
Chris Lattner349e9dd2006-03-10 05:51:05 +0000485}
486
487/// AdjustPriorityOfUnscheduledPreds - One of the predecessors of SU was just
488/// scheduled. If SU is not itself available, then there is at least one
489/// predecessor node that has not been scheduled yet. If SU has exactly ONE
490/// unscheduled predecessor, we want to increase its priority: it getting
491/// scheduled will make this node available, so it is better than some other
492/// node of the same priority that will not make a node available.
493void LatencyPriorityQueue::AdjustPriorityOfUnscheduledPreds(SUnit *SU) {
Chris Lattner572003c2006-03-12 00:38:57 +0000494 if (SU->isPending) return; // All preds scheduled.
Chris Lattner349e9dd2006-03-10 05:51:05 +0000495
496 SUnit *OnlyAvailablePred = getSingleUnscheduledPred(SU);
497 if (OnlyAvailablePred == 0 || !OnlyAvailablePred->isAvailable) return;
498
499 // Okay, we found a single predecessor that is available, but not scheduled.
500 // Since it is available, it must be in the priority queue. First remove it.
501 RemoveFromPriorityQueue(OnlyAvailablePred);
502
503 // Reinsert the node into the priority queue, which recomputes its
504 // NumNodesSolelyBlocking value.
505 push(OnlyAvailablePred);
506}
507
Chris Lattner9df64752006-03-09 06:35:14 +0000508
509//===----------------------------------------------------------------------===//
510// Public Constructor Functions
511//===----------------------------------------------------------------------===//
512
Chris Lattner47639db2006-03-06 00:22:00 +0000513/// createTDListDAGScheduler - This creates a top-down list scheduler with the
514/// specified hazard recognizer.
515ScheduleDAG* llvm::createTDListDAGScheduler(SelectionDAG &DAG,
516 MachineBasicBlock *BB,
Chris Lattner543832d2006-03-08 04:25:59 +0000517 HazardRecognizer *HR) {
Evan Chengd38c22b2006-05-11 23:55:42 +0000518 return new ScheduleDAGList(DAG, BB, DAG.getTarget(),
Chris Lattner6398c132006-03-09 07:38:27 +0000519 new LatencyPriorityQueue(),
Chris Lattner9df64752006-03-09 06:35:14 +0000520 HR);
Evan Cheng31272342006-01-23 08:26:10 +0000521}