1*0b57cec5SDimitry Andric //=-- SystemZHazardRecognizer.h - SystemZ Hazard Recognizer -----*- C++ -*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric // 9*0b57cec5SDimitry Andric // This file defines a hazard recognizer for the SystemZ scheduler. 10*0b57cec5SDimitry Andric // 11*0b57cec5SDimitry Andric // This class is used by the SystemZ scheduling strategy to maintain 12*0b57cec5SDimitry Andric // the state during scheduling, and provide cost functions for 13*0b57cec5SDimitry Andric // scheduling candidates. This includes: 14*0b57cec5SDimitry Andric // 15*0b57cec5SDimitry Andric // * Decoder grouping. A decoder group can maximally hold 3 uops, and 16*0b57cec5SDimitry Andric // instructions that always begin a new group should be scheduled when 17*0b57cec5SDimitry Andric // the current decoder group is empty. 18*0b57cec5SDimitry Andric // * Processor resources usage. It is beneficial to balance the use of 19*0b57cec5SDimitry Andric // resources. 20*0b57cec5SDimitry Andric // 21*0b57cec5SDimitry Andric // A goal is to consider all instructions, also those outside of any 22*0b57cec5SDimitry Andric // scheduling region. Such instructions are "advanced" past and include 23*0b57cec5SDimitry Andric // single instructions before a scheduling region, branches etc. 24*0b57cec5SDimitry Andric // 25*0b57cec5SDimitry Andric // A block that has only one predecessor continues scheduling with the state 26*0b57cec5SDimitry Andric // of it (which may be updated by emitting branches). 27*0b57cec5SDimitry Andric // 28*0b57cec5SDimitry Andric // ===---------------------------------------------------------------------===// 29*0b57cec5SDimitry Andric 30*0b57cec5SDimitry Andric #include "SystemZHazardRecognizer.h" 31*0b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h" 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric using namespace llvm; 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric #define DEBUG_TYPE "machine-scheduler" 36*0b57cec5SDimitry Andric 37*0b57cec5SDimitry Andric // This is the limit of processor resource usage at which the 38*0b57cec5SDimitry Andric // scheduler should try to look for other instructions (not using the 39*0b57cec5SDimitry Andric // critical resource). 40*0b57cec5SDimitry Andric static cl::opt<int> ProcResCostLim("procres-cost-lim", cl::Hidden, 41*0b57cec5SDimitry Andric cl::desc("The OOO window for processor " 42*0b57cec5SDimitry Andric "resources during scheduling."), 43*0b57cec5SDimitry Andric cl::init(8)); 44*0b57cec5SDimitry Andric 45*0b57cec5SDimitry Andric unsigned SystemZHazardRecognizer:: 46*0b57cec5SDimitry Andric getNumDecoderSlots(SUnit *SU) const { 47*0b57cec5SDimitry Andric const MCSchedClassDesc *SC = getSchedClass(SU); 48*0b57cec5SDimitry Andric if (!SC->isValid()) 49*0b57cec5SDimitry Andric return 0; // IMPLICIT_DEF / KILL -- will not make impact in output. 50*0b57cec5SDimitry Andric 51*0b57cec5SDimitry Andric assert((SC->NumMicroOps != 2 || (SC->BeginGroup && !SC->EndGroup)) && 52*0b57cec5SDimitry Andric "Only cracked instruction can have 2 uops."); 53*0b57cec5SDimitry Andric assert((SC->NumMicroOps < 3 || (SC->BeginGroup && SC->EndGroup)) && 54*0b57cec5SDimitry Andric "Expanded instructions always group alone."); 55*0b57cec5SDimitry Andric assert((SC->NumMicroOps < 3 || (SC->NumMicroOps % 3 == 0)) && 56*0b57cec5SDimitry Andric "Expanded instructions fill the group(s)."); 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric return SC->NumMicroOps; 59*0b57cec5SDimitry Andric } 60*0b57cec5SDimitry Andric 61*0b57cec5SDimitry Andric unsigned SystemZHazardRecognizer::getCurrCycleIdx(SUnit *SU) const { 62*0b57cec5SDimitry Andric unsigned Idx = CurrGroupSize; 63*0b57cec5SDimitry Andric if (GrpCount % 2) 64*0b57cec5SDimitry Andric Idx += 3; 65*0b57cec5SDimitry Andric 66*0b57cec5SDimitry Andric if (SU != nullptr && !fitsIntoCurrentGroup(SU)) { 67*0b57cec5SDimitry Andric if (Idx == 1 || Idx == 2) 68*0b57cec5SDimitry Andric Idx = 3; 69*0b57cec5SDimitry Andric else if (Idx == 4 || Idx == 5) 70*0b57cec5SDimitry Andric Idx = 0; 71*0b57cec5SDimitry Andric } 72*0b57cec5SDimitry Andric 73*0b57cec5SDimitry Andric return Idx; 74*0b57cec5SDimitry Andric } 75*0b57cec5SDimitry Andric 76*0b57cec5SDimitry Andric ScheduleHazardRecognizer::HazardType SystemZHazardRecognizer:: 77*0b57cec5SDimitry Andric getHazardType(SUnit *m, int Stalls) { 78*0b57cec5SDimitry Andric return (fitsIntoCurrentGroup(m) ? NoHazard : Hazard); 79*0b57cec5SDimitry Andric } 80*0b57cec5SDimitry Andric 81*0b57cec5SDimitry Andric void SystemZHazardRecognizer::Reset() { 82*0b57cec5SDimitry Andric CurrGroupSize = 0; 83*0b57cec5SDimitry Andric CurrGroupHas4RegOps = false; 84*0b57cec5SDimitry Andric clearProcResCounters(); 85*0b57cec5SDimitry Andric GrpCount = 0; 86*0b57cec5SDimitry Andric LastFPdOpCycleIdx = UINT_MAX; 87*0b57cec5SDimitry Andric LastEmittedMI = nullptr; 88*0b57cec5SDimitry Andric LLVM_DEBUG(CurGroupDbg = "";); 89*0b57cec5SDimitry Andric } 90*0b57cec5SDimitry Andric 91*0b57cec5SDimitry Andric bool 92*0b57cec5SDimitry Andric SystemZHazardRecognizer::fitsIntoCurrentGroup(SUnit *SU) const { 93*0b57cec5SDimitry Andric const MCSchedClassDesc *SC = getSchedClass(SU); 94*0b57cec5SDimitry Andric if (!SC->isValid()) 95*0b57cec5SDimitry Andric return true; 96*0b57cec5SDimitry Andric 97*0b57cec5SDimitry Andric // A cracked instruction only fits into schedule if the current 98*0b57cec5SDimitry Andric // group is empty. 99*0b57cec5SDimitry Andric if (SC->BeginGroup) 100*0b57cec5SDimitry Andric return (CurrGroupSize == 0); 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric // An instruction with 4 register operands will not fit in last slot. 103*0b57cec5SDimitry Andric assert ((CurrGroupSize < 2 || !CurrGroupHas4RegOps) && 104*0b57cec5SDimitry Andric "Current decoder group is already full!"); 105*0b57cec5SDimitry Andric if (CurrGroupSize == 2 && has4RegOps(SU->getInstr())) 106*0b57cec5SDimitry Andric return false; 107*0b57cec5SDimitry Andric 108*0b57cec5SDimitry Andric // Since a full group is handled immediately in EmitInstruction(), 109*0b57cec5SDimitry Andric // SU should fit into current group. NumSlots should be 1 or 0, 110*0b57cec5SDimitry Andric // since it is not a cracked or expanded instruction. 111*0b57cec5SDimitry Andric assert ((getNumDecoderSlots(SU) <= 1) && (CurrGroupSize < 3) && 112*0b57cec5SDimitry Andric "Expected normal instruction to fit in non-full group!"); 113*0b57cec5SDimitry Andric 114*0b57cec5SDimitry Andric return true; 115*0b57cec5SDimitry Andric } 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric bool SystemZHazardRecognizer::has4RegOps(const MachineInstr *MI) const { 118*0b57cec5SDimitry Andric const MachineFunction &MF = *MI->getParent()->getParent(); 119*0b57cec5SDimitry Andric const TargetRegisterInfo *TRI = &TII->getRegisterInfo(); 120*0b57cec5SDimitry Andric const MCInstrDesc &MID = MI->getDesc(); 121*0b57cec5SDimitry Andric unsigned Count = 0; 122*0b57cec5SDimitry Andric for (unsigned OpIdx = 0; OpIdx < MID.getNumOperands(); OpIdx++) { 123*0b57cec5SDimitry Andric const TargetRegisterClass *RC = TII->getRegClass(MID, OpIdx, TRI, MF); 124*0b57cec5SDimitry Andric if (RC == nullptr) 125*0b57cec5SDimitry Andric continue; 126*0b57cec5SDimitry Andric if (OpIdx >= MID.getNumDefs() && 127*0b57cec5SDimitry Andric MID.getOperandConstraint(OpIdx, MCOI::TIED_TO) != -1) 128*0b57cec5SDimitry Andric continue; 129*0b57cec5SDimitry Andric Count++; 130*0b57cec5SDimitry Andric } 131*0b57cec5SDimitry Andric return Count >= 4; 132*0b57cec5SDimitry Andric } 133*0b57cec5SDimitry Andric 134*0b57cec5SDimitry Andric void SystemZHazardRecognizer::nextGroup() { 135*0b57cec5SDimitry Andric if (CurrGroupSize == 0) 136*0b57cec5SDimitry Andric return; 137*0b57cec5SDimitry Andric 138*0b57cec5SDimitry Andric LLVM_DEBUG(dumpCurrGroup("Completed decode group")); 139*0b57cec5SDimitry Andric LLVM_DEBUG(CurGroupDbg = "";); 140*0b57cec5SDimitry Andric 141*0b57cec5SDimitry Andric int NumGroups = ((CurrGroupSize > 3) ? (CurrGroupSize / 3) : 1); 142*0b57cec5SDimitry Andric assert((CurrGroupSize <= 3 || CurrGroupSize % 3 == 0) && 143*0b57cec5SDimitry Andric "Current decoder group bad."); 144*0b57cec5SDimitry Andric 145*0b57cec5SDimitry Andric // Reset counter for next group. 146*0b57cec5SDimitry Andric CurrGroupSize = 0; 147*0b57cec5SDimitry Andric CurrGroupHas4RegOps = false; 148*0b57cec5SDimitry Andric 149*0b57cec5SDimitry Andric GrpCount += ((unsigned) NumGroups); 150*0b57cec5SDimitry Andric 151*0b57cec5SDimitry Andric // Decrease counters for execution units. 152*0b57cec5SDimitry Andric for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i) 153*0b57cec5SDimitry Andric ProcResourceCounters[i] = ((ProcResourceCounters[i] > NumGroups) 154*0b57cec5SDimitry Andric ? (ProcResourceCounters[i] - NumGroups) 155*0b57cec5SDimitry Andric : 0); 156*0b57cec5SDimitry Andric 157*0b57cec5SDimitry Andric // Clear CriticalResourceIdx if it is now below the threshold. 158*0b57cec5SDimitry Andric if (CriticalResourceIdx != UINT_MAX && 159*0b57cec5SDimitry Andric (ProcResourceCounters[CriticalResourceIdx] <= 160*0b57cec5SDimitry Andric ProcResCostLim)) 161*0b57cec5SDimitry Andric CriticalResourceIdx = UINT_MAX; 162*0b57cec5SDimitry Andric 163*0b57cec5SDimitry Andric LLVM_DEBUG(dumpState();); 164*0b57cec5SDimitry Andric } 165*0b57cec5SDimitry Andric 166*0b57cec5SDimitry Andric #ifndef NDEBUG // Debug output 167*0b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpSU(SUnit *SU, raw_ostream &OS) const { 168*0b57cec5SDimitry Andric OS << "SU(" << SU->NodeNum << "):"; 169*0b57cec5SDimitry Andric OS << TII->getName(SU->getInstr()->getOpcode()); 170*0b57cec5SDimitry Andric 171*0b57cec5SDimitry Andric const MCSchedClassDesc *SC = getSchedClass(SU); 172*0b57cec5SDimitry Andric if (!SC->isValid()) 173*0b57cec5SDimitry Andric return; 174*0b57cec5SDimitry Andric 175*0b57cec5SDimitry Andric for (TargetSchedModel::ProcResIter 176*0b57cec5SDimitry Andric PI = SchedModel->getWriteProcResBegin(SC), 177*0b57cec5SDimitry Andric PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) { 178*0b57cec5SDimitry Andric const MCProcResourceDesc &PRD = 179*0b57cec5SDimitry Andric *SchedModel->getProcResource(PI->ProcResourceIdx); 180*0b57cec5SDimitry Andric std::string FU(PRD.Name); 181*0b57cec5SDimitry Andric // trim e.g. Z13_FXaUnit -> FXa 182*0b57cec5SDimitry Andric FU = FU.substr(FU.find("_") + 1); 183*0b57cec5SDimitry Andric size_t Pos = FU.find("Unit"); 184*0b57cec5SDimitry Andric if (Pos != std::string::npos) 185*0b57cec5SDimitry Andric FU.resize(Pos); 186*0b57cec5SDimitry Andric if (FU == "LS") // LSUnit -> LSU 187*0b57cec5SDimitry Andric FU = "LSU"; 188*0b57cec5SDimitry Andric OS << "/" << FU; 189*0b57cec5SDimitry Andric 190*0b57cec5SDimitry Andric if (PI->Cycles > 1) 191*0b57cec5SDimitry Andric OS << "(" << PI->Cycles << "cyc)"; 192*0b57cec5SDimitry Andric } 193*0b57cec5SDimitry Andric 194*0b57cec5SDimitry Andric if (SC->NumMicroOps > 1) 195*0b57cec5SDimitry Andric OS << "/" << SC->NumMicroOps << "uops"; 196*0b57cec5SDimitry Andric if (SC->BeginGroup && SC->EndGroup) 197*0b57cec5SDimitry Andric OS << "/GroupsAlone"; 198*0b57cec5SDimitry Andric else if (SC->BeginGroup) 199*0b57cec5SDimitry Andric OS << "/BeginsGroup"; 200*0b57cec5SDimitry Andric else if (SC->EndGroup) 201*0b57cec5SDimitry Andric OS << "/EndsGroup"; 202*0b57cec5SDimitry Andric if (SU->isUnbuffered) 203*0b57cec5SDimitry Andric OS << "/Unbuffered"; 204*0b57cec5SDimitry Andric if (has4RegOps(SU->getInstr())) 205*0b57cec5SDimitry Andric OS << "/4RegOps"; 206*0b57cec5SDimitry Andric } 207*0b57cec5SDimitry Andric 208*0b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpCurrGroup(std::string Msg) const { 209*0b57cec5SDimitry Andric dbgs() << "++ " << Msg; 210*0b57cec5SDimitry Andric dbgs() << ": "; 211*0b57cec5SDimitry Andric 212*0b57cec5SDimitry Andric if (CurGroupDbg.empty()) 213*0b57cec5SDimitry Andric dbgs() << " <empty>\n"; 214*0b57cec5SDimitry Andric else { 215*0b57cec5SDimitry Andric dbgs() << "{ " << CurGroupDbg << " }"; 216*0b57cec5SDimitry Andric dbgs() << " (" << CurrGroupSize << " decoder slot" 217*0b57cec5SDimitry Andric << (CurrGroupSize > 1 ? "s":"") 218*0b57cec5SDimitry Andric << (CurrGroupHas4RegOps ? ", 4RegOps" : "") 219*0b57cec5SDimitry Andric << ")\n"; 220*0b57cec5SDimitry Andric } 221*0b57cec5SDimitry Andric } 222*0b57cec5SDimitry Andric 223*0b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpProcResourceCounters() const { 224*0b57cec5SDimitry Andric bool any = false; 225*0b57cec5SDimitry Andric 226*0b57cec5SDimitry Andric for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i) 227*0b57cec5SDimitry Andric if (ProcResourceCounters[i] > 0) { 228*0b57cec5SDimitry Andric any = true; 229*0b57cec5SDimitry Andric break; 230*0b57cec5SDimitry Andric } 231*0b57cec5SDimitry Andric 232*0b57cec5SDimitry Andric if (!any) 233*0b57cec5SDimitry Andric return; 234*0b57cec5SDimitry Andric 235*0b57cec5SDimitry Andric dbgs() << "++ | Resource counters: "; 236*0b57cec5SDimitry Andric for (unsigned i = 0; i < SchedModel->getNumProcResourceKinds(); ++i) 237*0b57cec5SDimitry Andric if (ProcResourceCounters[i] > 0) 238*0b57cec5SDimitry Andric dbgs() << SchedModel->getProcResource(i)->Name 239*0b57cec5SDimitry Andric << ":" << ProcResourceCounters[i] << " "; 240*0b57cec5SDimitry Andric dbgs() << "\n"; 241*0b57cec5SDimitry Andric 242*0b57cec5SDimitry Andric if (CriticalResourceIdx != UINT_MAX) 243*0b57cec5SDimitry Andric dbgs() << "++ | Critical resource: " 244*0b57cec5SDimitry Andric << SchedModel->getProcResource(CriticalResourceIdx)->Name 245*0b57cec5SDimitry Andric << "\n"; 246*0b57cec5SDimitry Andric } 247*0b57cec5SDimitry Andric 248*0b57cec5SDimitry Andric void SystemZHazardRecognizer::dumpState() const { 249*0b57cec5SDimitry Andric dumpCurrGroup("| Current decoder group"); 250*0b57cec5SDimitry Andric dbgs() << "++ | Current cycle index: " 251*0b57cec5SDimitry Andric << getCurrCycleIdx() << "\n"; 252*0b57cec5SDimitry Andric dumpProcResourceCounters(); 253*0b57cec5SDimitry Andric if (LastFPdOpCycleIdx != UINT_MAX) 254*0b57cec5SDimitry Andric dbgs() << "++ | Last FPd cycle index: " << LastFPdOpCycleIdx << "\n"; 255*0b57cec5SDimitry Andric } 256*0b57cec5SDimitry Andric 257*0b57cec5SDimitry Andric #endif //NDEBUG 258*0b57cec5SDimitry Andric 259*0b57cec5SDimitry Andric void SystemZHazardRecognizer::clearProcResCounters() { 260*0b57cec5SDimitry Andric ProcResourceCounters.assign(SchedModel->getNumProcResourceKinds(), 0); 261*0b57cec5SDimitry Andric CriticalResourceIdx = UINT_MAX; 262*0b57cec5SDimitry Andric } 263*0b57cec5SDimitry Andric 264*0b57cec5SDimitry Andric static inline bool isBranchRetTrap(MachineInstr *MI) { 265*0b57cec5SDimitry Andric return (MI->isBranch() || MI->isReturn() || 266*0b57cec5SDimitry Andric MI->getOpcode() == SystemZ::CondTrap); 267*0b57cec5SDimitry Andric } 268*0b57cec5SDimitry Andric 269*0b57cec5SDimitry Andric // Update state with SU as the next scheduled unit. 270*0b57cec5SDimitry Andric void SystemZHazardRecognizer:: 271*0b57cec5SDimitry Andric EmitInstruction(SUnit *SU) { 272*0b57cec5SDimitry Andric const MCSchedClassDesc *SC = getSchedClass(SU); 273*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "++ HazardRecognizer emitting "; dumpSU(SU, dbgs()); 274*0b57cec5SDimitry Andric dbgs() << "\n";); 275*0b57cec5SDimitry Andric LLVM_DEBUG(dumpCurrGroup("Decode group before emission");); 276*0b57cec5SDimitry Andric 277*0b57cec5SDimitry Andric // If scheduling an SU that must begin a new decoder group, move on 278*0b57cec5SDimitry Andric // to next group. 279*0b57cec5SDimitry Andric if (!fitsIntoCurrentGroup(SU)) 280*0b57cec5SDimitry Andric nextGroup(); 281*0b57cec5SDimitry Andric 282*0b57cec5SDimitry Andric LLVM_DEBUG(raw_string_ostream cgd(CurGroupDbg); 283*0b57cec5SDimitry Andric if (CurGroupDbg.length()) cgd << ", "; dumpSU(SU, cgd);); 284*0b57cec5SDimitry Andric 285*0b57cec5SDimitry Andric LastEmittedMI = SU->getInstr(); 286*0b57cec5SDimitry Andric 287*0b57cec5SDimitry Andric // After returning from a call, we don't know much about the state. 288*0b57cec5SDimitry Andric if (SU->isCall) { 289*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "++ Clearing state after call.\n";); 290*0b57cec5SDimitry Andric Reset(); 291*0b57cec5SDimitry Andric LastEmittedMI = SU->getInstr(); 292*0b57cec5SDimitry Andric return; 293*0b57cec5SDimitry Andric } 294*0b57cec5SDimitry Andric 295*0b57cec5SDimitry Andric // Increase counter for execution unit(s). 296*0b57cec5SDimitry Andric for (TargetSchedModel::ProcResIter 297*0b57cec5SDimitry Andric PI = SchedModel->getWriteProcResBegin(SC), 298*0b57cec5SDimitry Andric PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) { 299*0b57cec5SDimitry Andric // Don't handle FPd together with the other resources. 300*0b57cec5SDimitry Andric if (SchedModel->getProcResource(PI->ProcResourceIdx)->BufferSize == 1) 301*0b57cec5SDimitry Andric continue; 302*0b57cec5SDimitry Andric int &CurrCounter = 303*0b57cec5SDimitry Andric ProcResourceCounters[PI->ProcResourceIdx]; 304*0b57cec5SDimitry Andric CurrCounter += PI->Cycles; 305*0b57cec5SDimitry Andric // Check if this is now the new critical resource. 306*0b57cec5SDimitry Andric if ((CurrCounter > ProcResCostLim) && 307*0b57cec5SDimitry Andric (CriticalResourceIdx == UINT_MAX || 308*0b57cec5SDimitry Andric (PI->ProcResourceIdx != CriticalResourceIdx && 309*0b57cec5SDimitry Andric CurrCounter > 310*0b57cec5SDimitry Andric ProcResourceCounters[CriticalResourceIdx]))) { 311*0b57cec5SDimitry Andric LLVM_DEBUG( 312*0b57cec5SDimitry Andric dbgs() << "++ New critical resource: " 313*0b57cec5SDimitry Andric << SchedModel->getProcResource(PI->ProcResourceIdx)->Name 314*0b57cec5SDimitry Andric << "\n";); 315*0b57cec5SDimitry Andric CriticalResourceIdx = PI->ProcResourceIdx; 316*0b57cec5SDimitry Andric } 317*0b57cec5SDimitry Andric } 318*0b57cec5SDimitry Andric 319*0b57cec5SDimitry Andric // Make note of an instruction that uses a blocking resource (FPd). 320*0b57cec5SDimitry Andric if (SU->isUnbuffered) { 321*0b57cec5SDimitry Andric LastFPdOpCycleIdx = getCurrCycleIdx(SU); 322*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "++ Last FPd cycle index: " << LastFPdOpCycleIdx 323*0b57cec5SDimitry Andric << "\n";); 324*0b57cec5SDimitry Andric } 325*0b57cec5SDimitry Andric 326*0b57cec5SDimitry Andric // Insert SU into current group by increasing number of slots used 327*0b57cec5SDimitry Andric // in current group. 328*0b57cec5SDimitry Andric CurrGroupSize += getNumDecoderSlots(SU); 329*0b57cec5SDimitry Andric CurrGroupHas4RegOps |= has4RegOps(SU->getInstr()); 330*0b57cec5SDimitry Andric unsigned GroupLim = (CurrGroupHas4RegOps ? 2 : 3); 331*0b57cec5SDimitry Andric assert((CurrGroupSize <= GroupLim || CurrGroupSize == getNumDecoderSlots(SU)) 332*0b57cec5SDimitry Andric && "SU does not fit into decoder group!"); 333*0b57cec5SDimitry Andric 334*0b57cec5SDimitry Andric // Check if current group is now full/ended. If so, move on to next 335*0b57cec5SDimitry Andric // group to be ready to evaluate more candidates. 336*0b57cec5SDimitry Andric if (CurrGroupSize >= GroupLim || SC->EndGroup) 337*0b57cec5SDimitry Andric nextGroup(); 338*0b57cec5SDimitry Andric } 339*0b57cec5SDimitry Andric 340*0b57cec5SDimitry Andric int SystemZHazardRecognizer::groupingCost(SUnit *SU) const { 341*0b57cec5SDimitry Andric const MCSchedClassDesc *SC = getSchedClass(SU); 342*0b57cec5SDimitry Andric if (!SC->isValid()) 343*0b57cec5SDimitry Andric return 0; 344*0b57cec5SDimitry Andric 345*0b57cec5SDimitry Andric // If SU begins new group, it can either break a current group early 346*0b57cec5SDimitry Andric // or fit naturally if current group is empty (negative cost). 347*0b57cec5SDimitry Andric if (SC->BeginGroup) { 348*0b57cec5SDimitry Andric if (CurrGroupSize) 349*0b57cec5SDimitry Andric return 3 - CurrGroupSize; 350*0b57cec5SDimitry Andric return -1; 351*0b57cec5SDimitry Andric } 352*0b57cec5SDimitry Andric 353*0b57cec5SDimitry Andric // Similarly, a group-ending SU may either fit well (last in group), or 354*0b57cec5SDimitry Andric // end the group prematurely. 355*0b57cec5SDimitry Andric if (SC->EndGroup) { 356*0b57cec5SDimitry Andric unsigned resultingGroupSize = 357*0b57cec5SDimitry Andric (CurrGroupSize + getNumDecoderSlots(SU)); 358*0b57cec5SDimitry Andric if (resultingGroupSize < 3) 359*0b57cec5SDimitry Andric return (3 - resultingGroupSize); 360*0b57cec5SDimitry Andric return -1; 361*0b57cec5SDimitry Andric } 362*0b57cec5SDimitry Andric 363*0b57cec5SDimitry Andric // An instruction with 4 register operands will not fit in last slot. 364*0b57cec5SDimitry Andric if (CurrGroupSize == 2 && has4RegOps(SU->getInstr())) 365*0b57cec5SDimitry Andric return 1; 366*0b57cec5SDimitry Andric 367*0b57cec5SDimitry Andric // Most instructions can be placed in any decoder slot. 368*0b57cec5SDimitry Andric return 0; 369*0b57cec5SDimitry Andric } 370*0b57cec5SDimitry Andric 371*0b57cec5SDimitry Andric bool SystemZHazardRecognizer::isFPdOpPreferred_distance(SUnit *SU) const { 372*0b57cec5SDimitry Andric assert (SU->isUnbuffered); 373*0b57cec5SDimitry Andric // If this is the first FPd op, it should be scheduled high. 374*0b57cec5SDimitry Andric if (LastFPdOpCycleIdx == UINT_MAX) 375*0b57cec5SDimitry Andric return true; 376*0b57cec5SDimitry Andric // If this is not the first PFd op, it should go into the other side 377*0b57cec5SDimitry Andric // of the processor to use the other FPd unit there. This should 378*0b57cec5SDimitry Andric // generally happen if two FPd ops are placed with 2 other 379*0b57cec5SDimitry Andric // instructions between them (modulo 6). 380*0b57cec5SDimitry Andric unsigned SUCycleIdx = getCurrCycleIdx(SU); 381*0b57cec5SDimitry Andric if (LastFPdOpCycleIdx > SUCycleIdx) 382*0b57cec5SDimitry Andric return ((LastFPdOpCycleIdx - SUCycleIdx) == 3); 383*0b57cec5SDimitry Andric return ((SUCycleIdx - LastFPdOpCycleIdx) == 3); 384*0b57cec5SDimitry Andric } 385*0b57cec5SDimitry Andric 386*0b57cec5SDimitry Andric int SystemZHazardRecognizer:: 387*0b57cec5SDimitry Andric resourcesCost(SUnit *SU) { 388*0b57cec5SDimitry Andric int Cost = 0; 389*0b57cec5SDimitry Andric 390*0b57cec5SDimitry Andric const MCSchedClassDesc *SC = getSchedClass(SU); 391*0b57cec5SDimitry Andric if (!SC->isValid()) 392*0b57cec5SDimitry Andric return 0; 393*0b57cec5SDimitry Andric 394*0b57cec5SDimitry Andric // For a FPd op, either return min or max value as indicated by the 395*0b57cec5SDimitry Andric // distance to any prior FPd op. 396*0b57cec5SDimitry Andric if (SU->isUnbuffered) 397*0b57cec5SDimitry Andric Cost = (isFPdOpPreferred_distance(SU) ? INT_MIN : INT_MAX); 398*0b57cec5SDimitry Andric // For other instructions, give a cost to the use of the critical resource. 399*0b57cec5SDimitry Andric else if (CriticalResourceIdx != UINT_MAX) { 400*0b57cec5SDimitry Andric for (TargetSchedModel::ProcResIter 401*0b57cec5SDimitry Andric PI = SchedModel->getWriteProcResBegin(SC), 402*0b57cec5SDimitry Andric PE = SchedModel->getWriteProcResEnd(SC); PI != PE; ++PI) 403*0b57cec5SDimitry Andric if (PI->ProcResourceIdx == CriticalResourceIdx) 404*0b57cec5SDimitry Andric Cost = PI->Cycles; 405*0b57cec5SDimitry Andric } 406*0b57cec5SDimitry Andric 407*0b57cec5SDimitry Andric return Cost; 408*0b57cec5SDimitry Andric } 409*0b57cec5SDimitry Andric 410*0b57cec5SDimitry Andric void SystemZHazardRecognizer::emitInstruction(MachineInstr *MI, 411*0b57cec5SDimitry Andric bool TakenBranch) { 412*0b57cec5SDimitry Andric // Make a temporary SUnit. 413*0b57cec5SDimitry Andric SUnit SU(MI, 0); 414*0b57cec5SDimitry Andric 415*0b57cec5SDimitry Andric // Set interesting flags. 416*0b57cec5SDimitry Andric SU.isCall = MI->isCall(); 417*0b57cec5SDimitry Andric 418*0b57cec5SDimitry Andric const MCSchedClassDesc *SC = SchedModel->resolveSchedClass(MI); 419*0b57cec5SDimitry Andric for (const MCWriteProcResEntry &PRE : 420*0b57cec5SDimitry Andric make_range(SchedModel->getWriteProcResBegin(SC), 421*0b57cec5SDimitry Andric SchedModel->getWriteProcResEnd(SC))) { 422*0b57cec5SDimitry Andric switch (SchedModel->getProcResource(PRE.ProcResourceIdx)->BufferSize) { 423*0b57cec5SDimitry Andric case 0: 424*0b57cec5SDimitry Andric SU.hasReservedResource = true; 425*0b57cec5SDimitry Andric break; 426*0b57cec5SDimitry Andric case 1: 427*0b57cec5SDimitry Andric SU.isUnbuffered = true; 428*0b57cec5SDimitry Andric break; 429*0b57cec5SDimitry Andric default: 430*0b57cec5SDimitry Andric break; 431*0b57cec5SDimitry Andric } 432*0b57cec5SDimitry Andric } 433*0b57cec5SDimitry Andric 434*0b57cec5SDimitry Andric unsigned GroupSizeBeforeEmit = CurrGroupSize; 435*0b57cec5SDimitry Andric EmitInstruction(&SU); 436*0b57cec5SDimitry Andric 437*0b57cec5SDimitry Andric if (!TakenBranch && isBranchRetTrap(MI)) { 438*0b57cec5SDimitry Andric // NT Branch on second slot ends group. 439*0b57cec5SDimitry Andric if (GroupSizeBeforeEmit == 1) 440*0b57cec5SDimitry Andric nextGroup(); 441*0b57cec5SDimitry Andric } 442*0b57cec5SDimitry Andric 443*0b57cec5SDimitry Andric if (TakenBranch && CurrGroupSize > 0) 444*0b57cec5SDimitry Andric nextGroup(); 445*0b57cec5SDimitry Andric 446*0b57cec5SDimitry Andric assert ((!MI->isTerminator() || isBranchRetTrap(MI)) && 447*0b57cec5SDimitry Andric "Scheduler: unhandled terminator!"); 448*0b57cec5SDimitry Andric } 449*0b57cec5SDimitry Andric 450*0b57cec5SDimitry Andric void SystemZHazardRecognizer:: 451*0b57cec5SDimitry Andric copyState(SystemZHazardRecognizer *Incoming) { 452*0b57cec5SDimitry Andric // Current decoder group 453*0b57cec5SDimitry Andric CurrGroupSize = Incoming->CurrGroupSize; 454*0b57cec5SDimitry Andric LLVM_DEBUG(CurGroupDbg = Incoming->CurGroupDbg;); 455*0b57cec5SDimitry Andric 456*0b57cec5SDimitry Andric // Processor resources 457*0b57cec5SDimitry Andric ProcResourceCounters = Incoming->ProcResourceCounters; 458*0b57cec5SDimitry Andric CriticalResourceIdx = Incoming->CriticalResourceIdx; 459*0b57cec5SDimitry Andric 460*0b57cec5SDimitry Andric // FPd 461*0b57cec5SDimitry Andric LastFPdOpCycleIdx = Incoming->LastFPdOpCycleIdx; 462*0b57cec5SDimitry Andric GrpCount = Incoming->GrpCount; 463*0b57cec5SDimitry Andric } 464