blob: 1de11a1166df99ea7774377c6005f1240745e0ee [file] [log] [blame]
Jonas Paulsson8010b632016-10-20 08:27:16 +00001//-- 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
Jonas Paulsson57a705d2017-08-17 08:33:44 +000014// 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.
Jonas Paulsson8010b632016-10-20 08:27:16 +000016//===----------------------------------------------------------------------===//
17
18#include "SystemZMachineScheduler.h"
19
20using namespace llvm;
21
Evandro Menezes0cd23f562017-07-11 22:08:28 +000022#define DEBUG_TYPE "machine-scheduler"
Jonas Paulsson8010b632016-10-20 08:27:16 +000023
24#ifndef NDEBUG
25// Print the set of SUs
26void SystemZPostRASchedStrategy::SUSet::
Rafael Espindola6da25f42017-06-21 23:02:57 +000027dump(SystemZHazardRecognizer &HazardRec) const {
Jonas Paulsson8010b632016-10-20 08:27:16 +000028 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
Jonas Paulsson57a705d2017-08-17 08:33:44 +000038// Try to find a single predecessor that would be interesting for the
39// scheduler in the top-most region of MBB.
40static 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
60void SystemZPostRASchedStrategy::
61advanceTo(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) {
Shiva Chen801bf7e2018-05-09 02:42:00 +000068 if (I->isPosition() || I->isDebugInstr())
Jonas Paulsson57a705d2017-08-17 08:33:44 +000069 continue;
70 HazardRec->emitInstruction(&*I);
71 }
72}
73
Jonas Paulsson61fbcf52018-03-07 08:39:00 +000074void SystemZPostRASchedStrategy::initialize(ScheduleDAGMI *dag) {
75 DEBUG(HazardRec->dumpState(););
76}
77
Jonas Paulsson57a705d2017-08-17 08:33:44 +000078void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) {
79 assert ((SchedStates.find(NextMBB) == SchedStates.end()) &&
80 "Entering MBB twice?");
Jonas Paulsson61fbcf52018-03-07 08:39:00 +000081 DEBUG(dbgs() << "** Entering " << printMBBReference(*NextMBB));
Jonas Paulsson57a705d2017-08-17 08:33:44 +000082
83 MBB = NextMBB;
Jonas Paulsson61fbcf52018-03-07 08:39:00 +000084
Jonas Paulsson57a705d2017-08-17 08:33:44 +000085 /// Create a HazardRec for MBB, save it in SchedStates and set HazardRec to
86 /// point to it.
87 HazardRec = SchedStates[MBB] = new SystemZHazardRecognizer(TII, &SchedModel);
Jonas Paulsson61fbcf52018-03-07 08:39:00 +000088 DEBUG(const MachineLoop *Loop = MLI->getLoopFor(MBB);
89 if(Loop && Loop->getHeader() == MBB)
90 dbgs() << " (Loop header)";
91 dbgs() << ":\n";);
Jonas Paulsson57a705d2017-08-17 08:33:44 +000092
93 // Try to take over the state from a single predecessor, if it has been
94 // scheduled. If this is not possible, we are done.
95 MachineBasicBlock *SinglePredMBB =
96 getSingleSchedPred(MBB, MLI->getLoopFor(MBB));
97 if (SinglePredMBB == nullptr ||
98 SchedStates.find(SinglePredMBB) == SchedStates.end())
99 return;
100
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000101 DEBUG(dbgs() << "** Continued scheduling from "
102 << printMBBReference(*SinglePredMBB) << "\n";);
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000103
104 HazardRec->copyState(SchedStates[SinglePredMBB]);
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000105 DEBUG(HazardRec->dumpState(););
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000106
107 // Emit incoming terminator(s). Be optimistic and assume that branch
108 // prediction will generally do "the right thing".
109 for (MachineBasicBlock::iterator I = SinglePredMBB->getFirstTerminator();
110 I != SinglePredMBB->end(); I++) {
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000111 DEBUG(dbgs() << "** Emitting incoming branch: "; I->dump(););
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000112 bool TakenBranch = (I->isBranch() &&
113 (TII->getBranchInfo(*I).Target->isReg() || // Relative branch
114 TII->getBranchInfo(*I).Target->getMBB() == MBB));
115 HazardRec->emitInstruction(&*I, TakenBranch);
116 if (TakenBranch)
117 break;
118 }
119}
120
121void SystemZPostRASchedStrategy::leaveMBB() {
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000122 DEBUG(dbgs() << "** Leaving " << printMBBReference(*MBB) << "\n";);
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000123
124 // Advance to first terminator. The successor block will handle terminators
125 // dependent on CFG layout (T/NT branch etc).
126 advanceTo(MBB->getFirstTerminator());
127}
128
Jonas Paulsson8010b632016-10-20 08:27:16 +0000129SystemZPostRASchedStrategy::
130SystemZPostRASchedStrategy(const MachineSchedContext *C)
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000131 : MLI(C->MLI),
132 TII(static_cast<const SystemZInstrInfo *>
133 (C->MF->getSubtarget().getInstrInfo())),
134 MBB(nullptr), HazardRec(nullptr) {
135 const TargetSubtargetInfo *ST = &C->MF->getSubtarget();
Sanjay Patel0d7df362018-04-08 19:56:04 +0000136 SchedModel.init(ST);
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000137}
Jonas Paulsson8010b632016-10-20 08:27:16 +0000138
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000139SystemZPostRASchedStrategy::~SystemZPostRASchedStrategy() {
140 // Delete hazard recognizers kept around for each MBB.
141 for (auto I : SchedStates) {
142 SystemZHazardRecognizer *hazrec = I.second;
143 delete hazrec;
144 }
145}
146
147void SystemZPostRASchedStrategy::initPolicy(MachineBasicBlock::iterator Begin,
148 MachineBasicBlock::iterator End,
149 unsigned NumRegionInstrs) {
150 // Don't emit the terminators.
151 if (Begin->isTerminator())
152 return;
153
154 // Emit any instructions before start of region.
155 advanceTo(Begin);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000156}
157
158// Pick the next node to schedule.
159SUnit *SystemZPostRASchedStrategy::pickNode(bool &IsTopNode) {
160 // Only scheduling top-down.
161 IsTopNode = true;
162
163 if (Available.empty())
164 return nullptr;
165
166 // If only one choice, return it.
167 if (Available.size() == 1) {
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000168 DEBUG(dbgs() << "** Only one: ";
169 HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000170 return *Available.begin();
171 }
172
173 // All nodes that are possible to schedule are stored by in the
174 // Available set.
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000175 DEBUG(dbgs() << "** Available: "; Available.dump(*HazardRec););
Jonas Paulsson8010b632016-10-20 08:27:16 +0000176
177 Candidate Best;
178 for (auto *SU : Available) {
179
180 // SU is the next candidate to be compared against current Best.
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000181 Candidate c(SU, *HazardRec);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000182
183 // Remeber which SU is the best candidate.
184 if (Best.SU == nullptr || c < Best) {
185 Best = c;
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000186 DEBUG(dbgs() << "** Best so far: ";);
187 } else
188 DEBUG(dbgs() << "** Tried : ";);
189 DEBUG(HazardRec->dumpSU(c.SU, dbgs());
190 c.dumpCosts();
191 dbgs() << " Height:" << c.SU->getHeight();
192 dbgs() << "\n";);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000193
194 // Once we know we have seen all SUs that affect grouping or use unbuffered
195 // resources, we can stop iterating if Best looks good.
196 if (!SU->isScheduleHigh && Best.noCost())
197 break;
198 }
199
200 assert (Best.SU != nullptr);
201 return Best.SU;
202}
203
204SystemZPostRASchedStrategy::Candidate::
205Candidate(SUnit *SU_, SystemZHazardRecognizer &HazardRec) : Candidate() {
206 SU = SU_;
207
208 // Check the grouping cost. For a node that must begin / end a
209 // group, it is positive if it would do so prematurely, or negative
210 // if it would fit naturally into the schedule.
211 GroupingCost = HazardRec.groupingCost(SU);
212
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000213 // Check the resources cost for this SU.
Jonas Paulsson8010b632016-10-20 08:27:16 +0000214 ResourcesCost = HazardRec.resourcesCost(SU);
215}
216
217bool SystemZPostRASchedStrategy::Candidate::
218operator<(const Candidate &other) {
219
220 // Check decoder grouping.
221 if (GroupingCost < other.GroupingCost)
222 return true;
223 if (GroupingCost > other.GroupingCost)
224 return false;
225
226 // Compare the use of resources.
227 if (ResourcesCost < other.ResourcesCost)
228 return true;
229 if (ResourcesCost > other.ResourcesCost)
230 return false;
231
232 // Higher SU is otherwise generally better.
233 if (SU->getHeight() > other.SU->getHeight())
234 return true;
235 if (SU->getHeight() < other.SU->getHeight())
236 return false;
237
238 // If all same, fall back to original order.
239 if (SU->NodeNum < other.SU->NodeNum)
240 return true;
241
242 return false;
243}
244
245void SystemZPostRASchedStrategy::schedNode(SUnit *SU, bool IsTopNode) {
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000246 DEBUG(dbgs() << "** Scheduling SU(" << SU->NodeNum << ") ";
247 if (Available.size() == 1)
248 dbgs() << "(only one) ";
249 Candidate c(SU, *HazardRec);
250 c.dumpCosts();
251 dbgs() << "\n";);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000252
253 // Remove SU from Available set and update HazardRec.
254 Available.erase(SU);
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000255 HazardRec->EmitInstruction(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000256}
257
258void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {
259 // Set isScheduleHigh flag on all SUs that we want to consider first in
260 // pickNode().
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000261 const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000262 bool AffectsGrouping = (SC->isValid() && (SC->BeginGroup || SC->EndGroup));
263 SU->isScheduleHigh = (AffectsGrouping || SU->isUnbuffered);
264
265 // Put all released SUs in the Available set.
266 Available.insert(SU);
267}