blob: 9e8acdaabd97df0717803c4bbad1cc3765a3e76a [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 Paulsson9b0f28f2018-03-07 08:54:32 +000062unsigned SystemZHazardRecognizer::getCurrCycleIdx(SUnit *SU) const {
Jonas Paulsson8010b632016-10-20 08:27:16 +000063 unsigned Idx = CurrGroupSize;
64 if (GrpCount % 2)
65 Idx += 3;
Jonas Paulsson9b0f28f2018-03-07 08:54:32 +000066
67 if (SU != nullptr && !fitsIntoCurrentGroup(SU)) {
68 if (Idx == 1 || Idx == 2)
69 Idx = 3;
70 else if (Idx == 4 || Idx == 5)
71 Idx = 0;
72 }
73
Jonas Paulsson8010b632016-10-20 08:27:16 +000074 return Idx;
75}
76
77ScheduleHazardRecognizer::HazardType SystemZHazardRecognizer::
78getHazardType(SUnit *m, int Stalls) {
79 return (fitsIntoCurrentGroup(m) ? NoHazard : Hazard);
80}
81
82void SystemZHazardRecognizer::Reset() {
83 CurrGroupSize = 0;
84 clearProcResCounters();
85 GrpCount = 0;
86 LastFPdOpCycleIdx = UINT_MAX;
Jonas Paulsson57a705d2017-08-17 08:33:44 +000087 LastEmittedMI = nullptr;
Nicola Zaghend34e60c2018-05-14 12:53:11 +000088 LLVM_DEBUG(CurGroupDbg = "";);
Jonas Paulsson8010b632016-10-20 08:27:16 +000089}
90
91bool
92SystemZHazardRecognizer::fitsIntoCurrentGroup(SUnit *SU) const {
Jonas Paulsson57a705d2017-08-17 08:33:44 +000093 const MCSchedClassDesc *SC = getSchedClass(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +000094 if (!SC->isValid())
95 return true;
96
97 // A cracked instruction only fits into schedule if the current
98 // group is empty.
99 if (SC->BeginGroup)
100 return (CurrGroupSize == 0);
101
102 // Since a full group is handled immediately in EmitInstruction(),
103 // SU should fit into current group. NumSlots should be 1 or 0,
104 // since it is not a cracked or expanded instruction.
105 assert ((getNumDecoderSlots(SU) <= 1) && (CurrGroupSize < 3) &&
106 "Expected normal instruction to fit in non-full group!");
107
108 return true;
109}
110
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000111void SystemZHazardRecognizer::nextGroup() {
112 if (CurrGroupSize == 0)
113 return;
Jonas Paulsson8010b632016-10-20 08:27:16 +0000114
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000115 LLVM_DEBUG(dumpCurrGroup("Completed decode group"));
116 LLVM_DEBUG(CurGroupDbg = "";);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000117
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000118 GrpCount++;
Jonas Paulsson8010b632016-10-20 08:27:16 +0000119
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000120 // Reset counter for next group.
121 CurrGroupSize = 0;
Jonas Paulsson8010b632016-10-20 08:27:16 +0000122
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000123 // Decrease counters for execution units by one.
124 for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
125 if (ProcResourceCounters[i] > 0)
126 ProcResourceCounters[i]--;
Jonas Paulsson8010b632016-10-20 08:27:16 +0000127
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000128 // Clear CriticalResourceIdx if it is now below the threshold.
129 if (CriticalResourceIdx != UINT_MAX &&
130 (ProcResourceCounters[CriticalResourceIdx] <=
131 ProcResCostLim))
132 CriticalResourceIdx = UINT_MAX;
133
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000134 LLVM_DEBUG(dumpState(););
Jonas Paulsson8010b632016-10-20 08:27:16 +0000135}
136
137#ifndef NDEBUG // Debug output
138void SystemZHazardRecognizer::dumpSU(SUnit *SU, raw_ostream &OS) const {
139 OS << "SU(" << SU->NodeNum << "):";
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000140 OS << TII->getName(SU->getInstr()->getOpcode());
Jonas Paulsson8010b632016-10-20 08:27:16 +0000141
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000142 const MCSchedClassDesc *SC = getSchedClass(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000143 if (!SC->isValid())
144 return;
145
146 for (TargetSchedModel::ProcResIter
147 PI = SchedModel->getWriteProcResBegin(SC),
148 PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
149 const MCProcResourceDesc &PRD =
150 *SchedModel->getProcResource(PI->ProcResourceIdx);
151 std::string FU(PRD.Name);
152 // trim e.g. Z13_FXaUnit -> FXa
153 FU = FU.substr(FU.find("_") + 1);
154 FU.resize(FU.find("Unit"));
155 OS << "/" << FU;
156
157 if (PI->Cycles > 1)
158 OS << "(" << PI->Cycles << "cyc)";
159 }
160
161 if (SC->NumMicroOps > 1)
162 OS << "/" << SC->NumMicroOps << "uops";
163 if (SC->BeginGroup && SC->EndGroup)
164 OS << "/GroupsAlone";
165 else if (SC->BeginGroup)
166 OS << "/BeginsGroup";
167 else if (SC->EndGroup)
168 OS << "/EndsGroup";
169 if (SU->isUnbuffered)
170 OS << "/Unbuffered";
171}
172
173void SystemZHazardRecognizer::dumpCurrGroup(std::string Msg) const {
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000174 dbgs() << "++ " << Msg;
Jonas Paulsson8010b632016-10-20 08:27:16 +0000175 dbgs() << ": ";
176
177 if (CurGroupDbg.empty())
178 dbgs() << " <empty>\n";
179 else {
180 dbgs() << "{ " << CurGroupDbg << " }";
181 dbgs() << " (" << CurrGroupSize << " decoder slot"
182 << (CurrGroupSize > 1 ? "s":"")
183 << ")\n";
184 }
185}
186
187void SystemZHazardRecognizer::dumpProcResourceCounters() const {
188 bool any = false;
189
190 for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
191 if (ProcResourceCounters[i] > 0) {
192 any = true;
193 break;
194 }
195
196 if (!any)
197 return;
198
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000199 dbgs() << "++ | Resource counters: ";
Jonas Paulsson8010b632016-10-20 08:27:16 +0000200 for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000201 if (ProcResourceCounters[i] > 0)
202 dbgs() << SchedModel->getProcResource(i)->Name
203 << ":" << ProcResourceCounters[i] << " ";
204 dbgs() << "\n";
205
206 if (CriticalResourceIdx != UINT_MAX)
207 dbgs() << "++ | Critical resource: "
208 << SchedModel->getProcResource(CriticalResourceIdx)->Name
209 << "\n";
Jonas Paulsson8010b632016-10-20 08:27:16 +0000210}
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000211
212void SystemZHazardRecognizer::dumpState() const {
213 dumpCurrGroup("| Current decoder group");
214 dbgs() << "++ | Current cycle index: "
215 << getCurrCycleIdx() << "\n";
216 dumpProcResourceCounters();
217 if (LastFPdOpCycleIdx != UINT_MAX)
218 dbgs() << "++ | Last FPd cycle index: " << LastFPdOpCycleIdx << "\n";
219}
220
Jonas Paulsson8010b632016-10-20 08:27:16 +0000221#endif //NDEBUG
222
223void SystemZHazardRecognizer::clearProcResCounters() {
224 ProcResourceCounters.assign(SchedModel->getNumProcResourceKinds(), 0);
225 CriticalResourceIdx = UINT_MAX;
226}
227
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000228static inline bool isBranchRetTrap(MachineInstr *MI) {
229 return (MI->isBranch() || MI->isReturn() ||
230 MI->getOpcode() == SystemZ::CondTrap);
231}
232
Jonas Paulsson8010b632016-10-20 08:27:16 +0000233// Update state with SU as the next scheduled unit.
234void SystemZHazardRecognizer::
235EmitInstruction(SUnit *SU) {
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000236 const MCSchedClassDesc *SC = getSchedClass(SU);
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000237 LLVM_DEBUG(dbgs() << "++ HazardRecognizer emitting "; dumpSU(SU, dbgs());
238 dbgs() << "\n";);
239 LLVM_DEBUG(dumpCurrGroup("Decode group before emission"););
Jonas Paulsson8010b632016-10-20 08:27:16 +0000240
241 // If scheduling an SU that must begin a new decoder group, move on
242 // to next group.
243 if (!fitsIntoCurrentGroup(SU))
244 nextGroup();
245
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000246 LLVM_DEBUG(raw_string_ostream cgd(CurGroupDbg);
247 if (CurGroupDbg.length()) cgd << ", "; dumpSU(SU, cgd););
Jonas Paulsson8010b632016-10-20 08:27:16 +0000248
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000249 LastEmittedMI = SU->getInstr();
250
Jonas Paulsson8010b632016-10-20 08:27:16 +0000251 // After returning from a call, we don't know much about the state.
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000252 if (SU->isCall) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000253 LLVM_DEBUG(dbgs() << "++ Clearing state after call.\n";);
Jonas Paulsson91c853a2018-03-07 08:57:09 +0000254 Reset();
255 LastEmittedMI = SU->getInstr();
Jonas Paulsson8010b632016-10-20 08:27:16 +0000256 return;
257 }
258
259 // Increase counter for execution unit(s).
260 for (TargetSchedModel::ProcResIter
261 PI = SchedModel->getWriteProcResBegin(SC),
262 PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
263 // Don't handle FPd together with the other resources.
264 if (SchedModel->getProcResource(PI->ProcResourceIdx)->BufferSize == 1)
265 continue;
266 int &CurrCounter =
267 ProcResourceCounters[PI->ProcResourceIdx];
268 CurrCounter += PI->Cycles;
269 // Check if this is now the new critical resource.
270 if ((CurrCounter > ProcResCostLim) &&
271 (CriticalResourceIdx == UINT_MAX ||
272 (PI->ProcResourceIdx != CriticalResourceIdx &&
273 CurrCounter >
274 ProcResourceCounters[CriticalResourceIdx]))) {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000275 LLVM_DEBUG(
276 dbgs() << "++ New critical resource: "
277 << SchedModel->getProcResource(PI->ProcResourceIdx)->Name
278 << "\n";);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000279 CriticalResourceIdx = PI->ProcResourceIdx;
280 }
281 }
282
283 // Make note of an instruction that uses a blocking resource (FPd).
284 if (SU->isUnbuffered) {
Jonas Paulsson9b0f28f2018-03-07 08:54:32 +0000285 LastFPdOpCycleIdx = getCurrCycleIdx(SU);
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000286 LLVM_DEBUG(dbgs() << "++ Last FPd cycle index: " << LastFPdOpCycleIdx
287 << "\n";);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000288 }
289
290 // Insert SU into current group by increasing number of slots used
291 // in current group.
292 CurrGroupSize += getNumDecoderSlots(SU);
293 assert (CurrGroupSize <= 3);
294
295 // Check if current group is now full/ended. If so, move on to next
296 // group to be ready to evaluate more candidates.
Jonas Paulssone18dbeb2018-03-07 08:45:09 +0000297 if (CurrGroupSize == 3 || SC->EndGroup)
Jonas Paulsson8010b632016-10-20 08:27:16 +0000298 nextGroup();
299}
300
301int SystemZHazardRecognizer::groupingCost(SUnit *SU) const {
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000302 const MCSchedClassDesc *SC = getSchedClass(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000303 if (!SC->isValid())
304 return 0;
305
306 // If SU begins new group, it can either break a current group early
307 // or fit naturally if current group is empty (negative cost).
308 if (SC->BeginGroup) {
309 if (CurrGroupSize)
310 return 3 - CurrGroupSize;
311 return -1;
312 }
313
314 // Similarly, a group-ending SU may either fit well (last in group), or
315 // end the group prematurely.
316 if (SC->EndGroup) {
317 unsigned resultingGroupSize =
318 (CurrGroupSize + getNumDecoderSlots(SU));
319 if (resultingGroupSize < 3)
320 return (3 - resultingGroupSize);
321 return -1;
322 }
323
324 // Most instructions can be placed in any decoder slot.
325 return 0;
326}
327
Jonas Paulsson9b0f28f2018-03-07 08:54:32 +0000328bool SystemZHazardRecognizer::isFPdOpPreferred_distance(SUnit *SU) const {
Jonas Paulsson8010b632016-10-20 08:27:16 +0000329 assert (SU->isUnbuffered);
330 // If this is the first FPd op, it should be scheduled high.
331 if (LastFPdOpCycleIdx == UINT_MAX)
332 return true;
333 // If this is not the first PFd op, it should go into the other side
334 // of the processor to use the other FPd unit there. This should
335 // generally happen if two FPd ops are placed with 2 other
336 // instructions between them (modulo 6).
Jonas Paulsson9b0f28f2018-03-07 08:54:32 +0000337 unsigned SUCycleIdx = getCurrCycleIdx(SU);
338 if (LastFPdOpCycleIdx > SUCycleIdx)
339 return ((LastFPdOpCycleIdx - SUCycleIdx) == 3);
340 return ((SUCycleIdx - LastFPdOpCycleIdx) == 3);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000341}
342
343int SystemZHazardRecognizer::
344resourcesCost(SUnit *SU) {
345 int Cost = 0;
346
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000347 const MCSchedClassDesc *SC = getSchedClass(SU);
Jonas Paulsson8010b632016-10-20 08:27:16 +0000348 if (!SC->isValid())
349 return 0;
350
351 // For a FPd op, either return min or max value as indicated by the
352 // distance to any prior FPd op.
353 if (SU->isUnbuffered)
354 Cost = (isFPdOpPreferred_distance(SU) ? INT_MIN : INT_MAX);
355 // For other instructions, give a cost to the use of the critical resource.
356 else if (CriticalResourceIdx != UINT_MAX) {
357 for (TargetSchedModel::ProcResIter
358 PI = SchedModel->getWriteProcResBegin(SC),
359 PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI)
360 if (PI->ProcResourceIdx == CriticalResourceIdx)
361 Cost = PI->Cycles;
362 }
363
364 return Cost;
365}
366
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000367void SystemZHazardRecognizer::emitInstruction(MachineInstr *MI,
368 bool TakenBranch) {
369 // Make a temporary SUnit.
370 SUnit SU(MI, 0);
371
372 // Set interesting flags.
373 SU.isCall = MI->isCall();
374
375 const MCSchedClassDesc *SC = SchedModel->resolveSchedClass(MI);
376 for (const MCWriteProcResEntry &PRE :
377 make_range(SchedModel->getWriteProcResBegin(SC),
378 SchedModel->getWriteProcResEnd(SC))) {
379 switch (SchedModel->getProcResource(PRE.ProcResourceIdx)->BufferSize) {
380 case 0:
381 SU.hasReservedResource = true;
382 break;
383 case 1:
384 SU.isUnbuffered = true;
385 break;
386 default:
387 break;
388 }
389 }
390
Jonas Paulssone18dbeb2018-03-07 08:45:09 +0000391 unsigned GroupSizeBeforeEmit = CurrGroupSize;
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000392 EmitInstruction(&SU);
393
Jonas Paulssone18dbeb2018-03-07 08:45:09 +0000394 if (!TakenBranch && isBranchRetTrap(MI)) {
395 // NT Branch on second slot ends group.
396 if (GroupSizeBeforeEmit == 1)
397 nextGroup();
398 }
399
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000400 if (TakenBranch && CurrGroupSize > 0)
Jonas Paulsson61fbcf52018-03-07 08:39:00 +0000401 nextGroup();
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000402
403 assert ((!MI->isTerminator() || isBranchRetTrap(MI)) &&
404 "Scheduler: unhandled terminator!");
405}
406
407void SystemZHazardRecognizer::
408copyState(SystemZHazardRecognizer *Incoming) {
409 // Current decoder group
410 CurrGroupSize = Incoming->CurrGroupSize;
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000411 LLVM_DEBUG(CurGroupDbg = Incoming->CurGroupDbg;);
Jonas Paulsson57a705d2017-08-17 08:33:44 +0000412
413 // Processor resources
414 ProcResourceCounters = Incoming->ProcResourceCounters;
415 CriticalResourceIdx = Incoming->CriticalResourceIdx;
416
417 // FPd
418 LastFPdOpCycleIdx = Incoming->LastFPdOpCycleIdx;
419 GrpCount = Incoming->GrpCount;
420}