18010b631SJonas Paulsson //=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===//
28010b631SJonas Paulsson //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68010b631SJonas Paulsson //
78010b631SJonas Paulsson //===----------------------------------------------------------------------===//
88010b631SJonas Paulsson //
98010b631SJonas Paulsson // This file defines a hazard recognizer for the SystemZ scheduler.
108010b631SJonas Paulsson //
118010b631SJonas Paulsson // This class is used by the SystemZ scheduling strategy to maintain
128010b631SJonas Paulsson // the state during scheduling, and provide cost functions for
138010b631SJonas Paulsson // scheduling candidates. This includes:
148010b631SJonas Paulsson //
158010b631SJonas Paulsson // * Decoder grouping. A decoder group can maximally hold 3 uops, and
168010b631SJonas Paulsson // instructions that always begin a new group should be scheduled when
178010b631SJonas Paulsson // the current decoder group is empty.
188010b631SJonas Paulsson // * Processor resources usage. It is beneficial to balance the use of
198010b631SJonas Paulsson // resources.
208010b631SJonas Paulsson //
2157a705d9SJonas Paulsson // A goal is to consider all instructions, also those outside of any
2257a705d9SJonas Paulsson // scheduling region. Such instructions are "advanced" past and include
2357a705d9SJonas Paulsson // single instructions before a scheduling region, branches etc.
2457a705d9SJonas Paulsson //
2557a705d9SJonas Paulsson // A block that has only one predecessor continues scheduling with the state
2657a705d9SJonas Paulsson // of it (which may be updated by emitting branches).
2757a705d9SJonas Paulsson //
288010b631SJonas Paulsson // ===---------------------------------------------------------------------===//
298010b631SJonas Paulsson
308010b631SJonas Paulsson #include "SystemZHazardRecognizer.h"
318010b631SJonas Paulsson #include "llvm/ADT/Statistic.h"
328010b631SJonas Paulsson
338010b631SJonas Paulsson using namespace llvm;
348010b631SJonas Paulsson
350cd23f56SEvandro Menezes #define DEBUG_TYPE "machine-scheduler"
368010b631SJonas Paulsson
378010b631SJonas Paulsson // This is the limit of processor resource usage at which the
388010b631SJonas Paulsson // scheduler should try to look for other instructions (not using the
398010b631SJonas Paulsson // critical resource).
40ffd3715dSBenjamin Kramer static cl::opt<int> ProcResCostLim("procres-cost-lim", cl::Hidden,
418010b631SJonas Paulsson cl::desc("The OOO window for processor "
428010b631SJonas Paulsson "resources during scheduling."),
438010b631SJonas Paulsson cl::init(8));
448010b631SJonas Paulsson
458010b631SJonas Paulsson unsigned SystemZHazardRecognizer::
getNumDecoderSlots(SUnit * SU) const468010b631SJonas Paulsson getNumDecoderSlots(SUnit *SU) const {
4757a705d9SJonas Paulsson const MCSchedClassDesc *SC = getSchedClass(SU);
488010b631SJonas Paulsson if (!SC->isValid())
498010b631SJonas Paulsson return 0; // IMPLICIT_DEF / KILL -- will not make impact in output.
508010b631SJonas Paulsson
51f107b727SJonas Paulsson assert((SC->NumMicroOps != 2 || (SC->BeginGroup && !SC->EndGroup)) &&
52f107b727SJonas Paulsson "Only cracked instruction can have 2 uops.");
53f107b727SJonas Paulsson assert((SC->NumMicroOps < 3 || (SC->BeginGroup && SC->EndGroup)) &&
54f107b727SJonas Paulsson "Expanded instructions always group alone.");
55f107b727SJonas Paulsson assert((SC->NumMicroOps < 3 || (SC->NumMicroOps % 3 == 0)) &&
56f107b727SJonas Paulsson "Expanded instructions fill the group(s).");
578010b631SJonas Paulsson
58f107b727SJonas Paulsson return SC->NumMicroOps;
598010b631SJonas Paulsson }
608010b631SJonas Paulsson
getCurrCycleIdx(SUnit * SU) const619b0f28f0SJonas Paulsson unsigned SystemZHazardRecognizer::getCurrCycleIdx(SUnit *SU) const {
628010b631SJonas Paulsson unsigned Idx = CurrGroupSize;
638010b631SJonas Paulsson if (GrpCount % 2)
648010b631SJonas Paulsson Idx += 3;
659b0f28f0SJonas Paulsson
669b0f28f0SJonas Paulsson if (SU != nullptr && !fitsIntoCurrentGroup(SU)) {
679b0f28f0SJonas Paulsson if (Idx == 1 || Idx == 2)
689b0f28f0SJonas Paulsson Idx = 3;
699b0f28f0SJonas Paulsson else if (Idx == 4 || Idx == 5)
709b0f28f0SJonas Paulsson Idx = 0;
719b0f28f0SJonas Paulsson }
729b0f28f0SJonas Paulsson
738010b631SJonas Paulsson return Idx;
748010b631SJonas Paulsson }
758010b631SJonas Paulsson
768010b631SJonas Paulsson ScheduleHazardRecognizer::HazardType SystemZHazardRecognizer::
getHazardType(SUnit * SU,int Stalls)77480ad4afSSimon Pilgrim getHazardType(SUnit *SU, int Stalls) {
78480ad4afSSimon Pilgrim return (fitsIntoCurrentGroup(SU) ? NoHazard : Hazard);
798010b631SJonas Paulsson }
808010b631SJonas Paulsson
Reset()818010b631SJonas Paulsson void SystemZHazardRecognizer::Reset() {
828010b631SJonas Paulsson CurrGroupSize = 0;
832f12e45dSJonas Paulsson CurrGroupHas4RegOps = false;
848010b631SJonas Paulsson clearProcResCounters();
858010b631SJonas Paulsson GrpCount = 0;
868010b631SJonas Paulsson LastFPdOpCycleIdx = UINT_MAX;
8757a705d9SJonas Paulsson LastEmittedMI = nullptr;
88d34e60caSNicola Zaghen LLVM_DEBUG(CurGroupDbg = "";);
898010b631SJonas Paulsson }
908010b631SJonas Paulsson
918010b631SJonas Paulsson bool
fitsIntoCurrentGroup(SUnit * SU) const928010b631SJonas Paulsson SystemZHazardRecognizer::fitsIntoCurrentGroup(SUnit *SU) const {
9357a705d9SJonas Paulsson const MCSchedClassDesc *SC = getSchedClass(SU);
948010b631SJonas Paulsson if (!SC->isValid())
958010b631SJonas Paulsson return true;
968010b631SJonas Paulsson
978010b631SJonas Paulsson // A cracked instruction only fits into schedule if the current
988010b631SJonas Paulsson // group is empty.
998010b631SJonas Paulsson if (SC->BeginGroup)
1008010b631SJonas Paulsson return (CurrGroupSize == 0);
1018010b631SJonas Paulsson
1022f12e45dSJonas Paulsson // An instruction with 4 register operands will not fit in last slot.
103590b1fc8SJonas Paulsson assert ((CurrGroupSize < 2 || !CurrGroupHas4RegOps) &&
1042f12e45dSJonas Paulsson "Current decoder group is already full!");
1052f12e45dSJonas Paulsson if (CurrGroupSize == 2 && has4RegOps(SU->getInstr()))
1062f12e45dSJonas Paulsson return false;
1072f12e45dSJonas Paulsson
1088010b631SJonas Paulsson // Since a full group is handled immediately in EmitInstruction(),
1098010b631SJonas Paulsson // SU should fit into current group. NumSlots should be 1 or 0,
1108010b631SJonas Paulsson // since it is not a cracked or expanded instruction.
1118010b631SJonas Paulsson assert ((getNumDecoderSlots(SU) <= 1) && (CurrGroupSize < 3) &&
1128010b631SJonas Paulsson "Expected normal instruction to fit in non-full group!");
1138010b631SJonas Paulsson
1148010b631SJonas Paulsson return true;
1158010b631SJonas Paulsson }
1168010b631SJonas Paulsson
has4RegOps(const MachineInstr * MI) const1172f12e45dSJonas Paulsson bool SystemZHazardRecognizer::has4RegOps(const MachineInstr *MI) const {
1182f12e45dSJonas Paulsson const MachineFunction &MF = *MI->getParent()->getParent();
1192f12e45dSJonas Paulsson const TargetRegisterInfo *TRI = &TII->getRegisterInfo();
1202f12e45dSJonas Paulsson const MCInstrDesc &MID = MI->getDesc();
1212f12e45dSJonas Paulsson unsigned Count = 0;
1222f12e45dSJonas Paulsson for (unsigned OpIdx = 0; OpIdx < MID.getNumOperands(); OpIdx++) {
1232f12e45dSJonas Paulsson const TargetRegisterClass *RC = TII->getRegClass(MID, OpIdx, TRI, MF);
1242f12e45dSJonas Paulsson if (RC == nullptr)
1252f12e45dSJonas Paulsson continue;
1262f12e45dSJonas Paulsson if (OpIdx >= MID.getNumDefs() &&
1272f12e45dSJonas Paulsson MID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1)
1282f12e45dSJonas Paulsson continue;
1292f12e45dSJonas Paulsson Count++;
1302f12e45dSJonas Paulsson }
1312f12e45dSJonas Paulsson return Count >= 4;
1322f12e45dSJonas Paulsson }
1332f12e45dSJonas Paulsson
nextGroup()13461fbcf58SJonas Paulsson void SystemZHazardRecognizer::nextGroup() {
13561fbcf58SJonas Paulsson if (CurrGroupSize == 0)
13661fbcf58SJonas Paulsson return;
13761fbcf58SJonas Paulsson
138d34e60caSNicola Zaghen LLVM_DEBUG(dumpCurrGroup("Completed decode group"));
139d34e60caSNicola Zaghen LLVM_DEBUG(CurGroupDbg = "";);
1408010b631SJonas Paulsson
141f107b727SJonas Paulsson int NumGroups = ((CurrGroupSize > 3) ? (CurrGroupSize / 3) : 1);
142f107b727SJonas Paulsson assert((CurrGroupSize <= 3 || CurrGroupSize % 3 == 0) &&
143f107b727SJonas Paulsson "Current decoder group bad.");
1448010b631SJonas Paulsson
1458010b631SJonas Paulsson // Reset counter for next group.
1468010b631SJonas Paulsson CurrGroupSize = 0;
1472f12e45dSJonas Paulsson CurrGroupHas4RegOps = false;
1488010b631SJonas Paulsson
149f107b727SJonas Paulsson GrpCount += ((unsigned) NumGroups);
150f107b727SJonas Paulsson
1515438f1deSJonas Paulsson // Decrease counters for execution units.
1528010b631SJonas Paulsson for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
15325cbfdd4SJonas Paulsson ProcResourceCounters[i] = ((ProcResourceCounters[i] > NumGroups)
15425cbfdd4SJonas Paulsson ? (ProcResourceCounters[i] - NumGroups)
15525cbfdd4SJonas Paulsson : 0);
1568010b631SJonas Paulsson
1578010b631SJonas Paulsson // Clear CriticalResourceIdx if it is now below the threshold.
1588010b631SJonas Paulsson if (CriticalResourceIdx != UINT_MAX &&
1598010b631SJonas Paulsson (ProcResourceCounters[CriticalResourceIdx] <=
1608010b631SJonas Paulsson ProcResCostLim))
1618010b631SJonas Paulsson CriticalResourceIdx = UINT_MAX;
1628010b631SJonas Paulsson
163d34e60caSNicola Zaghen LLVM_DEBUG(dumpState(););
1648010b631SJonas Paulsson }
1658010b631SJonas Paulsson
1668010b631SJonas Paulsson #ifndef NDEBUG // Debug output
dumpSU(SUnit * SU,raw_ostream & OS) const1678010b631SJonas Paulsson void SystemZHazardRecognizer::dumpSU(SUnit *SU, raw_ostream &OS) const {
1688010b631SJonas Paulsson OS << "SU(" << SU->NodeNum << "):";
16957a705d9SJonas Paulsson OS << TII->getName(SU->getInstr()->getOpcode());
1708010b631SJonas Paulsson
17157a705d9SJonas Paulsson const MCSchedClassDesc *SC = getSchedClass(SU);
1728010b631SJonas Paulsson if (!SC->isValid())
1738010b631SJonas Paulsson return;
1748010b631SJonas Paulsson
1758010b631SJonas Paulsson for (TargetSchedModel::ProcResIter
1768010b631SJonas Paulsson PI = SchedModel->getWriteProcResBegin(SC),
1778010b631SJonas Paulsson PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
1788010b631SJonas Paulsson const MCProcResourceDesc &PRD =
1798010b631SJonas Paulsson *SchedModel->getProcResource(PI->ProcResourceIdx);
1808010b631SJonas Paulsson std::string FU(PRD.Name);
1818010b631SJonas Paulsson // trim e.g. Z13_FXaUnit -> FXa
182*c70f3686SFangrui Song FU = FU.substr(FU.find('_') + 1);
18359c94becSJonas Paulsson size_t Pos = FU.find("Unit");
18459c94becSJonas Paulsson if (Pos != std::string::npos)
18559c94becSJonas Paulsson FU.resize(Pos);
18659c94becSJonas Paulsson if (FU == "LS") // LSUnit -> LSU
18759c94becSJonas Paulsson FU = "LSU";
1888010b631SJonas Paulsson OS << "/" << FU;
1898010b631SJonas Paulsson
1908010b631SJonas Paulsson if (PI->Cycles > 1)
1918010b631SJonas Paulsson OS << "(" << PI->Cycles << "cyc)";
1928010b631SJonas Paulsson }
1938010b631SJonas Paulsson
1948010b631SJonas Paulsson if (SC->NumMicroOps > 1)
1958010b631SJonas Paulsson OS << "/" << SC->NumMicroOps << "uops";
1968010b631SJonas Paulsson if (SC->BeginGroup && SC->EndGroup)
1978010b631SJonas Paulsson OS << "/GroupsAlone";
1988010b631SJonas Paulsson else if (SC->BeginGroup)
1998010b631SJonas Paulsson OS << "/BeginsGroup";
2008010b631SJonas Paulsson else if (SC->EndGroup)
2018010b631SJonas Paulsson OS << "/EndsGroup";
2028010b631SJonas Paulsson if (SU->isUnbuffered)
2038010b631SJonas Paulsson OS << "/Unbuffered";
2042f12e45dSJonas Paulsson if (has4RegOps(SU->getInstr()))
2052f12e45dSJonas Paulsson OS << "/4RegOps";
2068010b631SJonas Paulsson }
2078010b631SJonas Paulsson
dumpCurrGroup(std::string Msg) const2088010b631SJonas Paulsson void SystemZHazardRecognizer::dumpCurrGroup(std::string Msg) const {
20961fbcf58SJonas Paulsson dbgs() << "++ " << Msg;
2108010b631SJonas Paulsson dbgs() << ": ";
2118010b631SJonas Paulsson
2128010b631SJonas Paulsson if (CurGroupDbg.empty())
2138010b631SJonas Paulsson dbgs() << " <empty>\n";
2148010b631SJonas Paulsson else {
2158010b631SJonas Paulsson dbgs() << "{ " << CurGroupDbg << " }";
2168010b631SJonas Paulsson dbgs() << " (" << CurrGroupSize << " decoder slot"
2178010b631SJonas Paulsson << (CurrGroupSize > 1 ? "s":"")
2182f12e45dSJonas Paulsson << (CurrGroupHas4RegOps ? ", 4RegOps" : "")
2198010b631SJonas Paulsson << ")\n";
2208010b631SJonas Paulsson }
2218010b631SJonas Paulsson }
2228010b631SJonas Paulsson
dumpProcResourceCounters() const2238010b631SJonas Paulsson void SystemZHazardRecognizer::dumpProcResourceCounters() const {
2248010b631SJonas Paulsson bool any = false;
2258010b631SJonas Paulsson
2268010b631SJonas Paulsson for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
2278010b631SJonas Paulsson if (ProcResourceCounters[i] > 0) {
2288010b631SJonas Paulsson any = true;
2298010b631SJonas Paulsson break;
2308010b631SJonas Paulsson }
2318010b631SJonas Paulsson
2328010b631SJonas Paulsson if (!any)
2338010b631SJonas Paulsson return;
2348010b631SJonas Paulsson
23561fbcf58SJonas Paulsson dbgs() << "++ | Resource counters: ";
2368010b631SJonas Paulsson for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i)
23761fbcf58SJonas Paulsson if (ProcResourceCounters[i] > 0)
23861fbcf58SJonas Paulsson dbgs() << SchedModel->getProcResource(i)->Name
23961fbcf58SJonas Paulsson << ":" << ProcResourceCounters[i] << " ";
24061fbcf58SJonas Paulsson dbgs() << "\n";
24161fbcf58SJonas Paulsson
24261fbcf58SJonas Paulsson if (CriticalResourceIdx != UINT_MAX)
24361fbcf58SJonas Paulsson dbgs() << "++ | Critical resource: "
24461fbcf58SJonas Paulsson << SchedModel->getProcResource(CriticalResourceIdx)->Name
24561fbcf58SJonas Paulsson << "\n";
2468010b631SJonas Paulsson }
24761fbcf58SJonas Paulsson
dumpState() const24861fbcf58SJonas Paulsson void SystemZHazardRecognizer::dumpState() const {
24961fbcf58SJonas Paulsson dumpCurrGroup("| Current decoder group");
25061fbcf58SJonas Paulsson dbgs() << "++ | Current cycle index: "
25161fbcf58SJonas Paulsson << getCurrCycleIdx() << "\n";
25261fbcf58SJonas Paulsson dumpProcResourceCounters();
25361fbcf58SJonas Paulsson if (LastFPdOpCycleIdx != UINT_MAX)
25461fbcf58SJonas Paulsson dbgs() << "++ | Last FPd cycle index: " << LastFPdOpCycleIdx << "\n";
2558010b631SJonas Paulsson }
25661fbcf58SJonas Paulsson
2578010b631SJonas Paulsson #endif //NDEBUG
2588010b631SJonas Paulsson
clearProcResCounters()2598010b631SJonas Paulsson void SystemZHazardRecognizer::clearProcResCounters() {
2608010b631SJonas Paulsson ProcResourceCounters.assign(SchedModel->getNumProcResourceKinds(), 0);
2618010b631SJonas Paulsson CriticalResourceIdx = UINT_MAX;
2628010b631SJonas Paulsson }
2638010b631SJonas Paulsson
isBranchRetTrap(MachineInstr * MI)26457a705d9SJonas Paulsson static inline bool isBranchRetTrap(MachineInstr *MI) {
26557a705d9SJonas Paulsson return (MI->isBranch() || MI->isReturn() ||
26657a705d9SJonas Paulsson MI->getOpcode() == SystemZ::CondTrap);
26757a705d9SJonas Paulsson }
26857a705d9SJonas Paulsson
2698010b631SJonas Paulsson // Update state with SU as the next scheduled unit.
2708010b631SJonas Paulsson void SystemZHazardRecognizer::
EmitInstruction(SUnit * SU)2718010b631SJonas Paulsson EmitInstruction(SUnit *SU) {
27257a705d9SJonas Paulsson const MCSchedClassDesc *SC = getSchedClass(SU);
273d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "++ HazardRecognizer emitting "; dumpSU(SU, dbgs());
27461fbcf58SJonas Paulsson dbgs() << "\n";);
275d34e60caSNicola Zaghen LLVM_DEBUG(dumpCurrGroup("Decode group before emission"););
2768010b631SJonas Paulsson
2778010b631SJonas Paulsson // If scheduling an SU that must begin a new decoder group, move on
2788010b631SJonas Paulsson // to next group.
2798010b631SJonas Paulsson if (!fitsIntoCurrentGroup(SU))
2808010b631SJonas Paulsson nextGroup();
2818010b631SJonas Paulsson
282d34e60caSNicola Zaghen LLVM_DEBUG(raw_string_ostream cgd(CurGroupDbg);
283d34e60caSNicola Zaghen if (CurGroupDbg.length()) cgd << ", "; dumpSU(SU, cgd););
2848010b631SJonas Paulsson
28557a705d9SJonas Paulsson LastEmittedMI = SU->getInstr();
28657a705d9SJonas Paulsson
2878010b631SJonas Paulsson // After returning from a call, we don't know much about the state.
28857a705d9SJonas Paulsson if (SU->isCall) {
289d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "++ Clearing state after call.\n";);
29091c853a7SJonas Paulsson Reset();
29191c853a7SJonas Paulsson LastEmittedMI = SU->getInstr();
2928010b631SJonas Paulsson return;
2938010b631SJonas Paulsson }
2948010b631SJonas Paulsson
2958010b631SJonas Paulsson // Increase counter for execution unit(s).
2968010b631SJonas Paulsson for (TargetSchedModel::ProcResIter
2978010b631SJonas Paulsson PI = SchedModel->getWriteProcResBegin(SC),
2988010b631SJonas Paulsson PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) {
2998010b631SJonas Paulsson // Don't handle FPd together with the other resources.
3008010b631SJonas Paulsson if (SchedModel->getProcResource(PI->ProcResourceIdx)->BufferSize == 1)
3018010b631SJonas Paulsson continue;
3028010b631SJonas Paulsson int &CurrCounter =
3038010b631SJonas Paulsson ProcResourceCounters[PI->ProcResourceIdx];
3048010b631SJonas Paulsson CurrCounter += PI->Cycles;
3058010b631SJonas Paulsson // Check if this is now the new critical resource.
3068010b631SJonas Paulsson if ((CurrCounter > ProcResCostLim) &&
3078010b631SJonas Paulsson (CriticalResourceIdx == UINT_MAX ||
3088010b631SJonas Paulsson (PI->ProcResourceIdx != CriticalResourceIdx &&
3098010b631SJonas Paulsson CurrCounter >
3108010b631SJonas Paulsson ProcResourceCounters[CriticalResourceIdx]))) {
311d34e60caSNicola Zaghen LLVM_DEBUG(
312d34e60caSNicola Zaghen dbgs() << "++ New critical resource: "
3138010b631SJonas Paulsson << SchedModel->getProcResource(PI->ProcResourceIdx)->Name
3148010b631SJonas Paulsson << "\n";);
3158010b631SJonas Paulsson CriticalResourceIdx = PI->ProcResourceIdx;
3168010b631SJonas Paulsson }
3178010b631SJonas Paulsson }
3188010b631SJonas Paulsson
3198010b631SJonas Paulsson // Make note of an instruction that uses a blocking resource (FPd).
3208010b631SJonas Paulsson if (SU->isUnbuffered) {
3219b0f28f0SJonas Paulsson LastFPdOpCycleIdx = getCurrCycleIdx(SU);
322d34e60caSNicola Zaghen LLVM_DEBUG(dbgs() << "++ Last FPd cycle index: " << LastFPdOpCycleIdx
323d34e60caSNicola Zaghen << "\n";);
3248010b631SJonas Paulsson }
3258010b631SJonas Paulsson
3268010b631SJonas Paulsson // Insert SU into current group by increasing number of slots used
3278010b631SJonas Paulsson // in current group.
3288010b631SJonas Paulsson CurrGroupSize += getNumDecoderSlots(SU);
3292f12e45dSJonas Paulsson CurrGroupHas4RegOps |= has4RegOps(SU->getInstr());
330f107b727SJonas Paulsson unsigned GroupLim = (CurrGroupHas4RegOps ? 2 : 3);
331f107b727SJonas Paulsson assert((CurrGroupSize <= GroupLim || CurrGroupSize == getNumDecoderSlots(SU))
332f107b727SJonas Paulsson && "SU does not fit into decoder group!");
3338010b631SJonas Paulsson
3348010b631SJonas Paulsson // Check if current group is now full/ended. If so, move on to next
3358010b631SJonas Paulsson // group to be ready to evaluate more candidates.
336f107b727SJonas Paulsson if (CurrGroupSize >= GroupLim || SC->EndGroup)
3378010b631SJonas Paulsson nextGroup();
3388010b631SJonas Paulsson }
3398010b631SJonas Paulsson
groupingCost(SUnit * SU) const3408010b631SJonas Paulsson int SystemZHazardRecognizer::groupingCost(SUnit *SU) const {
34157a705d9SJonas Paulsson const MCSchedClassDesc *SC = getSchedClass(SU);
3428010b631SJonas Paulsson if (!SC->isValid())
3438010b631SJonas Paulsson return 0;
3448010b631SJonas Paulsson
3458010b631SJonas Paulsson // If SU begins new group, it can either break a current group early
3468010b631SJonas Paulsson // or fit naturally if current group is empty (negative cost).
3478010b631SJonas Paulsson if (SC->BeginGroup) {
3488010b631SJonas Paulsson if (CurrGroupSize)
3498010b631SJonas Paulsson return 3 - CurrGroupSize;
3508010b631SJonas Paulsson return -1;
3518010b631SJonas Paulsson }
3528010b631SJonas Paulsson
3538010b631SJonas Paulsson // Similarly, a group-ending SU may either fit well (last in group), or
3548010b631SJonas Paulsson // end the group prematurely.
3558010b631SJonas Paulsson if (SC->EndGroup) {
3568010b631SJonas Paulsson unsigned resultingGroupSize =
3578010b631SJonas Paulsson (CurrGroupSize + getNumDecoderSlots(SU));
3588010b631SJonas Paulsson if (resultingGroupSize < 3)
3598010b631SJonas Paulsson return (3 - resultingGroupSize);
3608010b631SJonas Paulsson return -1;
3618010b631SJonas Paulsson }
3628010b631SJonas Paulsson
3632f12e45dSJonas Paulsson // An instruction with 4 register operands will not fit in last slot.
3642f12e45dSJonas Paulsson if (CurrGroupSize == 2 && has4RegOps(SU->getInstr()))
3652f12e45dSJonas Paulsson return 1;
3662f12e45dSJonas Paulsson
3678010b631SJonas Paulsson // Most instructions can be placed in any decoder slot.
3688010b631SJonas Paulsson return 0;
3698010b631SJonas Paulsson }
3708010b631SJonas Paulsson
isFPdOpPreferred_distance(SUnit * SU) const3719b0f28f0SJonas Paulsson bool SystemZHazardRecognizer::isFPdOpPreferred_distance(SUnit *SU) const {
3728010b631SJonas Paulsson assert (SU->isUnbuffered);
3738010b631SJonas Paulsson // If this is the first FPd op, it should be scheduled high.
3748010b631SJonas Paulsson if (LastFPdOpCycleIdx == UINT_MAX)
3758010b631SJonas Paulsson return true;
3768010b631SJonas Paulsson // If this is not the first PFd op, it should go into the other side
3778010b631SJonas Paulsson // of the processor to use the other FPd unit there. This should
3788010b631SJonas Paulsson // generally happen if two FPd ops are placed with 2 other
3798010b631SJonas Paulsson // instructions between them (modulo 6).
3809b0f28f0SJonas Paulsson unsigned SUCycleIdx = getCurrCycleIdx(SU);
3819b0f28f0SJonas Paulsson if (LastFPdOpCycleIdx > SUCycleIdx)
3829b0f28f0SJonas Paulsson return ((LastFPdOpCycleIdx - SUCycleIdx) == 3);
3839b0f28f0SJonas Paulsson return ((SUCycleIdx - LastFPdOpCycleIdx) == 3);
3848010b631SJonas Paulsson }
3858010b631SJonas Paulsson
3868010b631SJonas Paulsson int SystemZHazardRecognizer::
resourcesCost(SUnit * SU)3878010b631SJonas Paulsson resourcesCost(SUnit *SU) {
3888010b631SJonas Paulsson int Cost = 0;
3898010b631SJonas Paulsson
39057a705d9SJonas Paulsson const MCSchedClassDesc *SC = getSchedClass(SU);
3918010b631SJonas Paulsson if (!SC->isValid())
3928010b631SJonas Paulsson return 0;
3938010b631SJonas Paulsson
3948010b631SJonas Paulsson // For a FPd op, either return min or max value as indicated by the
3958010b631SJonas Paulsson // distance to any prior FPd op.
3968010b631SJonas Paulsson if (SU->isUnbuffered)
3978010b631SJonas Paulsson Cost = (isFPdOpPreferred_distance(SU) ? INT_MIN : INT_MAX);
3988010b631SJonas Paulsson // For other instructions, give a cost to the use of the critical resource.
3998010b631SJonas Paulsson else if (CriticalResourceIdx != UINT_MAX) {
4008010b631SJonas Paulsson for (TargetSchedModel::ProcResIter
4018010b631SJonas Paulsson PI = SchedModel->getWriteProcResBegin(SC),
4028010b631SJonas Paulsson PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI)
4038010b631SJonas Paulsson if (PI->ProcResourceIdx == CriticalResourceIdx)
4048010b631SJonas Paulsson Cost = PI->Cycles;
4058010b631SJonas Paulsson }
4068010b631SJonas Paulsson
4078010b631SJonas Paulsson return Cost;
4088010b631SJonas Paulsson }
4098010b631SJonas Paulsson
emitInstruction(MachineInstr * MI,bool TakenBranch)41057a705d9SJonas Paulsson void SystemZHazardRecognizer::emitInstruction(MachineInstr *MI,
41157a705d9SJonas Paulsson bool TakenBranch) {
41257a705d9SJonas Paulsson // Make a temporary SUnit.
41357a705d9SJonas Paulsson SUnit SU(MI, 0);
41457a705d9SJonas Paulsson
41557a705d9SJonas Paulsson // Set interesting flags.
41657a705d9SJonas Paulsson SU.isCall = MI->isCall();
41757a705d9SJonas Paulsson
41857a705d9SJonas Paulsson const MCSchedClassDesc *SC = SchedModel->resolveSchedClass(MI);
41957a705d9SJonas Paulsson for (const MCWriteProcResEntry &PRE :
42057a705d9SJonas Paulsson make_range(SchedModel->getWriteProcResBegin(SC),
42157a705d9SJonas Paulsson SchedModel->getWriteProcResEnd(SC))) {
42257a705d9SJonas Paulsson switch (SchedModel->getProcResource(PRE.ProcResourceIdx)->BufferSize) {
42357a705d9SJonas Paulsson case 0:
42457a705d9SJonas Paulsson SU.hasReservedResource = true;
42557a705d9SJonas Paulsson break;
42657a705d9SJonas Paulsson case 1:
42757a705d9SJonas Paulsson SU.isUnbuffered = true;
42857a705d9SJonas Paulsson break;
42957a705d9SJonas Paulsson default:
43057a705d9SJonas Paulsson break;
43157a705d9SJonas Paulsson }
43257a705d9SJonas Paulsson }
43357a705d9SJonas Paulsson
434e18dbeb2SJonas Paulsson unsigned GroupSizeBeforeEmit = CurrGroupSize;
43557a705d9SJonas Paulsson EmitInstruction(&SU);
43657a705d9SJonas Paulsson
437e18dbeb2SJonas Paulsson if (!TakenBranch && isBranchRetTrap(MI)) {
438e18dbeb2SJonas Paulsson // NT Branch on second slot ends group.
439e18dbeb2SJonas Paulsson if (GroupSizeBeforeEmit == 1)
440e18dbeb2SJonas Paulsson nextGroup();
441e18dbeb2SJonas Paulsson }
442e18dbeb2SJonas Paulsson
44357a705d9SJonas Paulsson if (TakenBranch && CurrGroupSize > 0)
44461fbcf58SJonas Paulsson nextGroup();
44557a705d9SJonas Paulsson
44657a705d9SJonas Paulsson assert ((!MI->isTerminator() || isBranchRetTrap(MI)) &&
44757a705d9SJonas Paulsson "Scheduler: unhandled terminator!");
44857a705d9SJonas Paulsson }
44957a705d9SJonas Paulsson
45057a705d9SJonas Paulsson void SystemZHazardRecognizer::
copyState(SystemZHazardRecognizer * Incoming)45157a705d9SJonas Paulsson copyState(SystemZHazardRecognizer *Incoming) {
45257a705d9SJonas Paulsson // Current decoder group
45357a705d9SJonas Paulsson CurrGroupSize = Incoming->CurrGroupSize;
454d34e60caSNicola Zaghen LLVM_DEBUG(CurGroupDbg = Incoming->CurGroupDbg;);
45557a705d9SJonas Paulsson
45657a705d9SJonas Paulsson // Processor resources
45757a705d9SJonas Paulsson ProcResourceCounters = Incoming->ProcResourceCounters;
45857a705d9SJonas Paulsson CriticalResourceIdx = Incoming->CriticalResourceIdx;
45957a705d9SJonas Paulsson
46057a705d9SJonas Paulsson // FPd
46157a705d9SJonas Paulsson LastFPdOpCycleIdx = Incoming->LastFPdOpCycleIdx;
46257a705d9SJonas Paulsson GrpCount = Incoming->GrpCount;
46357a705d9SJonas Paulsson }
464