TargetSchedule.cpp (256281) | TargetSchedule.cpp (263508) |
---|---|
1//===-- llvm/Target/TargetSchedule.cpp - Sched Machine Model ----*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// --- 79 unchanged lines hidden (view full) --- 88 } 89 return MI->isTransient() ? 0 : 1; 90} 91 92// The machine model may explicitly specify an invalid latency, which 93// effectively means infinite latency. Since users of the TargetSchedule API 94// don't know how to handle this, we convert it to a very large latency that is 95// easy to distinguish when debugging the DAG but won't induce overflow. | 1//===-- llvm/Target/TargetSchedule.cpp - Sched Machine Model ----*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// --- 79 unchanged lines hidden (view full) --- 88 } 89 return MI->isTransient() ? 0 : 1; 90} 91 92// The machine model may explicitly specify an invalid latency, which 93// effectively means infinite latency. Since users of the TargetSchedule API 94// don't know how to handle this, we convert it to a very large latency that is 95// easy to distinguish when debugging the DAG but won't induce overflow. |
96static unsigned convertLatency(int Cycles) { | 96static unsigned capLatency(int Cycles) { |
97 return Cycles >= 0 ? Cycles : 1000; 98} 99 | 97 return Cycles >= 0 ? Cycles : 1000; 98} 99 |
100/// If we can determine the operand latency from the def only, without machine 101/// model or itinerary lookup, do so. Otherwise return -1. 102int TargetSchedModel::getDefLatency(const MachineInstr *DefMI, 103 bool FindMin) const { 104 105 // Return a latency based on the itinerary properties and defining instruction 106 // if possible. Some common subtargets don't require per-operand latency, 107 // especially for minimum latencies. 108 if (FindMin) { 109 // If MinLatency is invalid, then use the itinerary for MinLatency. If no 110 // itinerary exists either, then use single cycle latency. 111 if (SchedModel.MinLatency < 0 && !hasInstrItineraries()) { 112 return 1; 113 } 114 return SchedModel.MinLatency; 115 } 116 else if (!hasInstrSchedModel() && !hasInstrItineraries()) { 117 return TII->defaultDefLatency(&SchedModel, DefMI); 118 } 119 // ...operand lookup required 120 return -1; 121} 122 | |
123/// Return the MCSchedClassDesc for this instruction. Some SchedClasses require 124/// evaluation of predicates that depend on instruction operands or flags. 125const MCSchedClassDesc *TargetSchedModel:: 126resolveSchedClass(const MachineInstr *MI) const { 127 128 // Get the definition's scheduling class descriptor from this machine model. 129 unsigned SchedClass = MI->getDesc().getSchedClass(); 130 const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SchedClass); --- 41 unchanged lines hidden (view full) --- 172 ++UseIdx; 173 } 174 return UseIdx; 175} 176 177// Top-level API for clients that know the operand indices. 178unsigned TargetSchedModel::computeOperandLatency( 179 const MachineInstr *DefMI, unsigned DefOperIdx, | 100/// Return the MCSchedClassDesc for this instruction. Some SchedClasses require 101/// evaluation of predicates that depend on instruction operands or flags. 102const MCSchedClassDesc *TargetSchedModel:: 103resolveSchedClass(const MachineInstr *MI) const { 104 105 // Get the definition's scheduling class descriptor from this machine model. 106 unsigned SchedClass = MI->getDesc().getSchedClass(); 107 const MCSchedClassDesc *SCDesc = SchedModel.getSchedClassDesc(SchedClass); --- 41 unchanged lines hidden (view full) --- 149 ++UseIdx; 150 } 151 return UseIdx; 152} 153 154// Top-level API for clients that know the operand indices. 155unsigned TargetSchedModel::computeOperandLatency( 156 const MachineInstr *DefMI, unsigned DefOperIdx, |
180 const MachineInstr *UseMI, unsigned UseOperIdx, 181 bool FindMin) const { | 157 const MachineInstr *UseMI, unsigned UseOperIdx) const { |
182 | 158 |
183 int DefLatency = getDefLatency(DefMI, FindMin); 184 if (DefLatency >= 0) 185 return DefLatency; | 159 if (!hasInstrSchedModel() && !hasInstrItineraries()) 160 return TII->defaultDefLatency(&SchedModel, DefMI); |
186 187 if (hasInstrItineraries()) { 188 int OperLatency = 0; 189 if (UseMI) { | 161 162 if (hasInstrItineraries()) { 163 int OperLatency = 0; 164 if (UseMI) { |
190 OperLatency = 191 TII->getOperandLatency(&InstrItins, DefMI, DefOperIdx, UseMI, UseOperIdx); | 165 OperLatency = TII->getOperandLatency(&InstrItins, DefMI, DefOperIdx, 166 UseMI, UseOperIdx); |
192 } 193 else { 194 unsigned DefClass = DefMI->getDesc().getSchedClass(); 195 OperLatency = InstrItins.getOperandCycle(DefClass, DefOperIdx); 196 } 197 if (OperLatency >= 0) 198 return OperLatency; 199 200 // No operand latency was found. 201 unsigned InstrLatency = TII->getInstrLatency(&InstrItins, DefMI); 202 203 // Expected latency is the max of the stage latency and itinerary props. 204 // Rather than directly querying InstrItins stage latency, we call a TII 205 // hook to allow subtargets to specialize latency. This hook is only 206 // applicable to the InstrItins model. InstrSchedModel should model all 207 // special cases without TII hooks. | 167 } 168 else { 169 unsigned DefClass = DefMI->getDesc().getSchedClass(); 170 OperLatency = InstrItins.getOperandCycle(DefClass, DefOperIdx); 171 } 172 if (OperLatency >= 0) 173 return OperLatency; 174 175 // No operand latency was found. 176 unsigned InstrLatency = TII->getInstrLatency(&InstrItins, DefMI); 177 178 // Expected latency is the max of the stage latency and itinerary props. 179 // Rather than directly querying InstrItins stage latency, we call a TII 180 // hook to allow subtargets to specialize latency. This hook is only 181 // applicable to the InstrItins model. InstrSchedModel should model all 182 // special cases without TII hooks. |
208 if (!FindMin) 209 InstrLatency = std::max(InstrLatency, 210 TII->defaultDefLatency(&SchedModel, DefMI)); | 183 InstrLatency = std::max(InstrLatency, 184 TII->defaultDefLatency(&SchedModel, DefMI)); |
211 return InstrLatency; 212 } | 185 return InstrLatency; 186 } |
213 assert(!FindMin && hasInstrSchedModel() && 214 "Expected a SchedModel for this cpu"); | 187 // hasInstrSchedModel() |
215 const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI); 216 unsigned DefIdx = findDefIdx(DefMI, DefOperIdx); 217 if (DefIdx < SCDesc->NumWriteLatencyEntries) { 218 // Lookup the definition's write latency in SubtargetInfo. 219 const MCWriteLatencyEntry *WLEntry = 220 STI->getWriteLatencyEntry(SCDesc, DefIdx); 221 unsigned WriteID = WLEntry->WriteResourceID; | 188 const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI); 189 unsigned DefIdx = findDefIdx(DefMI, DefOperIdx); 190 if (DefIdx < SCDesc->NumWriteLatencyEntries) { 191 // Lookup the definition's write latency in SubtargetInfo. 192 const MCWriteLatencyEntry *WLEntry = 193 STI->getWriteLatencyEntry(SCDesc, DefIdx); 194 unsigned WriteID = WLEntry->WriteResourceID; |
222 unsigned Latency = convertLatency(WLEntry->Cycles); | 195 unsigned Latency = capLatency(WLEntry->Cycles); |
223 if (!UseMI) 224 return Latency; 225 226 // Lookup the use's latency adjustment in SubtargetInfo. 227 const MCSchedClassDesc *UseDesc = resolveSchedClass(UseMI); 228 if (UseDesc->NumReadAdvanceEntries == 0) 229 return Latency; 230 unsigned UseIdx = findUseIdx(UseMI, UseOperIdx); | 196 if (!UseMI) 197 return Latency; 198 199 // Lookup the use's latency adjustment in SubtargetInfo. 200 const MCSchedClassDesc *UseDesc = resolveSchedClass(UseMI); 201 if (UseDesc->NumReadAdvanceEntries == 0) 202 return Latency; 203 unsigned UseIdx = findUseIdx(UseMI, UseOperIdx); |
231 return Latency - STI->getReadAdvanceCycles(UseDesc, UseIdx, WriteID); | 204 int Advance = STI->getReadAdvanceCycles(UseDesc, UseIdx, WriteID); 205 if (Advance > 0 && (unsigned)Advance > Latency) // unsigned wrap 206 return 0; 207 return Latency - Advance; |
232 } 233 // If DefIdx does not exist in the model (e.g. implicit defs), then return 234 // unit latency (defaultDefLatency may be too conservative). 235#ifndef NDEBUG 236 if (SCDesc->isValid() && !DefMI->getOperand(DefOperIdx).isImplicit() | 208 } 209 // If DefIdx does not exist in the model (e.g. implicit defs), then return 210 // unit latency (defaultDefLatency may be too conservative). 211#ifndef NDEBUG 212 if (SCDesc->isValid() && !DefMI->getOperand(DefOperIdx).isImplicit() |
237 && !DefMI->getDesc().OpInfo[DefOperIdx].isOptionalDef()) { | 213 && !DefMI->getDesc().OpInfo[DefOperIdx].isOptionalDef() 214 && SchedModel.isComplete()) { |
238 std::string Err; 239 raw_string_ostream ss(Err); 240 ss << "DefIdx " << DefIdx << " exceeds machine model writes for " 241 << *DefMI; 242 report_fatal_error(ss.str()); 243 } 244#endif 245 // FIXME: Automatically giving all implicit defs defaultDefLatency is 246 // undesirable. We should only do it for defs that are known to the MC 247 // desc like flags. Truly implicit defs should get 1 cycle latency. 248 return DefMI->isTransient() ? 0 : TII->defaultDefLatency(&SchedModel, DefMI); 249} 250 | 215 std::string Err; 216 raw_string_ostream ss(Err); 217 ss << "DefIdx " << DefIdx << " exceeds machine model writes for " 218 << *DefMI; 219 report_fatal_error(ss.str()); 220 } 221#endif 222 // FIXME: Automatically giving all implicit defs defaultDefLatency is 223 // undesirable. We should only do it for defs that are known to the MC 224 // desc like flags. Truly implicit defs should get 1 cycle latency. 225 return DefMI->isTransient() ? 0 : TII->defaultDefLatency(&SchedModel, DefMI); 226} 227 |
251unsigned TargetSchedModel::computeInstrLatency(const MachineInstr *MI) const { | 228unsigned 229TargetSchedModel::computeInstrLatency(const MachineInstr *MI, 230 bool UseDefaultDefLatency) const { |
252 // For the itinerary model, fall back to the old subtarget hook. 253 // Allow subtargets to compute Bundle latencies outside the machine model. | 231 // For the itinerary model, fall back to the old subtarget hook. 232 // Allow subtargets to compute Bundle latencies outside the machine model. |
254 if (hasInstrItineraries() || MI->isBundle()) | 233 if (hasInstrItineraries() || MI->isBundle() || 234 (!hasInstrSchedModel() && !UseDefaultDefLatency)) |
255 return TII->getInstrLatency(&InstrItins, MI); 256 257 if (hasInstrSchedModel()) { 258 const MCSchedClassDesc *SCDesc = resolveSchedClass(MI); 259 if (SCDesc->isValid()) { 260 unsigned Latency = 0; 261 for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries; 262 DefIdx != DefEnd; ++DefIdx) { 263 // Lookup the definition's write latency in SubtargetInfo. 264 const MCWriteLatencyEntry *WLEntry = 265 STI->getWriteLatencyEntry(SCDesc, DefIdx); | 235 return TII->getInstrLatency(&InstrItins, MI); 236 237 if (hasInstrSchedModel()) { 238 const MCSchedClassDesc *SCDesc = resolveSchedClass(MI); 239 if (SCDesc->isValid()) { 240 unsigned Latency = 0; 241 for (unsigned DefIdx = 0, DefEnd = SCDesc->NumWriteLatencyEntries; 242 DefIdx != DefEnd; ++DefIdx) { 243 // Lookup the definition's write latency in SubtargetInfo. 244 const MCWriteLatencyEntry *WLEntry = 245 STI->getWriteLatencyEntry(SCDesc, DefIdx); |
266 Latency = std::max(Latency, convertLatency(WLEntry->Cycles)); | 246 Latency = std::max(Latency, capLatency(WLEntry->Cycles)); |
267 } 268 return Latency; 269 } 270 } 271 return TII->defaultDefLatency(&SchedModel, MI); 272} 273 274unsigned TargetSchedModel:: 275computeOutputLatency(const MachineInstr *DefMI, unsigned DefOperIdx, 276 const MachineInstr *DepMI) const { | 247 } 248 return Latency; 249 } 250 } 251 return TII->defaultDefLatency(&SchedModel, MI); 252} 253 254unsigned TargetSchedModel:: 255computeOutputLatency(const MachineInstr *DefMI, unsigned DefOperIdx, 256 const MachineInstr *DepMI) const { |
277 // MinLatency == -1 is for in-order processors that always have unit 278 // MinLatency. MinLatency > 0 is for in-order processors with varying min 279 // latencies, but since this is not a RAW dep, we always use unit latency. 280 if (SchedModel.MinLatency != 0) | 257 if (SchedModel.MicroOpBufferSize <= 1) |
281 return 1; 282 | 258 return 1; 259 |
283 // MinLatency == 0 indicates an out-of-order processor that can dispatch | 260 // MicroOpBufferSize > 1 indicates an out-of-order processor that can dispatch |
284 // WAW dependencies in the same cycle. 285 286 // Treat predication as a data dependency for out-of-order cpus. In-order 287 // cpus do not need to treat predicated writes specially. 288 // 289 // TODO: The following hack exists because predication passes do not 290 // correctly append imp-use operands, and readsReg() strangely returns false 291 // for predicated defs. --- 5 unchanged lines hidden (view full) --- 297 298 // If we have a per operand scheduling model, check if this def is writing 299 // an unbuffered resource. If so, it treated like an in-order cpu. 300 if (hasInstrSchedModel()) { 301 const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI); 302 if (SCDesc->isValid()) { 303 for (const MCWriteProcResEntry *PRI = STI->getWriteProcResBegin(SCDesc), 304 *PRE = STI->getWriteProcResEnd(SCDesc); PRI != PRE; ++PRI) { | 261 // WAW dependencies in the same cycle. 262 263 // Treat predication as a data dependency for out-of-order cpus. In-order 264 // cpus do not need to treat predicated writes specially. 265 // 266 // TODO: The following hack exists because predication passes do not 267 // correctly append imp-use operands, and readsReg() strangely returns false 268 // for predicated defs. --- 5 unchanged lines hidden (view full) --- 274 275 // If we have a per operand scheduling model, check if this def is writing 276 // an unbuffered resource. If so, it treated like an in-order cpu. 277 if (hasInstrSchedModel()) { 278 const MCSchedClassDesc *SCDesc = resolveSchedClass(DefMI); 279 if (SCDesc->isValid()) { 280 for (const MCWriteProcResEntry *PRI = STI->getWriteProcResBegin(SCDesc), 281 *PRE = STI->getWriteProcResEnd(SCDesc); PRI != PRE; ++PRI) { |
305 if (!SchedModel.getProcResource(PRI->ProcResourceIdx)->IsBuffered) | 282 if (!SchedModel.getProcResource(PRI->ProcResourceIdx)->BufferSize) |
306 return 1; 307 } 308 } 309 } 310 return 0; 311} | 283 return 1; 284 } 285 } 286 } 287 return 0; 288} |