blob: 71bf3cc9d6d0e8adc82cfb151a1dfa9d1e5093c7 [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
Evan Cheng41484292006-01-23 08:25:34 +0000205 void Schedule();
206
Evan Chenga9c20912006-01-21 02:32:06 +0000207private:
Evan Chenga9c20912006-01-21 02:32:06 +0000208 static bool isDefiner(NodeInfo *A, NodeInfo *B);
Evan Chenga9c20912006-01-21 02:32:06 +0000209 void IncludeNode(NodeInfo *NI);
210 void VisitAll();
Evan Chenga9c20912006-01-21 02:32:06 +0000211 void GatherSchedulingInfo();
212 void FakeGroupDominators();
Evan Chenga9c20912006-01-21 02:32:06 +0000213 bool isStrongDependency(NodeInfo *A, NodeInfo *B);
214 bool isWeakDependency(NodeInfo *A, NodeInfo *B);
215 void ScheduleBackward();
216 void ScheduleForward();
Evan Chenga9c20912006-01-21 02:32:06 +0000217};
218
Evan Chenga9c20912006-01-21 02:32:06 +0000219//===----------------------------------------------------------------------===//
220/// Special case itineraries.
221///
222enum {
223 CallLatency = 40, // To push calls back in time
224
225 RSInteger = 0xC0000000, // Two integer units
226 RSFloat = 0x30000000, // Two float units
227 RSLoadStore = 0x0C000000, // Two load store units
228 RSBranch = 0x02000000 // One branch unit
229};
230static InstrStage CallStage = { CallLatency, RSBranch };
231static InstrStage LoadStage = { 5, RSLoadStore };
232static InstrStage StoreStage = { 2, RSLoadStore };
233static InstrStage IntStage = { 2, RSInteger };
234static InstrStage FloatStage = { 3, RSFloat };
235//===----------------------------------------------------------------------===//
236
Evan Chenga9c20912006-01-21 02:32:06 +0000237} // namespace
238
239//===----------------------------------------------------------------------===//
240
241
242//===----------------------------------------------------------------------===//
Evan Chenga9c20912006-01-21 02:32:06 +0000243/// isDefiner - Return true if node A is a definer for B.
244///
245bool ScheduleDAGSimple::isDefiner(NodeInfo *A, NodeInfo *B) {
246 // While there are A nodes
247 NodeGroupIterator NII(A);
248 while (NodeInfo *NI = NII.next()) {
249 // Extract node
250 SDNode *Node = NI->Node;
251 // While there operands in nodes of B
252 NodeGroupOpIterator NGOI(B);
253 while (!NGOI.isEnd()) {
254 SDOperand Op = NGOI.next();
255 // If node from A defines a node in B
256 if (Node == Op.Val) return true;
257 }
258 }
259 return false;
260}
261
Evan Chenga9c20912006-01-21 02:32:06 +0000262/// IncludeNode - Add node to NodeInfo vector.
263///
264void ScheduleDAGSimple::IncludeNode(NodeInfo *NI) {
265 // Get node
266 SDNode *Node = NI->Node;
267 // Ignore entry node
268 if (Node->getOpcode() == ISD::EntryToken) return;
269 // Check current count for node
270 int Count = NI->getPending();
271 // If the node is already in list
272 if (Count < 0) return;
273 // Decrement count to indicate a visit
274 Count--;
275 // If count has gone to zero then add node to list
276 if (!Count) {
277 // Add node
278 if (NI->isInGroup()) {
279 Ordering.push_back(NI->Group->getDominator());
280 } else {
281 Ordering.push_back(NI);
282 }
283 // indicate node has been added
284 Count--;
285 }
286 // Mark as visited with new count
287 NI->setPending(Count);
288}
289
Evan Chenga9c20912006-01-21 02:32:06 +0000290/// GatherSchedulingInfo - Get latency and resource information about each node.
291///
292void ScheduleDAGSimple::GatherSchedulingInfo() {
293 // Get instruction itineraries for the target
294 const InstrItineraryData InstrItins = TM.getInstrItineraryData();
295
296 // For each node
297 for (unsigned i = 0, N = NodeCount; i < N; i++) {
298 // Get node info
299 NodeInfo* NI = &Info[i];
300 SDNode *Node = NI->Node;
301
302 // If there are itineraries and it is a machine instruction
Evan Cheng4ef10862006-01-23 07:01:07 +0000303 if (InstrItins.isEmpty() || Heuristic == simpleNoItinScheduling) {
Evan Chenga9c20912006-01-21 02:32:06 +0000304 // If machine opcode
305 if (Node->isTargetOpcode()) {
306 // Get return type to guess which processing unit
307 MVT::ValueType VT = Node->getValueType(0);
308 // Get machine opcode
309 MachineOpCode TOpc = Node->getTargetOpcode();
310 NI->IsCall = TII->isCall(TOpc);
311 NI->IsLoad = TII->isLoad(TOpc);
312 NI->IsStore = TII->isStore(TOpc);
313
314 if (TII->isLoad(TOpc)) NI->StageBegin = &LoadStage;
315 else if (TII->isStore(TOpc)) NI->StageBegin = &StoreStage;
316 else if (MVT::isInteger(VT)) NI->StageBegin = &IntStage;
317 else if (MVT::isFloatingPoint(VT)) NI->StageBegin = &FloatStage;
318 if (NI->StageBegin) NI->StageEnd = NI->StageBegin + 1;
319 }
320 } else if (Node->isTargetOpcode()) {
321 // get machine opcode
322 MachineOpCode TOpc = Node->getTargetOpcode();
323 // Check to see if it is a call
324 NI->IsCall = TII->isCall(TOpc);
325 // Get itinerary stages for instruction
326 unsigned II = TII->getSchedClass(TOpc);
327 NI->StageBegin = InstrItins.begin(II);
328 NI->StageEnd = InstrItins.end(II);
329 }
330
331 // One slot for the instruction itself
332 NI->Latency = 1;
333
334 // Add long latency for a call to push it back in time
335 if (NI->IsCall) NI->Latency += CallLatency;
336
337 // Sum up all the latencies
338 for (InstrStage *Stage = NI->StageBegin, *E = NI->StageEnd;
339 Stage != E; Stage++) {
340 NI->Latency += Stage->Cycles;
341 }
342
343 // Sum up all the latencies for max tally size
344 NSlots += NI->Latency;
345 }
346
347 // Unify metrics if in a group
348 if (HasGroups) {
349 for (unsigned i = 0, N = NodeCount; i < N; i++) {
350 NodeInfo* NI = &Info[i];
351
352 if (NI->isInGroup()) {
353 NodeGroup *Group = NI->Group;
354
355 if (!Group->getDominator()) {
356 NIIterator NGI = Group->group_begin(), NGE = Group->group_end();
357 NodeInfo *Dominator = *NGI;
358 unsigned Latency = 0;
359
360 for (NGI++; NGI != NGE; NGI++) {
361 NodeInfo* NGNI = *NGI;
362 Latency += NGNI->Latency;
363 if (Dominator->Latency < NGNI->Latency) Dominator = NGNI;
364 }
365
366 Dominator->Latency = Latency;
367 Group->setDominator(Dominator);
368 }
369 }
370 }
371 }
372}
373
Evan Cheng4ef10862006-01-23 07:01:07 +0000374/// VisitAll - Visit each node breadth-wise to produce an initial ordering.
375/// Note that the ordering in the Nodes vector is reversed.
376void ScheduleDAGSimple::VisitAll() {
377 // Add first element to list
378 NodeInfo *NI = getNI(DAG.getRoot().Val);
379 if (NI->isInGroup()) {
380 Ordering.push_back(NI->Group->getDominator());
381 } else {
382 Ordering.push_back(NI);
383 }
384
385 // Iterate through all nodes that have been added
386 for (unsigned i = 0; i < Ordering.size(); i++) { // note: size() varies
387 // Visit all operands
388 NodeGroupOpIterator NGI(Ordering[i]);
389 while (!NGI.isEnd()) {
390 // Get next operand
391 SDOperand Op = NGI.next();
392 // Get node
393 SDNode *Node = Op.Val;
394 // Ignore passive nodes
395 if (isPassiveNode(Node)) continue;
396 // Check out node
397 IncludeNode(getNI(Node));
398 }
399 }
400
401 // Add entry node last (IncludeNode filters entry nodes)
402 if (DAG.getEntryNode().Val != DAG.getRoot().Val)
403 Ordering.push_back(getNI(DAG.getEntryNode().Val));
404
405 // Reverse the order
406 std::reverse(Ordering.begin(), Ordering.end());
407}
408
Evan Chenga9c20912006-01-21 02:32:06 +0000409/// FakeGroupDominators - Set dominators for non-scheduling.
410///
411void ScheduleDAGSimple::FakeGroupDominators() {
412 for (unsigned i = 0, N = NodeCount; i < N; i++) {
413 NodeInfo* NI = &Info[i];
414
415 if (NI->isInGroup()) {
416 NodeGroup *Group = NI->Group;
417
418 if (!Group->getDominator()) {
419 Group->setDominator(NI);
420 }
421 }
422 }
423}
424
Evan Chenga9c20912006-01-21 02:32:06 +0000425/// isStrongDependency - Return true if node A has results used by node B.
426/// I.E., B must wait for latency of A.
427bool ScheduleDAGSimple::isStrongDependency(NodeInfo *A, NodeInfo *B) {
428 // If A defines for B then it's a strong dependency or
429 // if a load follows a store (may be dependent but why take a chance.)
430 return isDefiner(A, B) || (A->IsStore && B->IsLoad);
431}
432
433/// isWeakDependency Return true if node A produces a result that will
434/// conflict with operands of B. It is assumed that we have called
435/// isStrongDependency prior.
436bool ScheduleDAGSimple::isWeakDependency(NodeInfo *A, NodeInfo *B) {
437 // TODO check for conflicting real registers and aliases
438#if 0 // FIXME - Since we are in SSA form and not checking register aliasing
439 return A->Node->getOpcode() == ISD::EntryToken || isStrongDependency(B, A);
440#else
441 return A->Node->getOpcode() == ISD::EntryToken;
442#endif
443}
444
445/// ScheduleBackward - Schedule instructions so that any long latency
446/// instructions and the critical path get pushed back in time. Time is run in
447/// reverse to allow code reuse of the Tally and eliminate the overhead of
448/// biasing every slot indices against NSlots.
449void ScheduleDAGSimple::ScheduleBackward() {
450 // Size and clear the resource tally
451 Tally.Initialize(NSlots);
452 // Get number of nodes to schedule
453 unsigned N = Ordering.size();
454
455 // For each node being scheduled
456 for (unsigned i = N; 0 < i--;) {
457 NodeInfo *NI = Ordering[i];
458 // Track insertion
459 unsigned Slot = NotFound;
460
461 // Compare against those previously scheduled nodes
462 unsigned j = i + 1;
463 for (; j < N; j++) {
464 // Get following instruction
465 NodeInfo *Other = Ordering[j];
466
467 // Check dependency against previously inserted nodes
468 if (isStrongDependency(NI, Other)) {
469 Slot = Other->Slot + Other->Latency;
470 break;
471 } else if (isWeakDependency(NI, Other)) {
472 Slot = Other->Slot;
473 break;
474 }
475 }
476
477 // If independent of others (or first entry)
478 if (Slot == NotFound) Slot = 0;
479
480#if 0 // FIXME - measure later
481 // Find a slot where the needed resources are available
482 if (NI->StageBegin != NI->StageEnd)
483 Slot = Tally.FindAndReserve(Slot, NI->StageBegin, NI->StageEnd);
484#endif
485
486 // Set node slot
487 NI->Slot = Slot;
488
489 // Insert sort based on slot
490 j = i + 1;
491 for (; j < N; j++) {
492 // Get following instruction
493 NodeInfo *Other = Ordering[j];
494 // Should we look further (remember slots are in reverse time)
495 if (Slot >= Other->Slot) break;
496 // Shuffle other into ordering
497 Ordering[j - 1] = Other;
498 }
499 // Insert node in proper slot
500 if (j != i + 1) Ordering[j - 1] = NI;
501 }
502}
503
504/// ScheduleForward - Schedule instructions to maximize packing.
505///
506void ScheduleDAGSimple::ScheduleForward() {
507 // Size and clear the resource tally
508 Tally.Initialize(NSlots);
509 // Get number of nodes to schedule
510 unsigned N = Ordering.size();
511
512 // For each node being scheduled
513 for (unsigned i = 0; i < N; i++) {
514 NodeInfo *NI = Ordering[i];
515 // Track insertion
516 unsigned Slot = NotFound;
517
518 // Compare against those previously scheduled nodes
519 unsigned j = i;
520 for (; 0 < j--;) {
521 // Get following instruction
522 NodeInfo *Other = Ordering[j];
523
524 // Check dependency against previously inserted nodes
525 if (isStrongDependency(Other, NI)) {
526 Slot = Other->Slot + Other->Latency;
527 break;
528 } else if (Other->IsCall || isWeakDependency(Other, NI)) {
529 Slot = Other->Slot;
530 break;
531 }
532 }
533
534 // If independent of others (or first entry)
535 if (Slot == NotFound) Slot = 0;
536
537 // Find a slot where the needed resources are available
538 if (NI->StageBegin != NI->StageEnd)
539 Slot = Tally.FindAndReserve(Slot, NI->StageBegin, NI->StageEnd);
540
541 // Set node slot
542 NI->Slot = Slot;
543
544 // Insert sort based on slot
545 j = i;
546 for (; 0 < j--;) {
547 // Get prior instruction
548 NodeInfo *Other = Ordering[j];
549 // Should we look further
550 if (Slot >= Other->Slot) break;
551 // Shuffle other into ordering
552 Ordering[j + 1] = Other;
553 }
554 // Insert node in proper slot
555 if (j != i) Ordering[j + 1] = NI;
556 }
557}
558
Evan Chenga9c20912006-01-21 02:32:06 +0000559/// Schedule - Order nodes according to selected style.
560///
561void ScheduleDAGSimple::Schedule() {
Evan Chenga9c20912006-01-21 02:32:06 +0000562 // Test to see if scheduling should occur
Evan Cheng4ef10862006-01-23 07:01:07 +0000563 bool ShouldSchedule = NodeCount > 3 && Heuristic != noScheduling;
Evan Chenga9c20912006-01-21 02:32:06 +0000564 // Don't waste time if is only entry and return
565 if (ShouldSchedule) {
566 // Get latency and resource requirements
567 GatherSchedulingInfo();
568 } else if (HasGroups) {
569 // Make sure all the groups have dominators
570 FakeGroupDominators();
571 }
572
573 // Breadth first walk of DAG
574 VisitAll();
575
576#ifndef NDEBUG
577 static unsigned Count = 0;
578 Count++;
579 for (unsigned i = 0, N = Ordering.size(); i < N; i++) {
580 NodeInfo *NI = Ordering[i];
581 NI->Preorder = i;
582 }
583#endif
584
585 // Don't waste time if is only entry and return
586 if (ShouldSchedule) {
587 // Push back long instructions and critical path
588 ScheduleBackward();
589
590 // Pack instructions to maximize resource utilization
591 ScheduleForward();
592 }
593
594 DEBUG(printChanges(Count));
595
596 // Emit in scheduled order
597 EmitAll();
598}
599
Evan Chenga9c20912006-01-21 02:32:06 +0000600
601/// createSimpleDAGScheduler - This creates a simple two pass instruction
602/// scheduler.
Evan Cheng4ef10862006-01-23 07:01:07 +0000603llvm::ScheduleDAG* llvm::createSimpleDAGScheduler(SchedHeuristics Heuristic,
604 SelectionDAG &DAG,
Evan Chenga9c20912006-01-21 02:32:06 +0000605 MachineBasicBlock *BB) {
Evan Cheng4ef10862006-01-23 07:01:07 +0000606 return new ScheduleDAGSimple(Heuristic, DAG, BB, DAG.getTarget());
Evan Chenga9c20912006-01-21 02:32:06 +0000607}