blob: 4b0f925676361539a2d9c77e74c5219516c9935d [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) {
68 if (I->isPosition() || I->isDebugValue())
69 continue;
70 HazardRec->emitInstruction(&*I);
71 }
72}
73
74void SystemZPostRASchedStrategy::enterMBB(MachineBasicBlock *NextMBB) {
75 assert ((SchedStates.find(NextMBB) == SchedStates.end()) &&
76 "Entering MBB twice?");
77 DEBUG (dbgs() << "+++ Entering MBB#" << NextMBB->getNumber());
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 MBB#"
97 << SinglePredMBB->getNumber() << "\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
115void SystemZPostRASchedStrategy::leaveMBB() {
116 DEBUG (dbgs() << "+++ Leaving MBB#" << MBB->getNumber() << "\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
Jonas Paulsson8010b632016-10-20 08:27:16 +0000123SystemZPostRASchedStrategy::
124SystemZPostRASchedStrategy(const MachineSchedContext *C)
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000125 : 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}
Jonas Paulsson8010b632016-10-20 08:27:16 +0000132
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000133SystemZPostRASchedStrategy::~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
141void 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);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000150}
151
152// Pick the next node to schedule.
153SUnit *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: ";
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000163 HazardRec->dumpSU(*Available.begin(), dbgs()); dbgs() << "\n";);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000164 return *Available.begin();
165 }
166
167 // All nodes that are possible to schedule are stored by in the
168 // Available set.
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000169 DEBUG(dbgs() << "+++ Available: "; Available.dump(*HazardRec););
Jonas Paulsson8010b632016-10-20 08:27:16 +0000170
171 Candidate Best;
172 for (auto *SU : Available) {
173
174 // SU is the next candidate to be compared against current Best.
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000175 Candidate c(SU, *HazardRec);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000176
177 // Remeber which SU is the best candidate.
178 if (Best.SU == nullptr || c < Best) {
179 Best = c;
180 DEBUG(dbgs() << "+++ Best sofar: ";
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000181 HazardRec->dumpSU(Best.SU, dbgs());
Jonas Paulsson8010b632016-10-20 08:27:16 +0000182 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
200SystemZPostRASchedStrategy::Candidate::
201Candidate(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
213bool SystemZPostRASchedStrategy::Candidate::
214operator<(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
241void 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);
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000246 HazardRec->EmitInstruction(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000247}
248
249void SystemZPostRASchedStrategy::releaseTopNode(SUnit *SU) {
250 // Set isScheduleHigh flag on all SUs that we want to consider first in
251 // pickNode().
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000252 const MCSchedClassDesc *SC = HazardRec->getSchedClass(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000253 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}