[llvm-commits] CVS: llvm/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp
Evan Cheng
evan.cheng at apple.com
Wed Jan 25 01:14:44 PST 2006
Changes in directory llvm/lib/CodeGen/SelectionDAG:
ScheduleDAGList.cpp updated: 1.1 -> 1.2
---
Log message:
Bottom up register usage reducing list scheduler.
---
Diffs of the changes: (+451 -21)
ScheduleDAGList.cpp | 472 +++++++++++++++++++++++++++++++++++++++++++++++++---
1 files changed, 451 insertions(+), 21 deletions(-)
Index: llvm/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp
diff -u llvm/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp:1.1 llvm/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp:1.2
--- llvm/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp:1.1 Mon Jan 23 02:26:10 2006
+++ llvm/lib/CodeGen/SelectionDAG/ScheduleDAGList.cpp Wed Jan 25 03:14:32 2006
@@ -1,4 +1,4 @@
-//===-- ScheduleDAGSimple.cpp - Implement a list scheduler for isel DAG ---===//
+//===---- ScheduleDAGList.cpp - Implement a list scheduler for isel DAG ---===//
//
// The LLVM Compiler Infrastructure
//
@@ -18,44 +18,474 @@
#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetInstrInfo.h"
-#include <algorithm>
+#include "llvm/Support/Debug.h"
+#include <climits>
+#include <iostream>
+#include <memory>
#include <queue>
using namespace llvm;
+namespace {
-namespace llvm {
-/// Sorting functions for ready queue.
-struct LSSortPred : public std::binary_function<SDOperand, SDOperand, bool> {
- bool operator()(const SDOperand* left, const SDOperand* right) const {
- return true;
+/// SUnit - Scheduling unit. It's an wrapper around either a single SDNode or a
+/// group of nodes flagged together.
+struct SUnit {
+ SDNode *Node; // Representative node.
+ std::vector<SDNode*> FlaggedNodes; // All nodes flagged to Node.
+ std::vector<SDNode*> Preds; // All real predecessors.
+ std::vector<SDNode*> ChainPreds; // All chain predecessors.
+ std::vector<SDNode*> Succs; // All real successors.
+ std::vector<SDNode*> ChainSuccs; // All chain successors.
+ int NumPredsLeft; // # of preds not scheduled.
+ int NumSuccsLeft; // # of succs not scheduled.
+ int Priority1; // Scheduling priority 1.
+ int Priority2; // Scheduling priority 2.
+ unsigned Latency; // Node latency.
+ unsigned CycleBound; // Upper/lower cycle to be scheduled at.
+ unsigned Slot; // Cycle node is scheduled at.
+
+ SUnit(SDNode *node)
+ : Node(node), NumPredsLeft(0), NumSuccsLeft(0),
+ Priority1(INT_MIN), Priority2(INT_MIN), Latency(0),
+ CycleBound(0), Slot(0) {}
+
+ void dump(const SelectionDAG *G, bool All=true) const;
+};
+
+void SUnit::dump(const SelectionDAG *G, bool All) const {
+ std::cerr << "SU: ";
+ Node->dump(G);
+ std::cerr << "\n";
+ if (All) {
+ std::cerr << "# preds left : " << NumPredsLeft << "\n";
+ std::cerr << "# succs left : " << NumSuccsLeft << "\n";
+ std::cerr << "Latency : " << Latency << "\n";
+ std::cerr << "Priority : " << Priority1 << " , " << Priority2 << "\n";
+ }
+
+ if (FlaggedNodes.size() != 0) {
+ if (All)
+ std::cerr << "Flagged nodes :\n";
+ for (unsigned i = 0, e = FlaggedNodes.size(); i != e; i++) {
+ std::cerr << " ";
+ FlaggedNodes[i]->dump(G);
+ std::cerr << "\n";
+ }
+ }
+
+ if (All) {
+ if (Preds.size() != 0) {
+ std::cerr << "Predecessors :\n";
+ for (unsigned i = 0, e = Preds.size(); i != e; i++) {
+ std::cerr << " ";
+ Preds[i]->dump(G);
+ std::cerr << "\n";
+ }
+ }
+ if (ChainPreds.size() != 0) {
+ std::cerr << "Chained Preds :\n";
+ for (unsigned i = 0, e = ChainPreds.size(); i != e; i++) {
+ std::cerr << " ";
+ ChainPreds[i]->dump(G);
+ std::cerr << "\n";
+ }
+ }
+ if (Succs.size() != 0) {
+ std::cerr << "Successors :\n";
+ for (unsigned i = 0, e = Succs.size(); i != e; i++) {
+ std::cerr << " ";
+ Succs[i]->dump(G);
+ std::cerr << "\n";
+ }
+ }
+ if (ChainSuccs.size() != 0) {
+ std::cerr << "Chained succs :\n";
+ for (unsigned i = 0, e = ChainSuccs.size(); i != e; i++) {
+ std::cerr << " ";
+ ChainSuccs[i]->dump(G);
+ std::cerr << "\n";
+ }
+ }
+ }
+}
+
+/// Sorting functions for the Available queue.
+struct ls_rr_sort : public std::binary_function<SUnit*, SUnit*, bool> {
+ bool operator()(const SUnit* left, const SUnit* right) const {
+ if (left->Priority1 > right->Priority1) {
+ return true;
+ } else if (left->Priority1 == right->Priority1) {
+ unsigned lf = left->FlaggedNodes.size();
+ unsigned rf = right->FlaggedNodes.size();
+ if (lf > rf)
+ return true;
+ else if (lf == rf) {
+ if (left->Priority2 > right->Priority2)
+ return true;
+ else if (left->Priority2 == right->Priority2) {
+ if (left->CycleBound > right->CycleBound)
+ return true;
+ else
+ return left->Node->getNodeDepth() < right->Node->getNodeDepth();
+ }
+ }
+ }
+
+ return false;
}
};
/// ScheduleDAGList - List scheduler.
-
class ScheduleDAGList : public ScheduleDAG {
private:
- LSSortPred &Cmp;
+ // SDNode to SUnit mapping (many to one).
+ std::map<SDNode*, SUnit*> SUnitMap;
+ // Available queue.
+ std::priority_queue<SUnit*, std::vector<SUnit*>, ls_rr_sort> Available;
+ // The schedule.
+ std::vector<SUnit*> Sequence;
+ // Current scheduling cycle.
+ unsigned CurrCycle;
- // Ready queue
- std::priority_queue<SDOperand*, std::vector<SDOperand*>, LSSortPred> Ready;
-
public:
ScheduleDAGList(SelectionDAG &dag, MachineBasicBlock *bb,
- const TargetMachine &tm, LSSortPred cmp)
- : ScheduleDAG(listSchedulingBURR, dag, bb, tm), Cmp(cmp), Ready(Cmp)
- {};
+ const TargetMachine &tm)
+ : ScheduleDAG(listSchedulingBURR, dag, bb, tm), CurrCycle(0) {};
+
+ ~ScheduleDAGList() {
+ for (std::map<SDNode*, SUnit*>::iterator I = SUnitMap.begin(),
+ E = SUnitMap.end(); I != E; ++I) {
+ SUnit *SU = I->second;
+ // Multiple SDNode* can point to one SUnit. Do ref counting, sort of.
+ if (SU->FlaggedNodes.size() == 0)
+ delete SU;
+ else
+ SU->FlaggedNodes.pop_back();
+ }
+ }
void Schedule();
+
+ void dump() const;
+
+private:
+ void ReleasePred(SUnit *PredSU);
+ void ScheduleNode(SUnit *SU);
+ int CalcNodePriority(SUnit *SU);
+ void CalculatePriorities();
+ void ListSchedule();
+ void BuildSchedUnits();
+ void EmitSchedule();
};
-} // end namespace llvm
+} // end namespace
+
+void ScheduleDAGList::ReleasePred(SUnit *PredSU) {
+ SDNode *PredNode = PredSU->Node;
+
+ PredSU->NumSuccsLeft--;
+ if (PredSU->NumSuccsLeft == 0) {
+ // EntryToken has to go last!
+ if (PredNode->getOpcode() != ISD::EntryToken)
+ Available.push(PredSU);
+ } else if (PredSU->NumSuccsLeft < 0) {
+#ifndef NDEBUG
+ std::cerr << "*** List scheduling failed! ***\n";
+ PredSU->dump(&DAG);
+ std::cerr << " has been released too many times!\n";
+ assert(0);
+#endif
+ }
+
+ // 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);
+}
+
+/// ScheduleNode - 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::ScheduleNode(SUnit *SU) {
+ Sequence.push_back(SU);
+ SU->Slot = CurrCycle;
+
+ // Bottom up: release predecessors
+ for (unsigned i = 0, e = SU->Preds.size(); i != e; i++)
+ ReleasePred(SUnitMap[SU->Preds[i]]);
+ for (unsigned i = 0, e = SU->ChainPreds.size(); i != e; i++)
+ ReleasePred(SUnitMap[SU->ChainPreds[i]]);
+
+ 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;
+}
+
+/// ListSchedule - The main loop of list scheduling.
+void ScheduleDAGList::ListSchedule() {
+ // Add root to Available queue
+ SUnit *Root = SUnitMap[DAG.getRoot().Val];
+ Available.push(Root);
+
+ // 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 (!Available.empty()) {
+ SUnit *CurrNode = Available.top();
+ Available.pop();
+
+ NotReady.clear();
+ while (!isReady(CurrNode, CurrCycle)) {
+ NotReady.push_back(CurrNode);
+ CurrNode = Available.top();
+ Available.pop();
+ }
+ for (unsigned i = 0, e = NotReady.size(); i != e; ++i)
+ Available.push(NotReady[i]);
+
+ DEBUG(std::cerr << "\n*** Scheduling: ");
+ DEBUG(CurrNode->dump(&DAG, false));
+ DEBUG(std::cerr << "\n");
+ ScheduleNode(CurrNode);
+ }
+
+ // Add entry node last
+ if (DAG.getEntryNode().Val != DAG.getRoot().Val) {
+ SUnit *Entry = SUnitMap[DAG.getEntryNode().Val];
+ Entry->Slot = CurrCycle;
+ Sequence.push_back(Entry);
+ }
+
+#ifndef NDEBUG
+ for (std::map<SDNode*, SUnit*>::iterator I = SUnitMap.begin(),
+ E = SUnitMap.end(); I != E; ++I) {
+ SUnit *SU = I->second;
+ if (SU->NumSuccsLeft != 0) {
+ std::cerr << "*** List scheduling failed! ***\n";
+ SU->dump(&DAG);
+ std::cerr << " has not been scheduled!\n";
+ assert(0);
+ }
+#endif
+ }
+
+
+ // Reverse the order if it is bottom up.
+ std::reverse(Sequence.begin(), Sequence.end());
+ DEBUG(std::cerr << "*** Final schedule ***\n");
+ DEBUG(dump());
+}
+
+/// CalcNodePriority - Priority 1 is just the number of live range genned - number
+/// of live range killed. Priority 2 is the Sethi Ullman number. It returns
+/// priority 2 since it is calculated recursively.
+/// Smaller number is the higher priority in both cases.
+int ScheduleDAGList::CalcNodePriority(SUnit *SU) {
+ if (SU->Priority2 != INT_MIN)
+ return SU->Priority2;
+
+ SU->Priority1 = SU->Preds.size() - SU->Succs.size();
+
+ if (SU->Preds.size() == 0) {
+ SU->Priority2 = 1;
+ } else {
+ int Extra = 0;
+ for (unsigned i = 0, e = SU->Preds.size(); i != e; i++) {
+ SDNode *PredN = SU->Preds[i];
+ SUnit *PredSU = SUnitMap[PredN];
+ int PredPriority = CalcNodePriority(PredSU);
+ if (PredPriority > SU->Priority2) {
+ SU->Priority2 = PredPriority;
+ Extra = 0;
+ } else if (PredPriority == SU->Priority2)
+ Extra++;
+ }
+
+ if (SU->Node->getOpcode() != ISD::TokenFactor)
+ SU->Priority2 += Extra;
+ else
+ SU->Priority2 = (Extra == 1) ? 0 : Extra-1;
+ }
+
+ return SU->Priority2;
+}
+
+/// CalculatePriorities - Calculate priorities of all scheduling units.
+void ScheduleDAGList::CalculatePriorities() {
+ for (std::map<SDNode*, SUnit*>::iterator I = SUnitMap.begin(),
+ E = SUnitMap.end(); I != E; ++I) {
+ SUnit *SU = I->second;
+ // FIXME: assumes uniform latency for now.
+ SU->Latency = 1;
+ (void)CalcNodePriority(SU);
+ DEBUG(I->second->dump(&DAG));
+ DEBUG(std::cerr << "\n");
+ }
+}
+
+static bool isChainUse(SDNode *N, SDNode *UseN) {
+ for (unsigned i = 0, e = UseN->getNumOperands(); i != e; i++) {
+ SDOperand Op = UseN->getOperand(i);
+ if (Op.Val == N) {
+ MVT::ValueType VT = N->getValueType(Op.ResNo);
+ if (VT == MVT::Other)
+ return true;
+ }
+ }
+ return false;
+}
+
+void ScheduleDAGList::BuildSchedUnits() {
+ for (unsigned i = 0, N = NodeCount; i < N; i++) {
+ NodeInfo *NI = &Info[i];
+ SDNode *N = NI->Node;
+ if (!isPassiveNode(N)) {
+ SUnit *SU;
+ if (NI->isInGroup()) {
+ if (NI != NI->Group->getBottom()) // Bottom up, so only look at bottom
+ continue; // node of the NodeGroup
+
+ SU = new SUnit(N);
+
+ // Find the flagged nodes.
+ SDOperand FlagOp = N->getOperand(N->getNumOperands() - 1);
+ SDNode *Flag = FlagOp.Val;
+ unsigned ResNo = FlagOp.ResNo;
+ while (Flag->getValueType(ResNo) == MVT::Flag) {
+ NodeInfo *FNI = getNI(Flag);
+ assert(FNI->Group == NI->Group);
+ SU->FlaggedNodes.insert(SU->FlaggedNodes.begin(), Flag);
+ SUnitMap[Flag] = SU;
+
+ FlagOp = Flag->getOperand(Flag->getNumOperands() - 1);
+ Flag = FlagOp.Val;
+ ResNo = FlagOp.ResNo;
+ }
+
+ // Find all predecessors (of the group).
+ NodeGroupOpIterator NGOI(NI);
+ while (!NGOI.isEnd()) {
+ SDOperand Op = NGOI.next();
+ SDNode *OpN = Op.Val;
+ MVT::ValueType VT = OpN->getValueType(Op.ResNo);
+ NodeInfo *OpNI = getNI(OpN);
+ if (OpNI->Group != NI->Group && !isPassiveNode(OpN)) {
+ assert(VT != MVT::Flag);
+ if (VT == MVT::Other)
+ SU->ChainPreds.push_back(OpN);
+ else
+ SU->Preds.push_back(OpN);
+ SU->NumPredsLeft++;
+ }
+ }
+
+ // Find all successors (of the group).
+ NodeGroupIterator NGI(NI);
+ while (NodeInfo *GNI = NGI.next()) {
+ SDNode *GN = GNI->Node;
+ for (SDNode::use_iterator ui = GN->use_begin(), e = GN->use_end();
+ ui != e; ++ui) {
+ SDNode *UseN = *ui;
+ NodeInfo *UseNI = getNI(UseN);
+ if (UseNI->Group != NI->Group) {
+ if (isChainUse(GN, UseN))
+ SU->ChainSuccs.push_back(UseN);
+ else
+ SU->Succs.push_back(UseN);
+ SU->NumSuccsLeft++;
+ }
+ }
+ }
+ } else {
+ SU = new SUnit(N);
+
+ // Find node predecessors.
+ for (unsigned j = 0, e = N->getNumOperands(); j != e; j++) {
+ SDOperand Op = N->getOperand(j);
+ SDNode *OpN = Op.Val;
+ MVT::ValueType VT = OpN->getValueType(Op.ResNo);
+ if (!isPassiveNode(OpN)) {
+ assert(VT != MVT::Flag);
+ if (VT == MVT::Other)
+ SU->ChainPreds.push_back(OpN);
+ else
+ SU->Preds.push_back(OpN);
+ SU->NumPredsLeft++;
+ }
+ }
+
+ // Find node successors.
+ for (SDNode::use_iterator ui = N->use_begin(), e = N->use_end();
+ ui != e; ++ui) {
+ SDNode *UseN = *ui;
+ if (isChainUse(N, UseN))
+ SU->ChainSuccs.push_back(UseN);
+ else
+ SU->Succs.push_back(UseN);
+ SU->NumSuccsLeft++;
+ }
+ }
+
+ SUnitMap[N] = SU;
+ }
+ }
+
+#ifndef NDEBUG
+ for (std::map<SDNode*, SUnit*>::iterator I = SUnitMap.begin(),
+ E = SUnitMap.end(); I != E; ++I) {
+ SUnit *SU = I->second;
+ DEBUG(I->second->dump(&DAG));
+ DEBUG(std::cerr << "\n");
+ }
+#endif
+}
+
+/// EmitSchedule - Emit the machine code in scheduled order.
+void ScheduleDAGList::EmitSchedule() {
+ for (unsigned i = 0, e = Sequence.size(); i != e; i++) {
+ SDNode *N;
+ SUnit *SU = Sequence[i];
+ for (unsigned j = 0, ee = SU->FlaggedNodes.size(); j != ee; j++) {
+ N = SU->FlaggedNodes[j];
+ EmitNode(getNI(N));
+ }
+ EmitNode(getNI(SU->Node));
+ }
+}
+
+/// dump - dump the schedule.
+void ScheduleDAGList::dump() const {
+ for (unsigned i = 0, e = Sequence.size(); i != e; i++) {
+ SUnit *SU = Sequence[i];
+ SU->dump(&DAG, false);
+ }
+}
+
+/// Schedule - Schedule the DAG using list scheduling.
+/// FIXME: Right now it only supports the burr (bottom up register reducing)
+/// heuristic.
void ScheduleDAGList::Schedule() {
+ DEBUG(std::cerr << "********** List Scheduling **********\n");
+
+ // Build scheduling units.
+ BuildSchedUnits();
+
+ // Calculate node prirorities.
+ CalculatePriorities();
+
+ // Execute the actual scheduling loop.
+ ListSchedule();
+
+ // Emit in scheduled order
+ EmitSchedule();
}
-
-llvm::ScheduleDAG*
-llvm::createBURRListDAGScheduler(SelectionDAG &DAG,
- MachineBasicBlock *BB) {
- return new ScheduleDAGList(DAG, BB, DAG.getTarget(), LSSortPred());
+llvm::ScheduleDAG* llvm::createBURRListDAGScheduler(SelectionDAG &DAG,
+ MachineBasicBlock *BB) {
+ return new ScheduleDAGList(DAG, BB, DAG.getTarget());
}
More information about the llvm-commits
mailing list