xref: /freebsd-src/contrib/llvm-project/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
10b57cec5SDimitry Andric //=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file defines a hazard recognizer for the SystemZ scheduler.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric // This class is used by the SystemZ scheduling strategy to maintain
120b57cec5SDimitry Andric // the state during scheduling, and provide cost functions for
130b57cec5SDimitry Andric // scheduling candidates. This includes:
140b57cec5SDimitry Andric //
150b57cec5SDimitry Andric // * Decoder grouping. A decoder group can maximally hold 3 uops, and
160b57cec5SDimitry Andric // instructions that always begin a new group should be scheduled when
170b57cec5SDimitry Andric // the current decoder group is empty.
180b57cec5SDimitry Andric // * Processor resources usage. It is beneficial to balance the use of
190b57cec5SDimitry Andric // resources.
200b57cec5SDimitry Andric //
210b57cec5SDimitry Andric // A goal is to consider all instructions, also those outside of any
220b57cec5SDimitry Andric // scheduling region. Such instructions are "advanced" past and include
230b57cec5SDimitry Andric // single instructions before a scheduling region, branches etc.
240b57cec5SDimitry Andric //
250b57cec5SDimitry Andric // A block that has only one predecessor continues scheduling with the state
260b57cec5SDimitry Andric // of it (which may be updated by emitting branches).
270b57cec5SDimitry Andric //
280b57cec5SDimitry Andric // ===---------------------------------------------------------------------===//
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric #include "SystemZHazardRecognizer.h"
310b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
320b57cec5SDimitry Andric 
330b57cec5SDimitry Andric using namespace llvm;
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler"
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric // This is the limit of processor resource usage at which the
380b57cec5SDimitry Andric // scheduler should try to look for other instructions (not using the
390b57cec5SDimitry Andric // critical resource).
400b57cec5SDimitry Andric static cl::opt<int> ProcResCostLim("procres-cost-lim", cl::Hidden,
410b57cec5SDimitry Andric                                    cl::desc("The OOO window for processor "
420b57cec5SDimitry Andric                                             "resources during scheduling."),
430b57cec5SDimitry Andric                                    cl::init(8));
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric unsigned SystemZHazardRecognizer::
getNumDecoderSlots(SUnit * SU) const460b57cec5SDimitry Andric getNumDecoderSlots(SUnit *SU) const {
470b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
480b57cec5SDimitry Andric   if (!SC->isValid())
490b57cec5SDimitry Andric     return 0; // IMPLICIT_DEF / KILL -- will not make impact in output.
500b57cec5SDimitry Andric 
510b57cec5SDimitry Andric   assert((SC->NumMicroOps != 2 || (SC->BeginGroup && !SC->EndGroup)) &&
520b57cec5SDimitry Andric          "Only cracked instruction can have 2 uops.");
530b57cec5SDimitry Andric   assert((SC->NumMicroOps < 3 || (SC->BeginGroup && SC->EndGroup)) &&
540b57cec5SDimitry Andric          "Expanded instructions always group alone.");
550b57cec5SDimitry Andric   assert((SC->NumMicroOps < 3 || (SC->NumMicroOps % 3 == 0)) &&
560b57cec5SDimitry Andric          "Expanded instructions fill the group(s).");
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric   return SC->NumMicroOps;
590b57cec5SDimitry Andric }
600b57cec5SDimitry Andric 
getCurrCycleIdx(SUnit * SU) const610b57cec5SDimitry Andric unsigned SystemZHazardRecognizer::getCurrCycleIdx(SUnit *SU) const {
620b57cec5SDimitry Andric   unsigned Idx = CurrGroupSize;
630b57cec5SDimitry Andric   if (GrpCount % 2)
640b57cec5SDimitry Andric     Idx += 3;
650b57cec5SDimitry Andric 
660b57cec5SDimitry Andric   if (SU != nullptr && !fitsIntoCurrentGroup(SU)) {
670b57cec5SDimitry Andric     if (Idx == 1 || Idx == 2)
680b57cec5SDimitry Andric       Idx = 3;
690b57cec5SDimitry Andric     else if (Idx == 4 || Idx == 5)
700b57cec5SDimitry Andric       Idx = 0;
710b57cec5SDimitry Andric   }
720b57cec5SDimitry Andric 
730b57cec5SDimitry Andric   return Idx;
740b57cec5SDimitry Andric }
750b57cec5SDimitry Andric 
760b57cec5SDimitry Andric ScheduleHazardRecognizer::HazardType SystemZHazardRecognizer::
getHazardType(SUnit * SU,int Stalls)77e8d8bef9SDimitry Andric getHazardType(SUnit *SU, int Stalls) {
78e8d8bef9SDimitry Andric   return (fitsIntoCurrentGroup(SU) ? NoHazard : Hazard);
790b57cec5SDimitry Andric }
800b57cec5SDimitry Andric 
Reset()810b57cec5SDimitry Andric void SystemZHazardRecognizer::Reset() {
820b57cec5SDimitry Andric   CurrGroupSize = 0;
830b57cec5SDimitry Andric   CurrGroupHas4RegOps = false;
840b57cec5SDimitry Andric   clearProcResCounters();
850b57cec5SDimitry Andric   GrpCount = 0;
860b57cec5SDimitry Andric   LastFPdOpCycleIdx = UINT_MAX;
870b57cec5SDimitry Andric   LastEmittedMI = nullptr;
880b57cec5SDimitry Andric   LLVM_DEBUG(CurGroupDbg = "";);
890b57cec5SDimitry Andric }
900b57cec5SDimitry Andric 
910b57cec5SDimitry Andric bool
fitsIntoCurrentGroup(SUnit * SU) const920b57cec5SDimitry Andric SystemZHazardRecognizer::fitsIntoCurrentGroup(SUnit *SU) const {
930b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
940b57cec5SDimitry Andric   if (!SC->isValid())
950b57cec5SDimitry Andric     return true;
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric   // A cracked instruction only fits into schedule if the current
980b57cec5SDimitry Andric   // group is empty.
990b57cec5SDimitry Andric   if (SC->BeginGroup)
1000b57cec5SDimitry Andric     return (CurrGroupSize == 0);
1010b57cec5SDimitry Andric 
1020b57cec5SDimitry Andric   // An instruction with 4 register operands will not fit in last slot.
1030b57cec5SDimitry Andric   assert ((CurrGroupSize < 2 || !CurrGroupHas4RegOps) &&
1040b57cec5SDimitry Andric           "Current decoder group is already full!");
1050b57cec5SDimitry Andric   if (CurrGroupSize == 2 && has4RegOps(SU->getInstr()))
1060b57cec5SDimitry Andric     return false;
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric   // Since a full group is handled immediately in EmitInstruction(),
1090b57cec5SDimitry Andric   // SU should fit into current group. NumSlots should be 1 or 0,
1100b57cec5SDimitry Andric   // since it is not a cracked or expanded instruction.
1110b57cec5SDimitry Andric   assert ((getNumDecoderSlots(SU) <= 1) && (CurrGroupSize < 3) &&
1120b57cec5SDimitry Andric           "Expected normal instruction to fit in non-full group!");
1130b57cec5SDimitry Andric 
1140b57cec5SDimitry Andric   return true;
1150b57cec5SDimitry Andric }
1160b57cec5SDimitry Andric 
has4RegOps(const MachineInstr * MI) const1170b57cec5SDimitry Andric bool SystemZHazardRecognizer::has4RegOps(const MachineInstr *MI) const {
1180b57cec5SDimitry Andric   const MachineFunction &MF = *MI->getParent()->getParent();
1190b57cec5SDimitry Andric   const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
1200b57cec5SDimitry Andric   const MCInstrDesc &MID = MI->getDesc();
1210b57cec5SDimitry Andric   unsigned Count = 0;
1220b57cec5SDimitry Andric   for (unsigned OpIdx = 0; OpIdx < MID.getNumOperands(); OpIdx++) {
1230b57cec5SDimitry Andric     const TargetRegisterClass *RC = TII->getRegClass(MID, OpIdx, TRI, MF);
1240b57cec5SDimitry Andric     if (RC == nullptr)
1250b57cec5SDimitry Andric       continue;
1260b57cec5SDimitry Andric     if (OpIdx >= MID.getNumDefs() &&
1270b57cec5SDimitry Andric         MID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
1280b57cec5SDimitry Andric       continue;
1290b57cec5SDimitry Andric     Count++;
1300b57cec5SDimitry Andric   }
1310b57cec5SDimitry Andric   return Count >= 4;
1320b57cec5SDimitry Andric }
1330b57cec5SDimitry Andric 
nextGroup()1340b57cec5SDimitry Andric void SystemZHazardRecognizer::nextGroup() {
1350b57cec5SDimitry Andric   if (CurrGroupSize == 0)
1360b57cec5SDimitry Andric     return;
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   LLVM_DEBUG(dumpCurrGroup("Completed decode group"));
1390b57cec5SDimitry Andric   LLVM_DEBUG(CurGroupDbg = "";);
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric   int NumGroups = ((CurrGroupSize > 3) ? (CurrGroupSize / 3) : 1);
1420b57cec5SDimitry Andric   assert((CurrGroupSize <= 3 || CurrGroupSize % 3 == 0) &&
1430b57cec5SDimitry Andric          "Current decoder group bad.");
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric   // Reset counter for next group.
1460b57cec5SDimitry Andric   CurrGroupSize = 0;
1470b57cec5SDimitry Andric   CurrGroupHas4RegOps = false;
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric   GrpCount += ((unsigned) NumGroups);
1500b57cec5SDimitry Andric 
1510b57cec5SDimitry Andric   // Decrease counters for execution units.
1520b57cec5SDimitry Andric   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
1530b57cec5SDimitry Andric     ProcResourceCounters[i] = ((ProcResourceCounters[i] > NumGroups)
1540b57cec5SDimitry Andric                                    ? (ProcResourceCounters[i] - NumGroups)
1550b57cec5SDimitry Andric                                    : 0);
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric   // Clear CriticalResourceIdx if it is now below the threshold.
1580b57cec5SDimitry Andric   if (CriticalResourceIdx != UINT_MAX &&
1590b57cec5SDimitry Andric       (ProcResourceCounters[CriticalResourceIdx] <=
1600b57cec5SDimitry Andric        ProcResCostLim))
1610b57cec5SDimitry Andric     CriticalResourceIdx = UINT_MAX;
1620b57cec5SDimitry Andric 
1630b57cec5SDimitry Andric   LLVM_DEBUG(dumpState(););
1640b57cec5SDimitry Andric }
1650b57cec5SDimitry Andric 
1660b57cec5SDimitry Andric #ifndef NDEBUG // Debug output
dumpSU(SUnit * SU,raw_ostream & OS) const1670b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpSU(SUnit *SU, raw_ostream &OS) const {
1680b57cec5SDimitry Andric   OS << "SU(" << SU->NodeNum << "):";
1690b57cec5SDimitry Andric   OS << TII->getName(SU->getInstr()->getOpcode());
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
1720b57cec5SDimitry Andric   if (!SC->isValid())
1730b57cec5SDimitry Andric     return;
1740b57cec5SDimitry Andric 
1750b57cec5SDimitry Andric   for (TargetSchedModel::ProcResIter
1760b57cec5SDimitry Andric          PI = SchedModel->getWriteProcResBegin(SC),
1770b57cec5SDimitry Andric          PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
1780b57cec5SDimitry Andric     const MCProcResourceDesc &PRD =
1790b57cec5SDimitry Andric       *SchedModel->getProcResource(PI->ProcResourceIdx);
1800b57cec5SDimitry Andric     std::string FU(PRD.Name);
1810b57cec5SDimitry Andric     // trim e.g. Z13_FXaUnit -> FXa
182e8d8bef9SDimitry Andric     FU = FU.substr(FU.find('_') + 1);
1830b57cec5SDimitry Andric     size_t Pos = FU.find("Unit");
1840b57cec5SDimitry Andric     if (Pos != std::string::npos)
1850b57cec5SDimitry Andric       FU.resize(Pos);
1860b57cec5SDimitry Andric     if (FU == "LS") // LSUnit -> LSU
1870b57cec5SDimitry Andric       FU = "LSU";
1880b57cec5SDimitry Andric     OS << "/" << FU;
1890b57cec5SDimitry Andric 
190*5f757f3fSDimitry Andric     if (PI->ReleaseAtCycle> 1)
191*5f757f3fSDimitry Andric       OS << "(" << PI->ReleaseAtCycle << "cyc)";
1920b57cec5SDimitry Andric   }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric   if (SC->NumMicroOps > 1)
1950b57cec5SDimitry Andric     OS << "/" << SC->NumMicroOps << "uops";
1960b57cec5SDimitry Andric   if (SC->BeginGroup && SC->EndGroup)
1970b57cec5SDimitry Andric     OS << "/GroupsAlone";
1980b57cec5SDimitry Andric   else if (SC->BeginGroup)
1990b57cec5SDimitry Andric     OS << "/BeginsGroup";
2000b57cec5SDimitry Andric   else if (SC->EndGroup)
2010b57cec5SDimitry Andric     OS << "/EndsGroup";
2020b57cec5SDimitry Andric   if (SU->isUnbuffered)
2030b57cec5SDimitry Andric     OS << "/Unbuffered";
2040b57cec5SDimitry Andric   if (has4RegOps(SU->getInstr()))
2050b57cec5SDimitry Andric     OS << "/4RegOps";
2060b57cec5SDimitry Andric }
2070b57cec5SDimitry Andric 
dumpCurrGroup(std::string Msg) const2080b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpCurrGroup(std::string Msg) const {
2090b57cec5SDimitry Andric   dbgs() << "++ " << Msg;
2100b57cec5SDimitry Andric   dbgs() << ": ";
2110b57cec5SDimitry Andric 
2120b57cec5SDimitry Andric   if (CurGroupDbg.empty())
2130b57cec5SDimitry Andric     dbgs() << " <empty>\n";
2140b57cec5SDimitry Andric   else {
2150b57cec5SDimitry Andric     dbgs() << "{ " << CurGroupDbg << " }";
2160b57cec5SDimitry Andric     dbgs() << " (" << CurrGroupSize << " decoder slot"
2170b57cec5SDimitry Andric            << (CurrGroupSize > 1 ? "s":"")
2180b57cec5SDimitry Andric            << (CurrGroupHas4RegOps ? ", 4RegOps" : "")
2190b57cec5SDimitry Andric            << ")\n";
2200b57cec5SDimitry Andric   }
2210b57cec5SDimitry Andric }
2220b57cec5SDimitry Andric 
dumpProcResourceCounters() const2230b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpProcResourceCounters() const {
2240b57cec5SDimitry Andric   bool any = false;
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
2270b57cec5SDimitry Andric     if (ProcResourceCounters[i] > 0) {
2280b57cec5SDimitry Andric       any = true;
2290b57cec5SDimitry Andric       break;
2300b57cec5SDimitry Andric     }
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   if (!any)
2330b57cec5SDimitry Andric     return;
2340b57cec5SDimitry Andric 
2350b57cec5SDimitry Andric   dbgs() << "++ | Resource counters: ";
2360b57cec5SDimitry Andric   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
2370b57cec5SDimitry Andric     if (ProcResourceCounters[i] > 0)
2380b57cec5SDimitry Andric       dbgs() << SchedModel->getProcResource(i)->Name
2390b57cec5SDimitry Andric              << ":" << ProcResourceCounters[i] << " ";
2400b57cec5SDimitry Andric   dbgs() << "\n";
2410b57cec5SDimitry Andric 
2420b57cec5SDimitry Andric   if (CriticalResourceIdx != UINT_MAX)
2430b57cec5SDimitry Andric     dbgs() << "++ | Critical resource: "
2440b57cec5SDimitry Andric            << SchedModel->getProcResource(CriticalResourceIdx)->Name
2450b57cec5SDimitry Andric            << "\n";
2460b57cec5SDimitry Andric }
2470b57cec5SDimitry Andric 
dumpState() const2480b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpState() const {
2490b57cec5SDimitry Andric   dumpCurrGroup("| Current decoder group");
2500b57cec5SDimitry Andric   dbgs() << "++ | Current cycle index: "
2510b57cec5SDimitry Andric          << getCurrCycleIdx() << "\n";
2520b57cec5SDimitry Andric   dumpProcResourceCounters();
2530b57cec5SDimitry Andric   if (LastFPdOpCycleIdx != UINT_MAX)
2540b57cec5SDimitry Andric     dbgs() << "++ | Last FPd cycle index: " << LastFPdOpCycleIdx << "\n";
2550b57cec5SDimitry Andric }
2560b57cec5SDimitry Andric 
2570b57cec5SDimitry Andric #endif //NDEBUG
2580b57cec5SDimitry Andric 
clearProcResCounters()2590b57cec5SDimitry Andric void SystemZHazardRecognizer::clearProcResCounters() {
2600b57cec5SDimitry Andric   ProcResourceCounters.assign(SchedModel->getNumProcResourceKinds(), 0);
2610b57cec5SDimitry Andric   CriticalResourceIdx = UINT_MAX;
2620b57cec5SDimitry Andric }
2630b57cec5SDimitry Andric 
isBranchRetTrap(MachineInstr * MI)2640b57cec5SDimitry Andric static inline bool isBranchRetTrap(MachineInstr *MI) {
2650b57cec5SDimitry Andric   return (MI->isBranch() || MI->isReturn() ||
2660b57cec5SDimitry Andric           MI->getOpcode() == SystemZ::CondTrap);
2670b57cec5SDimitry Andric }
2680b57cec5SDimitry Andric 
2690b57cec5SDimitry Andric // Update state with SU as the next scheduled unit.
2700b57cec5SDimitry Andric void SystemZHazardRecognizer::
EmitInstruction(SUnit * SU)2710b57cec5SDimitry Andric EmitInstruction(SUnit *SU) {
2720b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
2730b57cec5SDimitry Andric   LLVM_DEBUG(dbgs() << "++ HazardRecognizer emitting "; dumpSU(SU, dbgs());
2740b57cec5SDimitry Andric              dbgs() << "\n";);
2750b57cec5SDimitry Andric   LLVM_DEBUG(dumpCurrGroup("Decode group before emission"););
2760b57cec5SDimitry Andric 
2770b57cec5SDimitry Andric   // If scheduling an SU that must begin a new decoder group, move on
2780b57cec5SDimitry Andric   // to next group.
2790b57cec5SDimitry Andric   if (!fitsIntoCurrentGroup(SU))
2800b57cec5SDimitry Andric     nextGroup();
2810b57cec5SDimitry Andric 
2820b57cec5SDimitry Andric   LLVM_DEBUG(raw_string_ostream cgd(CurGroupDbg);
2830b57cec5SDimitry Andric              if (CurGroupDbg.length()) cgd << ", "; dumpSU(SU, cgd););
2840b57cec5SDimitry Andric 
2850b57cec5SDimitry Andric   LastEmittedMI = SU->getInstr();
2860b57cec5SDimitry Andric 
2870b57cec5SDimitry Andric   // After returning from a call, we don't know much about the state.
2880b57cec5SDimitry Andric   if (SU->isCall) {
2890b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "++ Clearing state after call.\n";);
2900b57cec5SDimitry Andric     Reset();
2910b57cec5SDimitry Andric     LastEmittedMI = SU->getInstr();
2920b57cec5SDimitry Andric     return;
2930b57cec5SDimitry Andric   }
2940b57cec5SDimitry Andric 
2950b57cec5SDimitry Andric   // Increase counter for execution unit(s).
2960b57cec5SDimitry Andric   for (TargetSchedModel::ProcResIter
2970b57cec5SDimitry Andric          PI = SchedModel->getWriteProcResBegin(SC),
2980b57cec5SDimitry Andric          PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
2990b57cec5SDimitry Andric     // Don't handle FPd together with the other resources.
3000b57cec5SDimitry Andric     if (SchedModel->getProcResource(PI->ProcResourceIdx)->BufferSize == 1)
3010b57cec5SDimitry Andric       continue;
3020b57cec5SDimitry Andric     int &CurrCounter =
3030b57cec5SDimitry Andric       ProcResourceCounters[PI->ProcResourceIdx];
304*5f757f3fSDimitry Andric     CurrCounter += PI->ReleaseAtCycle;
3050b57cec5SDimitry Andric     // Check if this is now the new critical resource.
3060b57cec5SDimitry Andric     if ((CurrCounter > ProcResCostLim) &&
3070b57cec5SDimitry Andric         (CriticalResourceIdx == UINT_MAX ||
3080b57cec5SDimitry Andric          (PI->ProcResourceIdx != CriticalResourceIdx &&
3090b57cec5SDimitry Andric           CurrCounter >
3100b57cec5SDimitry Andric           ProcResourceCounters[CriticalResourceIdx]))) {
3110b57cec5SDimitry Andric       LLVM_DEBUG(
3120b57cec5SDimitry Andric           dbgs() << "++ New critical resource: "
3130b57cec5SDimitry Andric                  << SchedModel->getProcResource(PI->ProcResourceIdx)->Name
3140b57cec5SDimitry Andric                  << "\n";);
3150b57cec5SDimitry Andric       CriticalResourceIdx = PI->ProcResourceIdx;
3160b57cec5SDimitry Andric     }
3170b57cec5SDimitry Andric   }
3180b57cec5SDimitry Andric 
3190b57cec5SDimitry Andric   // Make note of an instruction that uses a blocking resource (FPd).
3200b57cec5SDimitry Andric   if (SU->isUnbuffered) {
3210b57cec5SDimitry Andric     LastFPdOpCycleIdx = getCurrCycleIdx(SU);
3220b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "++ Last FPd cycle index: " << LastFPdOpCycleIdx
3230b57cec5SDimitry Andric                       << "\n";);
3240b57cec5SDimitry Andric   }
3250b57cec5SDimitry Andric 
3260b57cec5SDimitry Andric   // Insert SU into current group by increasing number of slots used
3270b57cec5SDimitry Andric   // in current group.
3280b57cec5SDimitry Andric   CurrGroupSize += getNumDecoderSlots(SU);
3290b57cec5SDimitry Andric   CurrGroupHas4RegOps |= has4RegOps(SU->getInstr());
3300b57cec5SDimitry Andric   unsigned GroupLim = (CurrGroupHas4RegOps ? 2 : 3);
3310b57cec5SDimitry Andric   assert((CurrGroupSize <= GroupLim || CurrGroupSize == getNumDecoderSlots(SU))
3320b57cec5SDimitry Andric          && "SU does not fit into decoder group!");
3330b57cec5SDimitry Andric 
3340b57cec5SDimitry Andric   // Check if current group is now full/ended. If so, move on to next
3350b57cec5SDimitry Andric   // group to be ready to evaluate more candidates.
3360b57cec5SDimitry Andric   if (CurrGroupSize >= GroupLim || SC->EndGroup)
3370b57cec5SDimitry Andric     nextGroup();
3380b57cec5SDimitry Andric }
3390b57cec5SDimitry Andric 
groupingCost(SUnit * SU) const3400b57cec5SDimitry Andric int SystemZHazardRecognizer::groupingCost(SUnit *SU) const {
3410b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
3420b57cec5SDimitry Andric   if (!SC->isValid())
3430b57cec5SDimitry Andric     return 0;
3440b57cec5SDimitry Andric 
3450b57cec5SDimitry Andric   // If SU begins new group, it can either break a current group early
3460b57cec5SDimitry Andric   // or fit naturally if current group is empty (negative cost).
3470b57cec5SDimitry Andric   if (SC->BeginGroup) {
3480b57cec5SDimitry Andric     if (CurrGroupSize)
3490b57cec5SDimitry Andric       return 3 - CurrGroupSize;
3500b57cec5SDimitry Andric     return -1;
3510b57cec5SDimitry Andric   }
3520b57cec5SDimitry Andric 
3530b57cec5SDimitry Andric   // Similarly, a group-ending SU may either fit well (last in group), or
3540b57cec5SDimitry Andric   // end the group prematurely.
3550b57cec5SDimitry Andric   if (SC->EndGroup) {
3560b57cec5SDimitry Andric     unsigned resultingGroupSize =
3570b57cec5SDimitry Andric       (CurrGroupSize + getNumDecoderSlots(SU));
3580b57cec5SDimitry Andric     if (resultingGroupSize < 3)
3590b57cec5SDimitry Andric       return (3 - resultingGroupSize);
3600b57cec5SDimitry Andric     return -1;
3610b57cec5SDimitry Andric   }
3620b57cec5SDimitry Andric 
3630b57cec5SDimitry Andric   // An instruction with 4 register operands will not fit in last slot.
3640b57cec5SDimitry Andric   if (CurrGroupSize == 2 && has4RegOps(SU->getInstr()))
3650b57cec5SDimitry Andric     return 1;
3660b57cec5SDimitry Andric 
3670b57cec5SDimitry Andric   // Most instructions can be placed in any decoder slot.
3680b57cec5SDimitry Andric   return 0;
3690b57cec5SDimitry Andric }
3700b57cec5SDimitry Andric 
isFPdOpPreferred_distance(SUnit * SU) const3710b57cec5SDimitry Andric bool SystemZHazardRecognizer::isFPdOpPreferred_distance(SUnit *SU) const {
3720b57cec5SDimitry Andric   assert (SU->isUnbuffered);
3730b57cec5SDimitry Andric   // If this is the first FPd op, it should be scheduled high.
3740b57cec5SDimitry Andric   if (LastFPdOpCycleIdx == UINT_MAX)
3750b57cec5SDimitry Andric     return true;
3760b57cec5SDimitry Andric   // If this is not the first PFd op, it should go into the other side
3770b57cec5SDimitry Andric   // of the processor to use the other FPd unit there. This should
3780b57cec5SDimitry Andric   // generally happen if two FPd ops are placed with 2 other
3790b57cec5SDimitry Andric   // instructions between them (modulo 6).
3800b57cec5SDimitry Andric   unsigned SUCycleIdx = getCurrCycleIdx(SU);
3810b57cec5SDimitry Andric   if (LastFPdOpCycleIdx > SUCycleIdx)
3820b57cec5SDimitry Andric     return ((LastFPdOpCycleIdx - SUCycleIdx) == 3);
3830b57cec5SDimitry Andric   return ((SUCycleIdx - LastFPdOpCycleIdx) == 3);
3840b57cec5SDimitry Andric }
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric int SystemZHazardRecognizer::
resourcesCost(SUnit * SU)3870b57cec5SDimitry Andric resourcesCost(SUnit *SU) {
3880b57cec5SDimitry Andric   int Cost = 0;
3890b57cec5SDimitry Andric 
3900b57cec5SDimitry Andric   const MCSchedClassDesc *SC = getSchedClass(SU);
3910b57cec5SDimitry Andric   if (!SC->isValid())
3920b57cec5SDimitry Andric     return 0;
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric   // For a FPd op, either return min or max value as indicated by the
3950b57cec5SDimitry Andric   // distance to any prior FPd op.
3960b57cec5SDimitry Andric   if (SU->isUnbuffered)
3970b57cec5SDimitry Andric     Cost = (isFPdOpPreferred_distance(SU) ? INT_MIN : INT_MAX);
3980b57cec5SDimitry Andric   // For other instructions, give a cost to the use of the critical resource.
3990b57cec5SDimitry Andric   else if (CriticalResourceIdx != UINT_MAX) {
4000b57cec5SDimitry Andric     for (TargetSchedModel::ProcResIter
4010b57cec5SDimitry Andric            PI = SchedModel->getWriteProcResBegin(SC),
4020b57cec5SDimitry Andric            PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI)
4030b57cec5SDimitry Andric       if (PI->ProcResourceIdx == CriticalResourceIdx)
404*5f757f3fSDimitry Andric         Cost = PI->ReleaseAtCycle;
4050b57cec5SDimitry Andric   }
4060b57cec5SDimitry Andric 
4070b57cec5SDimitry Andric   return Cost;
4080b57cec5SDimitry Andric }
4090b57cec5SDimitry Andric 
emitInstruction(MachineInstr * MI,bool TakenBranch)4100b57cec5SDimitry Andric void SystemZHazardRecognizer::emitInstruction(MachineInstr *MI,
4110b57cec5SDimitry Andric                                               bool TakenBranch) {
4120b57cec5SDimitry Andric   // Make a temporary SUnit.
4130b57cec5SDimitry Andric   SUnit SU(MI, 0);
4140b57cec5SDimitry Andric 
4150b57cec5SDimitry Andric   // Set interesting flags.
4160b57cec5SDimitry Andric   SU.isCall = MI->isCall();
4170b57cec5SDimitry Andric 
4180b57cec5SDimitry Andric   const MCSchedClassDesc *SC = SchedModel->resolveSchedClass(MI);
4190b57cec5SDimitry Andric   for (const MCWriteProcResEntry &PRE :
4200b57cec5SDimitry Andric          make_range(SchedModel->getWriteProcResBegin(SC),
4210b57cec5SDimitry Andric                     SchedModel->getWriteProcResEnd(SC))) {
4220b57cec5SDimitry Andric     switch (SchedModel->getProcResource(PRE.ProcResourceIdx)->BufferSize) {
4230b57cec5SDimitry Andric     case 0:
4240b57cec5SDimitry Andric       SU.hasReservedResource = true;
4250b57cec5SDimitry Andric       break;
4260b57cec5SDimitry Andric     case 1:
4270b57cec5SDimitry Andric       SU.isUnbuffered = true;
4280b57cec5SDimitry Andric       break;
4290b57cec5SDimitry Andric     default:
4300b57cec5SDimitry Andric       break;
4310b57cec5SDimitry Andric     }
4320b57cec5SDimitry Andric   }
4330b57cec5SDimitry Andric 
4340b57cec5SDimitry Andric   unsigned GroupSizeBeforeEmit = CurrGroupSize;
4350b57cec5SDimitry Andric   EmitInstruction(&SU);
4360b57cec5SDimitry Andric 
4370b57cec5SDimitry Andric   if (!TakenBranch && isBranchRetTrap(MI)) {
4380b57cec5SDimitry Andric     // NT Branch on second slot ends group.
4390b57cec5SDimitry Andric     if (GroupSizeBeforeEmit == 1)
4400b57cec5SDimitry Andric       nextGroup();
4410b57cec5SDimitry Andric   }
4420b57cec5SDimitry Andric 
4430b57cec5SDimitry Andric   if (TakenBranch && CurrGroupSize > 0)
4440b57cec5SDimitry Andric     nextGroup();
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric   assert ((!MI->isTerminator() || isBranchRetTrap(MI)) &&
4470b57cec5SDimitry Andric           "Scheduler: unhandled terminator!");
4480b57cec5SDimitry Andric }
4490b57cec5SDimitry Andric 
4500b57cec5SDimitry Andric void SystemZHazardRecognizer::
copyState(SystemZHazardRecognizer * Incoming)4510b57cec5SDimitry Andric copyState(SystemZHazardRecognizer *Incoming) {
4520b57cec5SDimitry Andric   // Current decoder group
4530b57cec5SDimitry Andric   CurrGroupSize = Incoming->CurrGroupSize;
4540b57cec5SDimitry Andric   LLVM_DEBUG(CurGroupDbg = Incoming->CurGroupDbg;);
4550b57cec5SDimitry Andric 
4560b57cec5SDimitry Andric   // Processor resources
4570b57cec5SDimitry Andric   ProcResourceCounters = Incoming->ProcResourceCounters;
4580b57cec5SDimitry Andric   CriticalResourceIdx = Incoming->CriticalResourceIdx;
4590b57cec5SDimitry Andric 
4600b57cec5SDimitry Andric   // FPd
4610b57cec5SDimitry Andric   LastFPdOpCycleIdx = Incoming->LastFPdOpCycleIdx;
4620b57cec5SDimitry Andric   GrpCount = Incoming->GrpCount;
4630b57cec5SDimitry Andric }
464