LLVM 23.0.0git
MCSchedule.cpp
Go to the documentation of this file.
1//===- MCSchedule.cpp - 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 defines the default scheduling model.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/MC/MCSchedule.h"
14#include "llvm/ADT/APFloat.h"
15#include "llvm/ADT/APSInt.h"
16#include "llvm/MC/MCInst.h"
17#include "llvm/MC/MCInstrDesc.h"
18#include "llvm/MC/MCInstrInfo.h"
21#include <optional>
22#include <type_traits>
23
24using namespace llvm;
25
26cl::OptionCategory llvm::MCScheduleOptions("Machine scheduling model options");
27
28static constexpr float DefaultReservationStationScaleFactor = 1.0f;
29
31 "sched-model-reservation-station-scale-factor", cl::Hidden,
33 cl::desc("Scale the buffer size of all reservation stations by a positive "
34 "factor. Buffer sizes of -1/0/1 (unlimited/unbuffered/in-order) "
35 "are preserved. Likewise, if the scaled result is <= 1, the "
36 "original size is kept. Computed sizes "
37 "are truncated towards zero."));
38
39static_assert(std::is_trivial_v<MCSchedModel>,
40 "MCSchedModel is required to be a trivial type");
41const MCSchedModel MCSchedModel::Default = {DefaultIssueWidth,
42 DefaultMicroOpBufferSize,
43 DefaultLoopMicroOpBufferSize,
44 DefaultLoadLatency,
45 DefaultHighLatency,
46 DefaultMispredictPenalty,
47 false,
48 true,
49 /*EnableIntervals=*/false,
50 0,
51 nullptr,
52 nullptr,
53 0,
54 0,
55 nullptr,
56 nullptr,
57 nullptr};
58
60 const MCSchedClassDesc &SCDesc) {
61 int Latency = 0;
62 for (unsigned DefIdx = 0, DefEnd = SCDesc.NumWriteLatencyEntries;
63 DefIdx != DefEnd; ++DefIdx) {
64 // Lookup the definition's write latency in SubtargetInfo.
65 const MCWriteLatencyEntry *WLEntry =
66 STI.getWriteLatencyEntry(&SCDesc, DefIdx);
67 // Early exit if we found an invalid latency.
68 if (WLEntry->Cycles < 0)
69 return WLEntry->Cycles;
70 Latency = std::max(Latency, static_cast<int>(WLEntry->Cycles));
71 }
72 return Latency;
73}
74
76 unsigned SchedClass) const {
77 const MCSchedClassDesc &SCDesc = *getSchedClassDesc(SchedClass);
78 if (!SCDesc.isValid())
79 return 0;
80 if (!SCDesc.isVariant())
81 return MCSchedModel::computeInstrLatency(STI, SCDesc);
82
83 llvm_unreachable("unsupported variant scheduling class");
84}
85
87 const MCInstrInfo &MCII,
88 const MCInst &Inst) const {
91 STI, MCII, Inst,
92 [&](const MCSchedClassDesc *SCDesc) -> const MCSchedClassDesc * {
93 if (!SCDesc->isValid())
94 return nullptr;
95
96 unsigned CPUID = getProcessorID();
97 unsigned SchedClass = 0;
98 while (SCDesc->isVariant()) {
99 SchedClass =
100 STI.resolveVariantSchedClass(SchedClass, &Inst, &MCII, CPUID);
101 SCDesc = getSchedClassDesc(SchedClass);
102 }
103
104 if (!SchedClass) {
105 assert(false && "unsupported variant scheduling class");
106 return nullptr;
107 }
108
109 return SCDesc;
110 });
111}
112
113double
115 const MCSchedClassDesc &SCDesc) {
116 std::optional<double> MinThroughput;
117 const MCSchedModel &SM = STI.getSchedModel();
118 const MCWriteProcResEntry *I = STI.getWriteProcResBegin(&SCDesc);
119 const MCWriteProcResEntry *E = STI.getWriteProcResEnd(&SCDesc);
120 for (; I != E; ++I) {
121 if (!I->ReleaseAtCycle || I->ReleaseAtCycle == I->AcquireAtCycle)
122 continue;
123 assert(I->ReleaseAtCycle > I->AcquireAtCycle && "invalid resource segment");
124 unsigned NumUnits = SM.getProcResource(I->ProcResourceIdx)->NumUnits;
125 double Throughput =
126 double(NumUnits) / double(I->ReleaseAtCycle - I->AcquireAtCycle);
127 MinThroughput =
128 MinThroughput ? std::min(*MinThroughput, Throughput) : Throughput;
129 }
130 if (MinThroughput)
131 return 1.0 / *MinThroughput;
132
133 // If no throughput value was calculated, assume that we can execute at the
134 // maximum issue width scaled by number of micro-ops for the schedule class.
135 return ((double)SCDesc.NumMicroOps) / SM.IssueWidth;
136}
137
138double
140 const MCInstrInfo &MCII,
141 const MCInst &Inst) const {
142 unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass();
143 const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass);
144
145 // If there's no valid class, assume that the instruction executes/completes
146 // at the maximum issue width.
147 if (!SCDesc->isValid())
148 return 1.0 / IssueWidth;
149
150 unsigned CPUID = getProcessorID();
151 while (SCDesc->isVariant()) {
152 SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, &MCII, CPUID);
153 SCDesc = getSchedClassDesc(SchedClass);
154 }
155
156 if (SchedClass)
157 return MCSchedModel::getReciprocalThroughput(STI, *SCDesc);
158
159 llvm_unreachable("unsupported variant scheduling class");
160}
161
162double
164 const InstrItineraryData &IID) {
165 std::optional<double> Throughput;
166 const InstrStage *I = IID.beginStage(SchedClass);
167 const InstrStage *E = IID.endStage(SchedClass);
168 for (; I != E; ++I) {
169 if (!I->getCycles())
170 continue;
171 double Temp = llvm::popcount(I->getUnits()) * 1.0 / I->getCycles();
172 Throughput = Throughput ? std::min(*Throughput, Temp) : Temp;
173 }
174 if (Throughput)
175 return 1.0 / *Throughput;
176
177 // If there are no execution resources specified for this class, then assume
178 // that it can execute at the maximum default issue width.
179 return 1.0 / DefaultIssueWidth;
180}
181
182unsigned
184 unsigned WriteResourceID) {
185 if (Entries.empty())
186 return 0;
187
188 int DelayCycles = 0;
189 for (const MCReadAdvanceEntry &E : Entries) {
190 if (E.WriteResourceID != WriteResourceID)
191 continue;
192 DelayCycles = std::min(DelayCycles, E.Cycles);
193 }
194
195 return std::abs(DelayCycles);
196}
197
199 const MCSchedClassDesc &SCDesc) {
200
202 if (Entries.empty())
203 return 0;
204
205 unsigned MaxLatency = 0;
206 unsigned WriteResourceID = 0;
207 unsigned DefEnd = SCDesc.NumWriteLatencyEntries;
208
209 for (unsigned DefIdx = 0; DefIdx != DefEnd; ++DefIdx) {
210 // Lookup the definition's write latency in SubtargetInfo.
211 const MCWriteLatencyEntry *WLEntry =
212 STI.getWriteLatencyEntry(&SCDesc, DefIdx);
213 unsigned Cycles = 0;
214 // If latency is Invalid (<0), consider 0 cycle latency
215 if (WLEntry->Cycles > 0)
216 Cycles = (unsigned)WLEntry->Cycles;
217 if (Cycles > MaxLatency) {
218 MaxLatency = Cycles;
219 WriteResourceID = WLEntry->WriteResourceID;
220 }
221 }
222
223 for (const MCReadAdvanceEntry &E : Entries) {
224 if (E.WriteResourceID == WriteResourceID)
225 return E.Cycles;
226 }
227
228 // Unable to find WriteResourceID in MCReadAdvanceEntry Entries
229 return 0;
230}
231
232/// Return the buffer size of the resource. If a positive scale factor
233/// is provided and the original buffer size is > 1, the size is scaled
234/// accordingly.
235int MCSchedModel::getResourceBufferSize(unsigned ProcResourceIdx) const {
236 int BufferSize = getProcResource(ProcResourceIdx)->BufferSize;
237
238 // Skip scaling when factor is 1 (the default).
239 // Use native float comparison to avoid overhead on the hot fast
240 // path, as 1.0f is exactly representable
243 return BufferSize;
244
245 // Skip scaling for special buffer sizes (-1,0,1)
246 if (BufferSize <= 1)
247 return BufferSize;
248
249 // Skip invalid (non-positive) scale factors
251 if (Scale.isNegative() || Scale.isZero())
252 return BufferSize;
253
254 // Scale and truncate the positive computed size towards zero
255 APFloat Product(static_cast<float>(BufferSize));
256 Product.multiply(Scale, APFloat::rmTowardZero);
257 APSInt Result(32, /*IsUnsigned=*/false);
258 bool IsExact;
259 if (Product.convertToInteger(Result, APFloat::rmTowardZero, &IsExact) &
261 return BufferSize;
262 int Scaled = static_cast<int>(Result.getExtValue());
263
264 // Avoid producing special buffer sizes (-1,0,1)
265 if (Scaled <= 1)
266 return BufferSize;
267
268 return Scaled;
269}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
This file declares a class to represent arbitrary precision floating point values and provide a varie...
This file implements the APSInt class, which is a simple class that represents an arbitrary sized int...
@ Scaled
#define LLVM_LIKELY(EXPR)
Definition Compiler.h:335
static cl::opt< float > ReservationStationScaleFactor("sched-model-reservation-station-scale-factor", cl::Hidden, cl::init(DefaultReservationStationScaleFactor), cl::cat(MCScheduleOptions), cl::desc("Scale the buffer size of all reservation stations by a positive " "factor. Buffer sizes of -1/0/1 (unlimited/unbuffered/in-order) " "are preserved. Likewise, if the scaled result is <= 1, the " "original size is kept. Computed sizes " "are truncated towards zero."))
static constexpr float DefaultReservationStationScaleFactor
#define I(x, y, z)
Definition MD5.cpp:57
static constexpr unsigned SM(unsigned Version)
static constexpr roundingMode rmTowardZero
Definition APFloat.h:348
bool isNegative() const
Definition APFloat.h:1538
opStatus multiply(const APFloat &RHS, roundingMode RM)
Definition APFloat.h:1258
bool isZero() const
Definition APFloat.h:1534
opStatus convertToInteger(MutableArrayRef< integerPart > Input, unsigned int Width, bool IsSigned, roundingMode RM, bool *IsExact) const
Definition APFloat.h:1391
An arbitrary precision integer that knows its signedness.
Definition APSInt.h:24
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
bool empty() const
Check if the array is empty.
Definition ArrayRef.h:136
const InstrStage * beginStage(unsigned ItinClassIndx) const
Return the first stage of the itinerary.
const InstrStage * endStage(unsigned ItinClassIndx) const
Return the last+1 stage of the itinerary.
Instances of this class represent a single low-level machine instruction.
Definition MCInst.h:188
unsigned getOpcode() const
Definition MCInst.h:202
unsigned getSchedClass() const
Return the scheduling class for this instruction.
Interface to description of machine instruction set.
Definition MCInstrInfo.h:27
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
Definition MCInstrInfo.h:90
Generic base class for all target subtargets.
const MCWriteProcResEntry * getWriteProcResEnd(const MCSchedClassDesc *SC) const
virtual unsigned resolveVariantSchedClass(unsigned SchedClass, const MCInst *MI, const MCInstrInfo *MCII, unsigned CPUID) const
Resolve a variant scheduling class for the given MCInst and CPU.
ArrayRef< MCReadAdvanceEntry > getReadAdvanceEntries(const MCSchedClassDesc &SC) const
Return the set of ReadAdvance entries declared by the scheduling class descriptor in input.
const MCWriteLatencyEntry * getWriteLatencyEntry(const MCSchedClassDesc *SC, unsigned DefIdx) const
const MCWriteProcResEntry * getWriteProcResBegin(const MCSchedClassDesc *SC) const
Return an iterator at the first process resource consumed by the given scheduling class.
const MCSchedModel & getSchedModel() const
Get the machine model for this subtarget's CPU.
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
constexpr int popcount(T Value) noexcept
Count the number of set bits in a value.
Definition bit.h:156
cl::OptionCategory MCScheduleOptions
These values represent a non-pipelined step in the execution of an instruction.
Specify the number of cycles allowed after instruction issue before a particular use operand reads it...
Definition MCSchedule.h:114
Summarize the scheduling resources required for an instruction of a particular scheduling class.
Definition MCSchedule.h:129
bool isVariant() const
Definition MCSchedule.h:150
uint16_t NumWriteLatencyEntries
Definition MCSchedule.h:143
Machine model for scheduling, bundling, and heuristics.
Definition MCSchedule.h:264
static LLVM_ABI const MCSchedModel Default
Returns the default initialized model.
Definition MCSchedule.h:435
static LLVM_ABI unsigned getForwardingDelayCycles(ArrayRef< MCReadAdvanceEntry > Entries, unsigned WriteResourceIdx=0)
Returns the maximum forwarding delay for register reads dependent on writes of scheduling class Write...
const MCSchedClassDesc * getSchedClassDesc(unsigned SchedClassIdx) const
Definition MCSchedule.h:372
unsigned getProcessorID() const
Definition MCSchedule.h:343
static LLVM_ABI int computeInstrLatency(const MCSubtargetInfo &STI, const MCSchedClassDesc &SCDesc)
Returns the latency value for the scheduling class.
friend class InstrItineraryData
Definition MCSchedule.h:336
const MCProcResourceDesc * getProcResource(unsigned ProcResourceIdx) const
Definition MCSchedule.h:365
static LLVM_ABI unsigned getBypassDelayCycles(const MCSubtargetInfo &STI, const MCSchedClassDesc &SCDesc)
Returns the bypass delay cycle for the maximum latency write cycle.
static LLVM_ABI double getReciprocalThroughput(const MCSubtargetInfo &STI, const MCSchedClassDesc &SCDesc)
LLVM_ABI int getResourceBufferSize(unsigned ProcResourceIdx) const
Return the buffer size of the resource.
static const unsigned DefaultIssueWidth
Definition MCSchedule.h:277
Specify the latency in cpu cycles for a particular scheduling class and def index.
Definition MCSchedule.h:97
Identify one of the processor resource kinds consumed by a particular scheduling class for the specif...
Definition MCSchedule.h:74