1 //===-- ScheduleDAGSimple.cpp - Implement a trivial DAG scheduler ---------===//
3 // The LLVM Compiler Infrastructure
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.
8 //===----------------------------------------------------------------------===//
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.
14 //===----------------------------------------------------------------------===//
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"
21 #include "llvm/Support/Debug.h"
25 //===----------------------------------------------------------------------===//
27 /// BitsIterator - Provides iteration through individual bits in a bit vector.
32 T Bits; // Bits left to iterate through
36 BitsIterator(T Initial) : Bits(Initial) {}
38 /// Next - Returns the next bit set or zero if exhausted.
40 // Get the rightmost bit set
41 T Result = Bits & -Bits;
44 // Return single bit or zero
49 //===----------------------------------------------------------------------===//
52 //===----------------------------------------------------------------------===//
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.)
63 std::vector<T> Tally; // Resources used per slot
64 typedef typename std::vector<T>::iterator Iter;
67 /// SlotsAvailable - Returns true if all units are available.
69 bool SlotsAvailable(Iter Begin, unsigned N, unsigned ResourceSet,
71 assert(N && "Must check availability with N != 0");
72 // Determine end of interval
74 assert(End <= Tally.end() && "Tally is not large enough for schedule");
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
83 if (*Interval & Res) break;
84 } while (Interval != Begin);
87 if (Interval == Begin) {
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");
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;
112 // Made it all the way through
116 /// FindAndReserveStages - Return true if the stages can be completed. If
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
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;
130 Reserve(Begin, N, Resource);
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");
141 // Set resource bit in each slot
142 for (; Begin < End; Begin++)
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) {
152 // Try all possible slots forward
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);
162 /// Initialize - Resize and zero the tally to the specified number of time
164 inline void Initialize(unsigned N) {
165 Tally.assign(N, 0); // Initialize tally to all zeros.
168 // FindAndReserve - Locate an ideal slot for the specified stages and mark
170 unsigned FindAndReserve(unsigned Slot, InstrStage *StageBegin,
171 InstrStage *StageEnd) {
173 Iter Begin = Tally.begin() + Slot;
175 Iter Where = FindSlots(Begin, StageBegin, StageEnd);
176 // Distance is slot number
177 unsigned Final = Where - Tally.begin();
183 //===----------------------------------------------------------------------===//
185 /// ScheduleDAGSimple - Simple two pass scheduler.
187 class ScheduleDAGSimple : public ScheduleDAG {
189 ResourceTally<unsigned> Tally; // Resource usage tally
190 unsigned NSlots; // Total latency
191 static const unsigned NotFound = ~0U; // Search marker
196 ScheduleDAGSimple(SchedHeuristics hstc, SelectionDAG &dag,
197 MachineBasicBlock *bb, const TargetMachine &tm)
198 : ScheduleDAG(hstc, dag, bb, tm), Tally(), NSlots(0) {
199 assert(&TII && "Target doesn't provide instr info?");
200 assert(&MRI && "Target doesn't provide register info?");
203 virtual ~ScheduleDAGSimple() {};
206 static bool isDefiner(NodeInfo *A, NodeInfo *B);
207 void IncludeNode(NodeInfo *NI);
210 void GatherSchedulingInfo();
211 void FakeGroupDominators();
212 bool isStrongDependency(NodeInfo *A, NodeInfo *B);
213 bool isWeakDependency(NodeInfo *A, NodeInfo *B);
214 void ScheduleBackward();
215 void ScheduleForward();
218 //===----------------------------------------------------------------------===//
219 /// Special case itineraries.
222 CallLatency = 40, // To push calls back in time
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
229 static InstrStage CallStage = { CallLatency, RSBranch };
230 static InstrStage LoadStage = { 5, RSLoadStore };
231 static InstrStage StoreStage = { 2, RSLoadStore };
232 static InstrStage IntStage = { 2, RSInteger };
233 static InstrStage FloatStage = { 3, RSFloat };
234 //===----------------------------------------------------------------------===//
238 //===----------------------------------------------------------------------===//
241 //===----------------------------------------------------------------------===//
242 /// isDefiner - Return true if node A is a definer for B.
244 bool ScheduleDAGSimple::isDefiner(NodeInfo *A, NodeInfo *B) {
245 // While there are A nodes
246 NodeGroupIterator NII(A);
247 while (NodeInfo *NI = NII.next()) {
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;
261 /// IncludeNode - Add node to NodeInfo vector.
263 void ScheduleDAGSimple::IncludeNode(NodeInfo *NI) {
265 SDNode *Node = NI->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
274 // If count has gone to zero then add node to list
277 if (NI->isInGroup()) {
278 Ordering.push_back(NI->Group->getDominator());
280 Ordering.push_back(NI);
282 // indicate node has been added
285 // Mark as visited with new count
286 NI->setPending(Count);
289 /// GatherSchedulingInfo - Get latency and resource information about each node.
291 void ScheduleDAGSimple::GatherSchedulingInfo() {
292 // Get instruction itineraries for the target
293 const InstrItineraryData InstrItins = TM.getInstrItineraryData();
296 for (unsigned i = 0, N = NodeCount; i < N; i++) {
298 NodeInfo* NI = &Info[i];
299 SDNode *Node = NI->Node;
301 // If there are itineraries and it is a machine instruction
302 if (InstrItins.isEmpty() || Heuristic == simpleNoItinScheduling) {
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);
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;
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);
330 // One slot for the instruction itself
333 // Add long latency for a call to push it back in time
334 if (NI->IsCall) NI->Latency += CallLatency;
336 // Sum up all the latencies
337 for (InstrStage *Stage = NI->StageBegin, *E = NI->StageEnd;
338 Stage != E; Stage++) {
339 NI->Latency += Stage->Cycles;
342 // Sum up all the latencies for max tally size
343 NSlots += NI->Latency;
346 // Unify metrics if in a group
348 for (unsigned i = 0, N = NodeCount; i < N; i++) {
349 NodeInfo* NI = &Info[i];
351 if (NI->isInGroup()) {
352 NodeGroup *Group = NI->Group;
354 if (!Group->getDominator()) {
355 NIIterator NGI = Group->group_begin(), NGE = Group->group_end();
356 NodeInfo *Dominator = *NGI;
357 unsigned Latency = 0;
359 for (NGI++; NGI != NGE; NGI++) {
360 NodeInfo* NGNI = *NGI;
361 Latency += NGNI->Latency;
362 if (Dominator->Latency < NGNI->Latency) Dominator = NGNI;
365 Dominator->Latency = Latency;
366 Group->setDominator(Dominator);
373 /// VisitAll - Visit each node breadth-wise to produce an initial ordering.
374 /// Note that the ordering in the Nodes vector is reversed.
375 void 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());
381 Ordering.push_back(NI);
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()) {
390 SDOperand Op = NGI.next();
392 SDNode *Node = Op.Val;
393 // Ignore passive nodes
394 if (isPassiveNode(Node)) continue;
396 IncludeNode(getNI(Node));
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));
405 std::reverse(Ordering.begin(), Ordering.end());
408 /// FakeGroupDominators - Set dominators for non-scheduling.
410 void ScheduleDAGSimple::FakeGroupDominators() {
411 for (unsigned i = 0, N = NodeCount; i < N; i++) {
412 NodeInfo* NI = &Info[i];
414 if (NI->isInGroup()) {
415 NodeGroup *Group = NI->Group;
417 if (!Group->getDominator()) {
418 Group->setDominator(NI);
424 /// isStrongDependency - Return true if node A has results used by node B.
425 /// I.E., B must wait for latency of A.
426 bool 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);
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.
435 bool 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);
440 return A->Node->getOpcode() == ISD::EntryToken;
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.
448 void 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();
454 // For each node being scheduled
455 for (unsigned i = N; 0 < i--;) {
456 NodeInfo *NI = Ordering[i];
458 unsigned Slot = NotFound;
460 // Compare against those previously scheduled nodes
463 // Get following instruction
464 NodeInfo *Other = Ordering[j];
466 // Check dependency against previously inserted nodes
467 if (isStrongDependency(NI, Other)) {
468 Slot = Other->Slot + Other->Latency;
470 } else if (isWeakDependency(NI, Other)) {
476 // If independent of others (or first entry)
477 if (Slot == NotFound) Slot = 0;
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);
488 // Insert sort based on slot
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;
498 // Insert node in proper slot
499 if (j != i + 1) Ordering[j - 1] = NI;
503 /// ScheduleForward - Schedule instructions to maximize packing.
505 void 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();
511 // For each node being scheduled
512 for (unsigned i = 0; i < N; i++) {
513 NodeInfo *NI = Ordering[i];
515 unsigned Slot = NotFound;
517 // Compare against those previously scheduled nodes
520 // Get following instruction
521 NodeInfo *Other = Ordering[j];
523 // Check dependency against previously inserted nodes
524 if (isStrongDependency(Other, NI)) {
525 Slot = Other->Slot + Other->Latency;
527 } else if (Other->IsCall || isWeakDependency(Other, NI)) {
533 // If independent of others (or first entry)
534 if (Slot == NotFound) Slot = 0;
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);
543 // Insert sort based on slot
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;
553 // Insert node in proper slot
554 if (j != i) Ordering[j + 1] = NI;
558 /// Schedule - Order nodes according to selected style.
560 void ScheduleDAGSimple::Schedule() {
561 // Test to see if scheduling should occur
562 bool ShouldSchedule = NodeCount > 3 && Heuristic != noScheduling;
563 // 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();
572 // Breadth first walk of DAG
576 static unsigned Count = 0;
578 for (unsigned i = 0, N = Ordering.size(); i < N; i++) {
579 NodeInfo *NI = Ordering[i];
584 // Don't waste time if is only entry and return
585 if (ShouldSchedule) {
586 // Push back long instructions and critical path
589 // Pack instructions to maximize resource utilization
593 DEBUG(printChanges(Count));
595 // Emit in scheduled order
600 /// createSimpleDAGScheduler - This creates a simple two pass instruction
602 llvm::ScheduleDAG* llvm::createSimpleDAGScheduler(SchedHeuristics Heuristic,
604 MachineBasicBlock *BB) {
605 return new ScheduleDAGSimple(Heuristic, DAG, BB, DAG.getTarget());