diff options
Diffstat (limited to 'llvm/lib/CodeGen')
| -rw-r--r-- | llvm/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp | 120 | 
1 files changed, 120 insertions, 0 deletions
| diff --git a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp index 705e4de272a..39c4f4e85ca 100644 --- a/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/ScheduleDAGRRList.cpp @@ -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 | 

