| //-- SystemZMachineScheduler.cpp - SystemZ Scheduler Interface -*- C++ -*---==// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // -------------------------- Post RA scheduling ---------------------------- // |
| // SystemZPostRASchedStrategy is a scheduling strategy which is plugged into |
| // the MachineScheduler. It has a sorted Available set of SUs and a pickNode() |
| // implementation that looks to optimize decoder grouping and balance the |
| // usage of processor resources. |
| //===----------------------------------------------------------------------===// |
| |
| #include "SystemZMachineScheduler.h" |
| |
| using namespace llvm; |
| |
| #define DEBUG_TYPE "machine-scheduler" |
| |
| #ifndef NDEBUG |
| // Print the set of SUs |
| void SystemZPostRASchedStrategy::SUSet:: |
| dump(SystemZHazardRecognizer &HazardRec) const { |
| dbgs() << "{"; |
| for (auto &SU : *this) { |
| HazardRec.dumpSU(SU, dbgs()); |
| if (SU != *rbegin()) |
| dbgs() << ", "; |
| } |
| dbgs() << "}\n"; |
| } |
| #endif |
| |
| SystemZPostRASchedStrategy:: |
| SystemZPostRASchedStrategy(const MachineSchedContext *C) |
| : DAG(nullptr), HazardRec(C) {} |
| |
| void SystemZPostRASchedStrategy::initialize(ScheduleDAGMI *dag) { |
| DAG = dag; |
| HazardRec.setDAG(dag); |
| HazardRec.Reset(); |
| } |
| |
| // Pick the next node to schedule. |
| SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) { |
| // Only scheduling top-down. |
| IsTopNode = true; |
| |
| if (Available.empty()) |
| return nullptr; |
| |
| // If only one choice, return it. |
| if (Available.size() == 1) { |
| DEBUG (dbgs() << "+++ Only one: "; |
| HazardRec.dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";); |
| return *Available.begin(); |
| } |
| |
| // All nodes that are possible to schedule are stored by in the |
| // Available set. |
| DEBUG(dbgs() << "+++ Available: "; Available.dump(HazardRec);); |
| |
| Candidate Best; |
| for (auto *SU : Available) { |
| |
| // SU is the next candidate to be compared against current Best. |
| Candidate c(SU, HazardRec); |
| |
| // Remeber which SU is the best candidate. |
| if (Best.SU == nullptr || c < Best) { |
| Best = c; |
| DEBUG(dbgs() << "+++ Best sofar: "; |
| HazardRec.dumpSU(Best.SU, dbgs()); |
| if (Best.GroupingCost != 0) |
| dbgs() << "\tGrouping cost:" << Best.GroupingCost; |
| if (Best.ResourcesCost != 0) |
| dbgs() << " Resource cost:" << Best.ResourcesCost; |
| dbgs() << " Height:" << Best.SU->getHeight(); |
| dbgs() << "\n";); |
| } |
| |
| // Once we know we have seen all SUs that affect grouping or use unbuffered |
| // resources, we can stop iterating if Best looks good. |
| if (!SU->isScheduleHigh && Best.noCost()) |
| break; |
| } |
| |
| assert (Best.SU != nullptr); |
| return Best.SU; |
| } |
| |
| SystemZPostRASchedStrategy::Candidate:: |
| Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() { |
| SU = SU_; |
| |
| // Check the grouping cost. For a node that must begin / end a |
| // group, it is positive if it would do so prematurely, or negative |
| // if it would fit naturally into the schedule. |
| GroupingCost = HazardRec.groupingCost(SU); |
| |
| // Check the resources cost for this SU. |
| ResourcesCost = HazardRec.resourcesCost(SU); |
| } |
| |
| bool SystemZPostRASchedStrategy::Candidate:: |
| operator<(const Candidate &other) { |
| |
| // Check decoder grouping. |
| if (GroupingCost < other.GroupingCost) |
| return true; |
| if (GroupingCost > other.GroupingCost) |
| return false; |
| |
| // Compare the use of resources. |
| if (ResourcesCost < other.ResourcesCost) |
| return true; |
| if (ResourcesCost > other.ResourcesCost) |
| return false; |
| |
| // Higher SU is otherwise generally better. |
| if (SU->getHeight() > other.SU->getHeight()) |
| return true; |
| if (SU->getHeight() < other.SU->getHeight()) |
| return false; |
| |
| // If all same, fall back to original order. |
| if (SU->NodeNum < other.SU->NodeNum) |
| return true; |
| |
| return false; |
| } |
| |
| void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) { |
| DEBUG(dbgs() << "+++ Scheduling SU(" << SU->NodeNum << ")\n";); |
| |
| // Remove SU from Available set and update HazardRec. |
| Available.erase(SU); |
| HazardRec.EmitInstruction(SU); |
| } |
| |
| void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) { |
| // Set isScheduleHigh flag on all SUs that we want to consider first in |
| // pickNode(). |
| const MCSchedClassDesc *SC = DAG->getSchedClass(SU); |
| bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup)); |
| SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered); |
| |
| // Put all released SUs in the Available set. |
| Available.insert(SU); |
| } |