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