19#define DEBUG_TYPE "machine-scheduler"
23class GCNMinRegScheduler {
28 Candidate(
const SUnit *SU_,
int Priority_ = 0)
29 : SU(SU_), Priority(Priority_) {}
36 std::vector<unsigned> NumPreds;
38 bool isScheduled(
const SUnit *SU)
const {
40 return NumPreds[SU->
NodeNum] == std::numeric_limits<unsigned>::max();
43 void setIsScheduled(
const SUnit *SU) {
45 NumPreds[SU->
NodeNum] = std::numeric_limits<unsigned>::max();
48 unsigned getNumPreds(
const SUnit *SU)
const {
50 assert(NumPreds[SU->
NodeNum] != std::numeric_limits<unsigned>::max());
54 unsigned decNumPreds(
const SUnit *SU) {
56 assert(NumPreds[SU->
NodeNum] != std::numeric_limits<unsigned>::max());
62 int getReadySuccessors(
const SUnit *SU)
const;
63 int getNotReadySuccessors(
const SUnit *SU)
const;
65 template <
typename Calc>
size_t findMax(
size_t Num, Calc
C);
67 Candidate* pickCandidate();
69 void bumpPredsPriority(
const SUnit *SchedSU,
int Priority);
70 void releaseSuccessors(
const SUnit* SU,
int Priority);
80 NumPreds.resize(SUnits.size());
81 for (
unsigned I = 0;
I < SUnits.size(); ++
I)
82 NumPreds[
I] = SUnits[
I].NumPredsLeft;
85int GCNMinRegScheduler::getReadySuccessors(
const SUnit *SU)
const {
86 unsigned NumSchedSuccs = 0;
87 for (
auto SDep : SU->
Succs) {
88 bool wouldBeScheduled =
true;
89 for (
auto PDep : SDep.getSUnit()->Preds) {
90 auto *PSU = PDep.getSUnit();
91 assert(!PSU->isBoundaryNode());
92 if (PSU != SU && !isScheduled(PSU)) {
93 wouldBeScheduled =
false;
97 NumSchedSuccs += wouldBeScheduled ? 1 : 0;
102int GCNMinRegScheduler::getNotReadySuccessors(
const SUnit *SU)
const {
103 return static_cast<int>(SU->
Succs.size()) - getReadySuccessors(SU);
106template <
typename Calc>
107size_t GCNMinRegScheduler::findMax(
size_t Num, Calc
C) {
110 using T =
decltype(
C(*RQ.
begin())) ;
112 T Max = std::numeric_limits<T>::min();
114 for (
auto I = RQ.
begin(); Num; --Num) {
132GCNMinRegScheduler::Candidate* GCNMinRegScheduler::pickCandidate() {
134 size_t Num = RQ.
size();
137 LLVM_DEBUG(
dbgs() <<
"\nSelecting max priority candidates among " << Num
139 Num = findMax(Num, [=](
const Candidate &
C) {
return C.Priority; });
142 LLVM_DEBUG(
dbgs() <<
"\nSelecting min non-ready producing candidate among "
144 Num = findMax(Num, [=](
const Candidate &
C) {
145 const auto *SU =
C.SU;
146 int Res = getNotReadySuccessors(SU);
148 <<
" successors, metric = " << -Res <<
'\n');
153 LLVM_DEBUG(
dbgs() <<
"\nSelecting most producing candidate among " << Num
155 Num = findMax(Num, [=](
const Candidate &
C) {
156 const auto *SU =
C.SU;
157 auto Res = getReadySuccessors(SU);
159 <<
" successors, metric = " << Res <<
'\n');
164 Num = Num ? Num : RQ.
size();
167 <<
"\nCan't find best candidate, selecting in program order among "
169 Num = findMax(Num, [=](
const Candidate &
C) {
return -(int64_t)
C.SU->NodeNum; });
176void GCNMinRegScheduler::bumpPredsPriority(
const SUnit *SchedSU,
int Priority) {
177 SmallPtrSet<const SUnit*, 32>
Set;
178 for (
const auto &S : SchedSU->
Succs) {
179 if (S.getSUnit()->isBoundaryNode() || isScheduled(S.getSUnit()) ||
182 for (
const auto &
P : S.getSUnit()->Preds) {
183 auto *PSU =
P.getSUnit();
184 assert(!PSU->isBoundaryNode());
185 if (PSU != SchedSU && !isScheduled(PSU)) {
191 while (!Worklist.empty()) {
192 const auto *SU = Worklist.pop_back_val();
194 for (
const auto &
P : SU->
Preds) {
195 if (!
P.getSUnit()->isBoundaryNode() && !isScheduled(
P.getSUnit()) &&
196 Set.insert(
P.getSUnit()).second)
197 Worklist.push_back(
P.getSUnit());
201 <<
"'s non-ready successors of " << Priority
202 <<
" priority in ready queue: ");
204 if (
Set.count(
C.SU)) {
205 C.Priority = Priority;
212void GCNMinRegScheduler::releaseSuccessors(
const SUnit* SU,
int Priority) {
213 for (
const auto &S : SU->
Succs) {
214 auto *SuccSU = S.getSUnit();
217 assert(SuccSU->isBoundaryNode() || getNumPreds(SuccSU) > 0);
218 if (!SuccSU->isBoundaryNode() && decNumPreds(SuccSU) == 0)
219 RQ.push_front(*
new (
Alloc.Allocate()) Candidate(SuccSU, Priority));
223std::vector<const SUnit*>
224GCNMinRegScheduler::schedule(ArrayRef<const SUnit*> TopRoots,
225 const ScheduleDAG &DAG) {
226 const auto &SUnits = DAG.
SUnits;
227 std::vector<const SUnit*> Schedule;
228 Schedule.reserve(SUnits.size());
230 initNumPreds(SUnits);
234 for (
const auto *SU : TopRoots) {
235 RQ.push_back(*
new (
Alloc.Allocate()) Candidate(SU, StepNo));
237 releaseSuccessors(&DAG.
EntrySU, StepNo);
239 while (!RQ.empty()) {
243 for (
auto &
C : RQ)
dbgs()
244 <<
' ' << *
C.SU <<
"(P" <<
C.Priority <<
')';
247 auto *
C = pickCandidate();
250 const auto *SU =
C->SU;
253 releaseSuccessors(SU, StepNo);
254 Schedule.push_back(SU);
257 if (getReadySuccessors(SU) == 0)
258 bumpPredsPriority(SU, StepNo);
262 assert(SUnits.size() == Schedule.size());
271 GCNMinRegScheduler S;
272 return S.schedule(TopRoots, DAG);
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< ShadowStackGC > C("shadow-stack", "Very portable GC for uncooperative code generators")
Represent a constant reference to an array (0 or more elements consecutively in memory),...
@ Data
Regular data dependence (aka true-dependence).
Scheduling unit. This is a node in the scheduling DAG.
unsigned NodeNum
Entry # of node in the node vector.
bool isBoundaryNode() const
Boundary nodes are placeholders for the boundary of the scheduling region.
SmallVector< SDep, 4 > Succs
All sunit successors.
SmallVector< SDep, 4 > Preds
All sunit predecessors.
std::vector< SUnit > SUnits
The scheduling units.
SUnit EntrySU
Special node for the region entry.
virtual void dumpNode(const SUnit &SU) const =0
A BumpPtrAllocator that allows only elements of a specific type to be allocated.
A simple intrusive list implementation.
void push_front(reference Node)
Insert a node at the front; never copies.
bool empty() const
Check if the list is empty in constant time.
void remove(reference N)
Remove a node by reference; never deletes.
size_type size() const
Calculate the size of the list in linear time.
This is an optimization pass for GlobalISel generic memory operations.
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...
std::vector< const SUnit * > makeMinRegSchedule(ArrayRef< const SUnit * > TopRoots, const ScheduleDAG &DAG)