Fix for PR1075: bottom-up register-reduction scheduling actually increases register pressure.

- Fixed bugs in sethi-ullman number computation and priority queue comparison
functions.
- Separate code that handles priority computation special cases from SU number computation.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@33025 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Evan Cheng 2007-01-08 23:50:38 +00:00
parent ddae4bd683
commit c62d4bb695

View File

@ -414,6 +414,12 @@ namespace {
}; };
} // end anonymous namespace } // end anonymous namespace
static inline bool isCopyFromLiveIn(const SUnit *SU) {
SDNode *N = SU->Node;
return N->getOpcode() == ISD::CopyFromReg &&
N->getOperand(N->getNumOperands()-1).getValueType() != MVT::Flag;
}
namespace { namespace {
template<class SF> template<class SF>
class VISIBILITY_HIDDEN RegReductionPriorityQueue class VISIBILITY_HIDDEN RegReductionPriorityQueue
@ -428,7 +434,7 @@ namespace {
std::vector<SUnit> &sunits) {} std::vector<SUnit> &sunits) {}
virtual void releaseState() {} virtual void releaseState() {}
virtual int getSethiUllmanNumber(unsigned NodeNum) const { virtual unsigned getSethiUllmanNumber(const SUnit *SU) const {
return 0; return 0;
} }
@ -464,7 +470,7 @@ 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<int> SethiUllmanNumbers; std::vector<unsigned> SethiUllmanNumbers;
const TargetInstrInfo *TII; const TargetInstrInfo *TII;
public: public:
@ -486,9 +492,30 @@ namespace {
SethiUllmanNumbers.clear(); SethiUllmanNumbers.clear();
} }
int getSethiUllmanNumber(unsigned NodeNum) const { unsigned getSethiUllmanNumber(const SUnit *SU) const {
assert(NodeNum < SethiUllmanNumbers.size()); assert(SU->NodeNum < SethiUllmanNumbers.size());
return SethiUllmanNumbers[NodeNum]; unsigned Opc = SU->Node->getOpcode();
if (Opc == ISD::CopyFromReg && !isCopyFromLiveIn(SU))
// CopyFromReg should be close to its def because it restricts
// allocation choices. But if it is a livein then perhaps we want it
// closer to its uses so it can be coalesced.
return 0xffff;
else if (Opc == ISD::TokenFactor || Opc == ISD::CopyToReg)
// CopyToReg should be close to its uses to facilitate coalescing and
// avoid spilling.
return 0;
else if (SU->NumSuccs == 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 large SethiUllman number so it will be scheduled right
// before its predecessors that it doesn't lengthen their live ranges.
return 0xffff;
else if (SU->NumPreds == 0)
// If SU does not have a def, schedule it close to its uses because it
// does not lengthen any live ranges.
return 0;
else
return SethiUllmanNumbers[SU->NodeNum];
} }
bool isDUOperand(const SUnit *SU1, const SUnit *SU2) { bool isDUOperand(const SUnit *SU1, const SUnit *SU2) {
@ -507,7 +534,7 @@ namespace {
bool canClobber(SUnit *SU, SUnit *Op); bool canClobber(SUnit *SU, SUnit *Op);
void AddPseudoTwoAddrDeps(); void AddPseudoTwoAddrDeps();
void CalculatePriorities(); void CalculatePriorities();
int CalcNodePriority(const SUnit *SU); unsigned CalcNodePriority(const SUnit *SU);
}; };
@ -520,7 +547,7 @@ 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<int> SethiUllmanNumbers; std::vector<unsigned> SethiUllmanNumbers;
public: public:
TDRegReductionPriorityQueue() {} TDRegReductionPriorityQueue() {}
@ -538,86 +565,38 @@ namespace {
SethiUllmanNumbers.clear(); SethiUllmanNumbers.clear();
} }
int getSethiUllmanNumber(unsigned NodeNum) const { unsigned getSethiUllmanNumber(const SUnit *SU) const {
assert(NodeNum < SethiUllmanNumbers.size()); assert(SU->NodeNum < SethiUllmanNumbers.size());
return SethiUllmanNumbers[NodeNum]; return SethiUllmanNumbers[SU->NodeNum];
} }
private: private:
void CalculatePriorities(); void CalculatePriorities();
int CalcNodePriority(const SUnit *SU); unsigned CalcNodePriority(const SUnit *SU);
}; };
} }
static bool isFloater(const SUnit *SU) {
if (SU->Node->isTargetOpcode()) {
if (SU->NumPreds == 0)
return true;
if (SU->NumPreds == 1) {
for (SUnit::const_pred_iterator I = SU->Preds.begin(),E = SU->Preds.end();
I != E; ++I) {
if (I->second) continue;
SUnit *PredSU = I->first;
unsigned Opc = PredSU->Node->getOpcode();
if (Opc != ISD::EntryToken && Opc != ISD::TokenFactor &&
Opc != ISD::CopyToReg)
return false;
}
return true;
}
}
return false;
}
static bool isSimpleFloaterUse(const SUnit *SU) {
unsigned NumOps = 0;
for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
I != E; ++I) {
if (I->second) continue;
if (++NumOps > 1)
return false;
if (!isFloater(I->first))
return false;
}
return true;
}
// Bottom up // Bottom up
bool bu_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const { bool bu_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const {
unsigned LeftNum = left->NodeNum;
unsigned RightNum = right->NodeNum;
bool LIsTarget = left->Node->isTargetOpcode(); bool LIsTarget = left->Node->isTargetOpcode();
bool RIsTarget = right->Node->isTargetOpcode(); bool RIsTarget = right->Node->isTargetOpcode();
int LPriority = SPQ->getSethiUllmanNumber(LeftNum); unsigned LPriority = SPQ->getSethiUllmanNumber(left);
int RPriority = SPQ->getSethiUllmanNumber(RightNum); unsigned RPriority = SPQ->getSethiUllmanNumber(right);
int LBonus = 0;
int RBonus = 0;
// Schedule floaters (e.g. load from some constant address) and those nodes
// with a single predecessor each first. They maintain / reduce register
// pressure.
if (isFloater(left) || isSimpleFloaterUse(left))
LBonus += 2;
if (isFloater(right) || isSimpleFloaterUse(right))
RBonus += 2;
// Special tie breaker: if two nodes share a operand, the one that use it // Special tie breaker: if two nodes share a operand, the one that use it
// as a def&use operand is preferred. // as a def&use operand is preferred.
if (LIsTarget && RIsTarget) { if (LIsTarget && RIsTarget) {
if (left->isTwoAddress && !right->isTwoAddress) { if (left->isTwoAddress && !right->isTwoAddress)
if (SPQ->isDUOperand(left, right)) if (SPQ->isDUOperand(left, right))
LBonus += 2; return false;
} if (!left->isTwoAddress && right->isTwoAddress)
if (!left->isTwoAddress && right->isTwoAddress) {
if (SPQ->isDUOperand(right, left)) if (SPQ->isDUOperand(right, left))
RBonus += 2; return true;
}
} }
if (LPriority+LBonus < RPriority+RBonus) if (LPriority > RPriority)
return true; return true;
else if (LPriority+LBonus == RPriority+RBonus) else if (LPriority == RPriority)
if (left->Height > right->Height) if (left->Height > right->Height)
return true; return true;
else if (left->Height == right->Height) else if (left->Height == right->Height)
@ -629,12 +608,6 @@ bool bu_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const {
return false; return false;
} }
static inline bool isCopyFromLiveIn(const SUnit *SU) {
SDNode *N = SU->Node;
return N->getOpcode() == ISD::CopyFromReg &&
N->getOperand(N->getNumOperands()-1).getValueType() != MVT::Flag;
}
// FIXME: This is probably too slow! // FIXME: This is probably too slow!
static void isReachable(SUnit *SU, SUnit *TargetSU, static void isReachable(SUnit *SU, SUnit *TargetSU,
std::set<SUnit *> &Visited, bool &Reached) { std::set<SUnit *> &Visited, bool &Reached) {
@ -723,47 +696,28 @@ void BURegReductionPriorityQueue<SF>::AddPseudoTwoAddrDeps() {
/// 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.
template<class SF> template<class SF>
int BURegReductionPriorityQueue<SF>::CalcNodePriority(const SUnit *SU) { unsigned BURegReductionPriorityQueue<SF>::CalcNodePriority(const SUnit *SU) {
int &SethiUllmanNumber = SethiUllmanNumbers[SU->NodeNum]; unsigned &SethiUllmanNumber = SethiUllmanNumbers[SU->NodeNum];
if (SethiUllmanNumber != 0) if (SethiUllmanNumber != 0)
return SethiUllmanNumber; return SethiUllmanNumber;
unsigned Opc = SU->Node->getOpcode(); unsigned Extra = 0;
if (Opc == ISD::CopyFromReg && !isCopyFromLiveIn(SU)) for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
// CopyFromReg should be close to its def because it restricts allocation I != E; ++I) {
// choices. But if it is a livein then perhaps we want it closer to the if (I->second) continue; // ignore chain preds
// uses so it can be coalesced. SUnit *PredSU = I->first;
SethiUllmanNumber = INT_MIN + 10; unsigned PredSethiUllman = CalcNodePriority(PredSU);
else if (Opc == ISD::TokenFactor || Opc == ISD::CopyToReg) if (PredSethiUllman > SethiUllmanNumber) {
// CopyToReg should be close to its uses to facilitate coalescing and avoid SethiUllmanNumber = PredSethiUllman;
// spilling. Extra = 0;
SethiUllmanNumber = INT_MAX - 10; } else if (PredSethiUllman == SethiUllmanNumber && !I->second)
else if (SU->NumSuccsLeft == 0) Extra++;
// 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)
// If SU does not have a def, schedule it close to its uses because it does
// not lengthen any live ranges.
SethiUllmanNumber = INT_MAX - 10;
else {
int Extra = 0;
for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
I != E; ++I) {
if (I->second) continue; // ignore chain preds
SUnit *PredSU = I->first;
int PredSethiUllman = CalcNodePriority(PredSU);
if (PredSethiUllman > SethiUllmanNumber) {
SethiUllmanNumber = PredSethiUllman;
Extra = 0;
} else if (PredSethiUllman == SethiUllmanNumber && !I->second)
Extra++;
}
SethiUllmanNumber += Extra;
} }
SethiUllmanNumber += Extra;
if (SethiUllmanNumber == 0)
SethiUllmanNumber = 1;
return SethiUllmanNumber; return SethiUllmanNumber;
} }
@ -796,10 +750,8 @@ static unsigned SumOfUnscheduledPredsOfSuccs(const SUnit *SU) {
// Top down // Top down
bool td_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const { bool td_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const {
unsigned LeftNum = left->NodeNum; unsigned LPriority = SPQ->getSethiUllmanNumber(left);
unsigned RightNum = right->NodeNum; unsigned RPriority = SPQ->getSethiUllmanNumber(right);
int LPriority = SPQ->getSethiUllmanNumber(LeftNum);
int RPriority = SPQ->getSethiUllmanNumber(RightNum);
bool LIsTarget = left->Node->isTargetOpcode(); bool LIsTarget = left->Node->isTargetOpcode();
bool RIsTarget = right->Node->isTargetOpcode(); bool RIsTarget = right->Node->isTargetOpcode();
bool LIsFloater = LIsTarget && left->NumPreds == 0; bool LIsFloater = LIsTarget && left->NumPreds == 0;
@ -852,30 +804,30 @@ bool td_ls_rr_sort::operator()(const SUnit *left, const SUnit *right) const {
/// 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.
template<class SF> template<class SF>
int TDRegReductionPriorityQueue<SF>::CalcNodePriority(const SUnit *SU) { unsigned TDRegReductionPriorityQueue<SF>::CalcNodePriority(const SUnit *SU) {
int &SethiUllmanNumber = SethiUllmanNumbers[SU->NodeNum]; unsigned &SethiUllmanNumber = SethiUllmanNumbers[SU->NodeNum];
if (SethiUllmanNumber != 0) if (SethiUllmanNumber != 0)
return SethiUllmanNumber; return SethiUllmanNumber;
unsigned Opc = SU->Node->getOpcode(); unsigned Opc = SU->Node->getOpcode();
if (Opc == ISD::TokenFactor || Opc == ISD::CopyToReg) if (Opc == ISD::TokenFactor || Opc == ISD::CopyToReg)
SethiUllmanNumber = INT_MAX - 10; SethiUllmanNumber = 0xffff;
else if (SU->NumSuccsLeft == 0) else if (SU->NumSuccsLeft == 0)
// If SU does not have a use, i.e. it doesn't produce a value that would // 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. // 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 // Give it a small SethiUllman number so it will be scheduled right before its
// predecessors that it doesn't lengthen their live ranges. // predecessors that it doesn't lengthen their live ranges.
SethiUllmanNumber = INT_MIN + 10; SethiUllmanNumber = 0;
else if (SU->NumPredsLeft == 0 && else if (SU->NumPredsLeft == 0 &&
(Opc != ISD::CopyFromReg || isCopyFromLiveIn(SU))) (Opc != ISD::CopyFromReg || isCopyFromLiveIn(SU)))
SethiUllmanNumber = 1; SethiUllmanNumber = 0xffff;
else { else {
int Extra = 0; int Extra = 0;
for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end(); for (SUnit::const_pred_iterator I = SU->Preds.begin(), E = SU->Preds.end();
I != E; ++I) { 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;
int PredSethiUllman = CalcNodePriority(PredSU); unsigned PredSethiUllman = CalcNodePriority(PredSU);
if (PredSethiUllman > SethiUllmanNumber) { if (PredSethiUllman > SethiUllmanNumber) {
SethiUllmanNumber = PredSethiUllman; SethiUllmanNumber = PredSethiUllman;
Extra = 0; Extra = 0;