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
26static constexpr float DefaultReservationStationScaleFactor = 1.0f;
27
29 "sched-model-reservation-station-scale-factor", cl::Hidden,
31 cl::desc("Scale the buffer size of all reservation stations by a positive "
32 "factor. Buffer sizes of -1/0/1 (unlimited/unbuffered/in-order) "
33 "are preserved. Likewise, if the scaled result is <= 1, the "
34 "original size is kept. Computed sizes "
35 "are truncated towards zero."));
36
37static_assert(std::is_trivial_v<MCSchedModel>,
38 "MCSchedModel is required to be a trivial type");
39const MCSchedModel MCSchedModel::Default = {DefaultIssueWidth,
40 DefaultMicroOpBufferSize,
41 DefaultLoopMicroOpBufferSize,
42 DefaultLoadLatency,
43 DefaultHighLatency,
44 DefaultMispredictPenalty,
45 false,
46 true,
47 /*EnableIntervals=*/false,
48 0,
49 nullptr,
50 nullptr,
51 0,
52 0,
53 nullptr,
54 nullptr,
55 nullptr};
56
58 const MCSchedClassDesc &SCDesc) {
59 int Latency = 0;
60 for (unsigned DefIdx = 0, DefEnd = SCDesc.NumWriteLatencyEntries;
61 DefIdx != DefEnd; ++DefIdx) {
62 // Lookup the definition's write latency in SubtargetInfo.
63 const MCWriteLatencyEntry *WLEntry =
64 STI.getWriteLatencyEntry(&SCDesc, DefIdx);
65 // Early exit if we found an invalid latency.
66 if (WLEntry->Cycles < 0)
67 return WLEntry->Cycles;
68 Latency = std::max(Latency, static_cast<int>(WLEntry->Cycles));
69 }
70 return Latency;
71}
72
74 unsigned SchedClass) const {
75 const MCSchedClassDesc &SCDesc = *getSchedClassDesc(SchedClass);
76 if (!SCDesc.isValid())
77 return 0;
78 if (!SCDesc.isVariant())
79 return MCSchedModel::computeInstrLatency(STI, SCDesc);
80
81 llvm_unreachable("unsupported variant scheduling class");
82}
83
85 const MCInstrInfo &MCII,
86 const MCInst &Inst) const {
89 STI, MCII, Inst,
90 [&](const MCSchedClassDesc *SCDesc) -> const MCSchedClassDesc * {
91 if (!SCDesc->isValid())
92 return nullptr;
93
94 unsigned CPUID = getProcessorID();
95 unsigned SchedClass = 0;
96 while (SCDesc->isVariant()) {
97 SchedClass =
98 STI.resolveVariantSchedClass(SchedClass, &Inst, &MCII, CPUID);
99 SCDesc = getSchedClassDesc(SchedClass);
100 }
101
102 if (!SchedClass) {
103 assert(false && "unsupported variant scheduling class");
104 return nullptr;
105 }
106
107 return SCDesc;
108 });
109}
110
111double
113 const MCSchedClassDesc &SCDesc) {
114 std::optional<double> MinThroughput;
115 const MCSchedModel &SM = STI.getSchedModel();
116 const MCWriteProcResEntry *I = STI.getWriteProcResBegin(&SCDesc);
117 const MCWriteProcResEntry *E = STI.getWriteProcResEnd(&SCDesc);
118 for (; I != E; ++I) {
119 if (!I->ReleaseAtCycle || I->ReleaseAtCycle == I->AcquireAtCycle)
120 continue;
121 assert(I->ReleaseAtCycle > I->AcquireAtCycle && "invalid resource segment");
122 unsigned NumUnits = SM.getProcResource(I->ProcResourceIdx)->NumUnits;
123 double Throughput =
124 double(NumUnits) / double(I->ReleaseAtCycle - I->AcquireAtCycle);
125 MinThroughput =
126 MinThroughput ? std::min(*MinThroughput, Throughput) : Throughput;
127 }
128 if (MinThroughput)
129 return 1.0 / *MinThroughput;
130
131 // If no throughput value was calculated, assume that we can execute at the
132 // maximum issue width scaled by number of micro-ops for the schedule class.
133 return ((double)SCDesc.NumMicroOps) / SM.IssueWidth;
134}
135
136double
138 const MCInstrInfo &MCII,
139 const MCInst &Inst) const {
140 unsigned SchedClass = MCII.get(Inst.getOpcode()).getSchedClass();
141 const MCSchedClassDesc *SCDesc = getSchedClassDesc(SchedClass);
142
143 // If there's no valid class, assume that the instruction executes/completes
144 // at the maximum issue width.
145 if (!SCDesc->isValid())
146 return 1.0 / IssueWidth;
147
148 unsigned CPUID = getProcessorID();
149 while (SCDesc->isVariant()) {
150 SchedClass = STI.resolveVariantSchedClass(SchedClass, &Inst, &MCII, CPUID);
151 SCDesc = getSchedClassDesc(SchedClass);
152 }
153
154 if (SchedClass)
155 return MCSchedModel::getReciprocalThroughput(STI, *SCDesc);
156
157 llvm_unreachable("unsupported variant scheduling class");
158}
159
160double
162 const InstrItineraryData &IID) {
163 std::optional<double> Throughput;
164 const InstrStage *I = IID.beginStage(SchedClass);
165 const InstrStage *E = IID.endStage(SchedClass);
166 for (; I != E; ++I) {
167 if (!I->getCycles())
168 continue;
169 double Temp = llvm::popcount(I->getUnits()) * 1.0 / I->getCycles();
170 Throughput = Throughput ? std::min(*Throughput, Temp) : Temp;
171 }
172 if (Throughput)
173 return 1.0 / *Throughput;
174
175 // If there are no execution resources specified for this class, then assume
176 // that it can execute at the maximum default issue width.
177 return 1.0 / DefaultIssueWidth;
178}
179
180unsigned
182 unsigned WriteResourceID) {
183 if (Entries.empty())
184 return 0;
185
186 int DelayCycles = 0;
187 for (const MCReadAdvanceEntry &E : Entries) {
188 if (E.WriteResourceID != WriteResourceID)
189 continue;
190 DelayCycles = std::min(DelayCycles, E.Cycles);
191 }
192
193 return std::abs(DelayCycles);
194}
195
197 const MCSchedClassDesc &SCDesc) {
198
200 if (Entries.empty())
201 return 0;
202
203 unsigned MaxLatency = 0;
204 unsigned WriteResourceID = 0;
205 unsigned DefEnd = SCDesc.NumWriteLatencyEntries;
206
207 for (unsigned DefIdx = 0; DefIdx != DefEnd; ++DefIdx) {
208 // Lookup the definition's write latency in SubtargetInfo.
209 const MCWriteLatencyEntry *WLEntry =
210 STI.getWriteLatencyEntry(&SCDesc, DefIdx);
211 unsigned Cycles = 0;
212 // If latency is Invalid (<0), consider 0 cycle latency
213 if (WLEntry->Cycles > 0)
214 Cycles = (unsigned)WLEntry->Cycles;
215 if (Cycles > MaxLatency) {
216 MaxLatency = Cycles;
217 WriteResourceID = WLEntry->WriteResourceID;
218 }
219 }
220
221 for (const MCReadAdvanceEntry &E : Entries) {
222 if (E.WriteResourceID == WriteResourceID)
223 return E.Cycles;
224 }
225
226 // Unable to find WriteResourceID in MCReadAdvanceEntry Entries
227 return 0;
228}
229
230/// Return the buffer size of the resource. If a positive scale factor
231/// is provided and the original buffer size is > 1, the size is scaled
232/// accordingly.
233int MCSchedModel::getResourceBufferSize(unsigned ProcResourceIdx) const {
234 int BufferSize = getProcResource(ProcResourceIdx)->BufferSize;
235
236 // Skip scaling when factor is 1 (the default).
237 // Use native float comparison to avoid overhead on the hot fast
238 // path, as 1.0f is exactly representable
241 return BufferSize;
242
243 // Skip scaling for special buffer sizes (-1,0,1)
244 if (BufferSize <= 1)
245 return BufferSize;
246
247 // Skip invalid (non-positive) scale factors
249 if (Scale.isNegative() || Scale.isZero())
250 return BufferSize;
251
252 // Scale and truncate the positive computed size towards zero
253 APFloat Product(static_cast<float>(BufferSize));
254 Product.multiply(Scale, APFloat::rmTowardZero);
255 APSInt Result(32, /*IsUnsigned=*/false);
256 bool IsExact;
257 if (Product.convertToInteger(Result, APFloat::rmTowardZero, &IsExact) &
259 return BufferSize;
260 int Scaled = static_cast<int>(Result.getExtValue());
261
262 // Avoid producing special buffer sizes (-1,0,1)
263 if (Scaled <= 1)
264 return BufferSize;
265
266 return Scaled;
267}
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 constexpr float DefaultReservationStationScaleFactor
static cl::opt< float > ReservationStationScaleFactor("sched-model-reservation-station-scale-factor", cl::Hidden, cl::init(DefaultReservationStationScaleFactor), 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."))
#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
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:108
Summarize the scheduling resources required for an instruction of a particular scheduling class.
Definition MCSchedule.h:123
bool isVariant() const
Definition MCSchedule.h:144
uint16_t NumWriteLatencyEntries
Definition MCSchedule.h:137
Machine model for scheduling, bundling, and heuristics.
Definition MCSchedule.h:258
static LLVM_ABI const MCSchedModel Default
Returns the default initialized model.
Definition MCSchedule.h:429
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:366
unsigned getProcessorID() const
Definition MCSchedule.h:337
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:330
const MCProcResourceDesc * getProcResource(unsigned ProcResourceIdx) const
Definition MCSchedule.h:359
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:271
Specify the latency in cpu cycles for a particular scheduling class and def index.
Definition MCSchedule.h:91
Identify one of the processor resource kinds consumed by a particular scheduling class for the specif...
Definition MCSchedule.h:68