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:
parent
ca3dc213dc
commit
2922daab4b
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user