mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-16 11:30:51 +00:00
Add a pre-pass to the burr-list scheduler which makes adjustments to
help out the register pressure reduction heuristics in the case of nodes with multiple uses. Currently this uses very conservative heuristics, so it doesn't have a broad impact, but in cases where it does help it can make a big difference. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@67586 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
f1c0ae9de5
commit
002b44f1d7
@ -988,6 +988,8 @@ namespace {
|
||||
SUnits = &sunits;
|
||||
// Add pseudo dependency edges for two-address nodes.
|
||||
AddPseudoTwoAddrDeps();
|
||||
// Reroute edges to nodes with multiple uses.
|
||||
PrescheduleNodesWithMultipleUses();
|
||||
// Calculate node priorities.
|
||||
CalculateSethiUllmanNumbers();
|
||||
}
|
||||
@ -1072,6 +1074,7 @@ namespace {
|
||||
protected:
|
||||
bool canClobber(const SUnit *SU, const SUnit *Op);
|
||||
void AddPseudoTwoAddrDeps();
|
||||
void PrescheduleNodesWithMultipleUses();
|
||||
void CalculateSethiUllmanNumbers();
|
||||
};
|
||||
|
||||
@ -1227,6 +1230,123 @@ static bool canClobberPhysRegDefs(const SUnit *SuccSU, const SUnit *SU,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// PrescheduleNodesWithMultipleUses - Nodes with multiple uses
|
||||
/// are not handled well by the general register pressure reduction
|
||||
/// heuristics. When presented with code like this:
|
||||
///
|
||||
/// N
|
||||
/// / |
|
||||
/// / |
|
||||
/// U store
|
||||
/// |
|
||||
/// ...
|
||||
///
|
||||
/// the heuristics tend to push the store up, but since the
|
||||
/// operand of the store has another use (U), this would increase
|
||||
/// the length of that other use (the U->N edge).
|
||||
///
|
||||
/// This function transforms code like the above to route U's
|
||||
/// dependence through the store when possible, like this:
|
||||
///
|
||||
/// N
|
||||
/// ||
|
||||
/// ||
|
||||
/// store
|
||||
/// |
|
||||
/// U
|
||||
/// |
|
||||
/// ...
|
||||
///
|
||||
/// This results in the store being scheduled immediately
|
||||
/// after N, which shortens the U->N live range, reducing
|
||||
/// register pressure.
|
||||
///
|
||||
template<class SF>
|
||||
void RegReductionPriorityQueue<SF>::PrescheduleNodesWithMultipleUses() {
|
||||
// Visit all the nodes in topological order, working top-down.
|
||||
for (unsigned i = 0, e = SUnits->size(); i != e; ++i) {
|
||||
SUnit *SU = &(*SUnits)[i];
|
||||
// For now, only look at nodes with no data successors, such as stores.
|
||||
// These are especially important, due to the heuristics in
|
||||
// getNodePriority for nodes with no data successors.
|
||||
if (SU->NumSuccs != 0)
|
||||
continue;
|
||||
// For now, only look at nodes with exactly one data predecessor.
|
||||
if (SU->NumPreds != 1)
|
||||
continue;
|
||||
// Avoid prescheduling copies to virtual registers, which don't behave
|
||||
// like other nodes from the perspective of scheduling heuristics.
|
||||
if (SDNode *N = SU->getNode())
|
||||
if (N->getOpcode() == ISD::CopyToReg &&
|
||||
TargetRegisterInfo::isVirtualRegister
|
||||
(cast<RegisterSDNode>(N->getOperand(1))->getReg()))
|
||||
continue;
|
||||
|
||||
// Locate the single data predecessor.
|
||||
SUnit *PredSU = 0;
|
||||
for (SUnit::const_pred_iterator II = SU->Preds.begin(),
|
||||
EE = SU->Preds.end(); II != EE; ++II)
|
||||
if (!II->isCtrl()) {
|
||||
PredSU = II->getSUnit();
|
||||
break;
|
||||
}
|
||||
assert(PredSU);
|
||||
|
||||
// Don't rewrite edges that carry physregs, because that requires additional
|
||||
// support infrastructure.
|
||||
if (PredSU->hasPhysRegDefs)
|
||||
continue;
|
||||
// Short-circuit the case where SU is PredSU's only data successor.
|
||||
if (PredSU->NumSuccs == 1)
|
||||
continue;
|
||||
// Avoid prescheduling to copies from virtual registers, which don't behave
|
||||
// like other nodes from the perspective of scheduling // heuristics.
|
||||
if (SDNode *N = SU->getNode())
|
||||
if (N->getOpcode() == ISD::CopyFromReg &&
|
||||
TargetRegisterInfo::isVirtualRegister
|
||||
(cast<RegisterSDNode>(N->getOperand(1))->getReg()))
|
||||
continue;
|
||||
|
||||
// Perform checks on the successors of PredSU.
|
||||
for (SUnit::const_succ_iterator II = PredSU->Succs.begin(),
|
||||
EE = PredSU->Succs.end(); II != EE; ++II) {
|
||||
SUnit *PredSuccSU = II->getSUnit();
|
||||
if (PredSuccSU == SU) continue;
|
||||
// If PredSU has another successor with no data successors, for
|
||||
// now don't attempt to choose either over the other.
|
||||
if (PredSuccSU->NumSuccs == 0)
|
||||
goto outer_loop_continue;
|
||||
// Don't break physical register dependencies.
|
||||
if (SU->hasPhysRegClobbers && PredSuccSU->hasPhysRegDefs)
|
||||
if (canClobberPhysRegDefs(PredSuccSU, SU, TII, TRI))
|
||||
goto outer_loop_continue;
|
||||
// Don't introduce graph cycles.
|
||||
if (scheduleDAG->IsReachable(SU, PredSuccSU))
|
||||
goto outer_loop_continue;
|
||||
}
|
||||
|
||||
// Ok, the transformation is safe and the heuristics suggest it is
|
||||
// profitable. Update the graph.
|
||||
DOUT << "Prescheduling SU # " << SU->NodeNum
|
||||
<< " next to PredSU # " << PredSU->NodeNum
|
||||
<< " to guide scheduling in the presence of multiple uses\n";
|
||||
for (unsigned i = 0; i != PredSU->Succs.size(); ++i) {
|
||||
SDep Edge = PredSU->Succs[i];
|
||||
assert(!Edge.isAssignedRegDep());
|
||||
SUnit *SuccSU = Edge.getSUnit();
|
||||
if (SuccSU != SU) {
|
||||
Edge.setSUnit(PredSU);
|
||||
scheduleDAG->RemovePred(SuccSU, Edge);
|
||||
scheduleDAG->AddPred(SU, Edge);
|
||||
Edge.setSUnit(SU);
|
||||
scheduleDAG->AddPred(SuccSU, Edge);
|
||||
--i;
|
||||
}
|
||||
}
|
||||
outer_loop_continue:;
|
||||
}
|
||||
}
|
||||
|
||||
/// AddPseudoTwoAddrDeps - If two nodes share an operand and one of them uses
|
||||
/// it as a def&use operand. Add a pseudo control edge from it to the other
|
||||
/// node (if it won't create a cycle) so the two-address one will be scheduled
|
||||
|
Loading…
Reference in New Issue
Block a user