Move some methods around so that BU specific code is together, TD specific code

is together, and direction independent code is together.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@26712 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2006-03-11 22:28:35 +00:00
parent 309cf8a713
commit 7d82b00048

View File

@ -217,252 +217,9 @@ SUnit *ScheduleDAGList::NewSUnit(SDNode *N) {
return &SUnits.back(); return &SUnits.back();
} }
/// ReleasePred - Decrement the NumSuccsLeft count of a predecessor. Add it to /// BuildSchedUnits - Build SUnits from the selection dag that we are input.
/// the Available queue is the count reaches zero. Also update its cycle bound. /// This SUnit graph is similar to the SelectionDAG, but represents flagged
void ScheduleDAGList::ReleasePred(SUnit *PredSU, bool isChain) { /// together nodes with a single SUnit.
// FIXME: the distance between two nodes is not always == the predecessor's
// latency. For example, the reader can very well read the register written
// by the predecessor later than the issue cycle. It also depends on the
// interrupt model (drain vs. freeze).
PredSU->CycleBound = std::max(PredSU->CycleBound,CurrCycle + PredSU->Latency);
if (!isChain)
PredSU->NumSuccsLeft--;
else
PredSU->NumChainSuccsLeft--;
#ifndef NDEBUG
if (PredSU->NumSuccsLeft < 0 || PredSU->NumChainSuccsLeft < 0) {
std::cerr << "*** List scheduling failed! ***\n";
PredSU->dump(&DAG);
std::cerr << " has been released too many times!\n";
assert(0);
}
#endif
if ((PredSU->NumSuccsLeft + PredSU->NumChainSuccsLeft) == 0) {
// EntryToken has to go last! Special case it here.
if (PredSU->Node->getOpcode() != ISD::EntryToken) {
PredSU->isAvailable = true;
PriorityQueue->push(PredSU);
}
}
}
/// ReleaseSucc - Decrement the NumPredsLeft count of a successor. Add it to
/// the Available queue is the count reaches zero. Also update its cycle bound.
void ScheduleDAGList::ReleaseSucc(SUnit *SuccSU, bool isChain) {
// FIXME: the distance between two nodes is not always == the predecessor's
// latency. For example, the reader can very well read the register written
// by the predecessor later than the issue cycle. It also depends on the
// interrupt model (drain vs. freeze).
SuccSU->CycleBound = std::max(SuccSU->CycleBound,CurrCycle + SuccSU->Latency);
if (!isChain)
SuccSU->NumPredsLeft--;
else
SuccSU->NumChainPredsLeft--;
#ifndef NDEBUG
if (SuccSU->NumPredsLeft < 0 || SuccSU->NumChainPredsLeft < 0) {
std::cerr << "*** List scheduling failed! ***\n";
SuccSU->dump(&DAG);
std::cerr << " has been released too many times!\n";
abort();
}
#endif
if ((SuccSU->NumPredsLeft + SuccSU->NumChainPredsLeft) == 0) {
SuccSU->isAvailable = true;
PriorityQueue->push(SuccSU);
}
}
/// ScheduleNodeBottomUp - Add the node to the schedule. Decrement the pending
/// count of its predecessors. If a predecessor pending count is zero, add it to
/// the Available queue.
void ScheduleDAGList::ScheduleNodeBottomUp(SUnit *SU) {
DEBUG(std::cerr << "*** Scheduling: ");
DEBUG(SU->dump(&DAG));
Sequence.push_back(SU);
// Bottom up: release predecessors
for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Preds.begin(),
E = SU->Preds.end(); I != E; ++I) {
ReleasePred(I->first, I->second);
if (!I->second)
SU->NumPredsLeft--;
}
CurrCycle++;
}
/// ScheduleNodeTopDown - Add the node to the schedule. Decrement the pending
/// count of its successors. If a successor pending count is zero, add it to
/// the Available queue.
void ScheduleDAGList::ScheduleNodeTopDown(SUnit *SU) {
DEBUG(std::cerr << "*** Scheduling: ");
DEBUG(SU->dump(&DAG));
Sequence.push_back(SU);
// Bottom up: release successors.
for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Succs.begin(),
E = SU->Succs.end(); I != E; ++I) {
ReleaseSucc(I->first, I->second);
if (!I->second)
SU->NumSuccsLeft--;
}
CurrCycle++;
}
/// isReady - True if node's lower cycle bound is less or equal to the current
/// scheduling cycle. Always true if all nodes have uniform latency 1.
static inline bool isReady(SUnit *SU, unsigned CurrCycle) {
return SU->CycleBound <= CurrCycle;
}
/// ListScheduleBottomUp - The main loop of list scheduling for bottom-up
/// schedulers.
void ScheduleDAGList::ListScheduleBottomUp() {
// Add root to Available queue.
PriorityQueue->push(SUnitMap[DAG.getRoot().Val]);
// While Available queue is not empty, grab the node with the highest
// priority. If it is not ready put it back. Schedule the node.
std::vector<SUnit*> NotReady;
while (!PriorityQueue->empty()) {
SUnit *CurrNode = PriorityQueue->pop();
while (!isReady(CurrNode, CurrCycle)) {
NotReady.push_back(CurrNode);
CurrNode = PriorityQueue->pop();
}
// Add the nodes that aren't ready back onto the available list.
PriorityQueue->push_all(NotReady);
NotReady.clear();
ScheduleNodeBottomUp(CurrNode);
CurrNode->isScheduled = true;
PriorityQueue->ScheduledNode(CurrNode);
}
// Add entry node last
if (DAG.getEntryNode().Val != DAG.getRoot().Val) {
SUnit *Entry = SUnitMap[DAG.getEntryNode().Val];
Sequence.push_back(Entry);
}
// Reverse the order if it is bottom up.
std::reverse(Sequence.begin(), Sequence.end());
#ifndef NDEBUG
// Verify that all SUnits were scheduled.
bool AnyNotSched = false;
for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
if (SUnits[i].NumSuccsLeft != 0 || SUnits[i].NumChainSuccsLeft != 0) {
if (!AnyNotSched)
std::cerr << "*** List scheduling failed! ***\n";
SUnits[i].dump(&DAG);
std::cerr << "has not been scheduled!\n";
AnyNotSched = true;
}
}
assert(!AnyNotSched);
#endif
}
/// ListScheduleTopDown - The main loop of list scheduling for top-down
/// schedulers.
void ScheduleDAGList::ListScheduleTopDown() {
// Emit the entry node first.
SUnit *Entry = SUnitMap[DAG.getEntryNode().Val];
ScheduleNodeTopDown(Entry);
HazardRec->EmitInstruction(Entry->Node);
// All leaves to Available queue.
for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
// It is available if it has no predecessors.
if (SUnits[i].Preds.size() == 0 && &SUnits[i] != Entry)
PriorityQueue->push(&SUnits[i]);
}
// While Available queue is not empty, grab the node with the highest
// priority. If it is not ready put it back. Schedule the node.
std::vector<SUnit*> NotReady;
while (!PriorityQueue->empty()) {
SUnit *FoundNode = 0;
bool HasNoopHazards = false;
do {
SUnit *CurNode = PriorityQueue->pop();
// Get the node represented by this SUnit.
SDNode *N = CurNode->Node;
// If this is a pseudo op, like copyfromreg, look to see if there is a
// real target node flagged to it. If so, use the target node.
for (unsigned i = 0, e = CurNode->FlaggedNodes.size();
N->getOpcode() < ISD::BUILTIN_OP_END && i != e; ++i)
N = CurNode->FlaggedNodes[i];
HazardRecognizer::HazardType HT = HazardRec->getHazardType(N);
if (HT == HazardRecognizer::NoHazard) {
FoundNode = CurNode;
break;
}
// Remember if this is a noop hazard.
HasNoopHazards |= HT == HazardRecognizer::NoopHazard;
NotReady.push_back(CurNode);
} while (!PriorityQueue->empty());
// Add the nodes that aren't ready back onto the available list.
PriorityQueue->push_all(NotReady);
NotReady.clear();
// If we found a node to schedule, do it now.
if (FoundNode) {
ScheduleNodeTopDown(FoundNode);
HazardRec->EmitInstruction(FoundNode->Node);
FoundNode->isScheduled = true;
PriorityQueue->ScheduledNode(FoundNode);
} else if (!HasNoopHazards) {
// Otherwise, we have a pipeline stall, but no other problem, just advance
// the current cycle and try again.
DEBUG(std::cerr << "*** Advancing cycle, no work to do\n");
HazardRec->AdvanceCycle();
++NumStalls;
} else {
// Otherwise, we have no instructions to issue and we have instructions
// that will fault if we don't do this right. This is the case for
// processors without pipeline interlocks and other cases.
DEBUG(std::cerr << "*** Emitting noop\n");
HazardRec->EmitNoop();
Sequence.push_back(0); // NULL SUnit* -> noop
++NumNoops;
}
}
#ifndef NDEBUG
// Verify that all SUnits were scheduled.
bool AnyNotSched = false;
for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
if (SUnits[i].NumPredsLeft != 0 || SUnits[i].NumChainPredsLeft != 0) {
if (!AnyNotSched)
std::cerr << "*** List scheduling failed! ***\n";
SUnits[i].dump(&DAG);
std::cerr << "has not been scheduled!\n";
AnyNotSched = true;
}
}
assert(!AnyNotSched);
#endif
}
void ScheduleDAGList::BuildSchedUnits() { void ScheduleDAGList::BuildSchedUnits() {
// Reserve entries in the vector for each of the SUnits we are creating. This // Reserve entries in the vector for each of the SUnits we are creating. This
// ensure that reallocation of the vector won't happen, so SUnit*'s won't get // ensure that reallocation of the vector won't happen, so SUnit*'s won't get
@ -649,6 +406,258 @@ void ScheduleDAGList::Schedule() {
EmitSchedule(); EmitSchedule();
} }
//===----------------------------------------------------------------------===//
// Bottom-Up Scheduling
//===----------------------------------------------------------------------===//
/// ReleasePred - Decrement the NumSuccsLeft count of a predecessor. Add it to
/// the Available queue is the count reaches zero. Also update its cycle bound.
void ScheduleDAGList::ReleasePred(SUnit *PredSU, bool isChain) {
// FIXME: the distance between two nodes is not always == the predecessor's
// latency. For example, the reader can very well read the register written
// by the predecessor later than the issue cycle. It also depends on the
// interrupt model (drain vs. freeze).
PredSU->CycleBound = std::max(PredSU->CycleBound,CurrCycle + PredSU->Latency);
if (!isChain)
PredSU->NumSuccsLeft--;
else
PredSU->NumChainSuccsLeft--;
#ifndef NDEBUG
if (PredSU->NumSuccsLeft < 0 || PredSU->NumChainSuccsLeft < 0) {
std::cerr << "*** List scheduling failed! ***\n";
PredSU->dump(&DAG);
std::cerr << " has been released too many times!\n";
assert(0);
}
#endif
if ((PredSU->NumSuccsLeft + PredSU->NumChainSuccsLeft) == 0) {
// EntryToken has to go last! Special case it here.
if (PredSU->Node->getOpcode() != ISD::EntryToken) {
PredSU->isAvailable = true;
PriorityQueue->push(PredSU);
}
}
}
/// ScheduleNodeBottomUp - Add the node to the schedule. Decrement the pending
/// count of its predecessors. If a predecessor pending count is zero, add it to
/// the Available queue.
void ScheduleDAGList::ScheduleNodeBottomUp(SUnit *SU) {
DEBUG(std::cerr << "*** Scheduling: ");
DEBUG(SU->dump(&DAG));
Sequence.push_back(SU);
// Bottom up: release predecessors
for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Preds.begin(),
E = SU->Preds.end(); I != E; ++I) {
ReleasePred(I->first, I->second);
if (!I->second)
SU->NumPredsLeft--;
}
CurrCycle++;
}
/// isReady - True if node's lower cycle bound is less or equal to the current
/// scheduling cycle. Always true if all nodes have uniform latency 1.
static inline bool isReady(SUnit *SU, unsigned CurrCycle) {
return SU->CycleBound <= CurrCycle;
}
/// ListScheduleBottomUp - The main loop of list scheduling for bottom-up
/// schedulers.
void ScheduleDAGList::ListScheduleBottomUp() {
// Add root to Available queue.
PriorityQueue->push(SUnitMap[DAG.getRoot().Val]);
// While Available queue is not empty, grab the node with the highest
// priority. If it is not ready put it back. Schedule the node.
std::vector<SUnit*> NotReady;
while (!PriorityQueue->empty()) {
SUnit *CurrNode = PriorityQueue->pop();
while (!isReady(CurrNode, CurrCycle)) {
NotReady.push_back(CurrNode);
CurrNode = PriorityQueue->pop();
}
// Add the nodes that aren't ready back onto the available list.
PriorityQueue->push_all(NotReady);
NotReady.clear();
ScheduleNodeBottomUp(CurrNode);
CurrNode->isScheduled = true;
PriorityQueue->ScheduledNode(CurrNode);
}
// Add entry node last
if (DAG.getEntryNode().Val != DAG.getRoot().Val) {
SUnit *Entry = SUnitMap[DAG.getEntryNode().Val];
Sequence.push_back(Entry);
}
// Reverse the order if it is bottom up.
std::reverse(Sequence.begin(), Sequence.end());
#ifndef NDEBUG
// Verify that all SUnits were scheduled.
bool AnyNotSched = false;
for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
if (SUnits[i].NumSuccsLeft != 0 || SUnits[i].NumChainSuccsLeft != 0) {
if (!AnyNotSched)
std::cerr << "*** List scheduling failed! ***\n";
SUnits[i].dump(&DAG);
std::cerr << "has not been scheduled!\n";
AnyNotSched = true;
}
}
assert(!AnyNotSched);
#endif
}
//===----------------------------------------------------------------------===//
// Top-Down Scheduling
//===----------------------------------------------------------------------===//
/// ReleaseSucc - Decrement the NumPredsLeft count of a successor. Add it to
/// the Available queue is the count reaches zero. Also update its cycle bound.
void ScheduleDAGList::ReleaseSucc(SUnit *SuccSU, bool isChain) {
// FIXME: the distance between two nodes is not always == the predecessor's
// latency. For example, the reader can very well read the register written
// by the predecessor later than the issue cycle. It also depends on the
// interrupt model (drain vs. freeze).
SuccSU->CycleBound = std::max(SuccSU->CycleBound,CurrCycle + SuccSU->Latency);
if (!isChain)
SuccSU->NumPredsLeft--;
else
SuccSU->NumChainPredsLeft--;
#ifndef NDEBUG
if (SuccSU->NumPredsLeft < 0 || SuccSU->NumChainPredsLeft < 0) {
std::cerr << "*** List scheduling failed! ***\n";
SuccSU->dump(&DAG);
std::cerr << " has been released too many times!\n";
abort();
}
#endif
if ((SuccSU->NumPredsLeft + SuccSU->NumChainPredsLeft) == 0) {
SuccSU->isAvailable = true;
PriorityQueue->push(SuccSU);
}
}
/// ScheduleNodeTopDown - Add the node to the schedule. Decrement the pending
/// count of its successors. If a successor pending count is zero, add it to
/// the Available queue.
void ScheduleDAGList::ScheduleNodeTopDown(SUnit *SU) {
DEBUG(std::cerr << "*** Scheduling: ");
DEBUG(SU->dump(&DAG));
Sequence.push_back(SU);
// Bottom up: release successors.
for (std::set<std::pair<SUnit*, bool> >::iterator I = SU->Succs.begin(),
E = SU->Succs.end(); I != E; ++I) {
ReleaseSucc(I->first, I->second);
if (!I->second)
SU->NumSuccsLeft--;
}
CurrCycle++;
}
/// ListScheduleTopDown - The main loop of list scheduling for top-down
/// schedulers.
void ScheduleDAGList::ListScheduleTopDown() {
// Emit the entry node first.
SUnit *Entry = SUnitMap[DAG.getEntryNode().Val];
ScheduleNodeTopDown(Entry);
HazardRec->EmitInstruction(Entry->Node);
// All leaves to Available queue.
for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
// It is available if it has no predecessors.
if (SUnits[i].Preds.size() == 0 && &SUnits[i] != Entry)
PriorityQueue->push(&SUnits[i]);
}
// While Available queue is not empty, grab the node with the highest
// priority. If it is not ready put it back. Schedule the node.
std::vector<SUnit*> NotReady;
while (!PriorityQueue->empty()) {
SUnit *FoundNode = 0;
bool HasNoopHazards = false;
do {
SUnit *CurNode = PriorityQueue->pop();
// Get the node represented by this SUnit.
SDNode *N = CurNode->Node;
// If this is a pseudo op, like copyfromreg, look to see if there is a
// real target node flagged to it. If so, use the target node.
for (unsigned i = 0, e = CurNode->FlaggedNodes.size();
N->getOpcode() < ISD::BUILTIN_OP_END && i != e; ++i)
N = CurNode->FlaggedNodes[i];
HazardRecognizer::HazardType HT = HazardRec->getHazardType(N);
if (HT == HazardRecognizer::NoHazard) {
FoundNode = CurNode;
break;
}
// Remember if this is a noop hazard.
HasNoopHazards |= HT == HazardRecognizer::NoopHazard;
NotReady.push_back(CurNode);
} while (!PriorityQueue->empty());
// Add the nodes that aren't ready back onto the available list.
PriorityQueue->push_all(NotReady);
NotReady.clear();
// If we found a node to schedule, do it now.
if (FoundNode) {
ScheduleNodeTopDown(FoundNode);
HazardRec->EmitInstruction(FoundNode->Node);
FoundNode->isScheduled = true;
PriorityQueue->ScheduledNode(FoundNode);
} else if (!HasNoopHazards) {
// Otherwise, we have a pipeline stall, but no other problem, just advance
// the current cycle and try again.
DEBUG(std::cerr << "*** Advancing cycle, no work to do\n");
HazardRec->AdvanceCycle();
++NumStalls;
} else {
// Otherwise, we have no instructions to issue and we have instructions
// that will fault if we don't do this right. This is the case for
// processors without pipeline interlocks and other cases.
DEBUG(std::cerr << "*** Emitting noop\n");
HazardRec->EmitNoop();
Sequence.push_back(0); // NULL SUnit* -> noop
++NumNoops;
}
}
#ifndef NDEBUG
// Verify that all SUnits were scheduled.
bool AnyNotSched = false;
for (unsigned i = 0, e = SUnits.size(); i != e; ++i) {
if (SUnits[i].NumPredsLeft != 0 || SUnits[i].NumChainPredsLeft != 0) {
if (!AnyNotSched)
std::cerr << "*** List scheduling failed! ***\n";
SUnits[i].dump(&DAG);
std::cerr << "has not been scheduled!\n";
AnyNotSched = true;
}
}
assert(!AnyNotSched);
#endif
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// RegReductionPriorityQueue Implementation // RegReductionPriorityQueue Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//