blob: d29711ef65e940e0765664649c2f9e52d9f42e80 [file] [log] [blame]
Jonas Paulsson8010b632016-10-20 08:27:16 +00001//=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- 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// This file defines a hazard recognizer for the SystemZ scheduler.
11//
12// This class is used by the SystemZ scheduling strategy to maintain
13// the state during scheduling, and provide cost functions for
14// scheduling candidates. This includes:
15//
16// * Decoder grouping. A decoder group can maximally hold 3 uops, and
17// instructions that always begin a new group should be scheduled when
18// the current decoder group is empty.
19// * Processor resources usage. It is beneficial to balance the use of
20// resources.
21//
Jonas Paulsson57a705d2017-08-17 08:33:44 +000022// A goal is to consider all instructions, also those outside of any
23// scheduling region. Such instructions are "advanced" past and include
24// single instructions before a scheduling region, branches etc.
25//
26// A block that has only one predecessor continues scheduling with the state
27// of it (which may be updated by emitting branches).
28//
Jonas Paulsson8010b632016-10-20 08:27:16 +000029// ===---------------------------------------------------------------------===//
30
31#include "SystemZHazardRecognizer.h"
32#include "llvm/ADT/Statistic.h"
33
34using namespace llvm;
35
Evandro Menezes0cd23f562017-07-11 22:08:28 +000036#define DEBUG_TYPE "machine-scheduler"
Jonas Paulsson8010b632016-10-20 08:27:16 +000037
38// This is the limit of processor resource usage at which the
39// scheduler should try to look for other instructions (not using the
40// critical resource).
Benjamin Kramerffd37152016-11-19 20:44:26 +000041static cl::opt<int> ProcResCostLim("procres-cost-lim", cl::Hidden,
42 cl::desc("The OOO window for processor "
43 "resources during scheduling."),
44 cl::init(8));
Jonas Paulsson8010b632016-10-20 08:27:16 +000045
Jonas Paulsson8010b632016-10-20 08:27:16 +000046unsigned SystemZHazardRecognizer::
47getNumDecoderSlots(SUnit *SU) const {
Jonas Paulsson57a705d2017-08-17 08:33:44 +000048 const MCSchedClassDesc *SC = getSchedClass(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +000049 if (!SC->isValid())
50 return 0; // IMPLICIT_DEF / KILL -- will not make impact in output.
51
52 if (SC->BeginGroup) {
53 if (!SC->EndGroup)
54 return 2; // Cracked instruction
55 else
56 return 3; // Expanded/group-alone instruction
57 }
58
59 return 1; // Normal instruction
60}
61
Jonas Paulsson61fbcf52018-03-07 08:39:00 +000062unsigned SystemZHazardRecognizer::getCurrCycleIdx() const {
Jonas Paulsson8010b632016-10-20 08:27:16 +000063 unsigned Idx = CurrGroupSize;
64 if (GrpCount % 2)
65 Idx += 3;
66 return Idx;
67}
68
69ScheduleHazardRecognizer::HazardType SystemZHazardRecognizer::
70getHazardType(SUnit *m, int Stalls) {
71 return (fitsIntoCurrentGroup(m) ? NoHazard : Hazard);
72}
73
74void SystemZHazardRecognizer::Reset() {
75 CurrGroupSize = 0;
76 clearProcResCounters();
77 GrpCount = 0;
78 LastFPdOpCycleIdx = UINT_MAX;
Jonas Paulsson57a705d2017-08-17 08:33:44 +000079 LastEmittedMI = nullptr;
Jonas Paulsson8010b632016-10-20 08:27:16 +000080 DEBUG(CurGroupDbg = "";);
81}
82
83bool
84SystemZHazardRecognizer::fitsIntoCurrentGroup(SUnit *SU) const {
Jonas Paulsson57a705d2017-08-17 08:33:44 +000085 const MCSchedClassDesc *SC = getSchedClass(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +000086 if (!SC->isValid())
87 return true;
88
89 // A cracked instruction only fits into schedule if the current
90 // group is empty.
91 if (SC->BeginGroup)
92 return (CurrGroupSize == 0);
93
94 // Since a full group is handled immediately in EmitInstruction(),
95 // SU should fit into current group. NumSlots should be 1 or 0,
96 // since it is not a cracked or expanded instruction.
97 assert ((getNumDecoderSlots(SU) <= 1) && (CurrGroupSize < 3) &&
98 "Expected normal instruction to fit in non-full group!");
99
100 return true;
101}
102
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000103void SystemZHazardRecognizer::nextGroup() {
104 if (CurrGroupSize == 0)
105 return;
Jonas Paulsson8010b632016-10-20 08:27:16 +0000106
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000107 DEBUG(dumpCurrGroup("Completed decode group"));
108 DEBUG(CurGroupDbg = "";);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000109
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000110 GrpCount++;
Jonas Paulsson8010b632016-10-20 08:27:16 +0000111
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000112 // Reset counter for next group.
113 CurrGroupSize = 0;
Jonas Paulsson8010b632016-10-20 08:27:16 +0000114
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000115 // Decrease counters for execution units by one.
116 for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
117 if (ProcResourceCounters[i] > 0)
118 ProcResourceCounters[i]--;
Jonas Paulsson8010b632016-10-20 08:27:16 +0000119
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000120 // Clear CriticalResourceIdx if it is now below the threshold.
121 if (CriticalResourceIdx != UINT_MAX &&
122 (ProcResourceCounters[CriticalResourceIdx] <=
123 ProcResCostLim))
124 CriticalResourceIdx = UINT_MAX;
125
126 DEBUG(dumpState(););
Jonas Paulsson8010b632016-10-20 08:27:16 +0000127}
128
129#ifndef NDEBUG // Debug output
130void SystemZHazardRecognizer::dumpSU(SUnit *SU, raw_ostream &OS) const {
131 OS << "SU(" << SU->NodeNum << "):";
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000132 OS << TII->getName(SU->getInstr()->getOpcode());
Jonas Paulsson8010b632016-10-20 08:27:16 +0000133
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000134 const MCSchedClassDesc *SC = getSchedClass(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000135 if (!SC->isValid())
136 return;
137
138 for (TargetSchedModel::ProcResIter
139 PI = SchedModel->getWriteProcResBegin(SC),
140 PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
141 const MCProcResourceDesc &PRD =
142 *SchedModel->getProcResource(PI->ProcResourceIdx);
143 std::string FU(PRD.Name);
144 // trim e.g. Z13_FXaUnit -> FXa
145 FU = FU.substr(FU.find("_") + 1);
146 FU.resize(FU.find("Unit"));
147 OS << "/" << FU;
148
149 if (PI->Cycles > 1)
150 OS << "(" << PI->Cycles << "cyc)";
151 }
152
153 if (SC->NumMicroOps > 1)
154 OS << "/" << SC->NumMicroOps << "uops";
155 if (SC->BeginGroup && SC->EndGroup)
156 OS << "/GroupsAlone";
157 else if (SC->BeginGroup)
158 OS << "/BeginsGroup";
159 else if (SC->EndGroup)
160 OS << "/EndsGroup";
161 if (SU->isUnbuffered)
162 OS << "/Unbuffered";
163}
164
165void SystemZHazardRecognizer::dumpCurrGroup(std::string Msg) const {
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000166 dbgs() << "++ " << Msg;
Jonas Paulsson8010b632016-10-20 08:27:16 +0000167 dbgs() << ": ";
168
169 if (CurGroupDbg.empty())
170 dbgs() << " <empty>\n";
171 else {
172 dbgs() << "{ " << CurGroupDbg << " }";
173 dbgs() << " (" << CurrGroupSize << " decoder slot"
174 << (CurrGroupSize > 1 ? "s":"")
175 << ")\n";
176 }
177}
178
179void SystemZHazardRecognizer::dumpProcResourceCounters() const {
180 bool any = false;
181
182 for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
183 if (ProcResourceCounters[i] > 0) {
184 any = true;
185 break;
186 }
187
188 if (!any)
189 return;
190
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000191 dbgs() << "++ | Resource counters: ";
Jonas Paulsson8010b632016-10-20 08:27:16 +0000192 for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000193 if (ProcResourceCounters[i] > 0)
194 dbgs() << SchedModel->getProcResource(i)->Name
195 << ":" << ProcResourceCounters[i] << " ";
196 dbgs() << "\n";
197
198 if (CriticalResourceIdx != UINT_MAX)
199 dbgs() << "++ | Critical resource: "
200 << SchedModel->getProcResource(CriticalResourceIdx)->Name
201 << "\n";
Jonas Paulsson8010b632016-10-20 08:27:16 +0000202}
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000203
204void SystemZHazardRecognizer::dumpState() const {
205 dumpCurrGroup("| Current decoder group");
206 dbgs() << "++ | Current cycle index: "
207 << getCurrCycleIdx() << "\n";
208 dumpProcResourceCounters();
209 if (LastFPdOpCycleIdx != UINT_MAX)
210 dbgs() << "++ | Last FPd cycle index: " << LastFPdOpCycleIdx << "\n";
211}
212
Jonas Paulsson8010b632016-10-20 08:27:16 +0000213#endif //NDEBUG
214
215void SystemZHazardRecognizer::clearProcResCounters() {
216 ProcResourceCounters.assign(SchedModel->getNumProcResourceKinds(), 0);
217 CriticalResourceIdx = UINT_MAX;
218}
219
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000220static inline bool isBranchRetTrap(MachineInstr *MI) {
221 return (MI->isBranch() || MI->isReturn() ||
222 MI->getOpcode() == SystemZ::CondTrap);
223}
224
Jonas Paulsson8010b632016-10-20 08:27:16 +0000225// Update state with SU as the next scheduled unit.
226void SystemZHazardRecognizer::
227EmitInstruction(SUnit *SU) {
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000228 const MCSchedClassDesc *SC = getSchedClass(SU);
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000229 DEBUG(dbgs() << "++ HazardRecognizer emitting "; dumpSU(SU, dbgs());
230 dbgs() << "\n";);
231 DEBUG(dumpCurrGroup("Decode group before emission"););
Jonas Paulsson8010b632016-10-20 08:27:16 +0000232
233 // If scheduling an SU that must begin a new decoder group, move on
234 // to next group.
235 if (!fitsIntoCurrentGroup(SU))
236 nextGroup();
237
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000238 DEBUG(raw_string_ostream cgd(CurGroupDbg);
239 if (CurGroupDbg.length())
240 cgd << ", ";
241 dumpSU(SU, cgd););
Jonas Paulsson8010b632016-10-20 08:27:16 +0000242
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000243 LastEmittedMI = SU->getInstr();
244
Jonas Paulsson8010b632016-10-20 08:27:16 +0000245 // After returning from a call, we don't know much about the state.
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000246 if (SU->isCall) {
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000247 DEBUG(dbgs() << "++ Clearing state after call.\n";);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000248 clearProcResCounters();
249 LastFPdOpCycleIdx = UINT_MAX;
250 CurrGroupSize += getNumDecoderSlots(SU);
251 assert (CurrGroupSize <= 3);
252 nextGroup();
253 return;
254 }
255
256 // Increase counter for execution unit(s).
257 for (TargetSchedModel::ProcResIter
258 PI = SchedModel->getWriteProcResBegin(SC),
259 PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
260 // Don't handle FPd together with the other resources.
261 if (SchedModel->getProcResource(PI->ProcResourceIdx)->BufferSize == 1)
262 continue;
263 int &CurrCounter =
264 ProcResourceCounters[PI->ProcResourceIdx];
265 CurrCounter += PI->Cycles;
266 // Check if this is now the new critical resource.
267 if ((CurrCounter > ProcResCostLim) &&
268 (CriticalResourceIdx == UINT_MAX ||
269 (PI->ProcResourceIdx != CriticalResourceIdx &&
270 CurrCounter >
271 ProcResourceCounters[CriticalResourceIdx]))) {
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000272 DEBUG(dbgs() << "++ New critical resource: "
273 << SchedModel->getProcResource(PI->ProcResourceIdx)->Name
274 << "\n";);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000275 CriticalResourceIdx = PI->ProcResourceIdx;
276 }
277 }
278
279 // Make note of an instruction that uses a blocking resource (FPd).
280 if (SU->isUnbuffered) {
281 LastFPdOpCycleIdx = getCurrCycleIdx();
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000282 DEBUG(dbgs() << "++ Last FPd cycle index: "
283 << LastFPdOpCycleIdx << "\n";);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000284 }
285
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000286 bool GroupEndingBranch =
287 (CurrGroupSize >= 1 && isBranchRetTrap(SU->getInstr()));
288
Jonas Paulsson8010b632016-10-20 08:27:16 +0000289 // Insert SU into current group by increasing number of slots used
290 // in current group.
291 CurrGroupSize += getNumDecoderSlots(SU);
292 assert (CurrGroupSize <= 3);
293
294 // Check if current group is now full/ended. If so, move on to next
295 // group to be ready to evaluate more candidates.
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000296 if (CurrGroupSize == 3 || SC->EndGroup || GroupEndingBranch)
Jonas Paulsson8010b632016-10-20 08:27:16 +0000297 nextGroup();
298}
299
300int SystemZHazardRecognizer::groupingCost(SUnit *SU) const {
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000301 const MCSchedClassDesc *SC = getSchedClass(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000302 if (!SC->isValid())
303 return 0;
304
305 // If SU begins new group, it can either break a current group early
306 // or fit naturally if current group is empty (negative cost).
307 if (SC->BeginGroup) {
308 if (CurrGroupSize)
309 return 3 - CurrGroupSize;
310 return -1;
311 }
312
313 // Similarly, a group-ending SU may either fit well (last in group), or
314 // end the group prematurely.
315 if (SC->EndGroup) {
316 unsigned resultingGroupSize =
317 (CurrGroupSize + getNumDecoderSlots(SU));
318 if (resultingGroupSize < 3)
319 return (3 - resultingGroupSize);
320 return -1;
321 }
322
323 // Most instructions can be placed in any decoder slot.
324 return 0;
325}
326
327bool SystemZHazardRecognizer::isFPdOpPreferred_distance(const SUnit *SU) {
328 assert (SU->isUnbuffered);
329 // If this is the first FPd op, it should be scheduled high.
330 if (LastFPdOpCycleIdx == UINT_MAX)
331 return true;
332 // If this is not the first PFd op, it should go into the other side
333 // of the processor to use the other FPd unit there. This should
334 // generally happen if two FPd ops are placed with 2 other
335 // instructions between them (modulo 6).
336 if (LastFPdOpCycleIdx > getCurrCycleIdx())
337 return ((LastFPdOpCycleIdx - getCurrCycleIdx()) == 3);
338 return ((getCurrCycleIdx() - LastFPdOpCycleIdx) == 3);
339}
340
341int SystemZHazardRecognizer::
342resourcesCost(SUnit *SU) {
343 int Cost = 0;
344
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000345 const MCSchedClassDesc *SC = getSchedClass(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000346 if (!SC->isValid())
347 return 0;
348
349 // For a FPd op, either return min or max value as indicated by the
350 // distance to any prior FPd op.
351 if (SU->isUnbuffered)
352 Cost = (isFPdOpPreferred_distance(SU) ? INT_MIN : INT_MAX);
353 // For other instructions, give a cost to the use of the critical resource.
354 else if (CriticalResourceIdx != UINT_MAX) {
355 for (TargetSchedModel::ProcResIter
356 PI = SchedModel->getWriteProcResBegin(SC),
357 PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI)
358 if (PI->ProcResourceIdx == CriticalResourceIdx)
359 Cost = PI->Cycles;
360 }
361
362 return Cost;
363}
364
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000365void SystemZHazardRecognizer::emitInstruction(MachineInstr *MI,
366 bool TakenBranch) {
367 // Make a temporary SUnit.
368 SUnit SU(MI, 0);
369
370 // Set interesting flags.
371 SU.isCall = MI->isCall();
372
373 const MCSchedClassDesc *SC = SchedModel->resolveSchedClass(MI);
374 for (const MCWriteProcResEntry &PRE :
375 make_range(SchedModel->getWriteProcResBegin(SC),
376 SchedModel->getWriteProcResEnd(SC))) {
377 switch (SchedModel->getProcResource(PRE.ProcResourceIdx)->BufferSize) {
378 case 0:
379 SU.hasReservedResource = true;
380 break;
381 case 1:
382 SU.isUnbuffered = true;
383 break;
384 default:
385 break;
386 }
387 }
388
389 EmitInstruction(&SU);
390
391 if (TakenBranch && CurrGroupSize > 0)
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000392 nextGroup();
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000393
394 assert ((!MI->isTerminator() || isBranchRetTrap(MI)) &&
395 "Scheduler: unhandled terminator!");
396}
397
398void SystemZHazardRecognizer::
399copyState(SystemZHazardRecognizer *Incoming) {
400 // Current decoder group
401 CurrGroupSize = Incoming->CurrGroupSize;
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000402 DEBUG(CurGroupDbg = Incoming->CurGroupDbg;);
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000403
404 // Processor resources
405 ProcResourceCounters = Incoming->ProcResourceCounters;
406 CriticalResourceIdx = Incoming->CriticalResourceIdx;
407
408 // FPd
409 LastFPdOpCycleIdx = Incoming->LastFPdOpCycleIdx;
410 GrpCount = Incoming->GrpCount;
411}