xref: /freebsd/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
1*0b57cec5SDimitry Andric //=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===//
2*0b57cec5SDimitry Andric //
3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0b57cec5SDimitry Andric //
7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
8*0b57cec5SDimitry Andric //
9*0b57cec5SDimitry Andric // This file defines a hazard recognizer for the SystemZ scheduler.
10*0b57cec5SDimitry Andric //
11*0b57cec5SDimitry Andric // This class is used by the SystemZ scheduling strategy to maintain
12*0b57cec5SDimitry Andric // the state during scheduling, and provide cost functions for
13*0b57cec5SDimitry Andric // scheduling candidates. This includes:
14*0b57cec5SDimitry Andric //
15*0b57cec5SDimitry Andric // * Decoder grouping. A decoder group can maximally hold 3 uops, and
16*0b57cec5SDimitry Andric // instructions that always begin a new group should be scheduled when
17*0b57cec5SDimitry Andric // the current decoder group is empty.
18*0b57cec5SDimitry Andric // * Processor resources usage. It is beneficial to balance the use of
19*0b57cec5SDimitry Andric // resources.
20*0b57cec5SDimitry Andric //
21*0b57cec5SDimitry Andric // A goal is to consider all instructions, also those outside of any
22*0b57cec5SDimitry Andric // scheduling region. Such instructions are "advanced" past and include
23*0b57cec5SDimitry Andric // single instructions before a scheduling region, branches etc.
24*0b57cec5SDimitry Andric //
25*0b57cec5SDimitry Andric // A block that has only one predecessor continues scheduling with the state
26*0b57cec5SDimitry Andric // of it (which may be updated by emitting branches).
27*0b57cec5SDimitry Andric //
28*0b57cec5SDimitry Andric // ===---------------------------------------------------------------------===//
29*0b57cec5SDimitry Andric 
30*0b57cec5SDimitry Andric #include "SystemZHazardRecognizer.h"
31*0b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
32*0b57cec5SDimitry Andric 
33*0b57cec5SDimitry Andric using namespace llvm;
34*0b57cec5SDimitry Andric 
35*0b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler"
36*0b57cec5SDimitry Andric 
37*0b57cec5SDimitry Andric // This is the limit of processor resource usage at which the
38*0b57cec5SDimitry Andric // scheduler should try to look for other instructions (not using the
39*0b57cec5SDimitry Andric // critical resource).
40*0b57cec5SDimitry Andric static cl::opt<int> ProcResCostLim("procres-cost-lim", cl::Hidden,
41*0b57cec5SDimitry Andric                                    cl::desc("The OOO window for processor "
42*0b57cec5SDimitry Andric                                             "resources during scheduling."),
43*0b57cec5SDimitry Andric                                    cl::init(8));
44*0b57cec5SDimitry Andric 
45*0b57cec5SDimitry Andric unsigned SystemZHazardRecognizer::
46*0b57cec5SDimitry Andric getNumDecoderSlots(SUnit *SU) const {
47*0b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
48*0b57cec5SDimitry Andric   if (!SC->isValid())
49*0b57cec5SDimitry Andric     return 0; // IMPLICIT_DEF / KILL -- will not make impact in output.
50*0b57cec5SDimitry Andric 
51*0b57cec5SDimitry Andric   assert((SC->NumMicroOps != 2 || (SC->BeginGroup && !SC->EndGroup)) &&
52*0b57cec5SDimitry Andric          "Only cracked instruction can have 2 uops.");
53*0b57cec5SDimitry Andric   assert((SC->NumMicroOps < 3 || (SC->BeginGroup && SC->EndGroup)) &&
54*0b57cec5SDimitry Andric          "Expanded instructions always group alone.");
55*0b57cec5SDimitry Andric   assert((SC->NumMicroOps < 3 || (SC->NumMicroOps % 3 == 0)) &&
56*0b57cec5SDimitry Andric          "Expanded instructions fill the group(s).");
57*0b57cec5SDimitry Andric 
58*0b57cec5SDimitry Andric   return SC->NumMicroOps;
59*0b57cec5SDimitry Andric }
60*0b57cec5SDimitry Andric 
61*0b57cec5SDimitry Andric unsigned SystemZHazardRecognizer::getCurrCycleIdx(SUnit *SU) const {
62*0b57cec5SDimitry Andric   unsigned Idx = CurrGroupSize;
63*0b57cec5SDimitry Andric   if (GrpCount % 2)
64*0b57cec5SDimitry Andric     Idx += 3;
65*0b57cec5SDimitry Andric 
66*0b57cec5SDimitry Andric   if (SU != nullptr && !fitsIntoCurrentGroup(SU)) {
67*0b57cec5SDimitry Andric     if (Idx == 1 || Idx == 2)
68*0b57cec5SDimitry Andric       Idx = 3;
69*0b57cec5SDimitry Andric     else if (Idx == 4 || Idx == 5)
70*0b57cec5SDimitry Andric       Idx = 0;
71*0b57cec5SDimitry Andric   }
72*0b57cec5SDimitry Andric 
73*0b57cec5SDimitry Andric   return Idx;
74*0b57cec5SDimitry Andric }
75*0b57cec5SDimitry Andric 
76*0b57cec5SDimitry Andric ScheduleHazardRecognizer::HazardType SystemZHazardRecognizer::
77*0b57cec5SDimitry Andric getHazardType(SUnit *m, int Stalls) {
78*0b57cec5SDimitry Andric   return (fitsIntoCurrentGroup(m) ? NoHazard : Hazard);
79*0b57cec5SDimitry Andric }
80*0b57cec5SDimitry Andric 
81*0b57cec5SDimitry Andric void SystemZHazardRecognizer::Reset() {
82*0b57cec5SDimitry Andric   CurrGroupSize = 0;
83*0b57cec5SDimitry Andric   CurrGroupHas4RegOps = false;
84*0b57cec5SDimitry Andric   clearProcResCounters();
85*0b57cec5SDimitry Andric   GrpCount = 0;
86*0b57cec5SDimitry Andric   LastFPdOpCycleIdx = UINT_MAX;
87*0b57cec5SDimitry Andric   LastEmittedMI = nullptr;
88*0b57cec5SDimitry Andric   LLVM_DEBUG(CurGroupDbg = "";);
89*0b57cec5SDimitry Andric }
90*0b57cec5SDimitry Andric 
91*0b57cec5SDimitry Andric bool
92*0b57cec5SDimitry Andric SystemZHazardRecognizer::fitsIntoCurrentGroup(SUnit *SU) const {
93*0b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
94*0b57cec5SDimitry Andric   if (!SC->isValid())
95*0b57cec5SDimitry Andric     return true;
96*0b57cec5SDimitry Andric 
97*0b57cec5SDimitry Andric   // A cracked instruction only fits into schedule if the current
98*0b57cec5SDimitry Andric   // group is empty.
99*0b57cec5SDimitry Andric   if (SC->BeginGroup)
100*0b57cec5SDimitry Andric     return (CurrGroupSize == 0);
101*0b57cec5SDimitry Andric 
102*0b57cec5SDimitry Andric   // An instruction with 4 register operands will not fit in last slot.
103*0b57cec5SDimitry Andric   assert ((CurrGroupSize < 2 || !CurrGroupHas4RegOps) &&
104*0b57cec5SDimitry Andric           "Current decoder group is already full!");
105*0b57cec5SDimitry Andric   if (CurrGroupSize == 2 && has4RegOps(SU->getInstr()))
106*0b57cec5SDimitry Andric     return false;
107*0b57cec5SDimitry Andric 
108*0b57cec5SDimitry Andric   // Since a full group is handled immediately in EmitInstruction(),
109*0b57cec5SDimitry Andric   // SU should fit into current group. NumSlots should be 1 or 0,
110*0b57cec5SDimitry Andric   // since it is not a cracked or expanded instruction.
111*0b57cec5SDimitry Andric   assert ((getNumDecoderSlots(SU) <= 1) && (CurrGroupSize < 3) &&
112*0b57cec5SDimitry Andric           "Expected normal instruction to fit in non-full group!");
113*0b57cec5SDimitry Andric 
114*0b57cec5SDimitry Andric   return true;
115*0b57cec5SDimitry Andric }
116*0b57cec5SDimitry Andric 
117*0b57cec5SDimitry Andric bool SystemZHazardRecognizer::has4RegOps(const MachineInstr *MI) const {
118*0b57cec5SDimitry Andric   const MachineFunction &MF = *MI->getParent()->getParent();
119*0b57cec5SDimitry Andric   const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
120*0b57cec5SDimitry Andric   const MCInstrDesc &MID = MI->getDesc();
121*0b57cec5SDimitry Andric   unsigned Count = 0;
122*0b57cec5SDimitry Andric   for (unsigned OpIdx = 0; OpIdx < MID.getNumOperands(); OpIdx++) {
123*0b57cec5SDimitry Andric     const TargetRegisterClass *RC = TII->getRegClass(MID, OpIdx, TRI, MF);
124*0b57cec5SDimitry Andric     if (RC == nullptr)
125*0b57cec5SDimitry Andric       continue;
126*0b57cec5SDimitry Andric     if (OpIdx >= MID.getNumDefs() &&
127*0b57cec5SDimitry Andric         MID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
128*0b57cec5SDimitry Andric       continue;
129*0b57cec5SDimitry Andric     Count++;
130*0b57cec5SDimitry Andric   }
131*0b57cec5SDimitry Andric   return Count >= 4;
132*0b57cec5SDimitry Andric }
133*0b57cec5SDimitry Andric 
134*0b57cec5SDimitry Andric void SystemZHazardRecognizer::nextGroup() {
135*0b57cec5SDimitry Andric   if (CurrGroupSize == 0)
136*0b57cec5SDimitry Andric     return;
137*0b57cec5SDimitry Andric 
138*0b57cec5SDimitry Andric   LLVM_DEBUG(dumpCurrGroup("Completed decode group"));
139*0b57cec5SDimitry Andric   LLVM_DEBUG(CurGroupDbg = "";);
140*0b57cec5SDimitry Andric 
141*0b57cec5SDimitry Andric   int NumGroups = ((CurrGroupSize > 3) ? (CurrGroupSize / 3) : 1);
142*0b57cec5SDimitry Andric   assert((CurrGroupSize <= 3 || CurrGroupSize % 3 == 0) &&
143*0b57cec5SDimitry Andric          "Current decoder group bad.");
144*0b57cec5SDimitry Andric 
145*0b57cec5SDimitry Andric   // Reset counter for next group.
146*0b57cec5SDimitry Andric   CurrGroupSize = 0;
147*0b57cec5SDimitry Andric   CurrGroupHas4RegOps = false;
148*0b57cec5SDimitry Andric 
149*0b57cec5SDimitry Andric   GrpCount += ((unsigned) NumGroups);
150*0b57cec5SDimitry Andric 
151*0b57cec5SDimitry Andric   // Decrease counters for execution units.
152*0b57cec5SDimitry Andric   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
153*0b57cec5SDimitry Andric     ProcResourceCounters[i] = ((ProcResourceCounters[i] > NumGroups)
154*0b57cec5SDimitry Andric                                    ? (ProcResourceCounters[i] - NumGroups)
155*0b57cec5SDimitry Andric                                    : 0);
156*0b57cec5SDimitry Andric 
157*0b57cec5SDimitry Andric   // Clear CriticalResourceIdx if it is now below the threshold.
158*0b57cec5SDimitry Andric   if (CriticalResourceIdx != UINT_MAX &&
159*0b57cec5SDimitry Andric       (ProcResourceCounters[CriticalResourceIdx] <=
160*0b57cec5SDimitry Andric        ProcResCostLim))
161*0b57cec5SDimitry Andric     CriticalResourceIdx = UINT_MAX;
162*0b57cec5SDimitry Andric 
163*0b57cec5SDimitry Andric   LLVM_DEBUG(dumpState(););
164*0b57cec5SDimitry Andric }
165*0b57cec5SDimitry Andric 
166*0b57cec5SDimitry Andric #ifndef NDEBUG // Debug output
167*0b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpSU(SUnit *SU, raw_ostream &OS) const {
168*0b57cec5SDimitry Andric   OS << "SU(" << SU->NodeNum << "):";
169*0b57cec5SDimitry Andric   OS << TII->getName(SU->getInstr()->getOpcode());
170*0b57cec5SDimitry Andric 
171*0b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
172*0b57cec5SDimitry Andric   if (!SC->isValid())
173*0b57cec5SDimitry Andric     return;
174*0b57cec5SDimitry Andric 
175*0b57cec5SDimitry Andric   for (TargetSchedModel::ProcResIter
176*0b57cec5SDimitry Andric          PI = SchedModel->getWriteProcResBegin(SC),
177*0b57cec5SDimitry Andric          PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
178*0b57cec5SDimitry Andric     const MCProcResourceDesc &PRD =
179*0b57cec5SDimitry Andric       *SchedModel->getProcResource(PI->ProcResourceIdx);
180*0b57cec5SDimitry Andric     std::string FU(PRD.Name);
181*0b57cec5SDimitry Andric     // trim e.g. Z13_FXaUnit -> FXa
182*0b57cec5SDimitry Andric     FU = FU.substr(FU.find("_") + 1);
183*0b57cec5SDimitry Andric     size_t Pos = FU.find("Unit");
184*0b57cec5SDimitry Andric     if (Pos != std::string::npos)
185*0b57cec5SDimitry Andric       FU.resize(Pos);
186*0b57cec5SDimitry Andric     if (FU == "LS") // LSUnit -> LSU
187*0b57cec5SDimitry Andric       FU = "LSU";
188*0b57cec5SDimitry Andric     OS << "/" << FU;
189*0b57cec5SDimitry Andric 
190*0b57cec5SDimitry Andric     if (PI->Cycles > 1)
191*0b57cec5SDimitry Andric       OS << "(" << PI->Cycles << "cyc)";
192*0b57cec5SDimitry Andric   }
193*0b57cec5SDimitry Andric 
194*0b57cec5SDimitry Andric   if (SC->NumMicroOps > 1)
195*0b57cec5SDimitry Andric     OS << "/" << SC->NumMicroOps << "uops";
196*0b57cec5SDimitry Andric   if (SC->BeginGroup && SC->EndGroup)
197*0b57cec5SDimitry Andric     OS << "/GroupsAlone";
198*0b57cec5SDimitry Andric   else if (SC->BeginGroup)
199*0b57cec5SDimitry Andric     OS << "/BeginsGroup";
200*0b57cec5SDimitry Andric   else if (SC->EndGroup)
201*0b57cec5SDimitry Andric     OS << "/EndsGroup";
202*0b57cec5SDimitry Andric   if (SU->isUnbuffered)
203*0b57cec5SDimitry Andric     OS << "/Unbuffered";
204*0b57cec5SDimitry Andric   if (has4RegOps(SU->getInstr()))
205*0b57cec5SDimitry Andric     OS << "/4RegOps";
206*0b57cec5SDimitry Andric }
207*0b57cec5SDimitry Andric 
208*0b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpCurrGroup(std::string Msg) const {
209*0b57cec5SDimitry Andric   dbgs() << "++ " << Msg;
210*0b57cec5SDimitry Andric   dbgs() << ": ";
211*0b57cec5SDimitry Andric 
212*0b57cec5SDimitry Andric   if (CurGroupDbg.empty())
213*0b57cec5SDimitry Andric     dbgs() << " <empty>\n";
214*0b57cec5SDimitry Andric   else {
215*0b57cec5SDimitry Andric     dbgs() << "{ " << CurGroupDbg << " }";
216*0b57cec5SDimitry Andric     dbgs() << " (" << CurrGroupSize << " decoder slot"
217*0b57cec5SDimitry Andric            << (CurrGroupSize > 1 ? "s":"")
218*0b57cec5SDimitry Andric            << (CurrGroupHas4RegOps ? ", 4RegOps" : "")
219*0b57cec5SDimitry Andric            << ")\n";
220*0b57cec5SDimitry Andric   }
221*0b57cec5SDimitry Andric }
222*0b57cec5SDimitry Andric 
223*0b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpProcResourceCounters() const {
224*0b57cec5SDimitry Andric   bool any = false;
225*0b57cec5SDimitry Andric 
226*0b57cec5SDimitry Andric   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
227*0b57cec5SDimitry Andric     if (ProcResourceCounters[i] > 0) {
228*0b57cec5SDimitry Andric       any = true;
229*0b57cec5SDimitry Andric       break;
230*0b57cec5SDimitry Andric     }
231*0b57cec5SDimitry Andric 
232*0b57cec5SDimitry Andric   if (!any)
233*0b57cec5SDimitry Andric     return;
234*0b57cec5SDimitry Andric 
235*0b57cec5SDimitry Andric   dbgs() << "++ | Resource counters: ";
236*0b57cec5SDimitry Andric   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
237*0b57cec5SDimitry Andric     if (ProcResourceCounters[i] > 0)
238*0b57cec5SDimitry Andric       dbgs() << SchedModel->getProcResource(i)->Name
239*0b57cec5SDimitry Andric              << ":" << ProcResourceCounters[i] << " ";
240*0b57cec5SDimitry Andric   dbgs() << "\n";
241*0b57cec5SDimitry Andric 
242*0b57cec5SDimitry Andric   if (CriticalResourceIdx != UINT_MAX)
243*0b57cec5SDimitry Andric     dbgs() << "++ | Critical resource: "
244*0b57cec5SDimitry Andric            << SchedModel->getProcResource(CriticalResourceIdx)->Name
245*0b57cec5SDimitry Andric            << "\n";
246*0b57cec5SDimitry Andric }
247*0b57cec5SDimitry Andric 
248*0b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpState() const {
249*0b57cec5SDimitry Andric   dumpCurrGroup("| Current decoder group");
250*0b57cec5SDimitry Andric   dbgs() << "++ | Current cycle index: "
251*0b57cec5SDimitry Andric          << getCurrCycleIdx() << "\n";
252*0b57cec5SDimitry Andric   dumpProcResourceCounters();
253*0b57cec5SDimitry Andric   if (LastFPdOpCycleIdx != UINT_MAX)
254*0b57cec5SDimitry Andric     dbgs() << "++ | Last FPd cycle index: " << LastFPdOpCycleIdx << "\n";
255*0b57cec5SDimitry Andric }
256*0b57cec5SDimitry Andric 
257*0b57cec5SDimitry Andric #endif //NDEBUG
258*0b57cec5SDimitry Andric 
259*0b57cec5SDimitry Andric void SystemZHazardRecognizer::clearProcResCounters() {
260*0b57cec5SDimitry Andric   ProcResourceCounters.assign(SchedModel->getNumProcResourceKinds(), 0);
261*0b57cec5SDimitry Andric   CriticalResourceIdx = UINT_MAX;
262*0b57cec5SDimitry Andric }
263*0b57cec5SDimitry Andric 
264*0b57cec5SDimitry Andric static inline bool isBranchRetTrap(MachineInstr *MI) {
265*0b57cec5SDimitry Andric   return (MI->isBranch() || MI->isReturn() ||
266*0b57cec5SDimitry Andric           MI->getOpcode() == SystemZ::CondTrap);
267*0b57cec5SDimitry Andric }
268*0b57cec5SDimitry Andric 
269*0b57cec5SDimitry Andric // Update state with SU as the next scheduled unit.
270*0b57cec5SDimitry Andric void SystemZHazardRecognizer::
271*0b57cec5SDimitry Andric EmitInstruction(SUnit *SU) {
272*0b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
273*0b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "++ HazardRecognizer emitting "; dumpSU(SU, dbgs());
274*0b57cec5SDimitry Andric              dbgs() << "\n";);
275*0b57cec5SDimitry Andric   LLVM_DEBUG(dumpCurrGroup("Decode group before emission"););
276*0b57cec5SDimitry Andric 
277*0b57cec5SDimitry Andric   // If scheduling an SU that must begin a new decoder group, move on
278*0b57cec5SDimitry Andric   // to next group.
279*0b57cec5SDimitry Andric   if (!fitsIntoCurrentGroup(SU))
280*0b57cec5SDimitry Andric     nextGroup();
281*0b57cec5SDimitry Andric 
282*0b57cec5SDimitry Andric   LLVM_DEBUG(raw_string_ostream cgd(CurGroupDbg);
283*0b57cec5SDimitry Andric              if (CurGroupDbg.length()) cgd << ", "; dumpSU(SU, cgd););
284*0b57cec5SDimitry Andric 
285*0b57cec5SDimitry Andric   LastEmittedMI = SU->getInstr();
286*0b57cec5SDimitry Andric 
287*0b57cec5SDimitry Andric   // After returning from a call, we don't know much about the state.
288*0b57cec5SDimitry Andric   if (SU->isCall) {
289*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "++ Clearing state after call.\n";);
290*0b57cec5SDimitry Andric     Reset();
291*0b57cec5SDimitry Andric     LastEmittedMI = SU->getInstr();
292*0b57cec5SDimitry Andric     return;
293*0b57cec5SDimitry Andric   }
294*0b57cec5SDimitry Andric 
295*0b57cec5SDimitry Andric   // Increase counter for execution unit(s).
296*0b57cec5SDimitry Andric   for (TargetSchedModel::ProcResIter
297*0b57cec5SDimitry Andric          PI = SchedModel->getWriteProcResBegin(SC),
298*0b57cec5SDimitry Andric          PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
299*0b57cec5SDimitry Andric     // Don't handle FPd together with the other resources.
300*0b57cec5SDimitry Andric     if (SchedModel->getProcResource(PI->ProcResourceIdx)->BufferSize == 1)
301*0b57cec5SDimitry Andric       continue;
302*0b57cec5SDimitry Andric     int &CurrCounter =
303*0b57cec5SDimitry Andric       ProcResourceCounters[PI->ProcResourceIdx];
304*0b57cec5SDimitry Andric     CurrCounter += PI->Cycles;
305*0b57cec5SDimitry Andric     // Check if this is now the new critical resource.
306*0b57cec5SDimitry Andric     if ((CurrCounter > ProcResCostLim) &&
307*0b57cec5SDimitry Andric         (CriticalResourceIdx == UINT_MAX ||
308*0b57cec5SDimitry Andric          (PI->ProcResourceIdx != CriticalResourceIdx &&
309*0b57cec5SDimitry Andric           CurrCounter >
310*0b57cec5SDimitry Andric           ProcResourceCounters[CriticalResourceIdx]))) {
311*0b57cec5SDimitry Andric       LLVM_DEBUG(
312*0b57cec5SDimitry Andric           dbgs() << "++ New critical resource: "
313*0b57cec5SDimitry Andric                  << SchedModel->getProcResource(PI->ProcResourceIdx)->Name
314*0b57cec5SDimitry Andric                  << "\n";);
315*0b57cec5SDimitry Andric       CriticalResourceIdx = PI->ProcResourceIdx;
316*0b57cec5SDimitry Andric     }
317*0b57cec5SDimitry Andric   }
318*0b57cec5SDimitry Andric 
319*0b57cec5SDimitry Andric   // Make note of an instruction that uses a blocking resource (FPd).
320*0b57cec5SDimitry Andric   if (SU->isUnbuffered) {
321*0b57cec5SDimitry Andric     LastFPdOpCycleIdx = getCurrCycleIdx(SU);
322*0b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "++ Last FPd cycle index: " << LastFPdOpCycleIdx
323*0b57cec5SDimitry Andric                       << "\n";);
324*0b57cec5SDimitry Andric   }
325*0b57cec5SDimitry Andric 
326*0b57cec5SDimitry Andric   // Insert SU into current group by increasing number of slots used
327*0b57cec5SDimitry Andric   // in current group.
328*0b57cec5SDimitry Andric   CurrGroupSize += getNumDecoderSlots(SU);
329*0b57cec5SDimitry Andric   CurrGroupHas4RegOps |= has4RegOps(SU->getInstr());
330*0b57cec5SDimitry Andric   unsigned GroupLim = (CurrGroupHas4RegOps ? 2 : 3);
331*0b57cec5SDimitry Andric   assert((CurrGroupSize <= GroupLim || CurrGroupSize == getNumDecoderSlots(SU))
332*0b57cec5SDimitry Andric          && "SU does not fit into decoder group!");
333*0b57cec5SDimitry Andric 
334*0b57cec5SDimitry Andric   // Check if current group is now full/ended. If so, move on to next
335*0b57cec5SDimitry Andric   // group to be ready to evaluate more candidates.
336*0b57cec5SDimitry Andric   if (CurrGroupSize >= GroupLim || SC->EndGroup)
337*0b57cec5SDimitry Andric     nextGroup();
338*0b57cec5SDimitry Andric }
339*0b57cec5SDimitry Andric 
340*0b57cec5SDimitry Andric int SystemZHazardRecognizer::groupingCost(SUnit *SU) const {
341*0b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
342*0b57cec5SDimitry Andric   if (!SC->isValid())
343*0b57cec5SDimitry Andric     return 0;
344*0b57cec5SDimitry Andric 
345*0b57cec5SDimitry Andric   // If SU begins new group, it can either break a current group early
346*0b57cec5SDimitry Andric   // or fit naturally if current group is empty (negative cost).
347*0b57cec5SDimitry Andric   if (SC->BeginGroup) {
348*0b57cec5SDimitry Andric     if (CurrGroupSize)
349*0b57cec5SDimitry Andric       return 3 - CurrGroupSize;
350*0b57cec5SDimitry Andric     return -1;
351*0b57cec5SDimitry Andric   }
352*0b57cec5SDimitry Andric 
353*0b57cec5SDimitry Andric   // Similarly, a group-ending SU may either fit well (last in group), or
354*0b57cec5SDimitry Andric   // end the group prematurely.
355*0b57cec5SDimitry Andric   if (SC->EndGroup) {
356*0b57cec5SDimitry Andric     unsigned resultingGroupSize =
357*0b57cec5SDimitry Andric       (CurrGroupSize + getNumDecoderSlots(SU));
358*0b57cec5SDimitry Andric     if (resultingGroupSize < 3)
359*0b57cec5SDimitry Andric       return (3 - resultingGroupSize);
360*0b57cec5SDimitry Andric     return -1;
361*0b57cec5SDimitry Andric   }
362*0b57cec5SDimitry Andric 
363*0b57cec5SDimitry Andric   // An instruction with 4 register operands will not fit in last slot.
364*0b57cec5SDimitry Andric   if (CurrGroupSize == 2 && has4RegOps(SU->getInstr()))
365*0b57cec5SDimitry Andric     return 1;
366*0b57cec5SDimitry Andric 
367*0b57cec5SDimitry Andric   // Most instructions can be placed in any decoder slot.
368*0b57cec5SDimitry Andric   return 0;
369*0b57cec5SDimitry Andric }
370*0b57cec5SDimitry Andric 
371*0b57cec5SDimitry Andric bool SystemZHazardRecognizer::isFPdOpPreferred_distance(SUnit *SU) const {
372*0b57cec5SDimitry Andric   assert (SU->isUnbuffered);
373*0b57cec5SDimitry Andric   // If this is the first FPd op, it should be scheduled high.
374*0b57cec5SDimitry Andric   if (LastFPdOpCycleIdx == UINT_MAX)
375*0b57cec5SDimitry Andric     return true;
376*0b57cec5SDimitry Andric   // If this is not the first PFd op, it should go into the other side
377*0b57cec5SDimitry Andric   // of the processor to use the other FPd unit there. This should
378*0b57cec5SDimitry Andric   // generally happen if two FPd ops are placed with 2 other
379*0b57cec5SDimitry Andric   // instructions between them (modulo 6).
380*0b57cec5SDimitry Andric   unsigned SUCycleIdx = getCurrCycleIdx(SU);
381*0b57cec5SDimitry Andric   if (LastFPdOpCycleIdx > SUCycleIdx)
382*0b57cec5SDimitry Andric     return ((LastFPdOpCycleIdx - SUCycleIdx) == 3);
383*0b57cec5SDimitry Andric   return ((SUCycleIdx - LastFPdOpCycleIdx) == 3);
384*0b57cec5SDimitry Andric }
385*0b57cec5SDimitry Andric 
386*0b57cec5SDimitry Andric int SystemZHazardRecognizer::
387*0b57cec5SDimitry Andric resourcesCost(SUnit *SU) {
388*0b57cec5SDimitry Andric   int Cost = 0;
389*0b57cec5SDimitry Andric 
390*0b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
391*0b57cec5SDimitry Andric   if (!SC->isValid())
392*0b57cec5SDimitry Andric     return 0;
393*0b57cec5SDimitry Andric 
394*0b57cec5SDimitry Andric   // For a FPd op, either return min or max value as indicated by the
395*0b57cec5SDimitry Andric   // distance to any prior FPd op.
396*0b57cec5SDimitry Andric   if (SU->isUnbuffered)
397*0b57cec5SDimitry Andric     Cost = (isFPdOpPreferred_distance(SU) ? INT_MIN : INT_MAX);
398*0b57cec5SDimitry Andric   // For other instructions, give a cost to the use of the critical resource.
399*0b57cec5SDimitry Andric   else if (CriticalResourceIdx != UINT_MAX) {
400*0b57cec5SDimitry Andric     for (TargetSchedModel::ProcResIter
401*0b57cec5SDimitry Andric            PI = SchedModel->getWriteProcResBegin(SC),
402*0b57cec5SDimitry Andric            PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI)
403*0b57cec5SDimitry Andric       if (PI->ProcResourceIdx == CriticalResourceIdx)
404*0b57cec5SDimitry Andric         Cost = PI->Cycles;
405*0b57cec5SDimitry Andric   }
406*0b57cec5SDimitry Andric 
407*0b57cec5SDimitry Andric   return Cost;
408*0b57cec5SDimitry Andric }
409*0b57cec5SDimitry Andric 
410*0b57cec5SDimitry Andric void SystemZHazardRecognizer::emitInstruction(MachineInstr *MI,
411*0b57cec5SDimitry Andric                                               bool TakenBranch) {
412*0b57cec5SDimitry Andric   // Make a temporary SUnit.
413*0b57cec5SDimitry Andric   SUnit SU(MI, 0);
414*0b57cec5SDimitry Andric 
415*0b57cec5SDimitry Andric   // Set interesting flags.
416*0b57cec5SDimitry Andric   SU.isCall = MI->isCall();
417*0b57cec5SDimitry Andric 
418*0b57cec5SDimitry Andric   const MCSchedClassDesc *SC = SchedModel->resolveSchedClass(MI);
419*0b57cec5SDimitry Andric   for (const MCWriteProcResEntry &PRE :
420*0b57cec5SDimitry Andric          make_range(SchedModel->getWriteProcResBegin(SC),
421*0b57cec5SDimitry Andric                     SchedModel->getWriteProcResEnd(SC))) {
422*0b57cec5SDimitry Andric     switch (SchedModel->getProcResource(PRE.ProcResourceIdx)->BufferSize) {
423*0b57cec5SDimitry Andric     case 0:
424*0b57cec5SDimitry Andric       SU.hasReservedResource = true;
425*0b57cec5SDimitry Andric       break;
426*0b57cec5SDimitry Andric     case 1:
427*0b57cec5SDimitry Andric       SU.isUnbuffered = true;
428*0b57cec5SDimitry Andric       break;
429*0b57cec5SDimitry Andric     default:
430*0b57cec5SDimitry Andric       break;
431*0b57cec5SDimitry Andric     }
432*0b57cec5SDimitry Andric   }
433*0b57cec5SDimitry Andric 
434*0b57cec5SDimitry Andric   unsigned GroupSizeBeforeEmit = CurrGroupSize;
435*0b57cec5SDimitry Andric   EmitInstruction(&SU);
436*0b57cec5SDimitry Andric 
437*0b57cec5SDimitry Andric   if (!TakenBranch && isBranchRetTrap(MI)) {
438*0b57cec5SDimitry Andric     // NT Branch on second slot ends group.
439*0b57cec5SDimitry Andric     if (GroupSizeBeforeEmit == 1)
440*0b57cec5SDimitry Andric       nextGroup();
441*0b57cec5SDimitry Andric   }
442*0b57cec5SDimitry Andric 
443*0b57cec5SDimitry Andric   if (TakenBranch && CurrGroupSize > 0)
444*0b57cec5SDimitry Andric     nextGroup();
445*0b57cec5SDimitry Andric 
446*0b57cec5SDimitry Andric   assert ((!MI->isTerminator() || isBranchRetTrap(MI)) &&
447*0b57cec5SDimitry Andric           "Scheduler: unhandled terminator!");
448*0b57cec5SDimitry Andric }
449*0b57cec5SDimitry Andric 
450*0b57cec5SDimitry Andric void SystemZHazardRecognizer::
451*0b57cec5SDimitry Andric copyState(SystemZHazardRecognizer *Incoming) {
452*0b57cec5SDimitry Andric   // Current decoder group
453*0b57cec5SDimitry Andric   CurrGroupSize = Incoming->CurrGroupSize;
454*0b57cec5SDimitry Andric   LLVM_DEBUG(CurGroupDbg = Incoming->CurGroupDbg;);
455*0b57cec5SDimitry Andric 
456*0b57cec5SDimitry Andric   // Processor resources
457*0b57cec5SDimitry Andric   ProcResourceCounters = Incoming->ProcResourceCounters;
458*0b57cec5SDimitry Andric   CriticalResourceIdx = Incoming->CriticalResourceIdx;
459*0b57cec5SDimitry Andric 
460*0b57cec5SDimitry Andric   // FPd
461*0b57cec5SDimitry Andric   LastFPdOpCycleIdx = Incoming->LastFPdOpCycleIdx;
462*0b57cec5SDimitry Andric   GrpCount = Incoming->GrpCount;
463*0b57cec5SDimitry Andric }
464