1 //===- llvm/MC/MCInstrItineraries.h - Scheduling ----------------*- 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 describes the structures used for instruction 10 // itineraries, stages, and operand reads/writes. This is used by 11 // schedulers to determine instruction stages and latencies. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_MC_MCINSTRITINERARIES_H 16 #define LLVM_MC_MCINSTRITINERARIES_H 17 18 #include "llvm/MC/MCSchedule.h" 19 #include <algorithm> 20 21 namespace llvm { 22 23 //===----------------------------------------------------------------------===// 24 /// These values represent a non-pipelined step in 25 /// the execution of an instruction. Cycles represents the number of 26 /// discrete time slots needed to complete the stage. Units represent 27 /// the choice of functional units that can be used to complete the 28 /// stage. Eg. IntUnit1, IntUnit2. NextCycles indicates how many 29 /// cycles should elapse from the start of this stage to the start of 30 /// the next stage in the itinerary. A value of -1 indicates that the 31 /// next stage should start immediately after the current one. 32 /// For example: 33 /// 34 /// { 1, x, -1 } 35 /// indicates that the stage occupies FU x for 1 cycle and that 36 /// the next stage starts immediately after this one. 37 /// 38 /// { 2, x|y, 1 } 39 /// indicates that the stage occupies either FU x or FU y for 2 40 /// consecutive cycles and that the next stage starts one cycle 41 /// after this stage starts. That is, the stage requirements 42 /// overlap in time. 43 /// 44 /// { 1, x, 0 } 45 /// indicates that the stage occupies FU x for 1 cycle and that 46 /// the next stage starts in this same cycle. This can be used to 47 /// indicate that the instruction requires multiple stages at the 48 /// same time. 49 /// 50 /// FU reservation can be of two different kinds: 51 /// - FUs which instruction actually requires 52 /// - FUs which instruction just reserves. Reserved unit is not available for 53 /// execution of other instruction. However, several instructions can reserve 54 /// the same unit several times. 55 /// Such two types of units reservation is used to model instruction domain 56 /// change stalls, FUs using the same resource (e.g. same register file), etc. 57 58 struct InstrStage { 59 enum ReservationKinds { 60 Required = 0, 61 Reserved = 1 62 }; 63 64 unsigned Cycles_; ///< Length of stage in machine cycles 65 unsigned Units_; ///< Choice of functional units 66 int NextCycles_; ///< Number of machine cycles to next stage 67 ReservationKinds Kind_; ///< Kind of the FU reservation 68 69 /// Returns the number of cycles the stage is occupied. getCyclesInstrStage70 unsigned getCycles() const { 71 return Cycles_; 72 } 73 74 /// Returns the choice of FUs. getUnitsInstrStage75 unsigned getUnits() const { 76 return Units_; 77 } 78 getReservationKindInstrStage79 ReservationKinds getReservationKind() const { 80 return Kind_; 81 } 82 83 /// Returns the number of cycles from the start of this stage to the 84 /// start of the next stage in the itinerary getNextCyclesInstrStage85 unsigned getNextCycles() const { 86 return (NextCycles_ >= 0) ? (unsigned)NextCycles_ : Cycles_; 87 } 88 }; 89 90 //===----------------------------------------------------------------------===// 91 /// An itinerary represents the scheduling information for an instruction. 92 /// This includes a set of stages occupied by the instruction and the pipeline 93 /// cycle in which operands are read and written. 94 /// 95 struct InstrItinerary { 96 int16_t NumMicroOps; ///< # of micro-ops, -1 means it's variable 97 uint16_t FirstStage; ///< Index of first stage in itinerary 98 uint16_t LastStage; ///< Index of last + 1 stage in itinerary 99 uint16_t FirstOperandCycle; ///< Index of first operand rd/wr 100 uint16_t LastOperandCycle; ///< Index of last + 1 operand rd/wr 101 }; 102 103 //===----------------------------------------------------------------------===// 104 /// Itinerary data supplied by a subtarget to be used by a target. 105 /// 106 class InstrItineraryData { 107 public: 108 MCSchedModel SchedModel = 109 MCSchedModel::GetDefaultSchedModel(); ///< Basic machine properties. 110 const InstrStage *Stages = nullptr; ///< Array of stages selected 111 const unsigned *OperandCycles = nullptr; ///< Array of operand cycles selected 112 const unsigned *Forwardings = nullptr; ///< Array of pipeline forwarding paths 113 const InstrItinerary *Itineraries = 114 nullptr; ///< Array of itineraries selected 115 116 InstrItineraryData() = default; InstrItineraryData(const MCSchedModel & SM,const InstrStage * S,const unsigned * OS,const unsigned * F)117 InstrItineraryData(const MCSchedModel &SM, const InstrStage *S, 118 const unsigned *OS, const unsigned *F) 119 : SchedModel(SM), Stages(S), OperandCycles(OS), Forwardings(F), 120 Itineraries(SchedModel.InstrItineraries) {} 121 122 /// Returns true if there are no itineraries. isEmpty()123 bool isEmpty() const { return Itineraries == nullptr; } 124 125 /// Returns true if the index is for the end marker itinerary. isEndMarker(unsigned ItinClassIndx)126 bool isEndMarker(unsigned ItinClassIndx) const { 127 return ((Itineraries[ItinClassIndx].FirstStage == UINT16_MAX) && 128 (Itineraries[ItinClassIndx].LastStage == UINT16_MAX)); 129 } 130 131 /// Return the first stage of the itinerary. beginStage(unsigned ItinClassIndx)132 const InstrStage *beginStage(unsigned ItinClassIndx) const { 133 unsigned StageIdx = Itineraries[ItinClassIndx].FirstStage; 134 return Stages + StageIdx; 135 } 136 137 /// Return the last+1 stage of the itinerary. endStage(unsigned ItinClassIndx)138 const InstrStage *endStage(unsigned ItinClassIndx) const { 139 unsigned StageIdx = Itineraries[ItinClassIndx].LastStage; 140 return Stages + StageIdx; 141 } 142 143 /// Return the total stage latency of the given class. The latency is 144 /// the maximum completion time for any stage in the itinerary. If no stages 145 /// exist, it defaults to one cycle. getStageLatency(unsigned ItinClassIndx)146 unsigned getStageLatency(unsigned ItinClassIndx) const { 147 // If the target doesn't provide itinerary information, use a simple 148 // non-zero default value for all instructions. 149 if (isEmpty()) 150 return 1; 151 152 // Calculate the maximum completion time for any stage. 153 unsigned Latency = 0, StartCycle = 0; 154 for (const InstrStage *IS = beginStage(ItinClassIndx), 155 *E = endStage(ItinClassIndx); IS != E; ++IS) { 156 Latency = std::max(Latency, StartCycle + IS->getCycles()); 157 StartCycle += IS->getNextCycles(); 158 } 159 return Latency; 160 } 161 162 /// Return the cycle for the given class and operand. Return -1 if no 163 /// cycle is specified for the operand. getOperandCycle(unsigned ItinClassIndx,unsigned OperandIdx)164 int getOperandCycle(unsigned ItinClassIndx, unsigned OperandIdx) const { 165 if (isEmpty()) 166 return -1; 167 168 unsigned FirstIdx = Itineraries[ItinClassIndx].FirstOperandCycle; 169 unsigned LastIdx = Itineraries[ItinClassIndx].LastOperandCycle; 170 if ((FirstIdx + OperandIdx) >= LastIdx) 171 return -1; 172 173 return (int)OperandCycles[FirstIdx + OperandIdx]; 174 } 175 176 /// Return true if there is a pipeline forwarding between instructions 177 /// of itinerary classes DefClass and UseClasses so that value produced by an 178 /// instruction of itinerary class DefClass, operand index DefIdx can be 179 /// bypassed when it's read by an instruction of itinerary class UseClass, 180 /// operand index UseIdx. hasPipelineForwarding(unsigned DefClass,unsigned DefIdx,unsigned UseClass,unsigned UseIdx)181 bool hasPipelineForwarding(unsigned DefClass, unsigned DefIdx, 182 unsigned UseClass, unsigned UseIdx) const { 183 unsigned FirstDefIdx = Itineraries[DefClass].FirstOperandCycle; 184 unsigned LastDefIdx = Itineraries[DefClass].LastOperandCycle; 185 if ((FirstDefIdx + DefIdx) >= LastDefIdx) 186 return false; 187 if (Forwardings[FirstDefIdx + DefIdx] == 0) 188 return false; 189 190 unsigned FirstUseIdx = Itineraries[UseClass].FirstOperandCycle; 191 unsigned LastUseIdx = Itineraries[UseClass].LastOperandCycle; 192 if ((FirstUseIdx + UseIdx) >= LastUseIdx) 193 return false; 194 195 return Forwardings[FirstDefIdx + DefIdx] == 196 Forwardings[FirstUseIdx + UseIdx]; 197 } 198 199 /// Compute and return the use operand latency of a given itinerary 200 /// class and operand index if the value is produced by an instruction of the 201 /// specified itinerary class and def operand index. getOperandLatency(unsigned DefClass,unsigned DefIdx,unsigned UseClass,unsigned UseIdx)202 int getOperandLatency(unsigned DefClass, unsigned DefIdx, 203 unsigned UseClass, unsigned UseIdx) const { 204 if (isEmpty()) 205 return -1; 206 207 int DefCycle = getOperandCycle(DefClass, DefIdx); 208 if (DefCycle == -1) 209 return -1; 210 211 int UseCycle = getOperandCycle(UseClass, UseIdx); 212 if (UseCycle == -1) 213 return -1; 214 215 UseCycle = DefCycle - UseCycle + 1; 216 if (UseCycle > 0 && 217 hasPipelineForwarding(DefClass, DefIdx, UseClass, UseIdx)) 218 // FIXME: This assumes one cycle benefit for every pipeline forwarding. 219 --UseCycle; 220 return UseCycle; 221 } 222 223 /// Return the number of micro-ops that the given class decodes to. 224 /// Return -1 for classes that require dynamic lookup via TargetInstrInfo. getNumMicroOps(unsigned ItinClassIndx)225 int getNumMicroOps(unsigned ItinClassIndx) const { 226 if (isEmpty()) 227 return 1; 228 return Itineraries[ItinClassIndx].NumMicroOps; 229 } 230 }; 231 232 } // end namespace llvm 233 234 #endif // LLVM_MC_MCINSTRITINERARIES_H 235