LLVM: lib/CodeGen/ScheduleDAG.cpp Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
24#include "llvm/Config/llvm-config.h"
29#include
30#include
31#include
32#include
33#include
34#include
35
36using namespace llvm;
37
38#define DEBUG_TYPE "pre-RA-sched"
39
40STATISTIC(NumNewPredsAdded, "Number of times a single predecessor was added");
42 "Number of times the topological order has been recomputed");
43
44#ifndef NDEBUG
47 cl::desc("Stress test instruction scheduling"));
48#endif
49
50void SchedulingPriorityQueue::anchor() {}
51
53 : TM(mf.getTarget()), TII(mf.getSubtarget().getInstrInfo()),
54 TRI(mf.getSubtarget().getRegisterInfo()), MF(mf),
55 MRI(mf.getRegInfo()) {
56#ifndef NDEBUG
58#endif
59}
60
62
68
70 if ( ||
->isMachineOpcode()) return nullptr;
71 return &TII->get(Node->getMachineOpcode());
72}
73
76 case Data: dbgs() << "Data"; break;
77 case Anti: dbgs() << "Anti"; break;
79 case Order: dbgs() << "Ord "; break;
80 }
81
87 break;
91 break;
94 switch(Contents.OrdKind) {
95 case Barrier: dbgs() << " Barrier"; break;
99 case Weak: dbgs() << " Weak"; break;
100 case Cluster: dbgs() << " Cluster"; break;
101 }
102 break;
103 }
104}
105
107
109
110
111 if ( && PredDep.getSUnit() == D.getSUnit())
112 return false;
113 if (PredDep.overlaps(D)) {
114
115
116 if (PredDep.getLatency() < D.getLatency()) {
117 SUnit *PredSU = PredDep.getSUnit();
118
119 SDep ForwardD = PredDep;
121 for (SDep &SuccDep : PredSU->Succs) {
122 if (SuccDep == ForwardD) {
124 break;
125 }
126 }
127 PredDep.setLatency(D.getLatency());
128
131 }
132 return false;
133 }
134 }
135
137 P.setSUnit(this);
139
141 assert(NumPreds < std::numeric_limits::max() &&
142 "NumPreds will overflow!");
143 assert(N->NumSuccs < std::numeric_limits::max() &&
144 "NumSuccs will overflow!");
146 ++N->NumSuccs;
147 }
148 if (->isScheduled) {
149 if (D.isWeak()) {
151 }
152 else {
154 "NumPredsLeft will overflow!");
156 }
157 }
159 if (D.isWeak()) {
160 ++N->WeakSuccsLeft;
161 }
162 else {
163 assert(N->NumSuccsLeft < std::numeric_limits::max() &&
164 "NumSuccsLeft will overflow!");
165 ++N->NumSuccsLeft;
166 }
167 }
172 return true;
173}
174
176
179 return;
180
182 P.setSUnit(this);
185 assert(Succ != N->Succs.end() && "Mismatching preds / succs lists!");
186
189 assert(N->NumSuccs > 0 && "NumSuccs will underflow!");
191 --N->NumSuccs;
192 }
193 if (->isScheduled) {
194 if (D.isWeak()) {
197 } else {
200 }
201 }
203 if (D.isWeak()) {
204 assert(N->WeakSuccsLeft > 0 && "WeakSuccsLeft will underflow!");
205 --N->WeakSuccsLeft;
206 } else {
207 assert(N->NumSuccsLeft > 0 && "NumSuccsLeft will underflow!");
208 --N->NumSuccsLeft;
209 }
210 }
211 N->Succs.erase(Succ);
215}
216
218 if (!isDepthCurrent) return;
221 do {
223 SU->isDepthCurrent = false;
224 for (SDep &SuccDep : SU->Succs) {
226 if (SuccSU->isDepthCurrent)
228 }
229 } while (!WorkList.empty());
230}
231
233 if (!isHeightCurrent) return;
236 do {
238 SU->isHeightCurrent = false;
239 for (SDep &PredDep : SU->Preds) {
241 if (PredSU->isHeightCurrent)
243 }
244 } while (!WorkList.empty());
245}
246
249 return;
251 Depth = NewDepth;
252 isDepthCurrent = true;
253}
254
257 return;
259 Height = NewHeight;
260 isHeightCurrent = true;
261}
262
263
264void SUnit::ComputeDepth() {
267 do {
269
270 bool Done = true;
271 unsigned MaxPredDepth = 0;
272 for (const SDep &PredDep : Cur->Preds) {
274 if (PredSU->isDepthCurrent)
275 MaxPredDepth = std::max(MaxPredDepth,
276 PredSU->Depth + PredDep.getLatency());
277 else {
278 Done = false;
280 }
281 }
282
285 if (MaxPredDepth != Cur->Depth) {
287 Cur->Depth = MaxPredDepth;
288 }
289 Cur->isDepthCurrent = true;
290 }
291 } while (!WorkList.empty());
292}
293
294
295void SUnit::ComputeHeight() {
298 do {
300
301 bool Done = true;
302 unsigned MaxSuccHeight = 0;
303 for (const SDep &SuccDep : Cur->Succs) {
305 if (SuccSU->isHeightCurrent)
306 MaxSuccHeight = std::max(MaxSuccHeight,
307 SuccSU->Height + SuccDep.getLatency());
308 else {
309 Done = false;
311 }
312 }
313
316 if (MaxSuccHeight != Cur->Height) {
318 Cur->Height = MaxSuccHeight;
319 }
320 Cur->isHeightCurrent = true;
321 }
322 } while (!WorkList.empty());
323}
324
327 return;
328
330 unsigned MaxDepth = BestI->getSUnit()->getDepth();
332 ++I) {
333 if (I->getKind() == SDep::Data && I->getSUnit()->getDepth() > MaxDepth) {
334 MaxDepth = I->getSUnit()->getDepth();
335 BestI = I;
336 }
337 }
338 if (BestI != Preds.begin())
340}
341
342#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
355
358 dbgs() << "EntrySU";
359 else if (&SU == &ExitSU)
360 dbgs() << "ExitSU";
361 else
363}
364
370
371 if (SU.Preds.size() > 0) {
372 dbgs() << " Predecessors:\n";
373 for (const SDep &Dep : SU.Preds) {
374 dbgs() << " ";
376 dbgs() << ": ";
378 dbgs() << '\n';
379 }
380 }
381 if (SU.Succs.size() > 0) {
382 dbgs() << " Successors:\n";
383 for (const SDep &Dep : SU.Succs) {
384 dbgs() << " ";
386 dbgs() << ": ";
388 dbgs() << '\n';
389 }
390 }
391}
392#endif
393
394#ifndef NDEBUG
396 bool AnyNotSched = false;
397 unsigned DeadNodes = 0;
401 ++DeadNodes;
402 continue;
403 }
404 if (!AnyNotSched)
405 dbgs() << "*** Scheduling failed! ***\n";
407 dbgs() << "has not been scheduled!\n";
408 AnyNotSched = true;
409 }
412 unsigned(std::numeric_limits::max())) {
413 if (!AnyNotSched)
414 dbgs() << "*** Scheduling failed! ***\n";
416 dbgs() << "has an unexpected "
417 << (isBottomUp ? "Height" : "Depth") << " value!\n";
418 AnyNotSched = true;
419 }
420 if (isBottomUp) {
422 if (!AnyNotSched)
423 dbgs() << "*** Scheduling failed! ***\n";
425 dbgs() << "has successors left!\n";
426 AnyNotSched = true;
427 }
428 } else {
430 if (!AnyNotSched)
431 dbgs() << "*** Scheduling failed! ***\n";
433 dbgs() << "has predecessors left!\n";
434 AnyNotSched = true;
435 }
436 }
437 }
438 assert(!AnyNotSched);
439 return SUnits.size() - DeadNodes;
440}
441#endif
442
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472 Dirty = false;
473 Updates.clear();
474
475 unsigned DAGSize = SUnits.size();
476 std::vector<SUnit*> WorkList;
477 WorkList.reserve(DAGSize);
478
479 Index2Node.resize(DAGSize);
480 Node2Index.resize(DAGSize);
481
482
483 if (ExitSU)
484 WorkList.push_back(ExitSU);
485 for (SUnit &SU : SUnits) {
486 int NodeNum = SU.NodeNum;
487 unsigned Degree = SU.Succs.size();
488
489 Node2Index[NodeNum] = Degree;
490
491
492 if (Degree == 0) {
493 assert(SU.Succs.empty() && "SUnit should have no successors");
494
495 WorkList.push_back(&SU);
496 }
497 }
498
499 int Id = DAGSize;
500 while (!WorkList.empty()) {
501 SUnit *SU = WorkList.back();
502 WorkList.pop_back();
503 if (SU->NodeNum < DAGSize)
504 Allocate(SU->NodeNum, --Id);
505 for (const SDep &PredDep : SU->Preds) {
507 if (SU->NodeNum < DAGSize && !--Node2Index[SU->NodeNum])
508
509
510 WorkList.push_back(SU);
511 }
512 }
513
514 Visited.resize(DAGSize);
515 NumTopoInits++;
516
517#ifndef NDEBUG
518
519 for (SUnit &SU : SUnits) {
520 for (const SDep &PD : SU.Preds) {
521 assert(Node2Index[SU.NodeNum] > Node2Index[PD.getSUnit()->NodeNum] &&
522 "Wrong topological sorting");
523 }
524 }
525#endif
526}
527
528void ScheduleDAGTopologicalSort::FixOrder() {
529
530 if (Dirty) {
532 return;
533 }
534
535
536 for (auto &U : Updates)
537 AddPred(U.first, U.second);
538 Updates.clear();
539}
540
542
543
544
545 Dirty = Dirty || Updates.size() > 10;
546
547 if (Dirty)
548 return;
549
550 Updates.emplace_back(Y, X);
551}
552
554 int UpperBound, LowerBound;
555 LowerBound = Node2Index[Y->NodeNum];
556 UpperBound = Node2Index[X->NodeNum];
557 bool HasLoop = false;
558
559 if (LowerBound < UpperBound) {
560
561 Visited.reset();
562 DFS(Y, UpperBound, HasLoop);
563 assert(!HasLoop && "Inserted edge creates a loop!");
564
565 Shift(Visited, LowerBound, UpperBound);
566 }
567
568 NumNewPredsAdded++;
569}
570
574
575void ScheduleDAGTopologicalSort::DFS(const SUnit *SU, int UpperBound,
576 bool &HasLoop) {
577 std::vector<const SUnit*> WorkList;
578 WorkList.reserve(SUnits.size());
579
580 WorkList.push_back(SU);
581 do {
582 SU = WorkList.back();
583 WorkList.pop_back();
587
588 if (s >= Node2Index.size())
589 continue;
590 if (Node2Index[s] == UpperBound) {
591 HasLoop = true;
592 return;
593 }
594
595 if (!Visited.test(s) && Node2Index[s] < UpperBound) {
596 WorkList.push_back(SuccDep.getSUnit());
597 }
598 }
599 } while (!WorkList.empty());
600}
601
603 const SUnit &TargetSU,
605 std::vector<const SUnit*> WorkList;
606 int LowerBound = Node2Index[StartSU.NodeNum];
607 int UpperBound = Node2Index[TargetSU.NodeNum];
608 bool Found = false;
610 std::vector Nodes;
611
612 if (LowerBound > UpperBound) {
614 return Nodes;
615 }
616
617 WorkList.reserve(SUnits.size());
618 Visited.reset();
619
620
621
622 WorkList.push_back(&StartSU);
623 do {
624 const SUnit *SU = WorkList.back();
625 WorkList.pop_back();
627 const SUnit *Succ = SD.getSUnit();
628 unsigned s = Succ->NodeNum;
629
631 continue;
632 if (Node2Index[s] == UpperBound) {
633 Found = true;
634 continue;
635 }
636
637 if (!Visited.test(s) && Node2Index[s] < UpperBound) {
638 Visited.set(s);
639 WorkList.push_back(Succ);
640 }
641 }
642 } while (!WorkList.empty());
643
644 if (!Found) {
646 return Nodes;
647 }
648
649 WorkList.clear();
650 VisitedBack.resize(SUnits.size());
651 Found = false;
652
653
654
655
656 WorkList.push_back(&TargetSU);
657 do {
658 const SUnit *SU = WorkList.back();
659 WorkList.pop_back();
661 const SUnit *Pred = SD.getSUnit();
662 unsigned s = Pred->NodeNum;
663
664 if (Pred->isBoundaryNode())
665 continue;
666 if (Node2Index[s] == LowerBound) {
667 Found = true;
668 continue;
669 }
670 if (!VisitedBack.test(s) && Visited.test(s)) {
671 VisitedBack.set(s);
672 WorkList.push_back(Pred);
673 Nodes.push_back(s);
674 }
675 }
676 } while (!WorkList.empty());
677
678 assert(Found && "Error in SUnit Graph!");
680 return Nodes;
681}
682
683void ScheduleDAGTopologicalSort::Shift(BitVector& Visited, int LowerBound,
684 int UpperBound) {
685 std::vector L;
686 int shift = 0;
687 int i;
688
689 for (i = LowerBound; i <= UpperBound; ++i) {
690
691 int w = Index2Node[i];
692 if (Visited.test(w)) {
693
694 Visited.reset(w);
695 L.push_back(w);
696 shift = shift + 1;
697 } else {
698 Allocate(w, i - shift);
699 }
700 }
701
702 for (unsigned LI : L) {
703 Allocate(LI, i - shift);
704 i = i + 1;
705 }
706}
707
709 FixOrder();
710
712 return true;
713 for (const SDep &PredDep : TargetSU->Preds)
716 return true;
717 return false;
718}
719
721 assert(SU->NodeNum == Index2Node.size() && "Node cannot be added at the end");
722 assert(SU->NumPreds == 0 && "Can only add SU's with no predecessors");
723 Node2Index.push_back(Index2Node.size());
724 Index2Node.push_back(SU->NodeNum);
725 Visited.resize(Node2Index.size());
726}
727
729 const SUnit *TargetSU) {
730 assert(TargetSU != nullptr && "Invalid target SUnit");
731 assert(SU != nullptr && "Invalid SUnit");
732 FixOrder();
733
734
735 int UpperBound, LowerBound;
736 LowerBound = Node2Index[TargetSU->NodeNum];
737 UpperBound = Node2Index[SU->NodeNum];
738 bool HasLoop = false;
739
740 if (LowerBound < UpperBound) {
741 Visited.reset();
742
743 DFS(TargetSU, UpperBound, HasLoop);
744 }
745 return HasLoop;
746}
747
748void ScheduleDAGTopologicalSort::Allocate(int n, int index) {
749 Node2Index[n] = index;
750 Index2Node[index] = n;
751}
752
755 : SUnits(sunits), ExitSU(exitsu) {}
756
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< StatepointGC > D("statepoint-example", "an example strategy for statepoint")
#define LLVM_DUMP_METHOD
Mark debug helper function definitions like dump() that should not be stripped from debug builds.
const HexagonInstrInfo * TII
Register const TargetRegisterInfo * TRI
static cl::opt< bool > StressSchedOpt("stress-sched", cl::Hidden, cl::init(false), cl::desc("Stress test instruction scheduling"))
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
static TableGen::Emitter::Opt Y("gen-skeleton-entry", EmitSkeleton, "Generate example skeleton entry")
static TableGen::Emitter::OptClass< SkeletonEmitter > X("gen-skeleton-class", "Generate example skeleton class")
bool test(unsigned Idx) const
void resize(unsigned N, bool t=false)
resize - Grow or shrink the bitvector.
Describe properties that are true of each instruction in the target description file.
Represents one node in the SelectionDAG.
Kind getKind() const
Returns an enum value representing the kind of the dependence.
@ Output
A register output-dependence (aka WAW).
@ Order
Any other ordering dependency.
@ Anti
A register anti-dependence (aka WAR).
@ Data
Regular data dependence (aka true-dependence).
void setLatency(unsigned Lat)
Sets the latency for this edge.
@ Cluster
Weak DAG edge linking a chain of clustered instrs.
@ Barrier
An unknown scheduling barrier.
@ Artificial
Arbitrary strong DAG edge (no real dependence).
@ MayAliasMem
Nonvolatile load/Store instructions that may alias.
@ Weak
Arbitrary weak DAG edge.
@ MustAliasMem
Nonvolatile load/Store instructions that must alias.
unsigned getLatency() const
Returns the latency value for this edge, which roughly means the minimum number of cycles that must e...
bool isAssignedRegDep() const
Tests if this is a Data dependence that is associated with a register.
Register getReg() const
Returns the register associated with this edge.
LLVM_ABI void dump(const TargetRegisterInfo *TRI=nullptr) const
Definition ScheduleDAG.cpp:74
Scheduling unit. This is a node in the scheduling DAG.
LLVM_ABI void setHeightToAtLeast(unsigned NewHeight)
If NewHeight is greater than this node's height value, set it to be the new height value.
Definition ScheduleDAG.cpp:255
unsigned NodeNum
Entry # of node in the node vector.
LLVM_ABI void biasCriticalPath()
Orders this node's predecessor edges such that the critical path edge occurs first.
Definition ScheduleDAG.cpp:325
unsigned getHeight() const
Returns the height of this node, which is the length of the maximum path down to any node which has n...
LLVM_ABI void setHeightDirty()
Sets a flag in this node to indicate that its stored Height value will require recomputation the next...
Definition ScheduleDAG.cpp:232
LLVM_ABI void removePred(const SDep &D)
Removes the specified edge as a pred of the current node if it exists.
Definition ScheduleDAG.cpp:175
unsigned short Latency
Node latency.
SmallVectorImpl< SDep >::iterator pred_iterator
bool isBoundaryNode() const
Boundary nodes are placeholders for the boundary of the scheduling region.
unsigned short NumRegDefsLeft
unsigned getDepth() const
Returns the depth of this node, which is the length of the maximum path up to any node which has no p...
bool isScheduled
True once scheduled.
unsigned ParentClusterIdx
The parent cluster id.
LLVM_ABI void dumpAttributes() const
Definition ScheduleDAG.cpp:343
SmallVector< SDep, 4 > Succs
All sunit successors.
SUnit(SDNode *node, unsigned nodenum)
Constructs an SUnit for pre-regalloc scheduling to represent an SDNode and any nodes flagged to it.
LLVM_ABI void setDepthDirty()
Sets a flag in this node to indicate that its stored Depth value will require recomputation the next ...
Definition ScheduleDAG.cpp:217
SmallVector< SDep, 4 > Preds
All sunit predecessors.
LLVM_ABI void setDepthToAtLeast(unsigned NewDepth)
If NewDepth is greater than this node's depth value, sets it to be the new depth value.
Definition ScheduleDAG.cpp:247
LLVM_ABI bool addPred(const SDep &D, bool Required=true)
Adds the specified edge as a pred of the current node if not already.
Definition ScheduleDAG.cpp:106
LLVM_ABI void RemovePred(SUnit *M, SUnit *N)
Updates the topological ordering to accommodate an edge to be removed from the specified node N from ...
Definition ScheduleDAG.cpp:571
LLVM_ABI bool WillCreateCycle(SUnit *TargetSU, SUnit *SU)
Returns true if addPred(TargetSU, SU) creates a cycle.
Definition ScheduleDAG.cpp:708
LLVM_ABI void AddSUnitWithoutPredecessors(const SUnit *SU)
Add a SUnit without predecessors to the end of the topological order.
Definition ScheduleDAG.cpp:720
LLVM_ABI ScheduleDAGTopologicalSort(std::vector< SUnit > &SUnits, SUnit *ExitSU)
Definition ScheduleDAG.cpp:754
LLVM_ABI std::vector< int > GetSubGraph(const SUnit &StartSU, const SUnit &TargetSU, bool &Success)
Returns an array of SUs that are both in the successor subtree of StartSU and in the predecessor subt...
Definition ScheduleDAG.cpp:602
LLVM_ABI void InitDAGTopologicalSorting()
Creates the initial topological ordering from the DAG to be scheduled.
Definition ScheduleDAG.cpp:443
LLVM_ABI void AddPred(SUnit *Y, SUnit *X)
Updates the topological ordering to accommodate an edge to be added from SUnit X to SUnit Y.
Definition ScheduleDAG.cpp:553
LLVM_ABI bool IsReachable(const SUnit *SU, const SUnit *TargetSU)
Checks if SU is reachable from TargetSU.
Definition ScheduleDAG.cpp:728
LLVM_ABI void AddPredQueued(SUnit *Y, SUnit *X)
Queues an update to the topological ordering to accommodate an edge to be added from SUnit X to SUnit...
Definition ScheduleDAG.cpp:541
MachineRegisterInfo & MRI
Virtual/real register map.
void clearDAG()
Clears the DAG state (between regions).
Definition ScheduleDAG.cpp:63
const TargetInstrInfo * TII
Target instruction information.
std::vector< SUnit > SUnits
The scheduling units.
const TargetRegisterInfo * TRI
Target processor register info.
SUnit EntrySU
Special node for the region entry.
MachineFunction & MF
Machine function.
ScheduleDAG(const ScheduleDAG &)=delete
void dumpNodeAll(const SUnit &SU) const
Definition ScheduleDAG.cpp:365
const TargetMachine & TM
Target processor.
unsigned VerifyScheduledDAG(bool isBottomUp)
Verifies that all SUnits were scheduled and that their state is consistent.
Definition ScheduleDAG.cpp:395
virtual void dumpNode(const SUnit &SU) const =0
void dumpNodeName(const SUnit &SU) const
Definition ScheduleDAG.cpp:356
SUnit ExitSU
Special node for the region exit.
virtual ~ScheduleHazardRecognizer()
typename SuperClass::iterator iterator
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
TargetRegisterInfo base class - We assume that the target defines a static array of TargetRegisterDes...
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto find(R &&Range, const T &Val)
Provide wrappers to std::find which take ranges instead of having to pass begin/end explicitly.
auto reverse(ContainerTy &&C)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
@ Success
The lock was released successfully.
constexpr unsigned InvalidClusterId
LLVM_ABI Printable printReg(Register Reg, const TargetRegisterInfo *TRI=nullptr, unsigned SubIdx=0, const MachineRegisterInfo *MRI=nullptr)
Prints virtual and physical registers with or without a TRI instance.
void swap(llvm::BitVector &LHS, llvm::BitVector &RHS)
Implement std::swap in terms of BitVector swap.