Refactor the priority mechanism one step further: now that it is a separate
class, sever its implementation from the interface. Now we can provide new implementations of the same interface (priority computation) without touching the scheduler itself. llvm-svn: 26630
This commit is contained in:
parent
c683a7232b
commit
9df647539d
|
|
@ -118,137 +118,25 @@ void SUnit::dump(const SelectionDAG *G, bool All) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
//===----------------------------------------------------------------------===//
|
||||||
class SchedulingPriorityQueue;
|
// SchedulingPriorityQueue - This interface is used to plug different
|
||||||
|
// priorities computation algorithms into the list scheduler. It implements the
|
||||||
|
// interface of a standard priority queue, where nodes are inserted in arbitrary
|
||||||
|
// order and returned in priority order. The computation of the priority and
|
||||||
|
// the representation of the queue are totally up to the implementation to
|
||||||
|
// decide.
|
||||||
|
//
|
||||||
|
class SchedulingPriorityQueue {
|
||||||
|
public:
|
||||||
|
virtual ~SchedulingPriorityQueue() {}
|
||||||
|
|
||||||
/// Sorting functions for the Available queue.
|
virtual void initNodes(const std::vector<SUnit> &SUnits) = 0;
|
||||||
struct ls_rr_sort : public std::binary_function<SUnit*, SUnit*, bool> {
|
virtual void releaseState() = 0;
|
||||||
SchedulingPriorityQueue *SPQ;
|
|
||||||
ls_rr_sort(SchedulingPriorityQueue *spq) : SPQ(spq) {}
|
|
||||||
ls_rr_sort(const ls_rr_sort &RHS) : SPQ(RHS.SPQ) {}
|
|
||||||
|
|
||||||
bool operator()(const SUnit* left, const SUnit* right) const;
|
|
||||||
};
|
|
||||||
} // end anonymous namespace
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
class SchedulingPriorityQueue {
|
|
||||||
// SUnits - The SUnits for the current graph.
|
|
||||||
std::vector<SUnit> &SUnits;
|
|
||||||
|
|
||||||
// SethiUllmanNumbers - The SethiUllman number for each node.
|
|
||||||
std::vector<int> SethiUllmanNumbers;
|
|
||||||
|
|
||||||
std::priority_queue<SUnit*, std::vector<SUnit*>, ls_rr_sort> Queue;
|
|
||||||
public:
|
|
||||||
SchedulingPriorityQueue(std::vector<SUnit> &sunits)
|
|
||||||
: SUnits(sunits), Queue(ls_rr_sort(this)) {
|
|
||||||
// Calculate node priorities.
|
|
||||||
CalculatePriorities();
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned getSethiUllmanNumber(unsigned NodeNum) const {
|
|
||||||
assert(NodeNum < SethiUllmanNumbers.size());
|
|
||||||
return SethiUllmanNumbers[NodeNum];
|
|
||||||
}
|
|
||||||
|
|
||||||
bool empty() const { return Queue.empty(); }
|
|
||||||
|
|
||||||
void push(SUnit *U) {
|
|
||||||
Queue.push(U);
|
|
||||||
}
|
|
||||||
SUnit *pop() {
|
|
||||||
SUnit *V = Queue.top();
|
|
||||||
Queue.pop();
|
|
||||||
return V;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
void CalculatePriorities();
|
|
||||||
int CalcNodePriority(SUnit *SU);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const {
|
|
||||||
unsigned LeftNum = left->NodeNum;
|
|
||||||
unsigned RightNum = right->NodeNum;
|
|
||||||
|
|
||||||
int LBonus = (int)left ->isDefNUseOperand;
|
virtual bool empty() const = 0;
|
||||||
int RBonus = (int)right->isDefNUseOperand;
|
virtual void push(SUnit *U) = 0;
|
||||||
|
virtual SUnit *pop() = 0;
|
||||||
// Special tie breaker: if two nodes share a operand, the one that
|
};
|
||||||
// use it as a def&use operand is preferred.
|
|
||||||
if (left->isTwoAddress && !right->isTwoAddress) {
|
|
||||||
SDNode *DUNode = left->Node->getOperand(0).Val;
|
|
||||||
if (DUNode->isOperand(right->Node))
|
|
||||||
LBonus++;
|
|
||||||
}
|
|
||||||
if (!left->isTwoAddress && right->isTwoAddress) {
|
|
||||||
SDNode *DUNode = right->Node->getOperand(0).Val;
|
|
||||||
if (DUNode->isOperand(left->Node))
|
|
||||||
RBonus++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Priority1 is just the number of live range genned.
|
|
||||||
int LPriority1 = left ->NumPredsLeft - LBonus;
|
|
||||||
int RPriority1 = right->NumPredsLeft - RBonus;
|
|
||||||
int LPriority2 = SPQ->getSethiUllmanNumber(LeftNum) + LBonus;
|
|
||||||
int RPriority2 = SPQ->getSethiUllmanNumber(RightNum) + RBonus;
|
|
||||||
|
|
||||||
if (LPriority1 > RPriority1)
|
|
||||||
return true;
|
|
||||||
else if (LPriority1 == RPriority1)
|
|
||||||
if (LPriority2 < RPriority2)
|
|
||||||
return true;
|
|
||||||
else if (LPriority2 == RPriority2)
|
|
||||||
if (left->CycleBound > right->CycleBound)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// CalcNodePriority - Priority is the Sethi Ullman number.
|
|
||||||
/// Smaller number is the higher priority.
|
|
||||||
int SchedulingPriorityQueue::CalcNodePriority(SUnit *SU) {
|
|
||||||
int &SethiUllmanNumber = SethiUllmanNumbers[SU->NodeNum];
|
|
||||||
if (SethiUllmanNumber != INT_MIN)
|
|
||||||
return SethiUllmanNumber;
|
|
||||||
|
|
||||||
if (SU->Preds.size() == 0) {
|
|
||||||
SethiUllmanNumber = 1;
|
|
||||||
} else {
|
|
||||||
int Extra = 0;
|
|
||||||
for (std::set<SUnit*>::iterator I = SU->Preds.begin(),
|
|
||||||
E = SU->Preds.end(); I != E; ++I) {
|
|
||||||
SUnit *PredSU = *I;
|
|
||||||
int PredSethiUllman = CalcNodePriority(PredSU);
|
|
||||||
if (PredSethiUllman > SethiUllmanNumber) {
|
|
||||||
SethiUllmanNumber = PredSethiUllman;
|
|
||||||
Extra = 0;
|
|
||||||
} else if (PredSethiUllman == SethiUllmanNumber)
|
|
||||||
Extra++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (SU->Node->getOpcode() != ISD::TokenFactor)
|
|
||||||
SethiUllmanNumber += Extra;
|
|
||||||
else
|
|
||||||
SethiUllmanNumber = (Extra == 1) ? 0 : Extra-1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return SethiUllmanNumber;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// CalculatePriorities - Calculate priorities of all scheduling units.
|
|
||||||
void SchedulingPriorityQueue::CalculatePriorities() {
|
|
||||||
SethiUllmanNumbers.assign(SUnits.size(), INT_MIN);
|
|
||||||
|
|
||||||
for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
|
|
||||||
// FIXME: assumes uniform latency for now.
|
|
||||||
SUnits[i].Latency = 1;
|
|
||||||
(void)CalcNodePriority(&SUnits[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -270,19 +158,25 @@ private:
|
||||||
/// it is top-down.
|
/// it is top-down.
|
||||||
bool isBottomUp;
|
bool isBottomUp;
|
||||||
|
|
||||||
|
/// PriorityQueue - The priority queue to use.
|
||||||
|
SchedulingPriorityQueue *PriorityQueue;
|
||||||
|
|
||||||
/// HazardRec - The hazard recognizer to use.
|
/// HazardRec - The hazard recognizer to use.
|
||||||
HazardRecognizer *HazardRec;
|
HazardRecognizer *HazardRec;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ScheduleDAGList(SelectionDAG &dag, MachineBasicBlock *bb,
|
ScheduleDAGList(SelectionDAG &dag, MachineBasicBlock *bb,
|
||||||
const TargetMachine &tm, bool isbottomup,
|
const TargetMachine &tm, bool isbottomup,
|
||||||
|
SchedulingPriorityQueue *priorityqueue,
|
||||||
HazardRecognizer *HR)
|
HazardRecognizer *HR)
|
||||||
: ScheduleDAG(listSchedulingBURR, dag, bb, tm),
|
: ScheduleDAG(listSchedulingBURR, dag, bb, tm),
|
||||||
CurrCycle(0), isBottomUp(isbottomup), HazardRec(HR) {
|
CurrCycle(0), isBottomUp(isbottomup),
|
||||||
|
PriorityQueue(priorityqueue), HazardRec(HR) {
|
||||||
}
|
}
|
||||||
|
|
||||||
~ScheduleDAGList() {
|
~ScheduleDAGList() {
|
||||||
delete HazardRec;
|
delete HazardRec;
|
||||||
|
delete PriorityQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Schedule();
|
void Schedule();
|
||||||
|
|
@ -603,6 +497,9 @@ void ScheduleDAGList::BuildSchedUnits() {
|
||||||
SU = NewSUnit(N);
|
SU = NewSUnit(N);
|
||||||
}
|
}
|
||||||
SUnitMap[N] = SU;
|
SUnitMap[N] = SU;
|
||||||
|
|
||||||
|
// FIXME: assumes uniform latency for now.
|
||||||
|
SU->Latency = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pass 2: add the preds, succs, etc.
|
// Pass 2: add the preds, succs, etc.
|
||||||
|
|
@ -701,14 +598,16 @@ void ScheduleDAGList::Schedule() {
|
||||||
// Build scheduling units.
|
// Build scheduling units.
|
||||||
BuildSchedUnits();
|
BuildSchedUnits();
|
||||||
|
|
||||||
SchedulingPriorityQueue PQ(SUnits);
|
PriorityQueue->initNodes(SUnits);
|
||||||
|
|
||||||
// Execute the actual scheduling loop Top-Down or Bottom-Up as appropriate.
|
// Execute the actual scheduling loop Top-Down or Bottom-Up as appropriate.
|
||||||
if (isBottomUp)
|
if (isBottomUp)
|
||||||
ListScheduleBottomUp(PQ);
|
ListScheduleBottomUp(*PriorityQueue);
|
||||||
else
|
else
|
||||||
ListScheduleTopDown(PQ);
|
ListScheduleTopDown(*PriorityQueue);
|
||||||
|
|
||||||
|
PriorityQueue->releaseState();
|
||||||
|
|
||||||
DEBUG(std::cerr << "*** Final schedule ***\n");
|
DEBUG(std::cerr << "*** Final schedule ***\n");
|
||||||
DEBUG(dump());
|
DEBUG(dump());
|
||||||
DEBUG(std::cerr << "\n");
|
DEBUG(std::cerr << "\n");
|
||||||
|
|
@ -717,9 +616,157 @@ void ScheduleDAGList::Schedule() {
|
||||||
EmitSchedule();
|
EmitSchedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// RegReductionPriorityQueue Implementation
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
//
|
||||||
|
// This is a SchedulingPriorityQueue that schedules using Sethi Ullman numbers
|
||||||
|
// to reduce register pressure.
|
||||||
|
//
|
||||||
|
namespace {
|
||||||
|
class RegReductionPriorityQueue;
|
||||||
|
|
||||||
|
/// Sorting functions for the Available queue.
|
||||||
|
struct ls_rr_sort : public std::binary_function<SUnit*, SUnit*, bool> {
|
||||||
|
RegReductionPriorityQueue *SPQ;
|
||||||
|
ls_rr_sort(RegReductionPriorityQueue *spq) : SPQ(spq) {}
|
||||||
|
ls_rr_sort(const ls_rr_sort &RHS) : SPQ(RHS.SPQ) {}
|
||||||
|
|
||||||
|
bool operator()(const SUnit* left, const SUnit* right) const;
|
||||||
|
};
|
||||||
|
} // end anonymous namespace
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
class RegReductionPriorityQueue : public SchedulingPriorityQueue {
|
||||||
|
// SUnits - The SUnits for the current graph.
|
||||||
|
const std::vector<SUnit> *SUnits;
|
||||||
|
|
||||||
|
// SethiUllmanNumbers - The SethiUllman number for each node.
|
||||||
|
std::vector<int> SethiUllmanNumbers;
|
||||||
|
|
||||||
|
std::priority_queue<SUnit*, std::vector<SUnit*>, ls_rr_sort> Queue;
|
||||||
|
public:
|
||||||
|
RegReductionPriorityQueue() : Queue(ls_rr_sort(this)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void initNodes(const std::vector<SUnit> &sunits) {
|
||||||
|
SUnits = &sunits;
|
||||||
|
// Calculate node priorities.
|
||||||
|
CalculatePriorities();
|
||||||
|
}
|
||||||
|
void releaseState() {
|
||||||
|
SUnits = 0;
|
||||||
|
SethiUllmanNumbers.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned getSethiUllmanNumber(unsigned NodeNum) const {
|
||||||
|
assert(NodeNum < SethiUllmanNumbers.size());
|
||||||
|
return SethiUllmanNumbers[NodeNum];
|
||||||
|
}
|
||||||
|
|
||||||
|
bool empty() const { return Queue.empty(); }
|
||||||
|
|
||||||
|
void push(SUnit *U) {
|
||||||
|
Queue.push(U);
|
||||||
|
}
|
||||||
|
SUnit *pop() {
|
||||||
|
SUnit *V = Queue.top();
|
||||||
|
Queue.pop();
|
||||||
|
return V;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
void CalculatePriorities();
|
||||||
|
int CalcNodePriority(const SUnit *SU);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const {
|
||||||
|
unsigned LeftNum = left->NodeNum;
|
||||||
|
unsigned RightNum = right->NodeNum;
|
||||||
|
|
||||||
|
int LBonus = (int)left ->isDefNUseOperand;
|
||||||
|
int RBonus = (int)right->isDefNUseOperand;
|
||||||
|
|
||||||
|
// Special tie breaker: if two nodes share a operand, the one that
|
||||||
|
// use it as a def&use operand is preferred.
|
||||||
|
if (left->isTwoAddress && !right->isTwoAddress) {
|
||||||
|
SDNode *DUNode = left->Node->getOperand(0).Val;
|
||||||
|
if (DUNode->isOperand(right->Node))
|
||||||
|
LBonus++;
|
||||||
|
}
|
||||||
|
if (!left->isTwoAddress && right->isTwoAddress) {
|
||||||
|
SDNode *DUNode = right->Node->getOperand(0).Val;
|
||||||
|
if (DUNode->isOperand(left->Node))
|
||||||
|
RBonus++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priority1 is just the number of live range genned.
|
||||||
|
int LPriority1 = left ->NumPredsLeft - LBonus;
|
||||||
|
int RPriority1 = right->NumPredsLeft - RBonus;
|
||||||
|
int LPriority2 = SPQ->getSethiUllmanNumber(LeftNum) + LBonus;
|
||||||
|
int RPriority2 = SPQ->getSethiUllmanNumber(RightNum) + RBonus;
|
||||||
|
|
||||||
|
if (LPriority1 > RPriority1)
|
||||||
|
return true;
|
||||||
|
else if (LPriority1 == RPriority1)
|
||||||
|
if (LPriority2 < RPriority2)
|
||||||
|
return true;
|
||||||
|
else if (LPriority2 == RPriority2)
|
||||||
|
if (left->CycleBound > right->CycleBound)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// CalcNodePriority - Priority is the Sethi Ullman number.
|
||||||
|
/// Smaller number is the higher priority.
|
||||||
|
int RegReductionPriorityQueue::CalcNodePriority(const SUnit *SU) {
|
||||||
|
int &SethiUllmanNumber = SethiUllmanNumbers[SU->NodeNum];
|
||||||
|
if (SethiUllmanNumber != INT_MIN)
|
||||||
|
return SethiUllmanNumber;
|
||||||
|
|
||||||
|
if (SU->Preds.size() == 0) {
|
||||||
|
SethiUllmanNumber = 1;
|
||||||
|
} else {
|
||||||
|
int Extra = 0;
|
||||||
|
for (std::set<SUnit*>::iterator I = SU->Preds.begin(),
|
||||||
|
E = SU->Preds.end(); I != E; ++I) {
|
||||||
|
SUnit *PredSU = *I;
|
||||||
|
int PredSethiUllman = CalcNodePriority(PredSU);
|
||||||
|
if (PredSethiUllman > SethiUllmanNumber) {
|
||||||
|
SethiUllmanNumber = PredSethiUllman;
|
||||||
|
Extra = 0;
|
||||||
|
} else if (PredSethiUllman == SethiUllmanNumber)
|
||||||
|
Extra++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SU->Node->getOpcode() != ISD::TokenFactor)
|
||||||
|
SethiUllmanNumber += Extra;
|
||||||
|
else
|
||||||
|
SethiUllmanNumber = (Extra == 1) ? 0 : Extra-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SethiUllmanNumber;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// CalculatePriorities - Calculate priorities of all scheduling units.
|
||||||
|
void RegReductionPriorityQueue::CalculatePriorities() {
|
||||||
|
SethiUllmanNumbers.assign(SUnits->size(), INT_MIN);
|
||||||
|
|
||||||
|
for (unsigned i = 0, e = SUnits->size(); i != e; ++i)
|
||||||
|
CalcNodePriority(&(*SUnits)[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
// Public Constructor Functions
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
llvm::ScheduleDAG* llvm::createBURRListDAGScheduler(SelectionDAG &DAG,
|
llvm::ScheduleDAG* llvm::createBURRListDAGScheduler(SelectionDAG &DAG,
|
||||||
MachineBasicBlock *BB) {
|
MachineBasicBlock *BB) {
|
||||||
return new ScheduleDAGList(DAG, BB, DAG.getTarget(), true,
|
return new ScheduleDAGList(DAG, BB, DAG.getTarget(), true,
|
||||||
|
new RegReductionPriorityQueue(),
|
||||||
new HazardRecognizer());
|
new HazardRecognizer());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -728,5 +775,7 @@ llvm::ScheduleDAG* llvm::createBURRListDAGScheduler(SelectionDAG &DAG,
|
||||||
ScheduleDAG* llvm::createTDListDAGScheduler(SelectionDAG &DAG,
|
ScheduleDAG* llvm::createTDListDAGScheduler(SelectionDAG &DAG,
|
||||||
MachineBasicBlock *BB,
|
MachineBasicBlock *BB,
|
||||||
HazardRecognizer *HR) {
|
HazardRecognizer *HR) {
|
||||||
return new ScheduleDAGList(DAG, BB, DAG.getTarget(), false, HR);
|
return new ScheduleDAGList(DAG, BB, DAG.getTarget(), false,
|
||||||
|
new RegReductionPriorityQueue(),
|
||||||
|
HR);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue