1d88c1a5aSDimitry Andric //=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===//
2d88c1a5aSDimitry Andric //
3d88c1a5aSDimitry Andric //                     The LLVM Compiler Infrastructure
4d88c1a5aSDimitry Andric //
5d88c1a5aSDimitry Andric // This file is distributed under the University of Illinois Open Source
6d88c1a5aSDimitry Andric // License. See LICENSE.TXT for details.
7d88c1a5aSDimitry Andric //
8d88c1a5aSDimitry Andric //===----------------------------------------------------------------------===//
9d88c1a5aSDimitry Andric //
10d88c1a5aSDimitry Andric // This file defines a hazard recognizer for the SystemZ scheduler.
11d88c1a5aSDimitry Andric //
12d88c1a5aSDimitry Andric // This class is used by the SystemZ scheduling strategy to maintain
13d88c1a5aSDimitry Andric // the state during scheduling, and provide cost functions for
14d88c1a5aSDimitry Andric // scheduling candidates. This includes:
15d88c1a5aSDimitry Andric //
16d88c1a5aSDimitry Andric // * Decoder grouping. A decoder group can maximally hold 3 uops, and
17d88c1a5aSDimitry Andric // instructions that always begin a new group should be scheduled when
18d88c1a5aSDimitry Andric // the current decoder group is empty.
19d88c1a5aSDimitry Andric // * Processor resources usage. It is beneficial to balance the use of
20d88c1a5aSDimitry Andric // resources.
21d88c1a5aSDimitry Andric //
222cab237bSDimitry Andric // A goal is to consider all instructions, also those outside of any
232cab237bSDimitry Andric // scheduling region. Such instructions are "advanced" past and include
242cab237bSDimitry Andric // single instructions before a scheduling region, branches etc.
252cab237bSDimitry Andric //
262cab237bSDimitry Andric // A block that has only one predecessor continues scheduling with the state
272cab237bSDimitry Andric // of it (which may be updated by emitting branches).
282cab237bSDimitry Andric //
29d88c1a5aSDimitry Andric // ===---------------------------------------------------------------------===//
30d88c1a5aSDimitry Andric 
31d88c1a5aSDimitry Andric #include "SystemZHazardRecognizer.h"
32d88c1a5aSDimitry Andric #include "llvm/ADT/Statistic.h"
33d88c1a5aSDimitry Andric 
34d88c1a5aSDimitry Andric using namespace llvm;
35d88c1a5aSDimitry Andric 
36c4394386SDimitry Andric #define DEBUG_TYPE "machine-scheduler"
37d88c1a5aSDimitry Andric 
38d88c1a5aSDimitry Andric // This is the limit of processor resource usage at which the
39d88c1a5aSDimitry Andric // scheduler should try to look for other instructions (not using the
40d88c1a5aSDimitry Andric // critical resource).
41d88c1a5aSDimitry Andric static cl::opt<int> ProcResCostLim("procres-cost-lim", cl::Hidden,
42d88c1a5aSDimitry Andric                                    cl::desc("The OOO window for processor "
43d88c1a5aSDimitry Andric                                             "resources during scheduling."),
44d88c1a5aSDimitry Andric                                    cl::init(8));
45d88c1a5aSDimitry Andric 
46d88c1a5aSDimitry Andric unsigned SystemZHazardRecognizer::
getNumDecoderSlots(SUnit * SU) const47d88c1a5aSDimitry Andric getNumDecoderSlots(SUnit *SU) const {
482cab237bSDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
49d88c1a5aSDimitry Andric   if (!SC->isValid())
50d88c1a5aSDimitry Andric     return 0; // IMPLICIT_DEF / KILL -- will not make impact in output.
51d88c1a5aSDimitry Andric 
52*b5893f02SDimitry Andric   assert((SC->NumMicroOps != 2 || (SC->BeginGroup && !SC->EndGroup)) &&
53*b5893f02SDimitry Andric          "Only cracked instruction can have 2 uops.");
54*b5893f02SDimitry Andric   assert((SC->NumMicroOps < 3 || (SC->BeginGroup && SC->EndGroup)) &&
55*b5893f02SDimitry Andric          "Expanded instructions always group alone.");
56*b5893f02SDimitry Andric   assert((SC->NumMicroOps < 3 || (SC->NumMicroOps % 3 == 0)) &&
57*b5893f02SDimitry Andric          "Expanded instructions fill the group(s).");
58d88c1a5aSDimitry Andric 
59*b5893f02SDimitry Andric   return SC->NumMicroOps;
60d88c1a5aSDimitry Andric }
61d88c1a5aSDimitry Andric 
getCurrCycleIdx(SUnit * SU) const624ba319b5SDimitry Andric unsigned SystemZHazardRecognizer::getCurrCycleIdx(SUnit *SU) const {
63d88c1a5aSDimitry Andric   unsigned Idx = CurrGroupSize;
64d88c1a5aSDimitry Andric   if (GrpCount % 2)
65d88c1a5aSDimitry Andric     Idx += 3;
664ba319b5SDimitry Andric 
674ba319b5SDimitry Andric   if (SU != nullptr && !fitsIntoCurrentGroup(SU)) {
684ba319b5SDimitry Andric     if (Idx == 1 || Idx == 2)
694ba319b5SDimitry Andric       Idx = 3;
704ba319b5SDimitry Andric     else if (Idx == 4 || Idx == 5)
714ba319b5SDimitry Andric       Idx = 0;
724ba319b5SDimitry Andric   }
734ba319b5SDimitry Andric 
74d88c1a5aSDimitry Andric   return Idx;
75d88c1a5aSDimitry Andric }
76d88c1a5aSDimitry Andric 
77d88c1a5aSDimitry Andric ScheduleHazardRecognizer::HazardType SystemZHazardRecognizer::
getHazardType(SUnit * m,int Stalls)78d88c1a5aSDimitry Andric getHazardType(SUnit *m, int Stalls) {
79d88c1a5aSDimitry Andric   return (fitsIntoCurrentGroup(m) ? NoHazard : Hazard);
80d88c1a5aSDimitry Andric }
81d88c1a5aSDimitry Andric 
Reset()82d88c1a5aSDimitry Andric void SystemZHazardRecognizer::Reset() {
83d88c1a5aSDimitry Andric   CurrGroupSize = 0;
844ba319b5SDimitry Andric   CurrGroupHas4RegOps = false;
85d88c1a5aSDimitry Andric   clearProcResCounters();
86d88c1a5aSDimitry Andric   GrpCount = 0;
87d88c1a5aSDimitry Andric   LastFPdOpCycleIdx = UINT_MAX;
882cab237bSDimitry Andric   LastEmittedMI = nullptr;
894ba319b5SDimitry Andric   LLVM_DEBUG(CurGroupDbg = "";);
90d88c1a5aSDimitry Andric }
91d88c1a5aSDimitry Andric 
92d88c1a5aSDimitry Andric bool
fitsIntoCurrentGroup(SUnit * SU) const93d88c1a5aSDimitry Andric SystemZHazardRecognizer::fitsIntoCurrentGroup(SUnit *SU) const {
942cab237bSDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
95d88c1a5aSDimitry Andric   if (!SC->isValid())
96d88c1a5aSDimitry Andric     return true;
97d88c1a5aSDimitry Andric 
98d88c1a5aSDimitry Andric   // A cracked instruction only fits into schedule if the current
99d88c1a5aSDimitry Andric   // group is empty.
100d88c1a5aSDimitry Andric   if (SC->BeginGroup)
101d88c1a5aSDimitry Andric     return (CurrGroupSize == 0);
102d88c1a5aSDimitry Andric 
1034ba319b5SDimitry Andric   // An instruction with 4 register operands will not fit in last slot.
1044ba319b5SDimitry Andric   assert ((CurrGroupSize < 2 || !CurrGroupHas4RegOps) &&
1054ba319b5SDimitry Andric           "Current decoder group is already full!");
1064ba319b5SDimitry Andric   if (CurrGroupSize == 2 && has4RegOps(SU->getInstr()))
1074ba319b5SDimitry Andric     return false;
1084ba319b5SDimitry Andric 
109d88c1a5aSDimitry Andric   // Since a full group is handled immediately in EmitInstruction(),
110d88c1a5aSDimitry Andric   // SU should fit into current group. NumSlots should be 1 or 0,
111d88c1a5aSDimitry Andric   // since it is not a cracked or expanded instruction.
112d88c1a5aSDimitry Andric   assert ((getNumDecoderSlots(SU) <= 1) && (CurrGroupSize < 3) &&
113d88c1a5aSDimitry Andric           "Expected normal instruction to fit in non-full group!");
114d88c1a5aSDimitry Andric 
115d88c1a5aSDimitry Andric   return true;
116d88c1a5aSDimitry Andric }
117d88c1a5aSDimitry Andric 
has4RegOps(const MachineInstr * MI) const1184ba319b5SDimitry Andric bool SystemZHazardRecognizer::has4RegOps(const MachineInstr *MI) const {
1194ba319b5SDimitry Andric   const MachineFunction &MF = *MI->getParent()->getParent();
1204ba319b5SDimitry Andric   const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
1214ba319b5SDimitry Andric   const MCInstrDesc &MID = MI->getDesc();
1224ba319b5SDimitry Andric   unsigned Count = 0;
1234ba319b5SDimitry Andric   for (unsigned OpIdx = 0; OpIdx < MID.getNumOperands(); OpIdx++) {
1244ba319b5SDimitry Andric     const TargetRegisterClass *RC = TII->getRegClass(MID, OpIdx, TRI, MF);
1254ba319b5SDimitry Andric     if (RC == nullptr)
1264ba319b5SDimitry Andric       continue;
1274ba319b5SDimitry Andric     if (OpIdx >= MID.getNumDefs() &&
1284ba319b5SDimitry Andric         MID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
1294ba319b5SDimitry Andric       continue;
1304ba319b5SDimitry Andric     Count++;
1314ba319b5SDimitry Andric   }
1324ba319b5SDimitry Andric   return Count >= 4;
1334ba319b5SDimitry Andric }
1344ba319b5SDimitry Andric 
nextGroup()1354ba319b5SDimitry Andric void SystemZHazardRecognizer::nextGroup() {
1364ba319b5SDimitry Andric   if (CurrGroupSize == 0)
1374ba319b5SDimitry Andric     return;
1384ba319b5SDimitry Andric 
1394ba319b5SDimitry Andric   LLVM_DEBUG(dumpCurrGroup("Completed decode group"));
1404ba319b5SDimitry Andric   LLVM_DEBUG(CurGroupDbg = "";);
141d88c1a5aSDimitry Andric 
142*b5893f02SDimitry Andric   int NumGroups = ((CurrGroupSize > 3) ? (CurrGroupSize / 3) : 1);
143*b5893f02SDimitry Andric   assert((CurrGroupSize <= 3 || CurrGroupSize % 3 == 0) &&
144*b5893f02SDimitry Andric          "Current decoder group bad.");
145d88c1a5aSDimitry Andric 
146d88c1a5aSDimitry Andric   // Reset counter for next group.
147d88c1a5aSDimitry Andric   CurrGroupSize = 0;
1484ba319b5SDimitry Andric   CurrGroupHas4RegOps = false;
149d88c1a5aSDimitry Andric 
150*b5893f02SDimitry Andric   GrpCount += ((unsigned) NumGroups);
151*b5893f02SDimitry Andric 
152*b5893f02SDimitry Andric   // Decrease counters for execution units.
153d88c1a5aSDimitry Andric   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
154*b5893f02SDimitry Andric     ProcResourceCounters[i] = ((ProcResourceCounters[i] > NumGroups)
155*b5893f02SDimitry Andric                                    ? (ProcResourceCounters[i] - NumGroups)
156*b5893f02SDimitry Andric                                    : 0);
157d88c1a5aSDimitry Andric 
158d88c1a5aSDimitry Andric   // Clear CriticalResourceIdx if it is now below the threshold.
159d88c1a5aSDimitry Andric   if (CriticalResourceIdx != UINT_MAX &&
160d88c1a5aSDimitry Andric       (ProcResourceCounters[CriticalResourceIdx] <=
161d88c1a5aSDimitry Andric        ProcResCostLim))
162d88c1a5aSDimitry Andric     CriticalResourceIdx = UINT_MAX;
163d88c1a5aSDimitry Andric 
1644ba319b5SDimitry Andric   LLVM_DEBUG(dumpState(););
165d88c1a5aSDimitry Andric }
166d88c1a5aSDimitry Andric 
167d88c1a5aSDimitry Andric #ifndef NDEBUG // Debug output
dumpSU(SUnit * SU,raw_ostream & OS) const168d88c1a5aSDimitry Andric void SystemZHazardRecognizer::dumpSU(SUnit *SU, raw_ostream &OS) const {
169d88c1a5aSDimitry Andric   OS << "SU(" << SU->NodeNum << "):";
1702cab237bSDimitry Andric   OS << TII->getName(SU->getInstr()->getOpcode());
171d88c1a5aSDimitry Andric 
1722cab237bSDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
173d88c1a5aSDimitry Andric   if (!SC->isValid())
174d88c1a5aSDimitry Andric     return;
175d88c1a5aSDimitry Andric 
176d88c1a5aSDimitry Andric   for (TargetSchedModel::ProcResIter
177d88c1a5aSDimitry Andric          PI = SchedModel->getWriteProcResBegin(SC),
178d88c1a5aSDimitry Andric          PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
179d88c1a5aSDimitry Andric     const MCProcResourceDesc &PRD =
180d88c1a5aSDimitry Andric       *SchedModel->getProcResource(PI->ProcResourceIdx);
181d88c1a5aSDimitry Andric     std::string FU(PRD.Name);
182d88c1a5aSDimitry Andric     // trim e.g. Z13_FXaUnit -> FXa
183d88c1a5aSDimitry Andric     FU = FU.substr(FU.find("_") + 1);
1844ba319b5SDimitry Andric     size_t Pos = FU.find("Unit");
1854ba319b5SDimitry Andric     if (Pos != std::string::npos)
1864ba319b5SDimitry Andric       FU.resize(Pos);
1874ba319b5SDimitry Andric     if (FU == "LS") // LSUnit -> LSU
1884ba319b5SDimitry Andric       FU = "LSU";
189d88c1a5aSDimitry Andric     OS << "/" << FU;
190d88c1a5aSDimitry Andric 
191d88c1a5aSDimitry Andric     if (PI->Cycles > 1)
192d88c1a5aSDimitry Andric       OS << "(" << PI->Cycles << "cyc)";
193d88c1a5aSDimitry Andric   }
194d88c1a5aSDimitry Andric 
195d88c1a5aSDimitry Andric   if (SC->NumMicroOps > 1)
196d88c1a5aSDimitry Andric     OS << "/" << SC->NumMicroOps << "uops";
197d88c1a5aSDimitry Andric   if (SC->BeginGroup && SC->EndGroup)
198d88c1a5aSDimitry Andric     OS << "/GroupsAlone";
199d88c1a5aSDimitry Andric   else if (SC->BeginGroup)
200d88c1a5aSDimitry Andric     OS << "/BeginsGroup";
201d88c1a5aSDimitry Andric   else if (SC->EndGroup)
202d88c1a5aSDimitry Andric     OS << "/EndsGroup";
203d88c1a5aSDimitry Andric   if (SU->isUnbuffered)
204d88c1a5aSDimitry Andric     OS << "/Unbuffered";
2054ba319b5SDimitry Andric   if (has4RegOps(SU->getInstr()))
2064ba319b5SDimitry Andric     OS << "/4RegOps";
207d88c1a5aSDimitry Andric }
208d88c1a5aSDimitry Andric 
dumpCurrGroup(std::string Msg) const209d88c1a5aSDimitry Andric void SystemZHazardRecognizer::dumpCurrGroup(std::string Msg) const {
2104ba319b5SDimitry Andric   dbgs() << "++ " << Msg;
211d88c1a5aSDimitry Andric   dbgs() << ": ";
212d88c1a5aSDimitry Andric 
213d88c1a5aSDimitry Andric   if (CurGroupDbg.empty())
214d88c1a5aSDimitry Andric     dbgs() << " <empty>\n";
215d88c1a5aSDimitry Andric   else {
216d88c1a5aSDimitry Andric     dbgs() << "{ " << CurGroupDbg << " }";
217d88c1a5aSDimitry Andric     dbgs() << " (" << CurrGroupSize << " decoder slot"
218d88c1a5aSDimitry Andric            << (CurrGroupSize > 1 ? "s":"")
2194ba319b5SDimitry Andric            << (CurrGroupHas4RegOps ? ", 4RegOps" : "")
220d88c1a5aSDimitry Andric            << ")\n";
221d88c1a5aSDimitry Andric   }
222d88c1a5aSDimitry Andric }
223d88c1a5aSDimitry Andric 
dumpProcResourceCounters() const224d88c1a5aSDimitry Andric void SystemZHazardRecognizer::dumpProcResourceCounters() const {
225d88c1a5aSDimitry Andric   bool any = false;
226d88c1a5aSDimitry Andric 
227d88c1a5aSDimitry Andric   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
228d88c1a5aSDimitry Andric     if (ProcResourceCounters[i] > 0) {
229d88c1a5aSDimitry Andric       any = true;
230d88c1a5aSDimitry Andric       break;
231d88c1a5aSDimitry Andric     }
232d88c1a5aSDimitry Andric 
233d88c1a5aSDimitry Andric   if (!any)
234d88c1a5aSDimitry Andric     return;
235d88c1a5aSDimitry Andric 
2364ba319b5SDimitry Andric   dbgs() << "++ | Resource counters: ";
237d88c1a5aSDimitry Andric   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
2384ba319b5SDimitry Andric     if (ProcResourceCounters[i] > 0)
2394ba319b5SDimitry Andric       dbgs() << SchedModel->getProcResource(i)->Name
2404ba319b5SDimitry Andric              << ":" << ProcResourceCounters[i] << " ";
2414ba319b5SDimitry Andric   dbgs() << "\n";
2424ba319b5SDimitry Andric 
2434ba319b5SDimitry Andric   if (CriticalResourceIdx != UINT_MAX)
2444ba319b5SDimitry Andric     dbgs() << "++ | Critical resource: "
2454ba319b5SDimitry Andric            << SchedModel->getProcResource(CriticalResourceIdx)->Name
2464ba319b5SDimitry Andric            << "\n";
247d88c1a5aSDimitry Andric }
2484ba319b5SDimitry Andric 
dumpState() const2494ba319b5SDimitry Andric void SystemZHazardRecognizer::dumpState() const {
2504ba319b5SDimitry Andric   dumpCurrGroup("| Current decoder group");
2514ba319b5SDimitry Andric   dbgs() << "++ | Current cycle index: "
2524ba319b5SDimitry Andric          << getCurrCycleIdx() << "\n";
2534ba319b5SDimitry Andric   dumpProcResourceCounters();
2544ba319b5SDimitry Andric   if (LastFPdOpCycleIdx != UINT_MAX)
2554ba319b5SDimitry Andric     dbgs() << "++ | Last FPd cycle index: " << LastFPdOpCycleIdx << "\n";
256d88c1a5aSDimitry Andric }
2574ba319b5SDimitry Andric 
258d88c1a5aSDimitry Andric #endif //NDEBUG
259d88c1a5aSDimitry Andric 
clearProcResCounters()260d88c1a5aSDimitry Andric void SystemZHazardRecognizer::clearProcResCounters() {
261d88c1a5aSDimitry Andric   ProcResourceCounters.assign(SchedModel->getNumProcResourceKinds(), 0);
262d88c1a5aSDimitry Andric   CriticalResourceIdx = UINT_MAX;
263d88c1a5aSDimitry Andric }
264d88c1a5aSDimitry Andric 
isBranchRetTrap(MachineInstr * MI)2652cab237bSDimitry Andric static inline bool isBranchRetTrap(MachineInstr *MI) {
2662cab237bSDimitry Andric   return (MI->isBranch() || MI->isReturn() ||
2672cab237bSDimitry Andric           MI->getOpcode() == SystemZ::CondTrap);
2682cab237bSDimitry Andric }
2692cab237bSDimitry Andric 
270d88c1a5aSDimitry Andric // Update state with SU as the next scheduled unit.
271d88c1a5aSDimitry Andric void SystemZHazardRecognizer::
EmitInstruction(SUnit * SU)272d88c1a5aSDimitry Andric EmitInstruction(SUnit *SU) {
2732cab237bSDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
2744ba319b5SDimitry Andric   LLVM_DEBUG(dbgs() << "++ HazardRecognizer emitting "; dumpSU(SU, dbgs());
2754ba319b5SDimitry Andric              dbgs() << "\n";);
2764ba319b5SDimitry Andric   LLVM_DEBUG(dumpCurrGroup("Decode group before emission"););
277d88c1a5aSDimitry Andric 
278d88c1a5aSDimitry Andric   // If scheduling an SU that must begin a new decoder group, move on
279d88c1a5aSDimitry Andric   // to next group.
280d88c1a5aSDimitry Andric   if (!fitsIntoCurrentGroup(SU))
281d88c1a5aSDimitry Andric     nextGroup();
282d88c1a5aSDimitry Andric 
2834ba319b5SDimitry Andric   LLVM_DEBUG(raw_string_ostream cgd(CurGroupDbg);
2844ba319b5SDimitry Andric              if (CurGroupDbg.length()) cgd << ", "; dumpSU(SU, cgd););
285d88c1a5aSDimitry Andric 
2862cab237bSDimitry Andric   LastEmittedMI = SU->getInstr();
2872cab237bSDimitry Andric 
288d88c1a5aSDimitry Andric   // After returning from a call, we don't know much about the state.
2892cab237bSDimitry Andric   if (SU->isCall) {
2904ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "++ Clearing state after call.\n";);
2914ba319b5SDimitry Andric     Reset();
2924ba319b5SDimitry Andric     LastEmittedMI = SU->getInstr();
293d88c1a5aSDimitry Andric     return;
294d88c1a5aSDimitry Andric   }
295d88c1a5aSDimitry Andric 
296d88c1a5aSDimitry Andric   // Increase counter for execution unit(s).
297d88c1a5aSDimitry Andric   for (TargetSchedModel::ProcResIter
298d88c1a5aSDimitry Andric          PI = SchedModel->getWriteProcResBegin(SC),
299d88c1a5aSDimitry Andric          PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
300d88c1a5aSDimitry Andric     // Don't handle FPd together with the other resources.
301d88c1a5aSDimitry Andric     if (SchedModel->getProcResource(PI->ProcResourceIdx)->BufferSize == 1)
302d88c1a5aSDimitry Andric       continue;
303d88c1a5aSDimitry Andric     int &CurrCounter =
304d88c1a5aSDimitry Andric       ProcResourceCounters[PI->ProcResourceIdx];
305d88c1a5aSDimitry Andric     CurrCounter += PI->Cycles;
306d88c1a5aSDimitry Andric     // Check if this is now the new critical resource.
307d88c1a5aSDimitry Andric     if ((CurrCounter > ProcResCostLim) &&
308d88c1a5aSDimitry Andric         (CriticalResourceIdx == UINT_MAX ||
309d88c1a5aSDimitry Andric          (PI->ProcResourceIdx != CriticalResourceIdx &&
310d88c1a5aSDimitry Andric           CurrCounter >
311d88c1a5aSDimitry Andric           ProcResourceCounters[CriticalResourceIdx]))) {
3124ba319b5SDimitry Andric       LLVM_DEBUG(
3134ba319b5SDimitry Andric           dbgs() << "++ New critical resource: "
314d88c1a5aSDimitry Andric                  << SchedModel->getProcResource(PI->ProcResourceIdx)->Name
315d88c1a5aSDimitry Andric                  << "\n";);
316d88c1a5aSDimitry Andric       CriticalResourceIdx = PI->ProcResourceIdx;
317d88c1a5aSDimitry Andric     }
318d88c1a5aSDimitry Andric   }
319d88c1a5aSDimitry Andric 
320d88c1a5aSDimitry Andric   // Make note of an instruction that uses a blocking resource (FPd).
321d88c1a5aSDimitry Andric   if (SU->isUnbuffered) {
3224ba319b5SDimitry Andric     LastFPdOpCycleIdx = getCurrCycleIdx(SU);
3234ba319b5SDimitry Andric     LLVM_DEBUG(dbgs() << "++ Last FPd cycle index: " << LastFPdOpCycleIdx
3244ba319b5SDimitry Andric                       << "\n";);
325d88c1a5aSDimitry Andric   }
326d88c1a5aSDimitry Andric 
327d88c1a5aSDimitry Andric   // Insert SU into current group by increasing number of slots used
328d88c1a5aSDimitry Andric   // in current group.
329d88c1a5aSDimitry Andric   CurrGroupSize += getNumDecoderSlots(SU);
3304ba319b5SDimitry Andric   CurrGroupHas4RegOps |= has4RegOps(SU->getInstr());
331*b5893f02SDimitry Andric   unsigned GroupLim = (CurrGroupHas4RegOps ? 2 : 3);
332*b5893f02SDimitry Andric   assert((CurrGroupSize <= GroupLim || CurrGroupSize == getNumDecoderSlots(SU))
333*b5893f02SDimitry Andric          && "SU does not fit into decoder group!");
334d88c1a5aSDimitry Andric 
335d88c1a5aSDimitry Andric   // Check if current group is now full/ended. If so, move on to next
336d88c1a5aSDimitry Andric   // group to be ready to evaluate more candidates.
337*b5893f02SDimitry Andric   if (CurrGroupSize >= GroupLim || SC->EndGroup)
338d88c1a5aSDimitry Andric     nextGroup();
339d88c1a5aSDimitry Andric }
340d88c1a5aSDimitry Andric 
groupingCost(SUnit * SU) const341d88c1a5aSDimitry Andric int SystemZHazardRecognizer::groupingCost(SUnit *SU) const {
3422cab237bSDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
343d88c1a5aSDimitry Andric   if (!SC->isValid())
344d88c1a5aSDimitry Andric     return 0;
345d88c1a5aSDimitry Andric 
346d88c1a5aSDimitry Andric   // If SU begins new group, it can either break a current group early
347d88c1a5aSDimitry Andric   // or fit naturally if current group is empty (negative cost).
348d88c1a5aSDimitry Andric   if (SC->BeginGroup) {
349d88c1a5aSDimitry Andric     if (CurrGroupSize)
350d88c1a5aSDimitry Andric       return 3 - CurrGroupSize;
351d88c1a5aSDimitry Andric     return -1;
352d88c1a5aSDimitry Andric   }
353d88c1a5aSDimitry Andric 
354d88c1a5aSDimitry Andric   // Similarly, a group-ending SU may either fit well (last in group), or
355d88c1a5aSDimitry Andric   // end the group prematurely.
356d88c1a5aSDimitry Andric   if (SC->EndGroup) {
357d88c1a5aSDimitry Andric     unsigned resultingGroupSize =
358d88c1a5aSDimitry Andric       (CurrGroupSize + getNumDecoderSlots(SU));
359d88c1a5aSDimitry Andric     if (resultingGroupSize < 3)
360d88c1a5aSDimitry Andric       return (3 - resultingGroupSize);
361d88c1a5aSDimitry Andric     return -1;
362d88c1a5aSDimitry Andric   }
363d88c1a5aSDimitry Andric 
3644ba319b5SDimitry Andric   // An instruction with 4 register operands will not fit in last slot.
3654ba319b5SDimitry Andric   if (CurrGroupSize == 2 && has4RegOps(SU->getInstr()))
3664ba319b5SDimitry Andric     return 1;
3674ba319b5SDimitry Andric 
368d88c1a5aSDimitry Andric   // Most instructions can be placed in any decoder slot.
369d88c1a5aSDimitry Andric   return 0;
370d88c1a5aSDimitry Andric }
371d88c1a5aSDimitry Andric 
isFPdOpPreferred_distance(SUnit * SU) const3724ba319b5SDimitry Andric bool SystemZHazardRecognizer::isFPdOpPreferred_distance(SUnit *SU) const {
373d88c1a5aSDimitry Andric   assert (SU->isUnbuffered);
374d88c1a5aSDimitry Andric   // If this is the first FPd op, it should be scheduled high.
375d88c1a5aSDimitry Andric   if (LastFPdOpCycleIdx == UINT_MAX)
376d88c1a5aSDimitry Andric     return true;
377d88c1a5aSDimitry Andric   // If this is not the first PFd op, it should go into the other side
378d88c1a5aSDimitry Andric   // of the processor to use the other FPd unit there. This should
379d88c1a5aSDimitry Andric   // generally happen if two FPd ops are placed with 2 other
380d88c1a5aSDimitry Andric   // instructions between them (modulo 6).
3814ba319b5SDimitry Andric   unsigned SUCycleIdx = getCurrCycleIdx(SU);
3824ba319b5SDimitry Andric   if (LastFPdOpCycleIdx > SUCycleIdx)
3834ba319b5SDimitry Andric     return ((LastFPdOpCycleIdx - SUCycleIdx) == 3);
3844ba319b5SDimitry Andric   return ((SUCycleIdx - LastFPdOpCycleIdx) == 3);
385d88c1a5aSDimitry Andric }
386d88c1a5aSDimitry Andric 
387d88c1a5aSDimitry Andric int SystemZHazardRecognizer::
resourcesCost(SUnit * SU)388d88c1a5aSDimitry Andric resourcesCost(SUnit *SU) {
389d88c1a5aSDimitry Andric   int Cost = 0;
390d88c1a5aSDimitry Andric 
3912cab237bSDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
392d88c1a5aSDimitry Andric   if (!SC->isValid())
393d88c1a5aSDimitry Andric     return 0;
394d88c1a5aSDimitry Andric 
395d88c1a5aSDimitry Andric   // For a FPd op, either return min or max value as indicated by the
396d88c1a5aSDimitry Andric   // distance to any prior FPd op.
397d88c1a5aSDimitry Andric   if (SU->isUnbuffered)
398d88c1a5aSDimitry Andric     Cost = (isFPdOpPreferred_distance(SU) ? INT_MIN : INT_MAX);
399d88c1a5aSDimitry Andric   // For other instructions, give a cost to the use of the critical resource.
400d88c1a5aSDimitry Andric   else if (CriticalResourceIdx != UINT_MAX) {
401d88c1a5aSDimitry Andric     for (TargetSchedModel::ProcResIter
402d88c1a5aSDimitry Andric            PI = SchedModel->getWriteProcResBegin(SC),
403d88c1a5aSDimitry Andric            PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI)
404d88c1a5aSDimitry Andric       if (PI->ProcResourceIdx == CriticalResourceIdx)
405d88c1a5aSDimitry Andric         Cost = PI->Cycles;
406d88c1a5aSDimitry Andric   }
407d88c1a5aSDimitry Andric 
408d88c1a5aSDimitry Andric   return Cost;
409d88c1a5aSDimitry Andric }
410d88c1a5aSDimitry Andric 
emitInstruction(MachineInstr * MI,bool TakenBranch)4112cab237bSDimitry Andric void SystemZHazardRecognizer::emitInstruction(MachineInstr *MI,
4122cab237bSDimitry Andric                                               bool TakenBranch) {
4132cab237bSDimitry Andric   // Make a temporary SUnit.
4142cab237bSDimitry Andric   SUnit SU(MI, 0);
4152cab237bSDimitry Andric 
4162cab237bSDimitry Andric   // Set interesting flags.
4172cab237bSDimitry Andric   SU.isCall = MI->isCall();
4182cab237bSDimitry Andric 
4192cab237bSDimitry Andric   const MCSchedClassDesc *SC = SchedModel->resolveSchedClass(MI);
4202cab237bSDimitry Andric   for (const MCWriteProcResEntry &PRE :
4212cab237bSDimitry Andric          make_range(SchedModel->getWriteProcResBegin(SC),
4222cab237bSDimitry Andric                     SchedModel->getWriteProcResEnd(SC))) {
4232cab237bSDimitry Andric     switch (SchedModel->getProcResource(PRE.ProcResourceIdx)->BufferSize) {
4242cab237bSDimitry Andric     case 0:
4252cab237bSDimitry Andric       SU.hasReservedResource = true;
4262cab237bSDimitry Andric       break;
4272cab237bSDimitry Andric     case 1:
4282cab237bSDimitry Andric       SU.isUnbuffered = true;
4292cab237bSDimitry Andric       break;
4302cab237bSDimitry Andric     default:
4312cab237bSDimitry Andric       break;
4322cab237bSDimitry Andric     }
4332cab237bSDimitry Andric   }
4342cab237bSDimitry Andric 
4354ba319b5SDimitry Andric   unsigned GroupSizeBeforeEmit = CurrGroupSize;
4362cab237bSDimitry Andric   EmitInstruction(&SU);
4372cab237bSDimitry Andric 
4384ba319b5SDimitry Andric   if (!TakenBranch && isBranchRetTrap(MI)) {
4394ba319b5SDimitry Andric     // NT Branch on second slot ends group.
4404ba319b5SDimitry Andric     if (GroupSizeBeforeEmit == 1)
4414ba319b5SDimitry Andric       nextGroup();
4424ba319b5SDimitry Andric   }
4434ba319b5SDimitry Andric 
4442cab237bSDimitry Andric   if (TakenBranch && CurrGroupSize > 0)
4454ba319b5SDimitry Andric     nextGroup();
4462cab237bSDimitry Andric 
4472cab237bSDimitry Andric   assert ((!MI->isTerminator() || isBranchRetTrap(MI)) &&
4482cab237bSDimitry Andric           "Scheduler: unhandled terminator!");
4492cab237bSDimitry Andric }
4502cab237bSDimitry Andric 
4512cab237bSDimitry Andric void SystemZHazardRecognizer::
copyState(SystemZHazardRecognizer * Incoming)4522cab237bSDimitry Andric copyState(SystemZHazardRecognizer *Incoming) {
4532cab237bSDimitry Andric   // Current decoder group
4542cab237bSDimitry Andric   CurrGroupSize = Incoming->CurrGroupSize;
4554ba319b5SDimitry Andric   LLVM_DEBUG(CurGroupDbg = Incoming->CurGroupDbg;);
4562cab237bSDimitry Andric 
4572cab237bSDimitry Andric   // Processor resources
4582cab237bSDimitry Andric   ProcResourceCounters = Incoming->ProcResourceCounters;
4592cab237bSDimitry Andric   CriticalResourceIdx = Incoming->CriticalResourceIdx;
4602cab237bSDimitry Andric 
4612cab237bSDimitry Andric   // FPd
4622cab237bSDimitry Andric   LastFPdOpCycleIdx = Incoming->LastFPdOpCycleIdx;
4632cab237bSDimitry Andric   GrpCount = Incoming->GrpCount;
4642cab237bSDimitry Andric }
465