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:: 460b57cec5SDimitry 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 610b57cec5SDimitry 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:: 77*e8d8bef9SDimitry Andric getHazardType(SUnit *SU, int Stalls) { 78*e8d8bef9SDimitry Andric return (fitsIntoCurrentGroup(SU) ? NoHazard : Hazard); 790b57cec5SDimitry Andric } 800b57cec5SDimitry Andric 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 920b57cec5SDimitry 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 1170b57cec5SDimitry 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 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 1670b57cec5SDimitry 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 182*e8d8bef9SDimitry 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 1900b57cec5SDimitry Andric if (PI->Cycles > 1) 1910b57cec5SDimitry Andric OS << "(" << PI->Cycles << "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 2080b57cec5SDimitry 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 2230b57cec5SDimitry 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 2480b57cec5SDimitry 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 2590b57cec5SDimitry Andric void SystemZHazardRecognizer::clearProcResCounters() { 2600b57cec5SDimitry Andric ProcResourceCounters.assign(SchedModel->getNumProcResourceKinds(), 0); 2610b57cec5SDimitry Andric CriticalResourceIdx = UINT_MAX; 2620b57cec5SDimitry Andric } 2630b57cec5SDimitry Andric 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:: 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]; 3040b57cec5SDimitry Andric CurrCounter += PI->Cycles; 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 3400b57cec5SDimitry 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 3710b57cec5SDimitry 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:: 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) 4040b57cec5SDimitry Andric Cost = PI->Cycles; 4050b57cec5SDimitry Andric } 4060b57cec5SDimitry Andric 4070b57cec5SDimitry Andric return Cost; 4080b57cec5SDimitry Andric } 4090b57cec5SDimitry Andric 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:: 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