xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZMachineScheduler.cpp (revision 349cc55c9796c4596a5b9904cd3281af295f878f)
10b57cec5SDimitry Andric //-- SystemZMachineScheduler.cpp - SystemZ Scheduler Interface -*- C++ -*---==//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // -------------------------- Post RA scheduling ---------------------------- //
100b57cec5SDimitry Andric // SystemZPostRASchedStrategy is a scheduling strategy which is plugged into
110b57cec5SDimitry Andric // the MachineScheduler. It has a sorted Available set of SUs and a pickNode()
120b57cec5SDimitry Andric // implementation that looks to optimize decoder grouping and balance the
130b57cec5SDimitry Andric // usage of processor resources. Scheduler states are saved for the end
140b57cec5SDimitry Andric // region of each MBB, so that a successor block can learn from it.
150b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
160b57cec5SDimitry Andric 
170b57cec5SDimitry Andric #include "SystemZMachineScheduler.h"
188bcb0991SDimitry Andric #include "llvm/CodeGen/MachineLoopInfo.h"
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric using namespace llvm;
210b57cec5SDimitry Andric 
220b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric #ifndef NDEBUG
250b57cec5SDimitry Andric // Print the set of SUs
260b57cec5SDimitry Andric void SystemZPostRASchedStrategy::SUSet::
dump(SystemZHazardRecognizer & HazardRec) const270b57cec5SDimitry Andric dump(SystemZHazardRecognizer &HazardRec) const {
280b57cec5SDimitry Andric   dbgs() << "{";
290b57cec5SDimitry Andric   for (auto &SU : *this) {
300b57cec5SDimitry Andric     HazardRec.dumpSU(SU, dbgs());
310b57cec5SDimitry Andric     if (SU != *rbegin())
320b57cec5SDimitry Andric       dbgs() << ",  ";
330b57cec5SDimitry Andric   }
340b57cec5SDimitry Andric   dbgs() << "}\n";
350b57cec5SDimitry Andric }
360b57cec5SDimitry Andric #endif
370b57cec5SDimitry Andric 
380b57cec5SDimitry Andric // Try to find a single predecessor that would be interesting for the
390b57cec5SDimitry Andric // scheduler in the top-most region of MBB.
getSingleSchedPred(MachineBasicBlock * MBB,const MachineLoop * Loop)400b57cec5SDimitry Andric static MachineBasicBlock *getSingleSchedPred(MachineBasicBlock *MBB,
410b57cec5SDimitry Andric                                              const MachineLoop *Loop) {
420b57cec5SDimitry Andric   MachineBasicBlock *PredMBB = nullptr;
430b57cec5SDimitry Andric   if (MBB->pred_size() == 1)
440b57cec5SDimitry Andric     PredMBB = *MBB->pred_begin();
450b57cec5SDimitry Andric 
460b57cec5SDimitry Andric   // The loop header has two predecessors, return the latch, but not for a
470b57cec5SDimitry Andric   // single block loop.
480b57cec5SDimitry Andric   if (MBB->pred_size() == 2 && Loop != nullptr && Loop->getHeader() == MBB) {
49*349cc55cSDimitry Andric     for (MachineBasicBlock *Pred : MBB->predecessors())
50*349cc55cSDimitry Andric       if (Loop->contains(Pred))
51*349cc55cSDimitry Andric         PredMBB = (Pred == MBB ? nullptr : Pred);
520b57cec5SDimitry Andric   }
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   assert ((PredMBB == nullptr || !Loop || Loop->contains(PredMBB))
550b57cec5SDimitry Andric           && "Loop MBB should not consider predecessor outside of loop.");
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   return PredMBB;
580b57cec5SDimitry Andric }
590b57cec5SDimitry Andric 
600b57cec5SDimitry Andric void SystemZPostRASchedStrategy::
advanceTo(MachineBasicBlock::iterator NextBegin)610b57cec5SDimitry Andric advanceTo(MachineBasicBlock::iterator NextBegin) {
620b57cec5SDimitry Andric   MachineBasicBlock::iterator LastEmittedMI = HazardRec->getLastEmittedMI();
630b57cec5SDimitry Andric   MachineBasicBlock::iterator I =
640b57cec5SDimitry Andric     ((LastEmittedMI != nullptr && LastEmittedMI->getParent() == MBB) ?
650b57cec5SDimitry Andric      std::next(LastEmittedMI) : MBB->begin());
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   for (; I != NextBegin; ++I) {
680b57cec5SDimitry Andric     if (I->isPosition() || I->isDebugInstr())
690b57cec5SDimitry Andric       continue;
700b57cec5SDimitry Andric     HazardRec->emitInstruction(&*I);
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric }
730b57cec5SDimitry Andric 
initialize(ScheduleDAGMI * dag)740b57cec5SDimitry Andric void SystemZPostRASchedStrategy::initialize(ScheduleDAGMI *dag) {
75e8d8bef9SDimitry Andric   Available.clear();  // -misched-cutoff.
760b57cec5SDimitry Andric   LLVM_DEBUG(HazardRec->dumpState(););
770b57cec5SDimitry Andric }
780b57cec5SDimitry Andric 
enterMBB(MachineBasicBlock * NextMBB)790b57cec5SDimitry Andric void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) {
800b57cec5SDimitry Andric   assert ((SchedStates.find(NextMBB) == SchedStates.end()) &&
810b57cec5SDimitry Andric           "Entering MBB twice?");
820b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "** Entering " << printMBBReference(*NextMBB));
830b57cec5SDimitry Andric 
840b57cec5SDimitry Andric   MBB = NextMBB;
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric   /// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to
870b57cec5SDimitry Andric   /// point to it.
880b57cec5SDimitry Andric   HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel);
890b57cec5SDimitry Andric   LLVM_DEBUG(const MachineLoop *Loop = MLI->getLoopFor(MBB);
900b57cec5SDimitry Andric              if (Loop && Loop->getHeader() == MBB) dbgs() << " (Loop header)";
910b57cec5SDimitry Andric              dbgs() << ":\n";);
920b57cec5SDimitry Andric 
930b57cec5SDimitry Andric   // Try to take over the state from a single predecessor, if it has been
940b57cec5SDimitry Andric   // scheduled. If this is not possible, we are done.
950b57cec5SDimitry Andric   MachineBasicBlock *SinglePredMBB =
960b57cec5SDimitry Andric     getSingleSchedPred(MBB, MLI->getLoopFor(MBB));
970b57cec5SDimitry Andric   if (SinglePredMBB == nullptr ||
980b57cec5SDimitry Andric       SchedStates.find(SinglePredMBB) == SchedStates.end())
990b57cec5SDimitry Andric     return;
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "** Continued scheduling from "
1020b57cec5SDimitry Andric                     << printMBBReference(*SinglePredMBB) << "\n";);
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric   HazardRec->copyState(SchedStates[SinglePredMBB]);
1050b57cec5SDimitry Andric   LLVM_DEBUG(HazardRec->dumpState(););
1060b57cec5SDimitry Andric 
1070b57cec5SDimitry Andric   // Emit incoming terminator(s). Be optimistic and assume that branch
1080b57cec5SDimitry Andric   // prediction will generally do "the right thing".
109*349cc55cSDimitry Andric   for (MachineInstr &MI : SinglePredMBB->terminators()) {
110*349cc55cSDimitry Andric     LLVM_DEBUG(dbgs() << "** Emitting incoming branch: "; MI.dump(););
111*349cc55cSDimitry Andric     bool TakenBranch = (MI.isBranch() &&
112*349cc55cSDimitry Andric                         (TII->getBranchInfo(MI).isIndirect() ||
113*349cc55cSDimitry Andric                          TII->getBranchInfo(MI).getMBBTarget() == MBB));
114*349cc55cSDimitry Andric     HazardRec->emitInstruction(&MI, TakenBranch);
1150b57cec5SDimitry Andric     if (TakenBranch)
1160b57cec5SDimitry Andric       break;
1170b57cec5SDimitry Andric   }
1180b57cec5SDimitry Andric }
1190b57cec5SDimitry Andric 
leaveMBB()1200b57cec5SDimitry Andric void SystemZPostRASchedStrategy::leaveMBB() {
1210b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "** Leaving " << printMBBReference(*MBB) << "\n";);
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   // Advance to first terminator. The successor block will handle terminators
1240b57cec5SDimitry Andric   // dependent on CFG layout (T/NT branch etc).
1250b57cec5SDimitry Andric   advanceTo(MBB->getFirstTerminator());
1260b57cec5SDimitry Andric }
1270b57cec5SDimitry Andric 
1280b57cec5SDimitry Andric SystemZPostRASchedStrategy::
SystemZPostRASchedStrategy(const MachineSchedContext * C)1290b57cec5SDimitry Andric SystemZPostRASchedStrategy(const MachineSchedContext *C)
1300b57cec5SDimitry Andric   : MLI(C->MLI),
1310b57cec5SDimitry Andric     TII(static_cast<const SystemZInstrInfo *>
1320b57cec5SDimitry Andric         (C->MF->getSubtarget().getInstrInfo())),
1330b57cec5SDimitry Andric     MBB(nullptr), HazardRec(nullptr) {
1340b57cec5SDimitry Andric   const TargetSubtargetInfo *ST = &C->MF->getSubtarget();
1350b57cec5SDimitry Andric   SchedModel.init(ST);
1360b57cec5SDimitry Andric }
1370b57cec5SDimitry Andric 
~SystemZPostRASchedStrategy()1380b57cec5SDimitry Andric SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() {
1390b57cec5SDimitry Andric   // Delete hazard recognizers kept around for each MBB.
1400b57cec5SDimitry Andric   for (auto I : SchedStates) {
1410b57cec5SDimitry Andric     SystemZHazardRecognizer *hazrec = I.second;
1420b57cec5SDimitry Andric     delete hazrec;
1430b57cec5SDimitry Andric   }
1440b57cec5SDimitry Andric }
1450b57cec5SDimitry Andric 
initPolicy(MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End,unsigned NumRegionInstrs)1460b57cec5SDimitry Andric void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin,
1470b57cec5SDimitry Andric                                             MachineBasicBlock::iterator End,
1480b57cec5SDimitry Andric                                             unsigned NumRegionInstrs) {
1490b57cec5SDimitry Andric   // Don't emit the terminators.
1500b57cec5SDimitry Andric   if (Begin->isTerminator())
1510b57cec5SDimitry Andric     return;
1520b57cec5SDimitry Andric 
1530b57cec5SDimitry Andric   // Emit any instructions before start of region.
1540b57cec5SDimitry Andric   advanceTo(Begin);
1550b57cec5SDimitry Andric }
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric // Pick the next node to schedule.
pickNode(bool & IsTopNode)1580b57cec5SDimitry Andric SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) {
1590b57cec5SDimitry Andric   // Only scheduling top-down.
1600b57cec5SDimitry Andric   IsTopNode = true;
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric   if (Available.empty())
1630b57cec5SDimitry Andric     return nullptr;
1640b57cec5SDimitry Andric 
1650b57cec5SDimitry Andric   // If only one choice, return it.
1660b57cec5SDimitry Andric   if (Available.size() == 1) {
1670b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "** Only one: ";
1680b57cec5SDimitry Andric                HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);
1690b57cec5SDimitry Andric     return *Available.begin();
1700b57cec5SDimitry Andric   }
1710b57cec5SDimitry Andric 
1720b57cec5SDimitry Andric   // All nodes that are possible to schedule are stored in the Available set.
1730b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "** Available: "; Available.dump(*HazardRec););
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   Candidate Best;
1760b57cec5SDimitry Andric   for (auto *SU : Available) {
1770b57cec5SDimitry Andric 
1780b57cec5SDimitry Andric     // SU is the next candidate to be compared against current Best.
1790b57cec5SDimitry Andric     Candidate c(SU, *HazardRec);
1800b57cec5SDimitry Andric 
1810b57cec5SDimitry Andric     // Remeber which SU is the best candidate.
1820b57cec5SDimitry Andric     if (Best.SU == nullptr || c < Best) {
1830b57cec5SDimitry Andric       Best = c;
1840b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "** Best so far: ";);
1850b57cec5SDimitry Andric     } else
1860b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "** Tried      : ";);
1870b57cec5SDimitry Andric     LLVM_DEBUG(HazardRec->dumpSU(c.SU, dbgs()); c.dumpCosts();
1880b57cec5SDimitry Andric                dbgs() << " Height:" << c.SU->getHeight(); dbgs() << "\n";);
1890b57cec5SDimitry Andric 
1900b57cec5SDimitry Andric     // Once we know we have seen all SUs that affect grouping or use unbuffered
1910b57cec5SDimitry Andric     // resources, we can stop iterating if Best looks good.
1920b57cec5SDimitry Andric     if (!SU->isScheduleHigh && Best.noCost())
1930b57cec5SDimitry Andric       break;
1940b57cec5SDimitry Andric   }
1950b57cec5SDimitry Andric 
1960b57cec5SDimitry Andric   assert (Best.SU != nullptr);
1970b57cec5SDimitry Andric   return Best.SU;
1980b57cec5SDimitry Andric }
1990b57cec5SDimitry Andric 
2000b57cec5SDimitry Andric SystemZPostRASchedStrategy::Candidate::
Candidate(SUnit * SU_,SystemZHazardRecognizer & HazardRec)2010b57cec5SDimitry Andric Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() {
2020b57cec5SDimitry Andric   SU = SU_;
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   // Check the grouping cost. For a node that must begin / end a
2050b57cec5SDimitry Andric   // group, it is positive if it would do so prematurely, or negative
2060b57cec5SDimitry Andric   // if it would fit naturally into the schedule.
2070b57cec5SDimitry Andric   GroupingCost = HazardRec.groupingCost(SU);
2080b57cec5SDimitry Andric 
2090b57cec5SDimitry Andric   // Check the resources cost for this SU.
2100b57cec5SDimitry Andric   ResourcesCost = HazardRec.resourcesCost(SU);
2110b57cec5SDimitry Andric }
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric bool SystemZPostRASchedStrategy::Candidate::
operator <(const Candidate & other)2140b57cec5SDimitry Andric operator<(const Candidate &other) {
2150b57cec5SDimitry Andric 
2160b57cec5SDimitry Andric   // Check decoder grouping.
2170b57cec5SDimitry Andric   if (GroupingCost < other.GroupingCost)
2180b57cec5SDimitry Andric     return true;
2190b57cec5SDimitry Andric   if (GroupingCost > other.GroupingCost)
2200b57cec5SDimitry Andric     return false;
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric   // Compare the use of resources.
2230b57cec5SDimitry Andric   if (ResourcesCost < other.ResourcesCost)
2240b57cec5SDimitry Andric     return true;
2250b57cec5SDimitry Andric   if (ResourcesCost > other.ResourcesCost)
2260b57cec5SDimitry Andric     return false;
2270b57cec5SDimitry Andric 
2280b57cec5SDimitry Andric   // Higher SU is otherwise generally better.
2290b57cec5SDimitry Andric   if (SU->getHeight() > other.SU->getHeight())
2300b57cec5SDimitry Andric     return true;
2310b57cec5SDimitry Andric   if (SU->getHeight() < other.SU->getHeight())
2320b57cec5SDimitry Andric     return false;
2330b57cec5SDimitry Andric 
2340b57cec5SDimitry Andric   // If all same, fall back to original order.
2350b57cec5SDimitry Andric   if (SU->NodeNum < other.SU->NodeNum)
2360b57cec5SDimitry Andric     return true;
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   return false;
2390b57cec5SDimitry Andric }
2400b57cec5SDimitry Andric 
schedNode(SUnit * SU,bool IsTopNode)2410b57cec5SDimitry Andric void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
2420b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "** Scheduling SU(" << SU->NodeNum << ") ";
2430b57cec5SDimitry Andric              if (Available.size() == 1) dbgs() << "(only one) ";
2440b57cec5SDimitry Andric              Candidate c(SU, *HazardRec); c.dumpCosts(); dbgs() << "\n";);
2450b57cec5SDimitry Andric 
2460b57cec5SDimitry Andric   // Remove SU from Available set and update HazardRec.
2470b57cec5SDimitry Andric   Available.erase(SU);
2480b57cec5SDimitry Andric   HazardRec->EmitInstruction(SU);
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric 
releaseTopNode(SUnit * SU)2510b57cec5SDimitry Andric void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {
2520b57cec5SDimitry Andric   // Set isScheduleHigh flag on all SUs that we want to consider first in
2530b57cec5SDimitry Andric   // pickNode().
2540b57cec5SDimitry Andric   const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU);
2550b57cec5SDimitry Andric   bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup));
2560b57cec5SDimitry Andric   SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered);
2570b57cec5SDimitry Andric 
2580b57cec5SDimitry Andric   // Put all released SUs in the Available set.
2590b57cec5SDimitry Andric   Available.insert(SU);
2600b57cec5SDimitry Andric }
261