1d88c1a5aSDimitry Andric //-- SystemZMachineScheduler.cpp - SystemZ Scheduler Interface -*- C++ -*---==//
2d88c1a5aSDimitry Andric //
3d88c1a5aSDimitry Andric //                     The LLVM Compiler Infrastructure
4d88c1a5aSDimitry Andric //
5d88c1a5aSDimitry Andric // This file is distributed under the University of Illinois Open Source
6d88c1a5aSDimitry Andric // License. See LICENSE.TXT for details.
7d88c1a5aSDimitry Andric //
8d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
9d88c1a5aSDimitry Andric //
10d88c1a5aSDimitry Andric // -------------------------- Post RA scheduling ---------------------------- //
11d88c1a5aSDimitry Andric // SystemZPostRASchedStrategy is a scheduling strategy which is plugged into
12d88c1a5aSDimitry Andric // the MachineScheduler. It has a sorted Available set of SUs and a pickNode()
13d88c1a5aSDimitry Andric // implementation that looks to optimize decoder grouping and balance the
142cab237bSDimitry Andric // usage of processor resources. Scheduler states are saved for the end
152cab237bSDimitry Andric // region of each MBB, so that a successor block can learn from it.
16d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
17d88c1a5aSDimitry Andric 
18d88c1a5aSDimitry Andric #include "SystemZMachineScheduler.h"
19d88c1a5aSDimitry Andric 
20d88c1a5aSDimitry Andric using namespace llvm;
21d88c1a5aSDimitry Andric 
22c4394386SDimitry Andric #define DEBUG_TYPE "machine-scheduler"
23d88c1a5aSDimitry Andric 
24d88c1a5aSDimitry Andric #ifndef NDEBUG
25d88c1a5aSDimitry Andric // Print the set of SUs
26d88c1a5aSDimitry Andric void SystemZPostRASchedStrategy::SUSet::
dump(SystemZHazardRecognizer & HazardRec) const27edd7eaddSDimitry Andric dump(SystemZHazardRecognizer &HazardRec) const {
28d88c1a5aSDimitry Andric   dbgs() << "{";
29d88c1a5aSDimitry Andric   for (auto &SU : *this) {
30d88c1a5aSDimitry Andric     HazardRec.dumpSU(SU, dbgs());
31d88c1a5aSDimitry Andric     if (SU != *rbegin())
32d88c1a5aSDimitry Andric       dbgs() << ",  ";
33d88c1a5aSDimitry Andric   }
34d88c1a5aSDimitry Andric   dbgs() << "}\n";
35d88c1a5aSDimitry Andric }
36d88c1a5aSDimitry Andric #endif
37d88c1a5aSDimitry Andric 
382cab237bSDimitry Andric // Try to find a single predecessor that would be interesting for the
392cab237bSDimitry Andric // scheduler in the top-most region of MBB.
getSingleSchedPred(MachineBasicBlock * MBB,const MachineLoop * Loop)402cab237bSDimitry Andric static MachineBasicBlock *getSingleSchedPred(MachineBasicBlock *MBB,
412cab237bSDimitry Andric                                              const MachineLoop *Loop) {
422cab237bSDimitry Andric   MachineBasicBlock *PredMBB = nullptr;
432cab237bSDimitry Andric   if (MBB->pred_size() == 1)
442cab237bSDimitry Andric     PredMBB = *MBB->pred_begin();
452cab237bSDimitry Andric 
462cab237bSDimitry Andric   // The loop header has two predecessors, return the latch, but not for a
472cab237bSDimitry Andric   // single block loop.
482cab237bSDimitry Andric   if (MBB->pred_size() == 2 && Loop != nullptr && Loop->getHeader() == MBB) {
492cab237bSDimitry Andric     for (auto I = MBB->pred_begin(); I != MBB->pred_end(); ++I)
502cab237bSDimitry Andric       if (Loop->contains(*I))
512cab237bSDimitry Andric         PredMBB = (*I == MBB ? nullptr : *I);
522cab237bSDimitry Andric   }
532cab237bSDimitry Andric 
542cab237bSDimitry Andric   assert ((PredMBB == nullptr || !Loop || Loop->contains(PredMBB))
552cab237bSDimitry Andric           && "Loop MBB should not consider predecessor outside of loop.");
562cab237bSDimitry Andric 
572cab237bSDimitry Andric   return PredMBB;
582cab237bSDimitry Andric }
592cab237bSDimitry Andric 
602cab237bSDimitry Andric void SystemZPostRASchedStrategy::
advanceTo(MachineBasicBlock::iterator NextBegin)612cab237bSDimitry Andric advanceTo(MachineBasicBlock::iterator NextBegin) {
622cab237bSDimitry Andric   MachineBasicBlock::iterator LastEmittedMI = HazardRec->getLastEmittedMI();
632cab237bSDimitry Andric   MachineBasicBlock::iterator I =
642cab237bSDimitry Andric     ((LastEmittedMI != nullptr && LastEmittedMI->getParent() == MBB) ?
652cab237bSDimitry Andric      std::next(LastEmittedMI) : MBB->begin());
662cab237bSDimitry Andric 
672cab237bSDimitry Andric   for (; I != NextBegin; ++I) {
68*4ba319b5SDimitry Andric     if (I->isPosition() || I->isDebugInstr())
692cab237bSDimitry Andric       continue;
702cab237bSDimitry Andric     HazardRec->emitInstruction(&*I);
712cab237bSDimitry Andric   }
722cab237bSDimitry Andric }
732cab237bSDimitry Andric 
initialize(ScheduleDAGMI * dag)74*4ba319b5SDimitry Andric void SystemZPostRASchedStrategy::initialize(ScheduleDAGMI *dag) {
75*4ba319b5SDimitry Andric   LLVM_DEBUG(HazardRec->dumpState(););
76*4ba319b5SDimitry Andric }
77*4ba319b5SDimitry Andric 
enterMBB(MachineBasicBlock * NextMBB)782cab237bSDimitry Andric void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) {
792cab237bSDimitry Andric   assert ((SchedStates.find(NextMBB) == SchedStates.end()) &&
802cab237bSDimitry Andric           "Entering MBB twice?");
81*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "** Entering " << printMBBReference(*NextMBB));
822cab237bSDimitry Andric 
832cab237bSDimitry Andric   MBB = NextMBB;
84*4ba319b5SDimitry Andric 
852cab237bSDimitry Andric   /// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to
862cab237bSDimitry Andric   /// point to it.
872cab237bSDimitry Andric   HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel);
88*4ba319b5SDimitry Andric   LLVM_DEBUG(const MachineLoop *Loop = MLI->getLoopFor(MBB);
89*4ba319b5SDimitry Andric              if (Loop && Loop->getHeader() == MBB) dbgs() << " (Loop header)";
902cab237bSDimitry Andric              dbgs() << ":\n";);
912cab237bSDimitry Andric 
922cab237bSDimitry Andric   // Try to take over the state from a single predecessor, if it has been
932cab237bSDimitry Andric   // scheduled. If this is not possible, we are done.
942cab237bSDimitry Andric   MachineBasicBlock *SinglePredMBB =
952cab237bSDimitry Andric     getSingleSchedPred(MBB, MLI->getLoopFor(MBB));
962cab237bSDimitry Andric   if (SinglePredMBB == nullptr ||
972cab237bSDimitry Andric       SchedStates.find(SinglePredMBB) == SchedStates.end())
982cab237bSDimitry Andric     return;
992cab237bSDimitry Andric 
100*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "** Continued scheduling from "
1012cab237bSDimitry Andric                     << printMBBReference(*SinglePredMBB) << "\n";);
1022cab237bSDimitry Andric 
1032cab237bSDimitry Andric   HazardRec->copyState(SchedStates[SinglePredMBB]);
104*4ba319b5SDimitry Andric   LLVM_DEBUG(HazardRec->dumpState(););
1052cab237bSDimitry Andric 
1062cab237bSDimitry Andric   // Emit incoming terminator(s). Be optimistic and assume that branch
1072cab237bSDimitry Andric   // prediction will generally do "the right thing".
1082cab237bSDimitry Andric   for (MachineBasicBlock::iterator I = SinglePredMBB->getFirstTerminator();
1092cab237bSDimitry Andric        I != SinglePredMBB->end(); I++) {
110*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "** Emitting incoming branch: "; I->dump(););
1112cab237bSDimitry Andric     bool TakenBranch = (I->isBranch() &&
1122cab237bSDimitry Andric       (TII->getBranchInfo(*I).Target->isReg() || // Relative branch
1132cab237bSDimitry Andric        TII->getBranchInfo(*I).Target->getMBB() == MBB));
1142cab237bSDimitry Andric     HazardRec->emitInstruction(&*I, TakenBranch);
1152cab237bSDimitry Andric     if (TakenBranch)
1162cab237bSDimitry Andric       break;
1172cab237bSDimitry Andric   }
1182cab237bSDimitry Andric }
1192cab237bSDimitry Andric 
leaveMBB()1202cab237bSDimitry Andric void SystemZPostRASchedStrategy::leaveMBB() {
121*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "** Leaving " << printMBBReference(*MBB) << "\n";);
1222cab237bSDimitry Andric 
1232cab237bSDimitry Andric   // Advance to first terminator. The successor block will handle terminators
1242cab237bSDimitry Andric   // dependent on CFG layout (T/NT branch etc).
1252cab237bSDimitry Andric   advanceTo(MBB->getFirstTerminator());
1262cab237bSDimitry Andric }
1272cab237bSDimitry Andric 
128d88c1a5aSDimitry Andric SystemZPostRASchedStrategy::
SystemZPostRASchedStrategy(const MachineSchedContext * C)129d88c1a5aSDimitry Andric SystemZPostRASchedStrategy(const MachineSchedContext *C)
1302cab237bSDimitry Andric   : MLI(C->MLI),
1312cab237bSDimitry Andric     TII(static_cast<const SystemZInstrInfo *>
1322cab237bSDimitry Andric         (C->MF->getSubtarget().getInstrInfo())),
1332cab237bSDimitry Andric     MBB(nullptr), HazardRec(nullptr) {
1342cab237bSDimitry Andric   const TargetSubtargetInfo *ST = &C->MF->getSubtarget();
135*4ba319b5SDimitry Andric   SchedModel.init(ST);
1362cab237bSDimitry Andric }
137d88c1a5aSDimitry Andric 
~SystemZPostRASchedStrategy()1382cab237bSDimitry Andric SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() {
1392cab237bSDimitry Andric   // Delete hazard recognizers kept around for each MBB.
1402cab237bSDimitry Andric   for (auto I : SchedStates) {
1412cab237bSDimitry Andric     SystemZHazardRecognizer *hazrec = I.second;
1422cab237bSDimitry Andric     delete hazrec;
1432cab237bSDimitry Andric   }
1442cab237bSDimitry Andric }
1452cab237bSDimitry Andric 
initPolicy(MachineBasicBlock::iterator Begin,MachineBasicBlock::iterator End,unsigned NumRegionInstrs)1462cab237bSDimitry Andric void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin,
1472cab237bSDimitry Andric                                             MachineBasicBlock::iterator End,
1482cab237bSDimitry Andric                                             unsigned NumRegionInstrs) {
1492cab237bSDimitry Andric   // Don't emit the terminators.
1502cab237bSDimitry Andric   if (Begin->isTerminator())
1512cab237bSDimitry Andric     return;
1522cab237bSDimitry Andric 
1532cab237bSDimitry Andric   // Emit any instructions before start of region.
1542cab237bSDimitry Andric   advanceTo(Begin);
155d88c1a5aSDimitry Andric }
156d88c1a5aSDimitry Andric 
157d88c1a5aSDimitry Andric // Pick the next node to schedule.
pickNode(bool & IsTopNode)158d88c1a5aSDimitry Andric SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) {
159d88c1a5aSDimitry Andric   // Only scheduling top-down.
160d88c1a5aSDimitry Andric   IsTopNode = true;
161d88c1a5aSDimitry Andric 
162d88c1a5aSDimitry Andric   if (Available.empty())
163d88c1a5aSDimitry Andric     return nullptr;
164d88c1a5aSDimitry Andric 
165d88c1a5aSDimitry Andric   // If only one choice, return it.
166d88c1a5aSDimitry Andric   if (Available.size() == 1) {
167*4ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "** Only one: ";
1682cab237bSDimitry Andric                HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);
169d88c1a5aSDimitry Andric     return *Available.begin();
170d88c1a5aSDimitry Andric   }
171d88c1a5aSDimitry Andric 
172*4ba319b5SDimitry Andric   // All nodes that are possible to schedule are stored in the Available set.
173*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "** Available: "; Available.dump(*HazardRec););
174d88c1a5aSDimitry Andric 
175d88c1a5aSDimitry Andric   Candidate Best;
176d88c1a5aSDimitry Andric   for (auto *SU : Available) {
177d88c1a5aSDimitry Andric 
178d88c1a5aSDimitry Andric     // SU is the next candidate to be compared against current Best.
1792cab237bSDimitry Andric     Candidate c(SU, *HazardRec);
180d88c1a5aSDimitry Andric 
181d88c1a5aSDimitry Andric     // Remeber which SU is the best candidate.
182d88c1a5aSDimitry Andric     if (Best.SU == nullptr || c < Best) {
183d88c1a5aSDimitry Andric       Best = c;
184*4ba319b5SDimitry Andric       LLVM_DEBUG(dbgs() << "** Best so far: ";);
185*4ba319b5SDimitry Andric     } else
186*4ba319b5SDimitry Andric       LLVM_DEBUG(dbgs() << "** Tried      : ";);
187*4ba319b5SDimitry Andric     LLVM_DEBUG(HazardRec->dumpSU(c.SU, dbgs()); c.dumpCosts();
188*4ba319b5SDimitry Andric                dbgs() << " Height:" << c.SU->getHeight(); dbgs() << "\n";);
189d88c1a5aSDimitry Andric 
190d88c1a5aSDimitry Andric     // Once we know we have seen all SUs that affect grouping or use unbuffered
191d88c1a5aSDimitry Andric     // resources, we can stop iterating if Best looks good.
192d88c1a5aSDimitry Andric     if (!SU->isScheduleHigh && Best.noCost())
193d88c1a5aSDimitry Andric       break;
194d88c1a5aSDimitry Andric   }
195d88c1a5aSDimitry Andric 
196d88c1a5aSDimitry Andric   assert (Best.SU != nullptr);
197d88c1a5aSDimitry Andric   return Best.SU;
198d88c1a5aSDimitry Andric }
199d88c1a5aSDimitry Andric 
200d88c1a5aSDimitry Andric SystemZPostRASchedStrategy::Candidate::
Candidate(SUnit * SU_,SystemZHazardRecognizer & HazardRec)201d88c1a5aSDimitry Andric Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() {
202d88c1a5aSDimitry Andric   SU = SU_;
203d88c1a5aSDimitry Andric 
204d88c1a5aSDimitry Andric   // Check the grouping cost. For a node that must begin / end a
205d88c1a5aSDimitry Andric   // group, it is positive if it would do so prematurely, or negative
206d88c1a5aSDimitry Andric   // if it would fit naturally into the schedule.
207d88c1a5aSDimitry Andric   GroupingCost = HazardRec.groupingCost(SU);
208d88c1a5aSDimitry Andric 
209d88c1a5aSDimitry Andric   // Check the resources cost for this SU.
210d88c1a5aSDimitry Andric   ResourcesCost = HazardRec.resourcesCost(SU);
211d88c1a5aSDimitry Andric }
212d88c1a5aSDimitry Andric 
213d88c1a5aSDimitry Andric bool SystemZPostRASchedStrategy::Candidate::
operator <(const Candidate & other)214d88c1a5aSDimitry Andric operator<(const Candidate &other) {
215d88c1a5aSDimitry Andric 
216d88c1a5aSDimitry Andric   // Check decoder grouping.
217d88c1a5aSDimitry Andric   if (GroupingCost < other.GroupingCost)
218d88c1a5aSDimitry Andric     return true;
219d88c1a5aSDimitry Andric   if (GroupingCost > other.GroupingCost)
220d88c1a5aSDimitry Andric     return false;
221d88c1a5aSDimitry Andric 
222d88c1a5aSDimitry Andric   // Compare the use of resources.
223d88c1a5aSDimitry Andric   if (ResourcesCost < other.ResourcesCost)
224d88c1a5aSDimitry Andric     return true;
225d88c1a5aSDimitry Andric   if (ResourcesCost > other.ResourcesCost)
226d88c1a5aSDimitry Andric     return false;
227d88c1a5aSDimitry Andric 
228d88c1a5aSDimitry Andric   // Higher SU is otherwise generally better.
229d88c1a5aSDimitry Andric   if (SU->getHeight() > other.SU->getHeight())
230d88c1a5aSDimitry Andric     return true;
231d88c1a5aSDimitry Andric   if (SU->getHeight() < other.SU->getHeight())
232d88c1a5aSDimitry Andric     return false;
233d88c1a5aSDimitry Andric 
234d88c1a5aSDimitry Andric   // If all same, fall back to original order.
235d88c1a5aSDimitry Andric   if (SU->NodeNum < other.SU->NodeNum)
236d88c1a5aSDimitry Andric     return true;
237d88c1a5aSDimitry Andric 
238d88c1a5aSDimitry Andric   return false;
239d88c1a5aSDimitry Andric }
240d88c1a5aSDimitry Andric 
schedNode(SUnit * SU,bool IsTopNode)241d88c1a5aSDimitry Andric void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
242*4ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "** Scheduling SU(" << SU->NodeNum << ") ";
243*4ba319b5SDimitry Andric              if (Available.size() == 1) dbgs() << "(only one) ";
244*4ba319b5SDimitry Andric              Candidate c(SU, *HazardRec); c.dumpCosts(); dbgs() << "\n";);
245d88c1a5aSDimitry Andric 
246d88c1a5aSDimitry Andric   // Remove SU from Available set and update HazardRec.
247d88c1a5aSDimitry Andric   Available.erase(SU);
2482cab237bSDimitry Andric   HazardRec->EmitInstruction(SU);
249d88c1a5aSDimitry Andric }
250d88c1a5aSDimitry Andric 
releaseTopNode(SUnit * SU)251d88c1a5aSDimitry Andric void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {
252d88c1a5aSDimitry Andric   // Set isScheduleHigh flag on all SUs that we want to consider first in
253d88c1a5aSDimitry Andric   // pickNode().
2542cab237bSDimitry Andric   const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU);
255d88c1a5aSDimitry Andric   bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup));
256d88c1a5aSDimitry Andric   SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered);
257d88c1a5aSDimitry Andric 
258d88c1a5aSDimitry Andric   // Put all released SUs in the Available set.
259d88c1a5aSDimitry Andric   Available.insert(SU);
260d88c1a5aSDimitry Andric }
261