blob: e9c41c2be4fa5c651482252c7cf4521cf898baef [file] [log] [blame]
Evan Chenga9c20912006-01-21 02:32:06 +00001//===-- ScheduleDAGSimple.cpp - Implement a trivial DAG scheduler ---------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file was developed by James M. Laskey and is distributed under the
6// University of Illinois Open Source License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This implements a simple two pass scheduler. The first pass attempts to push
11// backward any lengthy instructions and critical paths. The second pass packs
12// instructions into semi-optimal time slots.
13//
14//===----------------------------------------------------------------------===//
15
16#define DEBUG_TYPE "sched"
17#include "llvm/CodeGen/ScheduleDAG.h"
18#include "llvm/CodeGen/SelectionDAG.h"
19#include "llvm/Target/TargetMachine.h"
20#include "llvm/Target/TargetInstrInfo.h"
Evan Chenga9c20912006-01-21 02:32:06 +000021#include "llvm/Support/Debug.h"
Evan Chenga9c20912006-01-21 02:32:06 +000022using namespace llvm;
23
24namespace {
Evan Chenga9c20912006-01-21 02:32:06 +000025//===----------------------------------------------------------------------===//
26///
27/// BitsIterator - Provides iteration through individual bits in a bit vector.
28///
29template<class T>
30class BitsIterator {
31private:
32 T Bits; // Bits left to iterate through
33
34public:
35 /// Ctor.
36 BitsIterator(T Initial) : Bits(Initial) {}
37
38 /// Next - Returns the next bit set or zero if exhausted.
39 inline T Next() {
40 // Get the rightmost bit set
41 T Result = Bits & -Bits;
42 // Remove from rest
43 Bits &= ~Result;
44 // Return single bit or zero
45 return Result;
46 }
47};
48
49//===----------------------------------------------------------------------===//
50
51
52//===----------------------------------------------------------------------===//
53///
54/// ResourceTally - Manages the use of resources over time intervals. Each
55/// item (slot) in the tally vector represents the resources used at a given
56/// moment. A bit set to 1 indicates that a resource is in use, otherwise
57/// available. An assumption is made that the tally is large enough to schedule
58/// all current instructions (asserts otherwise.)
59///
60template<class T>
61class ResourceTally {
62private:
63 std::vector<T> Tally; // Resources used per slot
64 typedef typename std::vector<T>::iterator Iter;
65 // Tally iterator
66
67 /// SlotsAvailable - Returns true if all units are available.
68 ///
69 bool SlotsAvailable(Iter Begin, unsigned N, unsigned ResourceSet,
70 unsigned &Resource) {
71 assert(N && "Must check availability with N != 0");
72 // Determine end of interval
73 Iter End = Begin + N;
74 assert(End <= Tally.end() && "Tally is not large enough for schedule");
75
76 // Iterate thru each resource
77 BitsIterator<T> Resources(ResourceSet & ~*Begin);
78 while (unsigned Res = Resources.Next()) {
79 // Check if resource is available for next N slots
80 Iter Interval = End;
81 do {
82 Interval--;
83 if (*Interval & Res) break;
84 } while (Interval != Begin);
85
86 // If available for N
87 if (Interval == Begin) {
88 // Success
89 Resource = Res;
90 return true;
91 }
92 }
93
94 // No luck
95 Resource = 0;
96 return false;
97 }
98
99 /// RetrySlot - Finds a good candidate slot to retry search.
100 Iter RetrySlot(Iter Begin, unsigned N, unsigned ResourceSet) {
101 assert(N && "Must check availability with N != 0");
102 // Determine end of interval
103 Iter End = Begin + N;
104 assert(End <= Tally.end() && "Tally is not large enough for schedule");
105
106 while (Begin != End--) {
107 // Clear units in use
108 ResourceSet &= ~*End;
109 // If no units left then we should go no further
110 if (!ResourceSet) return End + 1;
111 }
112 // Made it all the way through
113 return Begin;
114 }
115
116 /// FindAndReserveStages - Return true if the stages can be completed. If
117 /// so mark as busy.
118 bool FindAndReserveStages(Iter Begin,
119 InstrStage *Stage, InstrStage *StageEnd) {
120 // If at last stage then we're done
121 if (Stage == StageEnd) return true;
122 // Get number of cycles for current stage
123 unsigned N = Stage->Cycles;
124 // Check to see if N slots are available, if not fail
125 unsigned Resource;
126 if (!SlotsAvailable(Begin, N, Stage->Units, Resource)) return false;
127 // Check to see if remaining stages are available, if not fail
128 if (!FindAndReserveStages(Begin + N, Stage + 1, StageEnd)) return false;
129 // Reserve resource
130 Reserve(Begin, N, Resource);
131 // Success
132 return true;
133 }
134
135 /// Reserve - Mark busy (set) the specified N slots.
136 void Reserve(Iter Begin, unsigned N, unsigned Resource) {
137 // Determine end of interval
138 Iter End = Begin + N;
139 assert(End <= Tally.end() && "Tally is not large enough for schedule");
140
141 // Set resource bit in each slot
142 for (; Begin < End; Begin++)
143 *Begin |= Resource;
144 }
145
146 /// FindSlots - Starting from Begin, locate consecutive slots where all stages
147 /// can be completed. Returns the address of first slot.
148 Iter FindSlots(Iter Begin, InstrStage *StageBegin, InstrStage *StageEnd) {
149 // Track position
150 Iter Cursor = Begin;
151
152 // Try all possible slots forward
153 while (true) {
154 // Try at cursor, if successful return position.
155 if (FindAndReserveStages(Cursor, StageBegin, StageEnd)) return Cursor;
156 // Locate a better position
157 Cursor = RetrySlot(Cursor + 1, StageBegin->Cycles, StageBegin->Units);
158 }
159 }
160
161public:
162 /// Initialize - Resize and zero the tally to the specified number of time
163 /// slots.
164 inline void Initialize(unsigned N) {
165 Tally.assign(N, 0); // Initialize tally to all zeros.
166 }
167
168 // FindAndReserve - Locate an ideal slot for the specified stages and mark
169 // as busy.
170 unsigned FindAndReserve(unsigned Slot, InstrStage *StageBegin,
171 InstrStage *StageEnd) {
172 // Where to begin
173 Iter Begin = Tally.begin() + Slot;
174 // Find a free slot
175 Iter Where = FindSlots(Begin, StageBegin, StageEnd);
176 // Distance is slot number
177 unsigned Final = Where - Tally.begin();
178 return Final;
179 }
180
181};
182
183//===----------------------------------------------------------------------===//
184///
185/// ScheduleDAGSimple - Simple two pass scheduler.
186///
187class ScheduleDAGSimple : public ScheduleDAG {
188private:
Evan Chenga9c20912006-01-21 02:32:06 +0000189 ResourceTally<unsigned> Tally; // Resource usage tally
190 unsigned NSlots; // Total latency
191 static const unsigned NotFound = ~0U; // Search marker
192
193public:
194
195 // Ctor.
Evan Cheng4ef10862006-01-23 07:01:07 +0000196 ScheduleDAGSimple(SchedHeuristics hstc, SelectionDAG &dag,
197 MachineBasicBlock *bb, const TargetMachine &tm)
198 : ScheduleDAG(hstc, dag, bb, tm), Tally(), NSlots(0) {
Evan Chenga9c20912006-01-21 02:32:06 +0000199 assert(&TII && "Target doesn't provide instr info?");
200 assert(&MRI && "Target doesn't provide register info?");
201 }
202
203 virtual ~ScheduleDAGSimple() {};
204
205private:
Evan Chenga9c20912006-01-21 02:32:06 +0000206 static bool isDefiner(NodeInfo *A, NodeInfo *B);
Evan Chenga9c20912006-01-21 02:32:06 +0000207 void IncludeNode(NodeInfo *NI);
208 void VisitAll();
209 void Schedule();
Evan Chenga9c20912006-01-21 02:32:06 +0000210 void GatherSchedulingInfo();
211 void FakeGroupDominators();
Evan Chenga9c20912006-01-21 02:32:06 +0000212 bool isStrongDependency(NodeInfo *A, NodeInfo *B);
213 bool isWeakDependency(NodeInfo *A, NodeInfo *B);
214 void ScheduleBackward();
215 void ScheduleForward();
Evan Chenga9c20912006-01-21 02:32:06 +0000216};
217
Evan Chenga9c20912006-01-21 02:32:06 +0000218//===----------------------------------------------------------------------===//
219/// Special case itineraries.
220///
221enum {
222 CallLatency = 40, // To push calls back in time
223
224 RSInteger = 0xC0000000, // Two integer units
225 RSFloat = 0x30000000, // Two float units
226 RSLoadStore = 0x0C000000, // Two load store units
227 RSBranch = 0x02000000 // One branch unit
228};
229static InstrStage CallStage = { CallLatency, RSBranch };
230static InstrStage LoadStage = { 5, RSLoadStore };
231static InstrStage StoreStage = { 2, RSLoadStore };
232static InstrStage IntStage = { 2, RSInteger };
233static InstrStage FloatStage = { 3, RSFloat };
234//===----------------------------------------------------------------------===//
235
Evan Chenga9c20912006-01-21 02:32:06 +0000236} // namespace
237
238//===----------------------------------------------------------------------===//
239
240
241//===----------------------------------------------------------------------===//
Evan Chenga9c20912006-01-21 02:32:06 +0000242/// isDefiner - Return true if node A is a definer for B.
243///
244bool ScheduleDAGSimple::isDefiner(NodeInfo *A, NodeInfo *B) {
245 // While there are A nodes
246 NodeGroupIterator NII(A);
247 while (NodeInfo *NI = NII.next()) {
248 // Extract node
249 SDNode *Node = NI->Node;
250 // While there operands in nodes of B
251 NodeGroupOpIterator NGOI(B);
252 while (!NGOI.isEnd()) {
253 SDOperand Op = NGOI.next();
254 // If node from A defines a node in B
255 if (Node == Op.Val) return true;
256 }
257 }
258 return false;
259}
260
Evan Chenga9c20912006-01-21 02:32:06 +0000261/// IncludeNode - Add node to NodeInfo vector.
262///
263void ScheduleDAGSimple::IncludeNode(NodeInfo *NI) {
264 // Get node
265 SDNode *Node = NI->Node;
266 // Ignore entry node
267 if (Node->getOpcode() == ISD::EntryToken) return;
268 // Check current count for node
269 int Count = NI->getPending();
270 // If the node is already in list
271 if (Count < 0) return;
272 // Decrement count to indicate a visit
273 Count--;
274 // If count has gone to zero then add node to list
275 if (!Count) {
276 // Add node
277 if (NI->isInGroup()) {
278 Ordering.push_back(NI->Group->getDominator());
279 } else {
280 Ordering.push_back(NI);
281 }
282 // indicate node has been added
283 Count--;
284 }
285 // Mark as visited with new count
286 NI->setPending(Count);
287}
288
Evan Chenga9c20912006-01-21 02:32:06 +0000289/// GatherSchedulingInfo - Get latency and resource information about each node.
290///
291void ScheduleDAGSimple::GatherSchedulingInfo() {
292 // Get instruction itineraries for the target
293 const InstrItineraryData InstrItins = TM.getInstrItineraryData();
294
295 // For each node
296 for (unsigned i = 0, N = NodeCount; i < N; i++) {
297 // Get node info
298 NodeInfo* NI = &Info[i];
299 SDNode *Node = NI->Node;
300
301 // If there are itineraries and it is a machine instruction
Evan Cheng4ef10862006-01-23 07:01:07 +0000302 if (InstrItins.isEmpty() || Heuristic == simpleNoItinScheduling) {
Evan Chenga9c20912006-01-21 02:32:06 +0000303 // If machine opcode
304 if (Node->isTargetOpcode()) {
305 // Get return type to guess which processing unit
306 MVT::ValueType VT = Node->getValueType(0);
307 // Get machine opcode
308 MachineOpCode TOpc = Node->getTargetOpcode();
309 NI->IsCall = TII->isCall(TOpc);
310 NI->IsLoad = TII->isLoad(TOpc);
311 NI->IsStore = TII->isStore(TOpc);
312
313 if (TII->isLoad(TOpc)) NI->StageBegin = &LoadStage;
314 else if (TII->isStore(TOpc)) NI->StageBegin = &StoreStage;
315 else if (MVT::isInteger(VT)) NI->StageBegin = &IntStage;
316 else if (MVT::isFloatingPoint(VT)) NI->StageBegin = &FloatStage;
317 if (NI->StageBegin) NI->StageEnd = NI->StageBegin + 1;
318 }
319 } else if (Node->isTargetOpcode()) {
320 // get machine opcode
321 MachineOpCode TOpc = Node->getTargetOpcode();
322 // Check to see if it is a call
323 NI->IsCall = TII->isCall(TOpc);
324 // Get itinerary stages for instruction
325 unsigned II = TII->getSchedClass(TOpc);
326 NI->StageBegin = InstrItins.begin(II);
327 NI->StageEnd = InstrItins.end(II);
328 }
329
330 // One slot for the instruction itself
331 NI->Latency = 1;
332
333 // Add long latency for a call to push it back in time
334 if (NI->IsCall) NI->Latency += CallLatency;
335
336 // Sum up all the latencies
337 for (InstrStage *Stage = NI->StageBegin, *E = NI->StageEnd;
338 Stage != E; Stage++) {
339 NI->Latency += Stage->Cycles;
340 }
341
342 // Sum up all the latencies for max tally size
343 NSlots += NI->Latency;
344 }
345
346 // Unify metrics if in a group
347 if (HasGroups) {
348 for (unsigned i = 0, N = NodeCount; i < N; i++) {
349 NodeInfo* NI = &Info[i];
350
351 if (NI->isInGroup()) {
352 NodeGroup *Group = NI->Group;
353
354 if (!Group->getDominator()) {
355 NIIterator NGI = Group->group_begin(), NGE = Group->group_end();
356 NodeInfo *Dominator = *NGI;
357 unsigned Latency = 0;
358
359 for (NGI++; NGI != NGE; NGI++) {
360 NodeInfo* NGNI = *NGI;
361 Latency += NGNI->Latency;
362 if (Dominator->Latency < NGNI->Latency) Dominator = NGNI;
363 }
364
365 Dominator->Latency = Latency;
366 Group->setDominator(Dominator);
367 }
368 }
369 }
370 }
371}
372
Evan Cheng4ef10862006-01-23 07:01:07 +0000373/// VisitAll - Visit each node breadth-wise to produce an initial ordering.
374/// Note that the ordering in the Nodes vector is reversed.
375void ScheduleDAGSimple::VisitAll() {
376 // Add first element to list
377 NodeInfo *NI = getNI(DAG.getRoot().Val);
378 if (NI->isInGroup()) {
379 Ordering.push_back(NI->Group->getDominator());
380 } else {
381 Ordering.push_back(NI);
382 }
383
384 // Iterate through all nodes that have been added
385 for (unsigned i = 0; i < Ordering.size(); i++) { // note: size() varies
386 // Visit all operands
387 NodeGroupOpIterator NGI(Ordering[i]);
388 while (!NGI.isEnd()) {
389 // Get next operand
390 SDOperand Op = NGI.next();
391 // Get node
392 SDNode *Node = Op.Val;
393 // Ignore passive nodes
394 if (isPassiveNode(Node)) continue;
395 // Check out node
396 IncludeNode(getNI(Node));
397 }
398 }
399
400 // Add entry node last (IncludeNode filters entry nodes)
401 if (DAG.getEntryNode().Val != DAG.getRoot().Val)
402 Ordering.push_back(getNI(DAG.getEntryNode().Val));
403
404 // Reverse the order
405 std::reverse(Ordering.begin(), Ordering.end());
406}
407
Evan Chenga9c20912006-01-21 02:32:06 +0000408/// FakeGroupDominators - Set dominators for non-scheduling.
409///
410void ScheduleDAGSimple::FakeGroupDominators() {
411 for (unsigned i = 0, N = NodeCount; i < N; i++) {
412 NodeInfo* NI = &Info[i];
413
414 if (NI->isInGroup()) {
415 NodeGroup *Group = NI->Group;
416
417 if (!Group->getDominator()) {
418 Group->setDominator(NI);
419 }
420 }
421 }
422}
423
Evan Chenga9c20912006-01-21 02:32:06 +0000424/// isStrongDependency - Return true if node A has results used by node B.
425/// I.E., B must wait for latency of A.
426bool ScheduleDAGSimple::isStrongDependency(NodeInfo *A, NodeInfo *B) {
427 // If A defines for B then it's a strong dependency or
428 // if a load follows a store (may be dependent but why take a chance.)
429 return isDefiner(A, B) || (A->IsStore && B->IsLoad);
430}
431
432/// isWeakDependency Return true if node A produces a result that will
433/// conflict with operands of B. It is assumed that we have called
434/// isStrongDependency prior.
435bool ScheduleDAGSimple::isWeakDependency(NodeInfo *A, NodeInfo *B) {
436 // TODO check for conflicting real registers and aliases
437#if 0 // FIXME - Since we are in SSA form and not checking register aliasing
438 return A->Node->getOpcode() == ISD::EntryToken || isStrongDependency(B, A);
439#else
440 return A->Node->getOpcode() == ISD::EntryToken;
441#endif
442}
443
444/// ScheduleBackward - Schedule instructions so that any long latency
445/// instructions and the critical path get pushed back in time. Time is run in
446/// reverse to allow code reuse of the Tally and eliminate the overhead of
447/// biasing every slot indices against NSlots.
448void ScheduleDAGSimple::ScheduleBackward() {
449 // Size and clear the resource tally
450 Tally.Initialize(NSlots);
451 // Get number of nodes to schedule
452 unsigned N = Ordering.size();
453
454 // For each node being scheduled
455 for (unsigned i = N; 0 < i--;) {
456 NodeInfo *NI = Ordering[i];
457 // Track insertion
458 unsigned Slot = NotFound;
459
460 // Compare against those previously scheduled nodes
461 unsigned j = i + 1;
462 for (; j < N; j++) {
463 // Get following instruction
464 NodeInfo *Other = Ordering[j];
465
466 // Check dependency against previously inserted nodes
467 if (isStrongDependency(NI, Other)) {
468 Slot = Other->Slot + Other->Latency;
469 break;
470 } else if (isWeakDependency(NI, Other)) {
471 Slot = Other->Slot;
472 break;
473 }
474 }
475
476 // If independent of others (or first entry)
477 if (Slot == NotFound) Slot = 0;
478
479#if 0 // FIXME - measure later
480 // Find a slot where the needed resources are available
481 if (NI->StageBegin != NI->StageEnd)
482 Slot = Tally.FindAndReserve(Slot, NI->StageBegin, NI->StageEnd);
483#endif
484
485 // Set node slot
486 NI->Slot = Slot;
487
488 // Insert sort based on slot
489 j = i + 1;
490 for (; j < N; j++) {
491 // Get following instruction
492 NodeInfo *Other = Ordering[j];
493 // Should we look further (remember slots are in reverse time)
494 if (Slot >= Other->Slot) break;
495 // Shuffle other into ordering
496 Ordering[j - 1] = Other;
497 }
498 // Insert node in proper slot
499 if (j != i + 1) Ordering[j - 1] = NI;
500 }
501}
502
503/// ScheduleForward - Schedule instructions to maximize packing.
504///
505void ScheduleDAGSimple::ScheduleForward() {
506 // Size and clear the resource tally
507 Tally.Initialize(NSlots);
508 // Get number of nodes to schedule
509 unsigned N = Ordering.size();
510
511 // For each node being scheduled
512 for (unsigned i = 0; i < N; i++) {
513 NodeInfo *NI = Ordering[i];
514 // Track insertion
515 unsigned Slot = NotFound;
516
517 // Compare against those previously scheduled nodes
518 unsigned j = i;
519 for (; 0 < j--;) {
520 // Get following instruction
521 NodeInfo *Other = Ordering[j];
522
523 // Check dependency against previously inserted nodes
524 if (isStrongDependency(Other, NI)) {
525 Slot = Other->Slot + Other->Latency;
526 break;
527 } else if (Other->IsCall || isWeakDependency(Other, NI)) {
528 Slot = Other->Slot;
529 break;
530 }
531 }
532
533 // If independent of others (or first entry)
534 if (Slot == NotFound) Slot = 0;
535
536 // Find a slot where the needed resources are available
537 if (NI->StageBegin != NI->StageEnd)
538 Slot = Tally.FindAndReserve(Slot, NI->StageBegin, NI->StageEnd);
539
540 // Set node slot
541 NI->Slot = Slot;
542
543 // Insert sort based on slot
544 j = i;
545 for (; 0 < j--;) {
546 // Get prior instruction
547 NodeInfo *Other = Ordering[j];
548 // Should we look further
549 if (Slot >= Other->Slot) break;
550 // Shuffle other into ordering
551 Ordering[j + 1] = Other;
552 }
553 // Insert node in proper slot
554 if (j != i) Ordering[j + 1] = NI;
555 }
556}
557
Evan Chenga9c20912006-01-21 02:32:06 +0000558/// Schedule - Order nodes according to selected style.
559///
560void ScheduleDAGSimple::Schedule() {
Evan Chenga9c20912006-01-21 02:32:06 +0000561 // Test to see if scheduling should occur
Evan Cheng4ef10862006-01-23 07:01:07 +0000562 bool ShouldSchedule = NodeCount > 3 && Heuristic != noScheduling;
Evan Chenga9c20912006-01-21 02:32:06 +0000563 // Don't waste time if is only entry and return
564 if (ShouldSchedule) {
565 // Get latency and resource requirements
566 GatherSchedulingInfo();
567 } else if (HasGroups) {
568 // Make sure all the groups have dominators
569 FakeGroupDominators();
570 }
571
572 // Breadth first walk of DAG
573 VisitAll();
574
575#ifndef NDEBUG
576 static unsigned Count = 0;
577 Count++;
578 for (unsigned i = 0, N = Ordering.size(); i < N; i++) {
579 NodeInfo *NI = Ordering[i];
580 NI->Preorder = i;
581 }
582#endif
583
584 // Don't waste time if is only entry and return
585 if (ShouldSchedule) {
586 // Push back long instructions and critical path
587 ScheduleBackward();
588
589 // Pack instructions to maximize resource utilization
590 ScheduleForward();
591 }
592
593 DEBUG(printChanges(Count));
594
595 // Emit in scheduled order
596 EmitAll();
597}
598
Evan Chenga9c20912006-01-21 02:32:06 +0000599
600/// createSimpleDAGScheduler - This creates a simple two pass instruction
601/// scheduler.
Evan Cheng4ef10862006-01-23 07:01:07 +0000602llvm::ScheduleDAG* llvm::createSimpleDAGScheduler(SchedHeuristics Heuristic,
603 SelectionDAG &DAG,
Evan Chenga9c20912006-01-21 02:32:06 +0000604 MachineBasicBlock *BB) {
Evan Cheng4ef10862006-01-23 07:01:07 +0000605 return new ScheduleDAGSimple(Heuristic, DAG, BB, DAG.getTarget());
Evan Chenga9c20912006-01-21 02:32:06 +0000606}