xref: /openbsd-src/gnu/llvm/llvm/lib/Target/SystemZ/SystemZHazardRecognizer.cpp (revision 73471bf04ceb096474c7f0fa83b1b65c70a787a1)
109467b48Spatrick //=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file defines a hazard recognizer for the SystemZ scheduler.
1009467b48Spatrick //
1109467b48Spatrick // This class is used by the SystemZ scheduling strategy to maintain
1209467b48Spatrick // the state during scheduling, and provide cost functions for
1309467b48Spatrick // scheduling candidates. This includes:
1409467b48Spatrick //
1509467b48Spatrick // * Decoder grouping. A decoder group can maximally hold 3 uops, and
1609467b48Spatrick // instructions that always begin a new group should be scheduled when
1709467b48Spatrick // the current decoder group is empty.
1809467b48Spatrick // * Processor resources usage. It is beneficial to balance the use of
1909467b48Spatrick // resources.
2009467b48Spatrick //
2109467b48Spatrick // A goal is to consider all instructions, also those outside of any
2209467b48Spatrick // scheduling region. Such instructions are "advanced" past and include
2309467b48Spatrick // single instructions before a scheduling region, branches etc.
2409467b48Spatrick //
2509467b48Spatrick // A block that has only one predecessor continues scheduling with the state
2609467b48Spatrick // of it (which may be updated by emitting branches).
2709467b48Spatrick //
2809467b48Spatrick // ===---------------------------------------------------------------------===//
2909467b48Spatrick 
3009467b48Spatrick #include "SystemZHazardRecognizer.h"
3109467b48Spatrick #include "llvm/ADT/Statistic.h"
3209467b48Spatrick 
3309467b48Spatrick using namespace llvm;
3409467b48Spatrick 
3509467b48Spatrick #define DEBUG_TYPE "machine-scheduler"
3609467b48Spatrick 
3709467b48Spatrick // This is the limit of processor resource usage at which the
3809467b48Spatrick // scheduler should try to look for other instructions (not using the
3909467b48Spatrick // critical resource).
4009467b48Spatrick static cl::opt<int> ProcResCostLim("procres-cost-lim", cl::Hidden,
4109467b48Spatrick                                    cl::desc("The OOO window for processor "
4209467b48Spatrick                                             "resources during scheduling."),
4309467b48Spatrick                                    cl::init(8));
4409467b48Spatrick 
4509467b48Spatrick unsigned SystemZHazardRecognizer::
getNumDecoderSlots(SUnit * SU) const4609467b48Spatrick getNumDecoderSlots(SUnit *SU) const {
4709467b48Spatrick   const MCSchedClassDesc *SC = getSchedClass(SU);
4809467b48Spatrick   if (!SC->isValid())
4909467b48Spatrick     return 0; // IMPLICIT_DEF / KILL -- will not make impact in output.
5009467b48Spatrick 
5109467b48Spatrick   assert((SC->NumMicroOps != 2 || (SC->BeginGroup && !SC->EndGroup)) &&
5209467b48Spatrick          "Only cracked instruction can have 2 uops.");
5309467b48Spatrick   assert((SC->NumMicroOps < 3 || (SC->BeginGroup && SC->EndGroup)) &&
5409467b48Spatrick          "Expanded instructions always group alone.");
5509467b48Spatrick   assert((SC->NumMicroOps < 3 || (SC->NumMicroOps % 3 == 0)) &&
5609467b48Spatrick          "Expanded instructions fill the group(s).");
5709467b48Spatrick 
5809467b48Spatrick   return SC->NumMicroOps;
5909467b48Spatrick }
6009467b48Spatrick 
getCurrCycleIdx(SUnit * SU) const6109467b48Spatrick unsigned SystemZHazardRecognizer::getCurrCycleIdx(SUnit *SU) const {
6209467b48Spatrick   unsigned Idx = CurrGroupSize;
6309467b48Spatrick   if (GrpCount % 2)
6409467b48Spatrick     Idx += 3;
6509467b48Spatrick 
6609467b48Spatrick   if (SU != nullptr && !fitsIntoCurrentGroup(SU)) {
6709467b48Spatrick     if (Idx == 1 || Idx == 2)
6809467b48Spatrick       Idx = 3;
6909467b48Spatrick     else if (Idx == 4 || Idx == 5)
7009467b48Spatrick       Idx = 0;
7109467b48Spatrick   }
7209467b48Spatrick 
7309467b48Spatrick   return Idx;
7409467b48Spatrick }
7509467b48Spatrick 
7609467b48Spatrick ScheduleHazardRecognizer::HazardType SystemZHazardRecognizer::
getHazardType(SUnit * SU,int Stalls)77*73471bf0Spatrick getHazardType(SUnit *SU, int Stalls) {
78*73471bf0Spatrick   return (fitsIntoCurrentGroup(SU) ? NoHazard : Hazard);
7909467b48Spatrick }
8009467b48Spatrick 
Reset()8109467b48Spatrick void SystemZHazardRecognizer::Reset() {
8209467b48Spatrick   CurrGroupSize = 0;
8309467b48Spatrick   CurrGroupHas4RegOps = false;
8409467b48Spatrick   clearProcResCounters();
8509467b48Spatrick   GrpCount = 0;
8609467b48Spatrick   LastFPdOpCycleIdx = UINT_MAX;
8709467b48Spatrick   LastEmittedMI = nullptr;
8809467b48Spatrick   LLVM_DEBUG(CurGroupDbg = "";);
8909467b48Spatrick }
9009467b48Spatrick 
9109467b48Spatrick bool
fitsIntoCurrentGroup(SUnit * SU) const9209467b48Spatrick SystemZHazardRecognizer::fitsIntoCurrentGroup(SUnit *SU) const {
9309467b48Spatrick   const MCSchedClassDesc *SC = getSchedClass(SU);
9409467b48Spatrick   if (!SC->isValid())
9509467b48Spatrick     return true;
9609467b48Spatrick 
9709467b48Spatrick   // A cracked instruction only fits into schedule if the current
9809467b48Spatrick   // group is empty.
9909467b48Spatrick   if (SC->BeginGroup)
10009467b48Spatrick     return (CurrGroupSize == 0);
10109467b48Spatrick 
10209467b48Spatrick   // An instruction with 4 register operands will not fit in last slot.
10309467b48Spatrick   assert ((CurrGroupSize < 2 || !CurrGroupHas4RegOps) &&
10409467b48Spatrick           "Current decoder group is already full!");
10509467b48Spatrick   if (CurrGroupSize == 2 && has4RegOps(SU->getInstr()))
10609467b48Spatrick     return false;
10709467b48Spatrick 
10809467b48Spatrick   // Since a full group is handled immediately in EmitInstruction(),
10909467b48Spatrick   // SU should fit into current group. NumSlots should be 1 or 0,
11009467b48Spatrick   // since it is not a cracked or expanded instruction.
11109467b48Spatrick   assert ((getNumDecoderSlots(SU) <= 1) && (CurrGroupSize < 3) &&
11209467b48Spatrick           "Expected normal instruction to fit in non-full group!");
11309467b48Spatrick 
11409467b48Spatrick   return true;
11509467b48Spatrick }
11609467b48Spatrick 
has4RegOps(const MachineInstr * MI) const11709467b48Spatrick bool SystemZHazardRecognizer::has4RegOps(const MachineInstr *MI) const {
11809467b48Spatrick   const MachineFunction &MF = *MI->getParent()->getParent();
11909467b48Spatrick   const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
12009467b48Spatrick   const MCInstrDesc &MID = MI->getDesc();
12109467b48Spatrick   unsigned Count = 0;
12209467b48Spatrick   for (unsigned OpIdx = 0; OpIdx < MID.getNumOperands(); OpIdx++) {
12309467b48Spatrick     const TargetRegisterClass *RC = TII->getRegClass(MID, OpIdx, TRI, MF);
12409467b48Spatrick     if (RC == nullptr)
12509467b48Spatrick       continue;
12609467b48Spatrick     if (OpIdx >= MID.getNumDefs() &&
12709467b48Spatrick         MID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
12809467b48Spatrick       continue;
12909467b48Spatrick     Count++;
13009467b48Spatrick   }
13109467b48Spatrick   return Count >= 4;
13209467b48Spatrick }
13309467b48Spatrick 
nextGroup()13409467b48Spatrick void SystemZHazardRecognizer::nextGroup() {
13509467b48Spatrick   if (CurrGroupSize == 0)
13609467b48Spatrick     return;
13709467b48Spatrick 
13809467b48Spatrick   LLVM_DEBUG(dumpCurrGroup("Completed decode group"));
13909467b48Spatrick   LLVM_DEBUG(CurGroupDbg = "";);
14009467b48Spatrick 
14109467b48Spatrick   int NumGroups = ((CurrGroupSize > 3) ? (CurrGroupSize / 3) : 1);
14209467b48Spatrick   assert((CurrGroupSize <= 3 || CurrGroupSize % 3 == 0) &&
14309467b48Spatrick          "Current decoder group bad.");
14409467b48Spatrick 
14509467b48Spatrick   // Reset counter for next group.
14609467b48Spatrick   CurrGroupSize = 0;
14709467b48Spatrick   CurrGroupHas4RegOps = false;
14809467b48Spatrick 
14909467b48Spatrick   GrpCount += ((unsigned) NumGroups);
15009467b48Spatrick 
15109467b48Spatrick   // Decrease counters for execution units.
15209467b48Spatrick   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
15309467b48Spatrick     ProcResourceCounters[i] = ((ProcResourceCounters[i] > NumGroups)
15409467b48Spatrick                                    ? (ProcResourceCounters[i] - NumGroups)
15509467b48Spatrick                                    : 0);
15609467b48Spatrick 
15709467b48Spatrick   // Clear CriticalResourceIdx if it is now below the threshold.
15809467b48Spatrick   if (CriticalResourceIdx != UINT_MAX &&
15909467b48Spatrick       (ProcResourceCounters[CriticalResourceIdx] <=
16009467b48Spatrick        ProcResCostLim))
16109467b48Spatrick     CriticalResourceIdx = UINT_MAX;
16209467b48Spatrick 
16309467b48Spatrick   LLVM_DEBUG(dumpState(););
16409467b48Spatrick }
16509467b48Spatrick 
16609467b48Spatrick #ifndef NDEBUG // Debug output
dumpSU(SUnit * SU,raw_ostream & OS) const16709467b48Spatrick void SystemZHazardRecognizer::dumpSU(SUnit *SU, raw_ostream &OS) const {
16809467b48Spatrick   OS << "SU(" << SU->NodeNum << "):";
16909467b48Spatrick   OS << TII->getName(SU->getInstr()->getOpcode());
17009467b48Spatrick 
17109467b48Spatrick   const MCSchedClassDesc *SC = getSchedClass(SU);
17209467b48Spatrick   if (!SC->isValid())
17309467b48Spatrick     return;
17409467b48Spatrick 
17509467b48Spatrick   for (TargetSchedModel::ProcResIter
17609467b48Spatrick          PI = SchedModel->getWriteProcResBegin(SC),
17709467b48Spatrick          PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
17809467b48Spatrick     const MCProcResourceDesc &PRD =
17909467b48Spatrick       *SchedModel->getProcResource(PI->ProcResourceIdx);
18009467b48Spatrick     std::string FU(PRD.Name);
18109467b48Spatrick     // trim e.g. Z13_FXaUnit -> FXa
182*73471bf0Spatrick     FU = FU.substr(FU.find('_') + 1);
18309467b48Spatrick     size_t Pos = FU.find("Unit");
18409467b48Spatrick     if (Pos != std::string::npos)
18509467b48Spatrick       FU.resize(Pos);
18609467b48Spatrick     if (FU == "LS") // LSUnit -> LSU
18709467b48Spatrick       FU = "LSU";
18809467b48Spatrick     OS << "/" << FU;
18909467b48Spatrick 
19009467b48Spatrick     if (PI->Cycles > 1)
19109467b48Spatrick       OS << "(" << PI->Cycles << "cyc)";
19209467b48Spatrick   }
19309467b48Spatrick 
19409467b48Spatrick   if (SC->NumMicroOps > 1)
19509467b48Spatrick     OS << "/" << SC->NumMicroOps << "uops";
19609467b48Spatrick   if (SC->BeginGroup && SC->EndGroup)
19709467b48Spatrick     OS << "/GroupsAlone";
19809467b48Spatrick   else if (SC->BeginGroup)
19909467b48Spatrick     OS << "/BeginsGroup";
20009467b48Spatrick   else if (SC->EndGroup)
20109467b48Spatrick     OS << "/EndsGroup";
20209467b48Spatrick   if (SU->isUnbuffered)
20309467b48Spatrick     OS << "/Unbuffered";
20409467b48Spatrick   if (has4RegOps(SU->getInstr()))
20509467b48Spatrick     OS << "/4RegOps";
20609467b48Spatrick }
20709467b48Spatrick 
dumpCurrGroup(std::string Msg) const20809467b48Spatrick void SystemZHazardRecognizer::dumpCurrGroup(std::string Msg) const {
20909467b48Spatrick   dbgs() << "++ " << Msg;
21009467b48Spatrick   dbgs() << ": ";
21109467b48Spatrick 
21209467b48Spatrick   if (CurGroupDbg.empty())
21309467b48Spatrick     dbgs() << " <empty>\n";
21409467b48Spatrick   else {
21509467b48Spatrick     dbgs() << "{ " << CurGroupDbg << " }";
21609467b48Spatrick     dbgs() << " (" << CurrGroupSize << " decoder slot"
21709467b48Spatrick            << (CurrGroupSize > 1 ? "s":"")
21809467b48Spatrick            << (CurrGroupHas4RegOps ? ", 4RegOps" : "")
21909467b48Spatrick            << ")\n";
22009467b48Spatrick   }
22109467b48Spatrick }
22209467b48Spatrick 
dumpProcResourceCounters() const22309467b48Spatrick void SystemZHazardRecognizer::dumpProcResourceCounters() const {
22409467b48Spatrick   bool any = false;
22509467b48Spatrick 
22609467b48Spatrick   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
22709467b48Spatrick     if (ProcResourceCounters[i] > 0) {
22809467b48Spatrick       any = true;
22909467b48Spatrick       break;
23009467b48Spatrick     }
23109467b48Spatrick 
23209467b48Spatrick   if (!any)
23309467b48Spatrick     return;
23409467b48Spatrick 
23509467b48Spatrick   dbgs() << "++ | Resource counters: ";
23609467b48Spatrick   for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
23709467b48Spatrick     if (ProcResourceCounters[i] > 0)
23809467b48Spatrick       dbgs() << SchedModel->getProcResource(i)->Name
23909467b48Spatrick              << ":" << ProcResourceCounters[i] << " ";
24009467b48Spatrick   dbgs() << "\n";
24109467b48Spatrick 
24209467b48Spatrick   if (CriticalResourceIdx != UINT_MAX)
24309467b48Spatrick     dbgs() << "++ | Critical resource: "
24409467b48Spatrick            << SchedModel->getProcResource(CriticalResourceIdx)->Name
24509467b48Spatrick            << "\n";
24609467b48Spatrick }
24709467b48Spatrick 
dumpState() const24809467b48Spatrick void SystemZHazardRecognizer::dumpState() const {
24909467b48Spatrick   dumpCurrGroup("| Current decoder group");
25009467b48Spatrick   dbgs() << "++ | Current cycle index: "
25109467b48Spatrick          << getCurrCycleIdx() << "\n";
25209467b48Spatrick   dumpProcResourceCounters();
25309467b48Spatrick   if (LastFPdOpCycleIdx != UINT_MAX)
25409467b48Spatrick     dbgs() << "++ | Last FPd cycle index: " << LastFPdOpCycleIdx << "\n";
25509467b48Spatrick }
25609467b48Spatrick 
25709467b48Spatrick #endif //NDEBUG
25809467b48Spatrick 
clearProcResCounters()25909467b48Spatrick void SystemZHazardRecognizer::clearProcResCounters() {
26009467b48Spatrick   ProcResourceCounters.assign(SchedModel->getNumProcResourceKinds(), 0);
26109467b48Spatrick   CriticalResourceIdx = UINT_MAX;
26209467b48Spatrick }
26309467b48Spatrick 
isBranchRetTrap(MachineInstr * MI)26409467b48Spatrick static inline bool isBranchRetTrap(MachineInstr *MI) {
26509467b48Spatrick   return (MI->isBranch() || MI->isReturn() ||
26609467b48Spatrick           MI->getOpcode() == SystemZ::CondTrap);
26709467b48Spatrick }
26809467b48Spatrick 
26909467b48Spatrick // Update state with SU as the next scheduled unit.
27009467b48Spatrick void SystemZHazardRecognizer::
EmitInstruction(SUnit * SU)27109467b48Spatrick EmitInstruction(SUnit *SU) {
27209467b48Spatrick   const MCSchedClassDesc *SC = getSchedClass(SU);
27309467b48Spatrick   LLVM_DEBUG(dbgs() << "++ HazardRecognizer emitting "; dumpSU(SU, dbgs());
27409467b48Spatrick              dbgs() << "\n";);
27509467b48Spatrick   LLVM_DEBUG(dumpCurrGroup("Decode group before emission"););
27609467b48Spatrick 
27709467b48Spatrick   // If scheduling an SU that must begin a new decoder group, move on
27809467b48Spatrick   // to next group.
27909467b48Spatrick   if (!fitsIntoCurrentGroup(SU))
28009467b48Spatrick     nextGroup();
28109467b48Spatrick 
28209467b48Spatrick   LLVM_DEBUG(raw_string_ostream cgd(CurGroupDbg);
28309467b48Spatrick              if (CurGroupDbg.length()) cgd << ", "; dumpSU(SU, cgd););
28409467b48Spatrick 
28509467b48Spatrick   LastEmittedMI = SU->getInstr();
28609467b48Spatrick 
28709467b48Spatrick   // After returning from a call, we don't know much about the state.
28809467b48Spatrick   if (SU->isCall) {
28909467b48Spatrick     LLVM_DEBUG(dbgs() << "++ Clearing state after call.\n";);
29009467b48Spatrick     Reset();
29109467b48Spatrick     LastEmittedMI = SU->getInstr();
29209467b48Spatrick     return;
29309467b48Spatrick   }
29409467b48Spatrick 
29509467b48Spatrick   // Increase counter for execution unit(s).
29609467b48Spatrick   for (TargetSchedModel::ProcResIter
29709467b48Spatrick          PI = SchedModel->getWriteProcResBegin(SC),
29809467b48Spatrick          PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
29909467b48Spatrick     // Don't handle FPd together with the other resources.
30009467b48Spatrick     if (SchedModel->getProcResource(PI->ProcResourceIdx)->BufferSize == 1)
30109467b48Spatrick       continue;
30209467b48Spatrick     int &CurrCounter =
30309467b48Spatrick       ProcResourceCounters[PI->ProcResourceIdx];
30409467b48Spatrick     CurrCounter += PI->Cycles;
30509467b48Spatrick     // Check if this is now the new critical resource.
30609467b48Spatrick     if ((CurrCounter > ProcResCostLim) &&
30709467b48Spatrick         (CriticalResourceIdx == UINT_MAX ||
30809467b48Spatrick          (PI->ProcResourceIdx != CriticalResourceIdx &&
30909467b48Spatrick           CurrCounter >
31009467b48Spatrick           ProcResourceCounters[CriticalResourceIdx]))) {
31109467b48Spatrick       LLVM_DEBUG(
31209467b48Spatrick           dbgs() << "++ New critical resource: "
31309467b48Spatrick                  << SchedModel->getProcResource(PI->ProcResourceIdx)->Name
31409467b48Spatrick                  << "\n";);
31509467b48Spatrick       CriticalResourceIdx = PI->ProcResourceIdx;
31609467b48Spatrick     }
31709467b48Spatrick   }
31809467b48Spatrick 
31909467b48Spatrick   // Make note of an instruction that uses a blocking resource (FPd).
32009467b48Spatrick   if (SU->isUnbuffered) {
32109467b48Spatrick     LastFPdOpCycleIdx = getCurrCycleIdx(SU);
32209467b48Spatrick     LLVM_DEBUG(dbgs() << "++ Last FPd cycle index: " << LastFPdOpCycleIdx
32309467b48Spatrick                       << "\n";);
32409467b48Spatrick   }
32509467b48Spatrick 
32609467b48Spatrick   // Insert SU into current group by increasing number of slots used
32709467b48Spatrick   // in current group.
32809467b48Spatrick   CurrGroupSize += getNumDecoderSlots(SU);
32909467b48Spatrick   CurrGroupHas4RegOps |= has4RegOps(SU->getInstr());
33009467b48Spatrick   unsigned GroupLim = (CurrGroupHas4RegOps ? 2 : 3);
33109467b48Spatrick   assert((CurrGroupSize <= GroupLim || CurrGroupSize == getNumDecoderSlots(SU))
33209467b48Spatrick          && "SU does not fit into decoder group!");
33309467b48Spatrick 
33409467b48Spatrick   // Check if current group is now full/ended. If so, move on to next
33509467b48Spatrick   // group to be ready to evaluate more candidates.
33609467b48Spatrick   if (CurrGroupSize >= GroupLim || SC->EndGroup)
33709467b48Spatrick     nextGroup();
33809467b48Spatrick }
33909467b48Spatrick 
groupingCost(SUnit * SU) const34009467b48Spatrick int SystemZHazardRecognizer::groupingCost(SUnit *SU) const {
34109467b48Spatrick   const MCSchedClassDesc *SC = getSchedClass(SU);
34209467b48Spatrick   if (!SC->isValid())
34309467b48Spatrick     return 0;
34409467b48Spatrick 
34509467b48Spatrick   // If SU begins new group, it can either break a current group early
34609467b48Spatrick   // or fit naturally if current group is empty (negative cost).
34709467b48Spatrick   if (SC->BeginGroup) {
34809467b48Spatrick     if (CurrGroupSize)
34909467b48Spatrick       return 3 - CurrGroupSize;
35009467b48Spatrick     return -1;
35109467b48Spatrick   }
35209467b48Spatrick 
35309467b48Spatrick   // Similarly, a group-ending SU may either fit well (last in group), or
35409467b48Spatrick   // end the group prematurely.
35509467b48Spatrick   if (SC->EndGroup) {
35609467b48Spatrick     unsigned resultingGroupSize =
35709467b48Spatrick       (CurrGroupSize + getNumDecoderSlots(SU));
35809467b48Spatrick     if (resultingGroupSize < 3)
35909467b48Spatrick       return (3 - resultingGroupSize);
36009467b48Spatrick     return -1;
36109467b48Spatrick   }
36209467b48Spatrick 
36309467b48Spatrick   // An instruction with 4 register operands will not fit in last slot.
36409467b48Spatrick   if (CurrGroupSize == 2 && has4RegOps(SU->getInstr()))
36509467b48Spatrick     return 1;
36609467b48Spatrick 
36709467b48Spatrick   // Most instructions can be placed in any decoder slot.
36809467b48Spatrick   return 0;
36909467b48Spatrick }
37009467b48Spatrick 
isFPdOpPreferred_distance(SUnit * SU) const37109467b48Spatrick bool SystemZHazardRecognizer::isFPdOpPreferred_distance(SUnit *SU) const {
37209467b48Spatrick   assert (SU->isUnbuffered);
37309467b48Spatrick   // If this is the first FPd op, it should be scheduled high.
37409467b48Spatrick   if (LastFPdOpCycleIdx == UINT_MAX)
37509467b48Spatrick     return true;
37609467b48Spatrick   // If this is not the first PFd op, it should go into the other side
37709467b48Spatrick   // of the processor to use the other FPd unit there. This should
37809467b48Spatrick   // generally happen if two FPd ops are placed with 2 other
37909467b48Spatrick   // instructions between them (modulo 6).
38009467b48Spatrick   unsigned SUCycleIdx = getCurrCycleIdx(SU);
38109467b48Spatrick   if (LastFPdOpCycleIdx > SUCycleIdx)
38209467b48Spatrick     return ((LastFPdOpCycleIdx - SUCycleIdx) == 3);
38309467b48Spatrick   return ((SUCycleIdx - LastFPdOpCycleIdx) == 3);
38409467b48Spatrick }
38509467b48Spatrick 
38609467b48Spatrick int SystemZHazardRecognizer::
resourcesCost(SUnit * SU)38709467b48Spatrick resourcesCost(SUnit *SU) {
38809467b48Spatrick   int Cost = 0;
38909467b48Spatrick 
39009467b48Spatrick   const MCSchedClassDesc *SC = getSchedClass(SU);
39109467b48Spatrick   if (!SC->isValid())
39209467b48Spatrick     return 0;
39309467b48Spatrick 
39409467b48Spatrick   // For a FPd op, either return min or max value as indicated by the
39509467b48Spatrick   // distance to any prior FPd op.
39609467b48Spatrick   if (SU->isUnbuffered)
39709467b48Spatrick     Cost = (isFPdOpPreferred_distance(SU) ? INT_MIN : INT_MAX);
39809467b48Spatrick   // For other instructions, give a cost to the use of the critical resource.
39909467b48Spatrick   else if (CriticalResourceIdx != UINT_MAX) {
40009467b48Spatrick     for (TargetSchedModel::ProcResIter
40109467b48Spatrick            PI = SchedModel->getWriteProcResBegin(SC),
40209467b48Spatrick            PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI)
40309467b48Spatrick       if (PI->ProcResourceIdx == CriticalResourceIdx)
40409467b48Spatrick         Cost = PI->Cycles;
40509467b48Spatrick   }
40609467b48Spatrick 
40709467b48Spatrick   return Cost;
40809467b48Spatrick }
40909467b48Spatrick 
emitInstruction(MachineInstr * MI,bool TakenBranch)41009467b48Spatrick void SystemZHazardRecognizer::emitInstruction(MachineInstr *MI,
41109467b48Spatrick                                               bool TakenBranch) {
41209467b48Spatrick   // Make a temporary SUnit.
41309467b48Spatrick   SUnit SU(MI, 0);
41409467b48Spatrick 
41509467b48Spatrick   // Set interesting flags.
41609467b48Spatrick   SU.isCall = MI->isCall();
41709467b48Spatrick 
41809467b48Spatrick   const MCSchedClassDesc *SC = SchedModel->resolveSchedClass(MI);
41909467b48Spatrick   for (const MCWriteProcResEntry &PRE :
42009467b48Spatrick          make_range(SchedModel->getWriteProcResBegin(SC),
42109467b48Spatrick                     SchedModel->getWriteProcResEnd(SC))) {
42209467b48Spatrick     switch (SchedModel->getProcResource(PRE.ProcResourceIdx)->BufferSize) {
42309467b48Spatrick     case 0:
42409467b48Spatrick       SU.hasReservedResource = true;
42509467b48Spatrick       break;
42609467b48Spatrick     case 1:
42709467b48Spatrick       SU.isUnbuffered = true;
42809467b48Spatrick       break;
42909467b48Spatrick     default:
43009467b48Spatrick       break;
43109467b48Spatrick     }
43209467b48Spatrick   }
43309467b48Spatrick 
43409467b48Spatrick   unsigned GroupSizeBeforeEmit = CurrGroupSize;
43509467b48Spatrick   EmitInstruction(&SU);
43609467b48Spatrick 
43709467b48Spatrick   if (!TakenBranch && isBranchRetTrap(MI)) {
43809467b48Spatrick     // NT Branch on second slot ends group.
43909467b48Spatrick     if (GroupSizeBeforeEmit == 1)
44009467b48Spatrick       nextGroup();
44109467b48Spatrick   }
44209467b48Spatrick 
44309467b48Spatrick   if (TakenBranch && CurrGroupSize > 0)
44409467b48Spatrick     nextGroup();
44509467b48Spatrick 
44609467b48Spatrick   assert ((!MI->isTerminator() || isBranchRetTrap(MI)) &&
44709467b48Spatrick           "Scheduler: unhandled terminator!");
44809467b48Spatrick }
44909467b48Spatrick 
45009467b48Spatrick void SystemZHazardRecognizer::
copyState(SystemZHazardRecognizer * Incoming)45109467b48Spatrick copyState(SystemZHazardRecognizer *Incoming) {
45209467b48Spatrick   // Current decoder group
45309467b48Spatrick   CurrGroupSize = Incoming->CurrGroupSize;
45409467b48Spatrick   LLVM_DEBUG(CurGroupDbg = Incoming->CurGroupDbg;);
45509467b48Spatrick 
45609467b48Spatrick   // Processor resources
45709467b48Spatrick   ProcResourceCounters = Incoming->ProcResourceCounters;
45809467b48Spatrick   CriticalResourceIdx = Incoming->CriticalResourceIdx;
45909467b48Spatrick 
46009467b48Spatrick   // FPd
46109467b48Spatrick   LastFPdOpCycleIdx = Incoming->LastFPdOpCycleIdx;
46209467b48Spatrick   GrpCount = Incoming->GrpCount;
46309467b48Spatrick }
464