1 //-- SystemZMachineScheduler.cpp - SystemZ Scheduler Interface -*- C++ -*---==//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // -------------------------- Post RA scheduling ---------------------------- //
11 // SystemZPostRASchedStrategy is a scheduling strategy which is plugged into
12 // the MachineScheduler. It has a sorted Available set of SUs and a pickNode()
13 // implementation that looks to optimize decoder grouping and balance the
14 // usage of processor resources. Scheduler states are saved for the end
15 // region of each MBB, so that a successor block can learn from it.
16 //===----------------------------------------------------------------------===//
17 
18 #include "SystemZMachineScheduler.h"
19 
20 using namespace llvm;
21 
22 #define DEBUG_TYPE "machine-scheduler"
23 
24 #ifndef NDEBUG
25 // Print the set of SUs
26 void SystemZPostRASchedStrategy::SUSet::
27 dump(SystemZHazardRecognizer &HazardRec) const {
28   dbgs() << "{";
29   for (auto &SU : *this) {
30     HazardRec.dumpSU(SU, dbgs());
31     if (SU != *rbegin())
32       dbgs() << ",  ";
33   }
34   dbgs() << "}\n";
35 }
36 #endif
37 
38 // Try to find a single predecessor that would be interesting for the
39 // scheduler in the top-most region of MBB.
40 static MachineBasicBlock *getSingleSchedPred(MachineBasicBlock *MBB,
41                                              const MachineLoop *Loop) {
42   MachineBasicBlock *PredMBB = nullptr;
43   if (MBB->pred_size() == 1)
44     PredMBB = *MBB->pred_begin();
45 
46   // The loop header has two predecessors, return the latch, but not for a
47   // single block loop.
48   if (MBB->pred_size() == 2 && Loop != nullptr && Loop->getHeader() == MBB) {
49     for (auto I = MBB->pred_begin(); I != MBB->pred_end(); ++I)
50       if (Loop->contains(*I))
51         PredMBB = (*I == MBB ? nullptr : *I);
52   }
53 
54   assert ((PredMBB == nullptr || !Loop || Loop->contains(PredMBB))
55           && "Loop MBB should not consider predecessor outside of loop.");
56 
57   return PredMBB;
58 }
59 
60 void SystemZPostRASchedStrategy::
61 advanceTo(MachineBasicBlock::iterator NextBegin) {
62   MachineBasicBlock::iterator LastEmittedMI = HazardRec->getLastEmittedMI();
63   MachineBasicBlock::iterator I =
64     ((LastEmittedMI != nullptr && LastEmittedMI->getParent() == MBB) ?
65      std::next(LastEmittedMI) : MBB->begin());
66 
67   for (; I != NextBegin; ++I) {
68     if (I->isPosition() || I->isDebugValue())
69       continue;
70     HazardRec->emitInstruction(&*I);
71   }
72 }
73 
74 void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) {
75   assert ((SchedStates.find(NextMBB) == SchedStates.end()) &&
76           "Entering MBB twice?");
77   DEBUG(dbgs() << "+++ Entering " << printMBBReference(*NextMBB));
78 
79   MBB = NextMBB;
80   /// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to
81   /// point to it.
82   HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel);
83   DEBUG (const MachineLoop *Loop = MLI->getLoopFor(MBB);
84          if(Loop && Loop->getHeader() == MBB)
85            dbgs() << " (Loop header)";
86          dbgs() << ":\n";);
87 
88   // Try to take over the state from a single predecessor, if it has been
89   // scheduled. If this is not possible, we are done.
90   MachineBasicBlock *SinglePredMBB =
91     getSingleSchedPred(MBB, MLI->getLoopFor(MBB));
92   if (SinglePredMBB == nullptr ||
93       SchedStates.find(SinglePredMBB) == SchedStates.end())
94     return;
95 
96   DEBUG(dbgs() << "+++ Continued scheduling from "
97                << printMBBReference(*SinglePredMBB) << "\n";);
98 
99   HazardRec->copyState(SchedStates[SinglePredMBB]);
100 
101   // Emit incoming terminator(s). Be optimistic and assume that branch
102   // prediction will generally do "the right thing".
103   for (MachineBasicBlock::iterator I = SinglePredMBB->getFirstTerminator();
104        I != SinglePredMBB->end(); I++) {
105     DEBUG (dbgs() << "+++ Emitting incoming branch: "; I->dump(););
106     bool TakenBranch = (I->isBranch() &&
107       (TII->getBranchInfo(*I).Target->isReg() || // Relative branch
108        TII->getBranchInfo(*I).Target->getMBB() == MBB));
109     HazardRec->emitInstruction(&*I, TakenBranch);
110     if (TakenBranch)
111       break;
112   }
113 }
114 
115 void SystemZPostRASchedStrategy::leaveMBB() {
116   DEBUG(dbgs() << "+++ Leaving " << printMBBReference(*MBB) << "\n";);
117 
118   // Advance to first terminator. The successor block will handle terminators
119   // dependent on CFG layout (T/NT branch etc).
120   advanceTo(MBB->getFirstTerminator());
121 }
122 
123 SystemZPostRASchedStrategy::
124 SystemZPostRASchedStrategy(const MachineSchedContext *C)
125   : MLI(C->MLI),
126     TII(static_cast<const SystemZInstrInfo *>
127         (C->MF->getSubtarget().getInstrInfo())),
128     MBB(nullptr), HazardRec(nullptr) {
129   const TargetSubtargetInfo *ST = &C->MF->getSubtarget();
130   SchedModel.init(ST->getSchedModel(), ST, TII);
131 }
132 
133 SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() {
134   // Delete hazard recognizers kept around for each MBB.
135   for (auto I : SchedStates) {
136     SystemZHazardRecognizer *hazrec = I.second;
137     delete hazrec;
138   }
139 }
140 
141 void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin,
142                                             MachineBasicBlock::iterator End,
143                                             unsigned NumRegionInstrs) {
144   // Don't emit the terminators.
145   if (Begin->isTerminator())
146     return;
147 
148   // Emit any instructions before start of region.
149   advanceTo(Begin);
150 }
151 
152 // Pick the next node to schedule.
153 SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) {
154   // Only scheduling top-down.
155   IsTopNode = true;
156 
157   if (Available.empty())
158     return nullptr;
159 
160   // If only one choice, return it.
161   if (Available.size() == 1) {
162     DEBUG (dbgs() << "+++ Only one: ";
163            HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);
164     return *Available.begin();
165   }
166 
167   // All nodes that are possible to schedule are stored by in the
168   // Available set.
169   DEBUG(dbgs() << "+++ Available: "; Available.dump(*HazardRec););
170 
171   Candidate Best;
172   for (auto *SU : Available) {
173 
174     // SU is the next candidate to be compared against current Best.
175     Candidate c(SU, *HazardRec);
176 
177     // Remeber which SU is the best candidate.
178     if (Best.SU == nullptr || c < Best) {
179       Best = c;
180       DEBUG(dbgs() << "+++ Best sofar: ";
181             HazardRec->dumpSU(Best.SU, dbgs());
182             if (Best.GroupingCost != 0)
183               dbgs() << "\tGrouping cost:" << Best.GroupingCost;
184             if (Best.ResourcesCost != 0)
185               dbgs() << " Resource cost:" << Best.ResourcesCost;
186             dbgs() << " Height:" << Best.SU->getHeight();
187             dbgs() << "\n";);
188     }
189 
190     // Once we know we have seen all SUs that affect grouping or use unbuffered
191     // resources, we can stop iterating if Best looks good.
192     if (!SU->isScheduleHigh && Best.noCost())
193       break;
194   }
195 
196   assert (Best.SU != nullptr);
197   return Best.SU;
198 }
199 
200 SystemZPostRASchedStrategy::Candidate::
201 Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() {
202   SU = SU_;
203 
204   // Check the grouping cost. For a node that must begin / end a
205   // group, it is positive if it would do so prematurely, or negative
206   // if it would fit naturally into the schedule.
207   GroupingCost = HazardRec.groupingCost(SU);
208 
209     // Check the resources cost for this SU.
210   ResourcesCost = HazardRec.resourcesCost(SU);
211 }
212 
213 bool SystemZPostRASchedStrategy::Candidate::
214 operator<(const Candidate &other) {
215 
216   // Check decoder grouping.
217   if (GroupingCost < other.GroupingCost)
218     return true;
219   if (GroupingCost > other.GroupingCost)
220     return false;
221 
222   // Compare the use of resources.
223   if (ResourcesCost < other.ResourcesCost)
224     return true;
225   if (ResourcesCost > other.ResourcesCost)
226     return false;
227 
228   // Higher SU is otherwise generally better.
229   if (SU->getHeight() > other.SU->getHeight())
230     return true;
231   if (SU->getHeight() < other.SU->getHeight())
232     return false;
233 
234   // If all same, fall back to original order.
235   if (SU->NodeNum < other.SU->NodeNum)
236     return true;
237 
238   return false;
239 }
240 
241 void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
242   DEBUG(dbgs() << "+++ Scheduling SU(" << SU->NodeNum << ")\n";);
243 
244   // Remove SU from Available set and update HazardRec.
245   Available.erase(SU);
246   HazardRec->EmitInstruction(SU);
247 }
248 
249 void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {
250   // Set isScheduleHigh flag on all SUs that we want to consider first in
251   // pickNode().
252   const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU);
253   bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup));
254   SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered);
255 
256   // Put all released SUs in the Available set.
257   Available.insert(SU);
258 }
259