Recommit [NFC] Better encapsulation of llvm::Optional Storage
[llvm-complete.git] / include / llvm / MCA / Instruction.h
blob658b7fe4f891c6e6ad9a291b3daea1a90fa7b0c2
1 //===--------------------- Instruction.h ------------------------*- 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 /// \file
9 ///
10 /// This file defines abstractions used by the Pipeline to model register reads,
11 /// register writes and instructions.
12 ///
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"
23 #ifndef NDEBUG
24 #include "llvm/Support/raw_ostream.h"
25 #endif
27 #include <memory>
29 namespace llvm {
31 namespace mca {
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.
40 int OpIndex;
41 // Write latency. Number of cycles before write-back stage.
42 unsigned Latency;
43 // This field is set to a value different than zero only if this
44 // is an implicit definition.
45 unsigned RegisterID;
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
53 // write-back stage).
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
57 // register").
58 bool IsOptionalDef;
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.
68 int OpIndex;
69 // The actual "UseIdx". This is used to query the ReadAdvance table. Explicit
70 // uses always come first in the sequence of uses.
71 unsigned UseIndex;
72 // This field is only set if this is an implicit read.
73 unsigned RegisterID;
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; };
81 class ReadState;
83 /// Tracks uses of a register definition (e.g. register write).
84 ///
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
88 /// back stage.
89 class WriteState {
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.
94 int CyclesLeft;
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.
100 unsigned RegisterID;
102 // Physical register file that serves register RegisterID.
103 unsigned PRFID;
105 // True if this write implicitly clears the upper portion of RegisterID's
106 // super-registers.
107 bool ClearsSuperRegs;
109 // True if this write is from a dependency breaking zero-idiom instruction.
110 bool WritesZero;
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.
116 bool IsEliminated;
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;
137 public:
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();
163 if (PartialWrite)
164 ++NumUsers;
165 return NumUsers;
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())
174 return false;
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.");
193 CyclesLeft = 0;
194 IsEliminated = true;
197 void setPRF(unsigned PRF) { PRFID = PRF; }
199 // On every cycle, update CyclesLeft and notify dependent users.
200 void cycleEvent();
201 void onInstructionIssued();
203 #ifndef NDEBUG
204 void dump() const;
205 #endif
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.
212 class ReadState {
213 const ReadDescriptor *RD;
214 // Physical register identified associated to this read.
215 unsigned RegisterID;
216 // Physical register file that serves register RegisterID.
217 unsigned PRFID;
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.
226 int CyclesLeft;
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.
233 bool IsReady;
234 // True if this is a read from a known zero register.
235 bool IsZero;
236 // True if this register read is from a dependency-breaking instruction.
237 bool IndependentFromDef;
239 public:
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; }
257 void cycleEvent();
258 void writeStartEvent(unsigned Cycles);
259 void setDependentWrites(unsigned Writes) {
260 DependentWrites = Writes;
261 IsReady = !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.
272 class CycleSegment {
273 unsigned Begin; // Inclusive.
274 unsigned End; // Exclusive.
275 bool Reserved; // Resources associated to this segment must be reserved.
277 public:
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) {
293 if (Begin)
294 Begin--;
295 if (End)
296 End--;
297 return *this;
300 bool isValid() const { return Begin <= End; }
301 unsigned size() const { return End - Begin; };
302 void subtract(unsigned Cycles) {
303 assert(End >= Cycles);
304 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
315 /// are used.
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 {
320 CycleSegment CS;
321 unsigned NumUnits;
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
330 struct InstrDesc {
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;
344 unsigned MaxLatency;
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;
352 bool MayLoad;
353 bool MayStore;
354 bool HasSideEffects;
355 bool BeginGroup;
356 bool EndGroup;
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;
390 public:
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 {
402 return any_of(Defs,
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();
410 return NumUsers;
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 {
423 enum InstrStage {
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.
438 int CyclesLeft;
440 // Retire Unit token ID for this instruction.
441 unsigned RCUTokenID;
443 public:
444 Instruction(const InstrDesc &D)
445 : InstructionBase(D), Stage(IS_INVALID), CyclesLeft(UNKNOWN_CYCLES),
446 RCUTokenID(0) {}
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.
458 void execute();
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
465 // updateWaiting().
466 void update();
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() &&
479 all_of(getDefs(),
480 [](const WriteState &W) { return W.isEliminated(); });
483 // Forces a transition from state IS_DISPATCHED to state IS_EXECUTED.
484 void forceExecuted();
486 void retire() {
487 assert(isExecuted() && "Instruction is in an invalid state!");
488 Stage = IS_RETIRED;
491 void cycleEvent();
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.
497 class InstRef {
498 std::pair<unsigned, Instruction *> Data;
500 public:
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; }
516 #ifndef NDEBUG
517 void print(raw_ostream &OS) const { OS << getSourceIndex(); }
518 #endif
521 #ifndef NDEBUG
522 inline raw_ostream &operator<<(raw_ostream &OS, const InstRef &IR) {
523 IR.print(OS);
524 return OS;
526 #endif
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.
533 class WriteRef {
534 std::pair<unsigned, WriteState *> Data;
535 static const unsigned INVALID_IID;
537 public:
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)
554 return false;
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; }
562 #ifndef NDEBUG
563 void dump() const;
564 #endif
567 } // namespace mca
568 } // namespace llvm
570 #endif // LLVM_MCA_INSTRUCTION_H