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 declares 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 #ifndef LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H 31*0b57cec5SDimitry Andric #define LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H 32*0b57cec5SDimitry Andric 33*0b57cec5SDimitry Andric #include "SystemZSubtarget.h" 34*0b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h" 35*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 36*0b57cec5SDimitry Andric #include "llvm/CodeGen/MachineScheduler.h" 37*0b57cec5SDimitry Andric #include "llvm/CodeGen/ScheduleHazardRecognizer.h" 38*0b57cec5SDimitry Andric #include "llvm/MC/MCInstrDesc.h" 39*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 40*0b57cec5SDimitry Andric #include <string> 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric namespace llvm { 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric /// SystemZHazardRecognizer maintains the state for one MBB during scheduling. 45*0b57cec5SDimitry Andric class SystemZHazardRecognizer : public ScheduleHazardRecognizer { 46*0b57cec5SDimitry Andric 47*0b57cec5SDimitry Andric const SystemZInstrInfo *TII; 48*0b57cec5SDimitry Andric const TargetSchedModel *SchedModel; 49*0b57cec5SDimitry Andric 50*0b57cec5SDimitry Andric /// Keep track of the number of decoder slots used in the current 51*0b57cec5SDimitry Andric /// decoder group. 52*0b57cec5SDimitry Andric unsigned CurrGroupSize; 53*0b57cec5SDimitry Andric 54*0b57cec5SDimitry Andric /// True if an instruction with four reg operands have been scheduled into 55*0b57cec5SDimitry Andric /// the current decoder group. 56*0b57cec5SDimitry Andric bool CurrGroupHas4RegOps; 57*0b57cec5SDimitry Andric 58*0b57cec5SDimitry Andric /// The tracking of resources here are quite similar to the common 59*0b57cec5SDimitry Andric /// code use of a critical resource. However, z13 differs in the way 60*0b57cec5SDimitry Andric /// that it has two processor sides which may be interesting to 61*0b57cec5SDimitry Andric /// model in the future (a work in progress). 62*0b57cec5SDimitry Andric 63*0b57cec5SDimitry Andric /// Counters for the number of uops scheduled per processor 64*0b57cec5SDimitry Andric /// resource. 65*0b57cec5SDimitry Andric SmallVector<int, 0> ProcResourceCounters; 66*0b57cec5SDimitry Andric 67*0b57cec5SDimitry Andric /// This is the resource with the greatest queue, which the 68*0b57cec5SDimitry Andric /// scheduler tries to avoid. 69*0b57cec5SDimitry Andric unsigned CriticalResourceIdx; 70*0b57cec5SDimitry Andric 71*0b57cec5SDimitry Andric /// Return the number of decoder slots MI requires. 72*0b57cec5SDimitry Andric inline unsigned getNumDecoderSlots(SUnit *SU) const; 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric /// Return true if MI fits into current decoder group. 75*0b57cec5SDimitry Andric bool fitsIntoCurrentGroup(SUnit *SU) const; 76*0b57cec5SDimitry Andric 77*0b57cec5SDimitry Andric /// Return true if this instruction has four register operands. 78*0b57cec5SDimitry Andric bool has4RegOps(const MachineInstr *MI) const; 79*0b57cec5SDimitry Andric 80*0b57cec5SDimitry Andric /// Two decoder groups per cycle are formed (for z13), meaning 2x3 81*0b57cec5SDimitry Andric /// instructions. This function returns a number between 0 and 5, 82*0b57cec5SDimitry Andric /// representing the current decoder slot of the current cycle. If an SU 83*0b57cec5SDimitry Andric /// is passed which will begin a new decoder group, the returned value is 84*0b57cec5SDimitry Andric /// the cycle index of the next group. 85*0b57cec5SDimitry Andric unsigned getCurrCycleIdx(SUnit *SU = nullptr) const; 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric /// LastFPdOpCycleIdx stores the numbeer returned by getCurrCycleIdx() 88*0b57cec5SDimitry Andric /// when a stalling operation is scheduled (which uses the FPd resource). 89*0b57cec5SDimitry Andric unsigned LastFPdOpCycleIdx; 90*0b57cec5SDimitry Andric 91*0b57cec5SDimitry Andric /// A counter of decoder groups scheduled. 92*0b57cec5SDimitry Andric unsigned GrpCount; 93*0b57cec5SDimitry Andric 94*0b57cec5SDimitry Andric unsigned getCurrGroupSize() {return CurrGroupSize;}; 95*0b57cec5SDimitry Andric 96*0b57cec5SDimitry Andric /// Start next decoder group. 97*0b57cec5SDimitry Andric void nextGroup(); 98*0b57cec5SDimitry Andric 99*0b57cec5SDimitry Andric /// Clear all counters for processor resources. 100*0b57cec5SDimitry Andric void clearProcResCounters(); 101*0b57cec5SDimitry Andric 102*0b57cec5SDimitry Andric /// With the goal of alternating processor sides for stalling (FPd) 103*0b57cec5SDimitry Andric /// ops, return true if it seems good to schedule an FPd op next. 104*0b57cec5SDimitry Andric bool isFPdOpPreferred_distance(SUnit *SU) const; 105*0b57cec5SDimitry Andric 106*0b57cec5SDimitry Andric /// Last emitted instruction or nullptr. 107*0b57cec5SDimitry Andric MachineInstr *LastEmittedMI; 108*0b57cec5SDimitry Andric 109*0b57cec5SDimitry Andric public: 110*0b57cec5SDimitry Andric SystemZHazardRecognizer(const SystemZInstrInfo *tii, 111*0b57cec5SDimitry Andric const TargetSchedModel *SM) 112*0b57cec5SDimitry Andric : TII(tii), SchedModel(SM) { 113*0b57cec5SDimitry Andric Reset(); 114*0b57cec5SDimitry Andric } 115*0b57cec5SDimitry Andric 116*0b57cec5SDimitry Andric HazardType getHazardType(SUnit *m, int Stalls = 0) override; 117*0b57cec5SDimitry Andric void Reset() override; 118*0b57cec5SDimitry Andric void EmitInstruction(SUnit *SU) override; 119*0b57cec5SDimitry Andric 120*0b57cec5SDimitry Andric /// Resolves and cache a resolved scheduling class for an SUnit. 121*0b57cec5SDimitry Andric const MCSchedClassDesc *getSchedClass(SUnit *SU) const { 122*0b57cec5SDimitry Andric if (!SU->SchedClass && SchedModel->hasInstrSchedModel()) 123*0b57cec5SDimitry Andric SU->SchedClass = SchedModel->resolveSchedClass(SU->getInstr()); 124*0b57cec5SDimitry Andric return SU->SchedClass; 125*0b57cec5SDimitry Andric } 126*0b57cec5SDimitry Andric 127*0b57cec5SDimitry Andric /// Wrap a non-scheduled instruction in an SU and emit it. 128*0b57cec5SDimitry Andric void emitInstruction(MachineInstr *MI, bool TakenBranch = false); 129*0b57cec5SDimitry Andric 130*0b57cec5SDimitry Andric // Cost functions used by SystemZPostRASchedStrategy while 131*0b57cec5SDimitry Andric // evaluating candidates. 132*0b57cec5SDimitry Andric 133*0b57cec5SDimitry Andric /// Return the cost of decoder grouping for SU. If SU must start a 134*0b57cec5SDimitry Andric /// new decoder group, this is negative if this fits the schedule or 135*0b57cec5SDimitry Andric /// positive if it would mean ending a group prematurely. For normal 136*0b57cec5SDimitry Andric /// instructions this returns 0. 137*0b57cec5SDimitry Andric int groupingCost(SUnit *SU) const; 138*0b57cec5SDimitry Andric 139*0b57cec5SDimitry Andric /// Return the cost of SU in regards to processor resources usage. 140*0b57cec5SDimitry Andric /// A positive value means it would be better to wait with SU, while 141*0b57cec5SDimitry Andric /// a negative value means it would be good to schedule SU next. 142*0b57cec5SDimitry Andric int resourcesCost(SUnit *SU); 143*0b57cec5SDimitry Andric 144*0b57cec5SDimitry Andric #ifndef NDEBUG 145*0b57cec5SDimitry Andric // Debug dumping. 146*0b57cec5SDimitry Andric std::string CurGroupDbg; // current group as text 147*0b57cec5SDimitry Andric void dumpSU(SUnit *SU, raw_ostream &OS) const; 148*0b57cec5SDimitry Andric void dumpCurrGroup(std::string Msg = "") const; 149*0b57cec5SDimitry Andric void dumpProcResourceCounters() const; 150*0b57cec5SDimitry Andric void dumpState() const; 151*0b57cec5SDimitry Andric #endif 152*0b57cec5SDimitry Andric 153*0b57cec5SDimitry Andric MachineBasicBlock::iterator getLastEmittedMI() { return LastEmittedMI; } 154*0b57cec5SDimitry Andric 155*0b57cec5SDimitry Andric /// Copy counters from end of single predecessor. 156*0b57cec5SDimitry Andric void copyState(SystemZHazardRecognizer *Incoming); 157*0b57cec5SDimitry Andric }; 158*0b57cec5SDimitry Andric 159*0b57cec5SDimitry Andric } // namespace llvm 160*0b57cec5SDimitry Andric 161*0b57cec5SDimitry Andric #endif /* LLVM_LIB_TARGET_SYSTEMZ_SYSTEMZHAZARDRECOGNIZER_H */ 162