1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 04:02:41 +01:00

Bottom up register pressure reduction work: clean up some hacks and enhanced

the heuristic to further reduce spills for several test cases. (Note, it may
not necessarily translate to runtime win!)

llvm-svn: 28076
This commit is contained in:
Evan Cheng 2006-05-03 02:10:45 +00:00
parent ca3dc213dc
commit 2922daab4b

View File

@ -32,13 +32,6 @@
#include "llvm/Support/CommandLine.h" #include "llvm/Support/CommandLine.h"
using namespace llvm; using namespace llvm;
namespace {
// TEMPORARY option to test a fix.
cl::opt<bool>
SchedIgnorStore("sched-ignore-store", cl::Hidden);
}
namespace { namespace {
Statistic<> NumNoops ("scheduler", "Number of noops inserted"); Statistic<> NumNoops ("scheduler", "Number of noops inserted");
Statistic<> NumStalls("scheduler", "Number of pipeline stalls"); Statistic<> NumStalls("scheduler", "Number of pipeline stalls");
@ -58,7 +51,6 @@ namespace {
short NumSuccsLeft; // # of succs not scheduled. short NumSuccsLeft; // # of succs not scheduled.
short NumChainPredsLeft; // # of chain preds not scheduled. short NumChainPredsLeft; // # of chain preds not scheduled.
short NumChainSuccsLeft; // # of chain succs not scheduled. short NumChainSuccsLeft; // # of chain succs not scheduled.
bool isStore : 1; // Is a store.
bool isTwoAddress : 1; // Is a two-address instruction. bool isTwoAddress : 1; // Is a two-address instruction.
bool isDefNUseOperand : 1; // Is a def&use operand. bool isDefNUseOperand : 1; // Is a def&use operand.
bool isPending : 1; // True once pending. bool isPending : 1; // True once pending.
@ -71,9 +63,9 @@ namespace {
SUnit(SDNode *node, unsigned nodenum) SUnit(SDNode *node, unsigned nodenum)
: Node(node), NumPredsLeft(0), NumSuccsLeft(0), : Node(node), NumPredsLeft(0), NumSuccsLeft(0),
NumChainPredsLeft(0), NumChainSuccsLeft(0), isStore(false), NumChainPredsLeft(0), NumChainSuccsLeft(0),
isTwoAddress(false), isDefNUseOperand(false), isTwoAddress(false), isDefNUseOperand(false), isPending(false),
isPending(false), isAvailable(false), isScheduled(false), isAvailable(false), isScheduled(false),
Latency(0), CycleBound(0), Cycle(0), NodeNum(nodenum) {} Latency(0), CycleBound(0), Cycle(0), NodeNum(nodenum) {}
void dump(const SelectionDAG *G) const; void dump(const SelectionDAG *G) const;
@ -82,7 +74,7 @@ namespace {
} }
void SUnit::dump(const SelectionDAG *G) const { void SUnit::dump(const SelectionDAG *G) const {
std::cerr << "SU: "; std::cerr << "SU(" << NodeNum << "): ";
Node->dump(G); Node->dump(G);
std::cerr << "\n"; std::cerr << "\n";
if (FlaggedNodes.size() != 0) { if (FlaggedNodes.size() != 0) {
@ -325,11 +317,13 @@ void ScheduleDAGList::BuildSchedUnits() {
if (MainNode->isTargetOpcode()) { if (MainNode->isTargetOpcode()) {
unsigned Opc = MainNode->getTargetOpcode(); unsigned Opc = MainNode->getTargetOpcode();
if (TII->isTwoAddrInstr(Opc)) if (TII->isTwoAddrInstr(Opc)) {
SU->isTwoAddress = true; SU->isTwoAddress = true;
if (TII->isStore(Opc)) SDNode *OpN = MainNode->getOperand(0).Val;
if (!SchedIgnorStore) SUnit *OpSU = SUnitMap[OpN];
SU->isStore = true; if (OpSU)
OpSU->isDefNUseOperand = true;
}
} }
// Find all predecessors and successors of the group. // Find all predecessors and successors of the group.
@ -345,7 +339,7 @@ void ScheduleDAGList::BuildSchedUnits() {
SUnit *OpSU = SUnitMap[OpN]; SUnit *OpSU = SUnitMap[OpN];
assert(OpSU && "Node has no SUnit!"); assert(OpSU && "Node has no SUnit!");
if (OpSU == SU) continue; // In the same group. if (OpSU == SU) continue; // In the same group.
MVT::ValueType OpVT = N->getOperand(i).getValueType(); MVT::ValueType OpVT = N->getOperand(i).getValueType();
assert(OpVT != MVT::Flag && "Flagged nodes should be in same sunit!"); assert(OpVT != MVT::Flag && "Flagged nodes should be in same sunit!");
bool isChain = OpVT == MVT::Other; bool isChain = OpVT == MVT::Other;
@ -470,6 +464,7 @@ void ScheduleDAGList::ScheduleNodeBottomUp(SUnit *SU, unsigned CurCycle) {
DEBUG(SU->dump(&DAG)); DEBUG(SU->dump(&DAG));
SU->Cycle = CurCycle; SU->Cycle = CurCycle;
AvailableQueue->ScheduledNode(SU);
Sequence.push_back(SU); Sequence.push_back(SU);
// Bottom up: release predecessors // Bottom up: release predecessors
@ -480,6 +475,8 @@ void ScheduleDAGList::ScheduleNodeBottomUp(SUnit *SU, unsigned CurCycle) {
// calculate directly. // calculate directly.
if (!I->second) if (!I->second)
SU->NumPredsLeft--; SU->NumPredsLeft--;
else
SU->NumChainPredsLeft--;
} }
} }
@ -499,9 +496,9 @@ void ScheduleDAGList::ListScheduleBottomUp() {
// While Available queue is not empty, grab the node with the highest // While Available queue is not empty, grab the node with the highest
// priority. If it is not ready put it back. Schedule the node. // priority. If it is not ready put it back. Schedule the node.
std::vector<SUnit*> NotReady; std::vector<SUnit*> NotReady;
SUnit *CurrNode = NULL;
while (!AvailableQueue->empty()) { while (!AvailableQueue->empty()) {
SUnit *CurrNode = AvailableQueue->pop(); SUnit *CurrNode = AvailableQueue->pop();
while (!isReady(CurrNode, CurrCycle)) { while (!isReady(CurrNode, CurrCycle)) {
NotReady.push_back(CurrNode); NotReady.push_back(CurrNode);
CurrNode = AvailableQueue->pop(); CurrNode = AvailableQueue->pop();
@ -514,7 +511,6 @@ void ScheduleDAGList::ListScheduleBottomUp() {
ScheduleNodeBottomUp(CurrNode, CurrCycle); ScheduleNodeBottomUp(CurrNode, CurrCycle);
CurrCycle++; CurrCycle++;
CurrNode->isScheduled = true; CurrNode->isScheduled = true;
AvailableQueue->ScheduledNode(CurrNode);
} }
// Add entry node last // Add entry node last
@ -748,12 +744,12 @@ namespace {
const std::vector<SUnit> *SUnits; const std::vector<SUnit> *SUnits;
// SethiUllmanNumbers - The SethiUllman number for each node. // SethiUllmanNumbers - The SethiUllman number for each node.
std::vector<unsigned> SethiUllmanNumbers; std::vector<int> SethiUllmanNumbers;
std::priority_queue<SUnit*, std::vector<SUnit*>, ls_rr_sort> Queue; std::priority_queue<SUnit*, std::vector<SUnit*>, ls_rr_sort> Queue;
public: public:
RegReductionPriorityQueue() : Queue(ls_rr_sort(this)) { RegReductionPriorityQueue() :
} Queue(ls_rr_sort(this)) {}
void initNodes(const std::vector<SUnit> &sunits) { void initNodes(const std::vector<SUnit> &sunits) {
SUnits = &sunits; SUnits = &sunits;
@ -765,7 +761,7 @@ namespace {
SethiUllmanNumbers.clear(); SethiUllmanNumbers.clear();
} }
unsigned getSethiUllmanNumber(unsigned NodeNum) const { int getSethiUllmanNumber(unsigned NodeNum) const {
assert(NodeNum < SethiUllmanNumbers.size()); assert(NodeNum < SethiUllmanNumbers.size());
return SethiUllmanNumbers[NodeNum]; return SethiUllmanNumbers[NodeNum];
} }
@ -785,88 +781,89 @@ namespace {
Queue.pop(); Queue.pop();
return V; return V;
} }
private: private:
void CalculatePriorities(); void CalculatePriorities();
unsigned CalcNodePriority(const SUnit *SU); int CalcNodePriority(const SUnit *SU);
}; };
} }
bool ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const { bool ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const {
unsigned LeftNum = left->NodeNum; unsigned LeftNum = left->NodeNum;
unsigned RightNum = right->NodeNum; unsigned RightNum = right->NodeNum;
bool LIsTarget = left->Node->isTargetOpcode();
int LBonus = (int)left ->isDefNUseOperand; bool RIsTarget = right->Node->isTargetOpcode();
int RBonus = (int)right->isDefNUseOperand; int LPriority = SPQ->getSethiUllmanNumber(LeftNum);
int RPriority = SPQ->getSethiUllmanNumber(RightNum);
bool LIsFloater = LIsTarget && (LPriority == 1 || LPriority == 0);
bool RIsFloater = RIsTarget && (RPriority == 1 || RPriority == 0);
// Special tie breaker: if two nodes share a operand, the one that // Schedule floaters (e.g. load from some constant address) and immediate use
// use it as a def&use operand is preferred. // of floaters (with no other operands) just before the use.
if (left->isTwoAddress && !right->isTwoAddress) { if (LIsFloater && !RIsFloater)
SDNode *DUNode = left->Node->getOperand(0).Val; LPriority += 2;
if (DUNode->isOperand(right->Node)) else if (!LIsFloater && RIsFloater)
LBonus++; RPriority += 2;
}
if (!left->isTwoAddress && right->isTwoAddress) {
SDNode *DUNode = right->Node->getOperand(0).Val;
if (DUNode->isOperand(left->Node))
RBonus++;
}
// Push stores up as much as possible. This really help code like this:
// load
// compute
// store
// load
// compute
// store
// This would make sure the scheduled code completed all computations and
// the stores before the next series of computation starts.
if (!left->isStore && right->isStore)
LBonus += 4;
if (left->isStore && !right->isStore)
RBonus += 4;
// Priority1 is just the number of live range genned. // Special tie breaker: if two nodes share a operand, the one that use it
int LPriority1 = left ->NumPredsLeft - LBonus; // as a def&use operand is preferred.
int RPriority1 = right->NumPredsLeft - RBonus; if (LIsTarget && RIsTarget) {
int LPriority2 = SPQ->getSethiUllmanNumber(LeftNum) + LBonus; if (left->isTwoAddress && !right->isTwoAddress) {
int RPriority2 = SPQ->getSethiUllmanNumber(RightNum) + RBonus; SDNode *DUNode = left->Node->getOperand(0).Val;
if (DUNode->isOperand(right->Node))
if (LPriority1 > RPriority1) LPriority += 2;
}
if (!left->isTwoAddress && right->isTwoAddress) {
SDNode *DUNode = right->Node->getOperand(0).Val;
if (DUNode->isOperand(left->Node))
RPriority += 2;
}
}
if (LPriority < RPriority)
return true; return true;
else if (LPriority1 == RPriority1) else if (LPriority == RPriority)
if (LPriority2 < RPriority2) if (left->NumPredsLeft > right->NumPredsLeft)
return true; return true;
else if (LPriority2 == RPriority2) else if (left->NumPredsLeft == right->NumPredsLeft)
if (left->CycleBound > right->CycleBound) if (left->CycleBound > right->CycleBound)
return true; return true;
return false; return false;
} }
/// CalcNodePriority - Priority is the Sethi Ullman number. /// CalcNodePriority - Priority is the Sethi Ullman number.
/// Smaller number is the higher priority. /// Smaller number is the higher priority.
unsigned RegReductionPriorityQueue::CalcNodePriority(const SUnit *SU) { int RegReductionPriorityQueue::CalcNodePriority(const SUnit *SU) {
unsigned &SethiUllmanNumber = SethiUllmanNumbers[SU->NodeNum]; int &SethiUllmanNumber = SethiUllmanNumbers[SU->NodeNum];
if (SethiUllmanNumber != 0) if (SethiUllmanNumber != 0)
return SethiUllmanNumber; return SethiUllmanNumber;
if (SU->Preds.size() == 0) { unsigned Opc = SU->Node->getOpcode();
if (Opc == ISD::TokenFactor || Opc == ISD::CopyToReg)
SethiUllmanNumber = INT_MAX - 10;
else if (SU->NumSuccsLeft == 0)
// If SU does not have a use, i.e. it doesn't produce a value that would
// be consumed (e.g. store), then it terminates a chain of computation.
// Give it a small SethiUllman number so it will be scheduled right before its
// predecessors that it doesn't lengthen their live ranges.
SethiUllmanNumber = INT_MIN + 10;
else if (SU->NumPredsLeft == 0 && Opc != ISD::CopyFromReg)
SethiUllmanNumber = 1; SethiUllmanNumber = 1;
} else { else {
int Extra = 0; int Extra = 0;
for (std::set<std::pair<SUnit*, bool> >::const_iterator for (std::set<std::pair<SUnit*, bool> >::const_iterator
I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) { I = SU->Preds.begin(), E = SU->Preds.end(); I != E; ++I) {
if (I->second) continue; // ignore chain preds. if (I->second) continue; // ignore chain preds
SUnit *PredSU = I->first; SUnit *PredSU = I->first;
unsigned PredSethiUllman = CalcNodePriority(PredSU); int PredSethiUllman = CalcNodePriority(PredSU);
if (PredSethiUllman > SethiUllmanNumber) { if (PredSethiUllman > SethiUllmanNumber) {
SethiUllmanNumber = PredSethiUllman; SethiUllmanNumber = PredSethiUllman;
Extra = 0; Extra = 0;
} else if (PredSethiUllman == SethiUllmanNumber) } else if (PredSethiUllman == SethiUllmanNumber && !I->second)
Extra++; Extra++;
} }
SethiUllmanNumber += Extra; SethiUllmanNumber += Extra;
} }
@ -964,7 +961,7 @@ public:
// single predecessor has a higher priority, since scheduling it will make // single predecessor has a higher priority, since scheduling it will make
// the node available. // the node available.
void ScheduledNode(SUnit *Node); void ScheduledNode(SUnit *Node);
private: private:
void CalculatePriorities(); void CalculatePriorities();
int CalcLatency(const SUnit &SU); int CalcLatency(const SUnit &SU);