1 //===--------------------- Instruction.h ------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 /// This file defines abstractions used by the Pipeline to model register reads,
11 /// register writes and instructions.
13 //===----------------------------------------------------------------------===//
15 #ifndef LLVM_MCA_INSTRUCTION_H
16 #define LLVM_MCA_INSTRUCTION_H
18 #include "llvm/ADT/ArrayRef.h"
19 #include "llvm/ADT/STLExtras.h"
20 #include "llvm/ADT/SmallVector.h"
21 #include "llvm/Support/MathExtras.h"
24 #include "llvm/Support/raw_ostream.h"
33 constexpr int UNKNOWN_CYCLES
= -512;
35 /// A register write descriptor.
36 struct WriteDescriptor
{
37 // Operand index. The index is negative for implicit writes only.
38 // For implicit writes, the actual operand index is computed performing
39 // a bitwise not of the OpIndex.
41 // Write latency. Number of cycles before write-back stage.
43 // This field is set to a value different than zero only if this
44 // is an implicit definition.
46 // Instruction itineraries would set this field to the SchedClass ID.
47 // Otherwise, it defaults to the WriteResourceID from the MCWriteLatencyEntry
48 // element associated to this write.
49 // When computing read latencies, this value is matched against the
50 // "ReadAdvance" information. The hardware backend may implement
51 // dedicated forwarding paths to quickly propagate write results to dependent
52 // instructions waiting in the reservation station (effectively bypassing the
54 unsigned SClassOrWriteResourceID
;
55 // True only if this is a write obtained from an optional definition.
56 // Optional definitions are allowed to reference regID zero (i.e. "no
60 bool isImplicitWrite() const { return OpIndex
< 0; };
63 /// A register read descriptor.
64 struct ReadDescriptor
{
65 // A MCOperand index. This is used by the Dispatch logic to identify register
66 // reads. Implicit reads have negative indices. The actual operand index of an
67 // implicit read is the bitwise not of field OpIndex.
69 // The actual "UseIdx". This is used to query the ReadAdvance table. Explicit
70 // uses always come first in the sequence of uses.
72 // This field is only set if this is an implicit read.
74 // Scheduling Class Index. It is used to query the scheduling model for the
75 // MCSchedClassDesc object.
76 unsigned SchedClassID
;
78 bool isImplicitRead() const { return OpIndex
< 0; };
83 /// Tracks uses of a register definition (e.g. register write).
85 /// Each implicit/explicit register write is associated with an instance of
86 /// this class. A WriteState object tracks the dependent users of a
87 /// register write. It also tracks how many cycles are left before the write
90 const WriteDescriptor
*WD
;
91 // On instruction issue, this field is set equal to the write latency.
92 // Before instruction issue, this field defaults to -512, a special
93 // value that represents an "unknown" number of cycles.
96 // Actual register defined by this write. This field is only used
97 // to speedup queries on the register file.
98 // For implicit writes, this field always matches the value of
99 // field RegisterID from WD.
102 // Physical register file that serves register RegisterID.
105 // True if this write implicitly clears the upper portion of RegisterID's
107 bool ClearsSuperRegs
;
109 // True if this write is from a dependency breaking zero-idiom instruction.
112 // True if this write has been eliminated at register renaming stage.
113 // Example: a register move doesn't consume scheduler/pipleline resources if
114 // it is eliminated at register renaming stage. It still consumes
115 // decode bandwidth, and ROB entries.
118 // This field is set if this is a partial register write, and it has a false
119 // dependency on any previous write of the same register (or a portion of it).
120 // DependentWrite must be able to complete before this write completes, so
121 // that we don't break the WAW, and the two writes can be merged together.
122 const WriteState
*DependentWrite
;
124 // A partial write that is in a false dependency with this write.
125 WriteState
*PartialWrite
;
127 unsigned DependentWriteCyclesLeft
;
129 // A list of dependent reads. Users is a set of dependent
130 // reads. A dependent read is added to the set only if CyclesLeft
131 // is "unknown". As soon as CyclesLeft is 'known', each user in the set
132 // gets notified with the actual CyclesLeft.
134 // The 'second' element of a pair is a "ReadAdvance" number of cycles.
135 SmallVector
<std::pair
<ReadState
*, int>, 4> Users
;
138 WriteState(const WriteDescriptor
&Desc
, unsigned RegID
,
139 bool clearsSuperRegs
= false, bool writesZero
= false)
140 : WD(&Desc
), CyclesLeft(UNKNOWN_CYCLES
), RegisterID(RegID
), PRFID(0),
141 ClearsSuperRegs(clearsSuperRegs
), WritesZero(writesZero
),
142 IsEliminated(false), DependentWrite(nullptr), PartialWrite(nullptr),
143 DependentWriteCyclesLeft(0) {}
145 WriteState(const WriteState
&Other
) = default;
146 WriteState
&operator=(const WriteState
&Other
) = default;
148 int getCyclesLeft() const { return CyclesLeft
; }
149 unsigned getWriteResourceID() const { return WD
->SClassOrWriteResourceID
; }
150 unsigned getRegisterID() const { return RegisterID
; }
151 unsigned getRegisterFileID() const { return PRFID
; }
152 unsigned getLatency() const { return WD
->Latency
; }
154 void addUser(ReadState
*Use
, int ReadAdvance
);
155 void addUser(WriteState
*Use
);
157 unsigned getDependentWriteCyclesLeft() const {
158 return DependentWriteCyclesLeft
;
161 unsigned getNumUsers() const {
162 unsigned NumUsers
= Users
.size();
168 bool clearsSuperRegisters() const { return ClearsSuperRegs
; }
169 bool isWriteZero() const { return WritesZero
; }
170 bool isEliminated() const { return IsEliminated
; }
172 bool isReady() const {
173 if (getDependentWrite())
175 unsigned CyclesLeft
= getDependentWriteCyclesLeft();
176 return !CyclesLeft
|| CyclesLeft
< getLatency();
179 bool isExecuted() const {
180 return CyclesLeft
!= UNKNOWN_CYCLES
&& CyclesLeft
<= 0;
183 const WriteState
*getDependentWrite() const { return DependentWrite
; }
184 void setDependentWrite(WriteState
*Other
) { DependentWrite
= Other
; }
185 void writeStartEvent(unsigned Cycles
) {
186 DependentWriteCyclesLeft
= Cycles
;
187 DependentWrite
= nullptr;
190 void setWriteZero() { WritesZero
= true; }
191 void setEliminated() {
192 assert(Users
.empty() && "Write is in an inconsistent state.");
197 void setPRF(unsigned PRF
) { PRFID
= PRF
; }
199 // On every cycle, update CyclesLeft and notify dependent users.
201 void onInstructionIssued();
208 /// Tracks register operand latency in cycles.
210 /// A read may be dependent on more than one write. This occurs when some
211 /// writes only partially update the register associated to this read.
213 const ReadDescriptor
*RD
;
214 // Physical register identified associated to this read.
216 // Physical register file that serves register RegisterID.
218 // Number of writes that contribute to the definition of RegisterID.
219 // In the absence of partial register updates, the number of DependentWrites
220 // cannot be more than one.
221 unsigned DependentWrites
;
222 // Number of cycles left before RegisterID can be read. This value depends on
223 // the latency of all the dependent writes. It defaults to UNKNOWN_CYCLES.
224 // It gets set to the value of field TotalCycles only when the 'CyclesLeft' of
225 // every dependent write is known.
227 // This field is updated on every writeStartEvent(). When the number of
228 // dependent writes (i.e. field DependentWrite) is zero, this value is
229 // propagated to field CyclesLeft.
230 unsigned TotalCycles
;
231 // This field is set to true only if there are no dependent writes, and
232 // there are no `CyclesLeft' to wait.
234 // True if this is a read from a known zero register.
236 // True if this register read is from a dependency-breaking instruction.
237 bool IndependentFromDef
;
240 ReadState(const ReadDescriptor
&Desc
, unsigned RegID
)
241 : RD(&Desc
), RegisterID(RegID
), PRFID(0), DependentWrites(0),
242 CyclesLeft(UNKNOWN_CYCLES
), TotalCycles(0), IsReady(true),
243 IsZero(false), IndependentFromDef(false) {}
245 const ReadDescriptor
&getDescriptor() const { return *RD
; }
246 unsigned getSchedClass() const { return RD
->SchedClassID
; }
247 unsigned getRegisterID() const { return RegisterID
; }
248 unsigned getRegisterFileID() const { return PRFID
; }
250 bool isPending() const { return !IndependentFromDef
&& CyclesLeft
> 0; }
251 bool isReady() const { return IsReady
; }
252 bool isImplicitRead() const { return RD
->isImplicitRead(); }
254 bool isIndependentFromDef() const { return IndependentFromDef
; }
255 void setIndependentFromDef() { IndependentFromDef
= true; }
258 void writeStartEvent(unsigned Cycles
);
259 void setDependentWrites(unsigned Writes
) {
260 DependentWrites
= Writes
;
264 bool isReadZero() const { return IsZero
; }
265 void setReadZero() { IsZero
= true; }
266 void setPRF(unsigned ID
) { PRFID
= ID
; }
269 /// A sequence of cycles.
271 /// This class can be used as a building block to construct ranges of cycles.
273 unsigned Begin
; // Inclusive.
274 unsigned End
; // Exclusive.
275 bool Reserved
; // Resources associated to this segment must be reserved.
278 CycleSegment(unsigned StartCycle
, unsigned EndCycle
, bool IsReserved
= false)
279 : Begin(StartCycle
), End(EndCycle
), Reserved(IsReserved
) {}
281 bool contains(unsigned Cycle
) const { return Cycle
>= Begin
&& Cycle
< End
; }
282 bool startsAfter(const CycleSegment
&CS
) const { return End
<= CS
.Begin
; }
283 bool endsBefore(const CycleSegment
&CS
) const { return Begin
>= CS
.End
; }
284 bool overlaps(const CycleSegment
&CS
) const {
285 return !startsAfter(CS
) && !endsBefore(CS
);
287 bool isExecuting() const { return Begin
== 0 && End
!= 0; }
288 bool isExecuted() const { return End
== 0; }
289 bool operator<(const CycleSegment
&Other
) const {
290 return Begin
< Other
.Begin
;
292 CycleSegment
&operator--(void) {
300 bool isValid() const { return Begin
<= End
; }
301 unsigned size() const { return End
- Begin
; };
302 void subtract(unsigned Cycles
) {
303 assert(End
>= Cycles
);
307 unsigned begin() const { return Begin
; }
308 unsigned end() const { return End
; }
309 void setEnd(unsigned NewEnd
) { End
= NewEnd
; }
310 bool isReserved() const { return Reserved
; }
311 void setReserved() { Reserved
= true; }
314 /// Helper used by class InstrDesc to describe how hardware resources
317 /// This class describes how many resource units of a specific resource kind
318 /// (and how many cycles) are "used" by an instruction.
319 struct ResourceUsage
{
322 ResourceUsage(CycleSegment Cycles
, unsigned Units
= 1)
323 : CS(Cycles
), NumUnits(Units
) {}
324 unsigned size() const { return CS
.size(); }
325 bool isReserved() const { return CS
.isReserved(); }
326 void setReserved() { CS
.setReserved(); }
329 /// An instruction descriptor
331 SmallVector
<WriteDescriptor
, 4> Writes
; // Implicit writes are at the end.
332 SmallVector
<ReadDescriptor
, 4> Reads
; // Implicit reads are at the end.
334 // For every resource used by an instruction of this kind, this vector
335 // reports the number of "consumed cycles".
336 SmallVector
<std::pair
<uint64_t, ResourceUsage
>, 4> Resources
;
338 // A list of buffered resources consumed by this instruction.
339 SmallVector
<uint64_t, 4> Buffers
;
341 unsigned UsedProcResUnits
;
342 unsigned UsedProcResGroups
;
345 // Number of MicroOps for this instruction.
346 unsigned NumMicroOps
;
347 // SchedClassID used to construct this InstrDesc.
348 // This information is currently used by views to do fast queries on the
349 // subtarget when computing the reciprocal throughput.
350 unsigned SchedClassID
;
358 // True if all buffered resources are in-order, and there is at least one
359 // buffer which is a dispatch hazard (BufferSize = 0).
360 bool MustIssueImmediately
;
362 // A zero latency instruction doesn't consume any scheduler resources.
363 bool isZeroLatency() const { return !MaxLatency
&& Resources
.empty(); }
365 InstrDesc() = default;
366 InstrDesc(const InstrDesc
&Other
) = delete;
367 InstrDesc
&operator=(const InstrDesc
&Other
) = delete;
370 /// Base class for instructions consumed by the simulation pipeline.
372 /// This class tracks data dependencies as well as generic properties
373 /// of the instruction.
374 class InstructionBase
{
375 const InstrDesc
&Desc
;
377 // This field is set for instructions that are candidates for move
378 // elimination. For more information about move elimination, see the
379 // definition of RegisterMappingTracker in RegisterFile.h
380 bool IsOptimizableMove
;
382 // Output dependencies.
383 // One entry per each implicit and explicit register definition.
384 SmallVector
<WriteState
, 4> Defs
;
386 // Input dependencies.
387 // One entry per each implicit and explicit register use.
388 SmallVector
<ReadState
, 4> Uses
;
391 InstructionBase(const InstrDesc
&D
) : Desc(D
), IsOptimizableMove(false) {}
393 SmallVectorImpl
<WriteState
> &getDefs() { return Defs
; }
394 const ArrayRef
<WriteState
> getDefs() const { return Defs
; }
395 SmallVectorImpl
<ReadState
> &getUses() { return Uses
; }
396 const ArrayRef
<ReadState
> getUses() const { return Uses
; }
397 const InstrDesc
&getDesc() const { return Desc
; }
399 unsigned getLatency() const { return Desc
.MaxLatency
; }
401 bool hasDependentUsers() const {
403 [](const WriteState
&Def
) { return Def
.getNumUsers() > 0; });
406 unsigned getNumUsers() const {
407 unsigned NumUsers
= 0;
408 for (const WriteState
&Def
: Defs
)
409 NumUsers
+= Def
.getNumUsers();
413 // Returns true if this instruction is a candidate for move elimination.
414 bool isOptimizableMove() const { return IsOptimizableMove
; }
415 void setOptimizableMove() { IsOptimizableMove
= true; }
418 /// An instruction propagated through the simulated instruction pipeline.
420 /// This class is used to monitor changes to the internal state of instructions
421 /// that are sent to the various components of the simulated hardware pipeline.
422 class Instruction
: public InstructionBase
{
424 IS_INVALID
, // Instruction in an invalid state.
425 IS_DISPATCHED
, // Instruction dispatched but operands are not ready.
426 IS_PENDING
, // Instruction is not ready, but operand latency is known.
427 IS_READY
, // Instruction dispatched and operands ready.
428 IS_EXECUTING
, // Instruction issued.
429 IS_EXECUTED
, // Instruction executed. Values are written back.
430 IS_RETIRED
// Instruction retired.
433 // The current instruction stage.
434 enum InstrStage Stage
;
436 // This value defaults to the instruction latency. This instruction is
437 // considered executed when field CyclesLeft goes to zero.
440 // Retire Unit token ID for this instruction.
444 Instruction(const InstrDesc
&D
)
445 : InstructionBase(D
), Stage(IS_INVALID
), CyclesLeft(UNKNOWN_CYCLES
),
448 unsigned getRCUTokenID() const { return RCUTokenID
; }
449 int getCyclesLeft() const { return CyclesLeft
; }
451 // Transition to the dispatch stage, and assign a RCUToken to this
452 // instruction. The RCUToken is used to track the completion of every
453 // register write performed by this instruction.
454 void dispatch(unsigned RCUTokenID
);
456 // Instruction issued. Transition to the IS_EXECUTING state, and update
457 // all the definitions.
460 // Force a transition from the IS_DISPATCHED state to the IS_READY or
461 // IS_PENDING state. State transitions normally occur either at the beginning
462 // of a new cycle (see method cycleEvent()), or as a result of another issue
463 // event. This method is called every time the instruction might have changed
464 // in state. It internally delegates to method updateDispatched() and
467 bool updateDispatched();
468 bool updatePending();
470 bool isDispatched() const { return Stage
== IS_DISPATCHED
; }
471 bool isPending() const { return Stage
== IS_PENDING
; }
472 bool isReady() const { return Stage
== IS_READY
; }
473 bool isExecuting() const { return Stage
== IS_EXECUTING
; }
474 bool isExecuted() const { return Stage
== IS_EXECUTED
; }
475 bool isRetired() const { return Stage
== IS_RETIRED
; }
477 bool isEliminated() const {
478 return isReady() && getDefs().size() &&
480 [](const WriteState
&W
) { return W
.isEliminated(); });
483 // Forces a transition from state IS_DISPATCHED to state IS_EXECUTED.
484 void forceExecuted();
487 assert(isExecuted() && "Instruction is in an invalid state!");
494 /// An InstRef contains both a SourceMgr index and Instruction pair. The index
495 /// is used as a unique identifier for the instruction. MCA will make use of
496 /// this index as a key throughout MCA.
498 std::pair
<unsigned, Instruction
*> Data
;
501 InstRef() : Data(std::make_pair(0, nullptr)) {}
502 InstRef(unsigned Index
, Instruction
*I
) : Data(std::make_pair(Index
, I
)) {}
504 bool operator==(const InstRef
&Other
) const { return Data
== Other
.Data
; }
506 unsigned getSourceIndex() const { return Data
.first
; }
507 Instruction
*getInstruction() { return Data
.second
; }
508 const Instruction
*getInstruction() const { return Data
.second
; }
510 /// Returns true if this references a valid instruction.
511 operator bool() const { return Data
.second
!= nullptr; }
513 /// Invalidate this reference.
514 void invalidate() { Data
.second
= nullptr; }
517 void print(raw_ostream
&OS
) const { OS
<< getSourceIndex(); }
522 inline raw_ostream
&operator<<(raw_ostream
&OS
, const InstRef
&IR
) {
528 /// A reference to a register write.
530 /// This class is mainly used by the register file to describe register
531 /// mappings. It correlates a register write to the source index of the
532 /// defining instruction.
534 std::pair
<unsigned, WriteState
*> Data
;
535 static const unsigned INVALID_IID
;
538 WriteRef() : Data(INVALID_IID
, nullptr) {}
539 WriteRef(unsigned SourceIndex
, WriteState
*WS
) : Data(SourceIndex
, WS
) {}
541 unsigned getSourceIndex() const { return Data
.first
; }
542 const WriteState
*getWriteState() const { return Data
.second
; }
543 WriteState
*getWriteState() { return Data
.second
; }
544 void invalidate() { Data
.second
= nullptr; }
545 bool isWriteZero() const {
546 assert(isValid() && "Invalid null WriteState found!");
547 return getWriteState()->isWriteZero();
550 /// Returns true if this register write has been executed, and the new
551 /// register value is therefore available to users.
552 bool isAvailable() const {
553 if (getSourceIndex() == INVALID_IID
)
555 const WriteState
*WS
= getWriteState();
556 return !WS
|| WS
->isExecuted();
559 bool isValid() const { return Data
.first
!= INVALID_IID
&& Data
.second
; }
560 bool operator==(const WriteRef
&Other
) const { return Data
== Other
.Data
; }
570 #endif // LLVM_MCA_INSTRUCTION_H