24#include "llvm/Config/llvm-config.h"
38#define DEBUG_TYPE "pre-RA-sched"
40STATISTIC(NumNewPredsAdded,
"Number of times a single predecessor was added");
42 "Number of times the topological order has been recomputed");
47 cl::desc(
"Stress test instruction scheduling"));
50void SchedulingPriorityQueue::anchor() {}
53 :
TM(mf.getTarget()),
TII(mf.getSubtarget().getInstrInfo()),
54 TRI(mf.getSubtarget().getRegisterInfo()),
MF(mf),
55 MRI(mf.getRegInfo()) {
70 if (!
Node || !
Node->isMachineOpcode())
return nullptr;
71 return &
TII->get(
Node->getMachineOpcode());
94 switch(Contents.OrdKind) {
111 if (!Required && PredDep.getSUnit() ==
D.getSUnit())
113 if (PredDep.overlaps(
D)) {
116 if (PredDep.getLatency() <
D.getLatency()) {
117 SUnit *PredSU = PredDep.getSUnit();
119 SDep ForwardD = PredDep;
122 if (SuccDep == ForwardD) {
127 PredDep.setLatency(
D.getLatency());
142 "NumPreds will overflow!");
143 assert(
N->NumSuccs < std::numeric_limits<unsigned>::max() &&
144 "NumSuccs will overflow!");
148 if (!
N->isScheduled) {
154 "NumPredsLeft will overflow!");
163 assert(
N->NumSuccsLeft < std::numeric_limits<unsigned>::max() &&
164 "NumSuccsLeft will overflow!");
169 N->Succs.push_back(
P);
185 assert(Succ !=
N->Succs.end() &&
"Mismatching preds / succs lists!");
189 assert(
N->NumSuccs > 0 &&
"NumSuccs will underflow!");
193 if (!
N->isScheduled) {
204 assert(
N->WeakSuccsLeft > 0 &&
"WeakSuccsLeft will underflow!");
207 assert(
N->NumSuccsLeft > 0 &&
"NumSuccsLeft will underflow!");
211 N->Succs.erase(Succ);
218 if (!isDepthCurrent)
return;
223 SU->isDepthCurrent =
false;
226 if (SuccSU->isDepthCurrent)
229 }
while (!WorkList.
empty());
233 if (!isHeightCurrent)
return;
238 SU->isHeightCurrent =
false;
241 if (PredSU->isHeightCurrent)
244 }
while (!WorkList.
empty());
252 isDepthCurrent =
true;
260 isHeightCurrent =
true;
264void SUnit::ComputeDepth() {
272 bool Descended =
false;
275 if (!PredSU->isDepthCurrent) {
284 unsigned MaxPredDepth = 0;
285 for (
const SDep &PredDep : Cur->
Preds)
286 MaxPredDepth = std::max(MaxPredDepth,
288 Cur->Depth = MaxPredDepth;
289 Cur->isDepthCurrent =
true;
290 }
while (!WorkList.
empty());
294void SUnit::ComputeHeight() {
300 bool Descended =
false;
301 for (
const SDep &SuccDep : Cur->
Succs) {
303 if (!SuccSU->isHeightCurrent) {
312 unsigned MaxSuccHeight = 0;
313 for (
const SDep &SuccDep : Cur->
Succs)
314 MaxSuccHeight = std::max(MaxSuccHeight, SuccDep.
getSUnit()->Height +
316 Cur->Height = MaxSuccHeight;
317 Cur->isHeightCurrent =
true;
318 }
while (!WorkList.
empty());
326 unsigned MaxDepth = BestI->getSUnit()->getDepth();
329 if (
I->getKind() ==
SDep::Data &&
I->getSUnit()->getDepth() > MaxDepth) {
330 MaxDepth =
I->getSUnit()->getDepth();
334 if (BestI !=
Preds.begin())
340 "use ScheduleDAG::dumpNodeName for boundary nodes");
341 return OS <<
"SU(" << SU.
NodeNum <<
")";
344#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
373 if (SU.
Preds.size() > 0) {
374 dbgs() <<
" Predecessors:\n";
383 if (SU.
Succs.size() > 0) {
384 dbgs() <<
" Successors:\n";
398 bool AnyNotSched =
false;
399 unsigned DeadNodes = 0;
407 dbgs() <<
"*** Scheduling failed! ***\n";
409 dbgs() <<
"has not been scheduled!\n";
414 unsigned(std::numeric_limits<int>::max())) {
416 dbgs() <<
"*** Scheduling failed! ***\n";
418 dbgs() <<
"has an unexpected "
419 << (isBottomUp ?
"Height" :
"Depth") <<
" value!\n";
425 dbgs() <<
"*** Scheduling failed! ***\n";
427 dbgs() <<
"has successors left!\n";
433 dbgs() <<
"*** Scheduling failed! ***\n";
435 dbgs() <<
"has predecessors left!\n";
441 return SUnits.size() - DeadNodes;
478 unsigned DAGSize = SUnits.size();
479 std::vector<SUnit*> WorkList;
480 WorkList.reserve(DAGSize);
482 Index2Node.resize(DAGSize);
483 Node2Index.resize(DAGSize);
487 WorkList.push_back(ExitSU);
488 for (
SUnit &SU : SUnits) {
489 int NodeNum = SU.NodeNum;
490 unsigned Degree = SU.Succs.size();
492 Node2Index[NodeNum] = Degree;
496 assert(SU.Succs.empty() &&
"SUnit should have no successors");
498 WorkList.push_back(&SU);
503 while (!WorkList.empty()) {
504 SUnit *SU = WorkList.back();
513 WorkList.push_back(SU);
517 Visited.resize(DAGSize);
522 for (
SUnit &SU : SUnits) {
523 for (
const SDep &PD : SU.Preds) {
524 assert(Node2Index[SU.NodeNum] > Node2Index[PD.getSUnit()->NodeNum] &&
525 "Wrong topological sorting");
531void ScheduleDAGTopologicalSort::FixOrder() {
539 for (
auto &U : Updates)
548 Dirty = Dirty || Updates.size() > 10;
553 Updates.emplace_back(
Y,
X);
557 int UpperBound, LowerBound;
558 LowerBound = Node2Index[
Y->NodeNum];
559 UpperBound = Node2Index[
X->NodeNum];
560 bool HasLoop =
false;
562 if (LowerBound < UpperBound) {
565 DFS(
Y, UpperBound, HasLoop);
566 assert(!HasLoop &&
"Inserted edge creates a loop!");
568 Shift(Visited, LowerBound, UpperBound);
579void ScheduleDAGTopologicalSort::DFS(
const SUnit *SU,
int UpperBound,
581 std::vector<const SUnit*> WorkList;
582 WorkList.reserve(SUnits.size());
584 WorkList.push_back(SU);
586 SU = WorkList.back();
592 if (s >= Node2Index.size())
594 if (Node2Index[s] == UpperBound) {
599 if (!Visited.
test(s) && Node2Index[s] < UpperBound) {
600 WorkList.push_back(SuccDep.
getSUnit());
603 }
while (!WorkList.empty());
607 const SUnit &TargetSU,
609 std::vector<const SUnit*> WorkList;
610 int LowerBound = Node2Index[StartSU.
NodeNum];
611 int UpperBound = Node2Index[TargetSU.
NodeNum];
614 std::vector<int> Nodes;
616 if (LowerBound > UpperBound) {
621 WorkList.reserve(SUnits.size());
626 WorkList.push_back(&StartSU);
628 const SUnit *SU = WorkList.back();
631 const SUnit *Succ = SD.getSUnit();
636 if (Node2Index[s] == UpperBound) {
641 if (!Visited.test(s) && Node2Index[s] < UpperBound) {
643 WorkList.push_back(Succ);
646 }
while (!WorkList.empty());
654 VisitedBack.
resize(SUnits.size());
660 WorkList.push_back(&TargetSU);
662 const SUnit *SU = WorkList.back();
665 const SUnit *Pred = SD.getSUnit();
666 unsigned s = Pred->NodeNum;
668 if (Pred->isBoundaryNode())
670 if (Node2Index[s] == LowerBound) {
674 if (!VisitedBack.
test(s) && Visited.test(s)) {
676 WorkList.push_back(Pred);
680 }
while (!WorkList.empty());
682 assert(Found &&
"Error in SUnit Graph!");
687void ScheduleDAGTopologicalSort::Shift(
BitVector& Visited,
int LowerBound,
693 for (i = LowerBound; i <= UpperBound; ++i) {
695 int w = Index2Node[i];
696 if (Visited.
test(w)) {
702 Allocate(w, i - shift);
706 for (
unsigned LI : L) {
707 Allocate(LI, i - shift);
717 for (
const SDep &PredDep : TargetSU->
Preds)
725 assert(SU->
NodeNum == Index2Node.size() &&
"Node cannot be added at the end");
726 assert(SU->
NumPreds == 0 &&
"Can only add SU's with no predecessors");
727 Node2Index.push_back(Index2Node.size());
728 Index2Node.push_back(SU->
NodeNum);
729 Visited.resize(Node2Index.size());
733 const SUnit *TargetSU) {
734 assert(TargetSU !=
nullptr &&
"Invalid target SUnit");
735 assert(SU !=
nullptr &&
"Invalid SUnit");
739 int UpperBound, LowerBound;
740 LowerBound = Node2Index[TargetSU->
NodeNum];
741 UpperBound = Node2Index[SU->
NodeNum];
742 bool HasLoop =
false;
744 if (LowerBound < UpperBound) {
745 if (
auto It = Reachable.find({TargetSU->NodeNum, SU->NodeNum});
746 It != Reachable.end()) {
751 DFS(TargetSU, UpperBound, HasLoop);
761void ScheduleDAGTopologicalSort::Allocate(
int n,
int index) {
762 Node2Index[n] = index;
763 Index2Node[index] = n;
768 : SUnits(sunits), ExitSU(exitsu) {}
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")
bool test(unsigned Idx) const
Returns true if bit Idx is set.
BitVector & reset()
Reset all bits in the bitvector.
void resize(unsigned N, bool t=false)
Grow or shrink the bitvector.
BitVector & set()
Set all bits in 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
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.
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.
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...
LLVM_ABI void removePred(const SDep &D)
Removes the specified edge as a pred of the current node if it exists.
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
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 ...
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.
LLVM_ABI bool addPred(const SDep &D, bool Required=true)
Adds the specified edge as a pred of the current node if not already.
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 ...
LLVM_ABI bool WillCreateCycle(SUnit *TargetSU, SUnit *SU)
Returns true if addPred(TargetSU, SU) creates a cycle.
LLVM_ABI void AddSUnitWithoutPredecessors(const SUnit *SU)
Add a SUnit without predecessors to the end of the topological order.
LLVM_ABI ScheduleDAGTopologicalSort(std::vector< SUnit > &SUnits, SUnit *ExitSU)
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...
LLVM_ABI void InitDAGTopologicalSorting()
Creates the initial topological ordering from the DAG to be scheduled.
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.
LLVM_ABI bool IsReachable(const SUnit *SU, const SUnit *TargetSU)
Checks if SU is reachable from TargetSU.
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...
MachineRegisterInfo & MRI
Virtual/real register map.
void clearDAG()
Clears the DAG state (between regions).
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
const TargetMachine & TM
Target processor.
unsigned VerifyScheduledDAG(bool isBottomUp)
Verifies that all SUnits were scheduled and that their state is consistent.
virtual void dumpNode(const SUnit &SU) const =0
void dumpNodeName(const SUnit &SU) const
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...
This class implements an extremely fast bulk output stream that can only output to a stream.
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.
raw_ostream & operator<<(raw_ostream &OS, const APFixedPoint &FX)
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.