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//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_MCA_INSTRUCTION_H
16#define LLVM_MCA_INSTRUCTION_H
17
18#include "llvm/ADT/ArrayRef.h"
19#include "llvm/ADT/STLExtras.h"
20#include "llvm/ADT/SmallVector.h"
21#include "llvm/MC/MCRegister.h" // definition of MCPhysReg.
22#include "llvm/Support/Compiler.h"
23#include "llvm/Support/MathExtras.h"
24
25#ifndef NDEBUG
26#include "llvm/Support/raw_ostream.h"
27#endif
28
29#include <memory>
30
31namespace llvm {
32
33namespace mca {
34
35constexpr int UNKNOWN_CYCLES = -512;
36
37/// A representation of an mca::Instruction operand
38/// for use in mca::CustomBehaviour.
39class MCAOperand {
40 // This class is mostly copied from MCOperand within
41 // MCInst.h except that we don't keep track of
42 // expressions or sub-instructions.
43 enum MCAOperandType : unsigned char {
44 kInvalid, ///< Uninitialized, Relocatable immediate, or Sub-instruction.
45 kRegister, ///< Register operand.
46 kImmediate, ///< Immediate operand.
47 kSFPImmediate, ///< Single-floating-point immediate operand.
48 kDFPImmediate, ///< Double-Floating-point immediate operand.
49 };
50 MCAOperandType Kind;
51
52 union {
53 unsigned RegVal;
54 int64_t ImmVal;
55 uint32_t SFPImmVal;
56 uint64_t FPImmVal;
57 };
58
59 // We only store specific operands for specific instructions
60 // so an instruction's operand 3 may be stored within the list
61 // of MCAOperand as element 0. This Index attribute keeps track
62 // of the original index (3 for this example).
63 unsigned Index;
64
65public:
66 MCAOperand() : Kind(kInvalid), FPImmVal(), Index() {}
67
68 bool isValid() const { return Kind != kInvalid; }
69 bool isReg() const { return Kind == kRegister; }
70 bool isImm() const { return Kind == kImmediate; }
71 bool isSFPImm() const { return Kind == kSFPImmediate; }
72 bool isDFPImm() const { return Kind == kDFPImmediate; }
73
74 /// Returns the register number.
75 unsigned getReg() const {
76 assert(isReg() && "This is not a register operand!");
77 return RegVal;
78 }
79
80 int64_t getImm() const {
81 assert(isImm() && "This is not an immediate");
82 return ImmVal;
83 }
84
85 uint32_t getSFPImm() const {
86 assert(isSFPImm() && "This is not an SFP immediate");
87 return SFPImmVal;
88 }
89
90 uint64_t getDFPImm() const {
91 assert(isDFPImm() && "This is not an FP immediate");
92 return FPImmVal;
93 }
94
95 void setIndex(const unsigned Idx) { Index = Idx; }
96
97 unsigned getIndex() const { return Index; }
98
99 static MCAOperand createReg(unsigned Reg) {
100 MCAOperand Op;
101 Op.Kind = kRegister;
102 Op.RegVal = Reg;
103 return Op;
104 }
105
106 static MCAOperand createImm(int64_t Val) {
107 MCAOperand Op;
108 Op.Kind = kImmediate;
109 Op.ImmVal = Val;
110 return Op;
111 }
112
113 static MCAOperand createSFPImm(uint32_t Val) {
114 MCAOperand Op;
115 Op.Kind = kSFPImmediate;
116 Op.SFPImmVal = Val;
117 return Op;
118 }
119
120 static MCAOperand createDFPImm(uint64_t Val) {
121 MCAOperand Op;
122 Op.Kind = kDFPImmediate;
123 Op.FPImmVal = Val;
124 return Op;
125 }
126
127 static MCAOperand createInvalid() {
128 MCAOperand Op;
129 Op.Kind = kInvalid;
130 Op.FPImmVal = 0;
131 return Op;
132 }
133};
134
135/// A register write descriptor.
136struct WriteDescriptor {
137 // Operand index. The index is negative for implicit writes only.
138 // For implicit writes, the actual operand index is computed performing
139 // a bitwise not of the OpIndex.
140 int OpIndex;
141 // Write latency. Number of cycles before write-back stage.
142 unsigned Latency;
143 // This field is set to a value different than zero only if this
144 // is an implicit definition.
145 MCPhysReg RegisterID;
146 // Instruction itineraries would set this field to the SchedClass ID.
147 // Otherwise, it defaults to the WriteResourceID from the MCWriteLatencyEntry
148 // element associated to this write.
149 // When computing read latencies, this value is matched against the
150 // "ReadAdvance" information. The hardware backend may implement
151 // dedicated forwarding paths to quickly propagate write results to dependent
152 // instructions waiting in the reservation station (effectively bypassing the
153 // write-back stage).
154 unsigned SClassOrWriteResourceID;
155 // True only if this is a write obtained from an optional definition.
156 // Optional definitions are allowed to reference regID zero (i.e. "no
157 // register").
158 bool IsOptionalDef;
159
160 bool isImplicitWrite() const { return OpIndex < 0; };
161};
162
163/// A register read descriptor.
164struct ReadDescriptor {
165 // A MCOperand index. This is used by the Dispatch logic to identify register
166 // reads. Implicit reads have negative indices. The actual operand index of an
167 // implicit read is the bitwise not of field OpIndex.
168 int OpIndex;
169 // The actual "UseIdx". This is used to query the ReadAdvance table. Explicit
170 // uses always come first in the sequence of uses.
171 unsigned UseIndex;
172 // This field is only set if this is an implicit read.
173 MCPhysReg RegisterID;
174 // Scheduling Class Index. It is used to query the scheduling model for the
175 // MCSchedClassDesc object.
176 unsigned SchedClassID;
177
178 bool isImplicitRead() const { return OpIndex < 0; };
179};
180
181class ReadState;
182
183/// A critical data dependency descriptor.
184///
185/// Field RegID is set to the invalid register for memory dependencies.
186struct CriticalDependency {
187 unsigned IID;
188 MCPhysReg RegID;
189 unsigned Cycles;
190};
191
192/// Tracks uses of a register definition (e.g. register write).
193///
194/// Each implicit/explicit register write is associated with an instance of
195/// this class. A WriteState object tracks the dependent users of a
196/// register write. It also tracks how many cycles are left before the write
197/// back stage.
198class WriteState {
199 const WriteDescriptor *WD;
200 // On instruction issue, this field is set equal to the write latency.
201 // Before instruction issue, this field defaults to -512, a special
202 // value that represents an "unknown" number of cycles.
203 int CyclesLeft;
204
205 // Actual register defined by this write. This field is only used
206 // to speedup queries on the register file.
207 // For implicit writes, this field always matches the value of
208 // field RegisterID from WD.
209 MCPhysReg RegisterID;
210
211 // Physical register file that serves register RegisterID.
212 unsigned PRFID;
213
214 // True if this write implicitly clears the upper portion of RegisterID's
215 // super-registers.
216 bool ClearsSuperRegs;
217
218 // True if this write is from a dependency breaking zero-idiom instruction.
219 bool WritesZero;
220
221 // True if this write has been eliminated at register renaming stage.
222 // Example: a register move doesn't consume scheduler/pipleline resources if
223 // it is eliminated at register renaming stage. It still consumes
224 // decode bandwidth, and ROB entries.
225 bool IsEliminated;
226
227 // This field is set if this is a partial register write, and it has a false
228 // dependency on any previous write of the same register (or a portion of it).
229 // DependentWrite must be able to complete before this write completes, so
230 // that we don't break the WAW, and the two writes can be merged together.
231 const WriteState *DependentWrite;
232
233 // A partial write that is in a false dependency with this write.
234 WriteState *PartialWrite;
235 unsigned DependentWriteCyclesLeft;
236
237 // Critical register dependency for this write.
238 CriticalDependency CRD;
239
240 // A list of dependent reads. Users is a set of dependent
241 // reads. A dependent read is added to the set only if CyclesLeft
242 // is "unknown". As soon as CyclesLeft is 'known', each user in the set
243 // gets notified with the actual CyclesLeft.
244
245 // The 'second' element of a pair is a "ReadAdvance" number of cycles.
246 SmallVector<std::pair<ReadState *, int>, 4> Users;
247
248public:
249 WriteState(const WriteDescriptor &Desc, MCPhysReg RegID,
250 bool clearsSuperRegs = false, bool writesZero = false)
251 : WD(&Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID), PRFID(0),
252 ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero),
253 IsEliminated(false), DependentWrite(nullptr), PartialWrite(nullptr),
254 DependentWriteCyclesLeft(0), CRD() {}
255
256 WriteState(const WriteState &Other) = default;
257 WriteState &operator=(const WriteState &Other) = default;
258
259 int getCyclesLeft() const { return CyclesLeft; }
260 unsigned getWriteResourceID() const { return WD->SClassOrWriteResourceID; }
261 MCPhysReg getRegisterID() const { return RegisterID; }
262 void setRegisterID(const MCPhysReg RegID) { RegisterID = RegID; }
263 unsigned getRegisterFileID() const { return PRFID; }
264 unsigned getLatency() const { return WD->Latency; }
265 unsigned getDependentWriteCyclesLeft() const {
266 return DependentWriteCyclesLeft;
267 }
268 const WriteState *getDependentWrite() const { return DependentWrite; }
269 const CriticalDependency &getCriticalRegDep() const { return CRD; }
270
271 // This method adds Use to the set of data dependent reads. IID is the
272 // instruction identifier associated with this write. ReadAdvance is the
273 // number of cycles to subtract from the latency of this data dependency.
274 // Use is in a RAW dependency with this write.
275 LLVM_ABI void addUser(unsigned IID, ReadState *Use, int ReadAdvance);
276
277 // Use is a younger register write that is in a false dependency with this
278 // write. IID is the instruction identifier associated with this write.
279 LLVM_ABI void addUser(unsigned IID, WriteState *Use);
280
281 unsigned getNumUsers() const {
282 unsigned NumUsers = Users.size();
283 if (PartialWrite)
284 ++NumUsers;
285 return NumUsers;
286 }
287
288 bool clearsSuperRegisters() const { return ClearsSuperRegs; }
289 bool isWriteZero() const { return WritesZero; }
290 bool isEliminated() const { return IsEliminated; }
291
292 bool isReady() const {
293 if (DependentWrite)
294 return false;
295 unsigned CyclesLeft = getDependentWriteCyclesLeft();
296 return !CyclesLeft || CyclesLeft < getLatency();
297 }
298
299 bool isExecuted() const {
300 return CyclesLeft != UNKNOWN_CYCLES && CyclesLeft <= 0;
301 }
302
303 void setDependentWrite(const WriteState *Other) { DependentWrite = Other; }
304 LLVM_ABI void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
305 void setWriteZero() { WritesZero = true; }
306 void setEliminated() {
307 assert(Users.empty() && "Write is in an inconsistent state.");
308 CyclesLeft = 0;
309 IsEliminated = true;
310 }
311
312 void setPRF(unsigned PRF) { PRFID = PRF; }
313
314 // On every cycle, update CyclesLeft and notify dependent users.
315 LLVM_ABI void cycleEvent();
316 LLVM_ABI void onInstructionIssued(unsigned IID);
317
318#ifndef NDEBUG
319 void dump() const;
320#endif
321};
322
323/// Tracks register operand latency in cycles.
324///
325/// A read may be dependent on more than one write. This occurs when some
326/// writes only partially update the register associated to this read.
327class ReadState {
328 const ReadDescriptor *RD;
329 // Physical register identified associated to this read.
330 MCPhysReg RegisterID;
331 // Physical register file that serves register RegisterID.
332 unsigned PRFID;
333 // Number of writes that contribute to the definition of RegisterID.
334 // In the absence of partial register updates, the number of DependentWrites
335 // cannot be more than one.
336 unsigned DependentWrites;
337 // Number of cycles left before RegisterID can be read. This value depends on
338 // the latency of all the dependent writes. It defaults to UNKNOWN_CYCLES.
339 // It gets set to the value of field TotalCycles only when the 'CyclesLeft' of
340 // every dependent write is known.
341 int CyclesLeft;
342 // This field is updated on every writeStartEvent(). When the number of
343 // dependent writes (i.e. field DependentWrite) is zero, this value is
344 // propagated to field CyclesLeft.
345 unsigned TotalCycles;
346 // Longest register dependency.
347 CriticalDependency CRD;
348 // This field is set to true only if there are no dependent writes, and
349 // there are no `CyclesLeft' to wait.
350 bool IsReady;
351 // True if this is a read from a known zero register.
352 bool IsZero;
353 // True if this register read is from a dependency-breaking instruction.
354 bool IndependentFromDef;
355
356public:
357 ReadState(const ReadDescriptor &Desc, MCPhysReg RegID)
358 : RD(&Desc), RegisterID(RegID), PRFID(0), DependentWrites(0),
359 CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), CRD(), IsReady(true),
360 IsZero(false), IndependentFromDef(false) {}
361
362 const ReadDescriptor &getDescriptor() const { return *RD; }
363 unsigned getSchedClass() const { return RD->SchedClassID; }
364 MCPhysReg getRegisterID() const { return RegisterID; }
365 unsigned getRegisterFileID() const { return PRFID; }
366 const CriticalDependency &getCriticalRegDep() const { return CRD; }
367
368 bool isPending() const { return !IndependentFromDef && CyclesLeft > 0; }
369 bool isReady() const { return IsReady; }
370 bool isImplicitRead() const { return RD->isImplicitRead(); }
371
372 bool isIndependentFromDef() const { return IndependentFromDef; }
373 void setIndependentFromDef() { IndependentFromDef = true; }
374
375 LLVM_ABI void cycleEvent();
376 LLVM_ABI void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
377 void setDependentWrites(unsigned Writes) {
378 DependentWrites = Writes;
379 IsReady = !Writes;
380 }
381
382 bool isReadZero() const { return IsZero; }
383 void setReadZero() { IsZero = true; }
384 void setPRF(unsigned ID) { PRFID = ID; }
385};
386
387/// A sequence of cycles.
388///
389/// This class can be used as a building block to construct ranges of cycles.
390class CycleSegment {
391 unsigned Begin; // Inclusive.
392 unsigned End; // Exclusive.
393 bool Reserved; // Resources associated to this segment must be reserved.
394
395public:
396 CycleSegment(unsigned StartCycle, unsigned EndCycle, bool IsReserved = false)
397 : Begin(StartCycle), End(EndCycle), Reserved(IsReserved) {}
398
399 bool contains(unsigned Cycle) const { return Cycle >= Begin && Cycle < End; }
400 bool startsAfter(const CycleSegment &CS) const { return End <= CS.Begin; }
401 bool endsBefore(const CycleSegment &CS) const { return Begin >= CS.End; }
402 bool overlaps(const CycleSegment &CS) const {
403 return !startsAfter(CS) && !endsBefore(CS);
404 }
405 bool isExecuting() const { return Begin == 0 && End != 0; }
406 bool isExecuted() const { return End == 0; }
407 bool operator<(const CycleSegment &Other) const {
408 return Begin < Other.Begin;
409 }
410 CycleSegment &operator--() {
411 if (Begin)
412 Begin--;
413 if (End)
414 End--;
415 return *this;
416 }
417
418 bool isValid() const { return Begin <= End; }
419 unsigned size() const { return End - Begin; };
420 void subtract(unsigned Cycles) {
421 assert(End >= Cycles);
422 End -= Cycles;
423 }
424
425 unsigned begin() const { return Begin; }
426 unsigned end() const { return End; }
427 void setEnd(unsigned NewEnd) { End = NewEnd; }
428 bool isReserved() const { return Reserved; }
429 void setReserved() { Reserved = true; }
430};
431
432/// Helper used by class InstrDesc to describe how hardware resources
433/// are used.
434///
435/// This class describes how many resource units of a specific resource kind
436/// (and how many cycles) are "used" by an instruction.
437struct ResourceUsage {
438 CycleSegment CS;
439 unsigned NumUnits;
440 ResourceUsage(CycleSegment Cycles, unsigned Units = 1)
441 : CS(Cycles), NumUnits(Units) {}
442 unsigned size() const { return CS.size(); }
443 bool isReserved() const { return CS.isReserved(); }
444 void setReserved() { CS.setReserved(); }
445};
446
447/// An instruction descriptor
448struct InstrDesc {
449 SmallVector<WriteDescriptor, 2> Writes; // Implicit writes are at the end.
450 SmallVector<ReadDescriptor, 4> Reads; // Implicit reads are at the end.
451
452 // For every resource used by an instruction of this kind, this vector
453 // reports the number of "consumed cycles".
454 SmallVector<std::pair<uint64_t, ResourceUsage>, 4> Resources;
455
456 // A bitmask of used hardware buffers.
457 uint64_t UsedBuffers;
458
459 // A bitmask of used processor resource units.
460 uint64_t UsedProcResUnits;
461
462 // A bitmask of used processor resource groups.
463 uint64_t UsedProcResGroups;
464
465 unsigned MaxLatency;
466 // Number of MicroOps for this instruction.
467 unsigned NumMicroOps;
468 // SchedClassID used to construct this InstrDesc.
469 // This information is currently used by views to do fast queries on the
470 // subtarget when computing the reciprocal throughput.
471 unsigned SchedClassID;
472
473 // True if all buffered resources are in-order, and there is at least one
474 // buffer which is a dispatch hazard (BufferSize = 0).
475 unsigned MustIssueImmediately : 1;
476
477 // True if the corresponding mca::Instruction can be recycled. Currently only
478 // instructions that are neither variadic nor have any variant can be
479 // recycled.
480 unsigned IsRecyclable : 1;
481
482 // True if some of the consumed group resources are partially overlapping.
483 unsigned HasPartiallyOverlappingGroups : 1;
484
485 // A zero latency instruction doesn't consume any scheduler resources.
486 bool isZeroLatency() const { return !MaxLatency && Resources.empty(); }
487
488 InstrDesc() = default;
489 InstrDesc(const InstrDesc &Other) = delete;
490 InstrDesc &operator=(const InstrDesc &Other) = delete;
491};
492
493/// Base class for instructions consumed by the simulation pipeline.
494///
495/// This class tracks data dependencies as well as generic properties
496/// of the instruction.
497class InstructionBase {
498 const InstrDesc &Desc;
499
500 // This field is set for instructions that are candidates for move
501 // elimination. For more information about move elimination, see the
502 // definition of RegisterMappingTracker in RegisterFile.h
503 bool IsOptimizableMove;
504
505 // Output dependencies.
506 // One entry per each implicit and explicit register definition.
507 SmallVector<WriteState, 2> Defs;
508
509 // Input dependencies.
510 // One entry per each implicit and explicit register use.
511 SmallVector<ReadState, 4> Uses;
512
513 // List of operands which can be used by mca::CustomBehaviour
514 std::vector<MCAOperand> Operands;
515
516 // Instruction opcode which can be used by mca::CustomBehaviour
517 unsigned Opcode;
518
519 // Flags used by the LSUnit.
520 bool IsALoadBarrier : 1;
521 bool IsAStoreBarrier : 1;
522 // Flags copied from the InstrDesc and potentially modified by
523 // CustomBehaviour or (more likely) InstrPostProcess.
524 bool MayLoad : 1;
525 bool MayStore : 1;
526 bool HasSideEffects : 1;
527 bool BeginGroup : 1;
528 bool EndGroup : 1;
529 bool RetireOOO : 1;
530
531public:
532 InstructionBase(const InstrDesc &D, const unsigned Opcode)
533 : Desc(D), IsOptimizableMove(false), Operands(0), Opcode(Opcode),
534 IsALoadBarrier(false), IsAStoreBarrier(false) {}
535
536 SmallVectorImpl<WriteState> &getDefs() { return Defs; }
537 ArrayRef<WriteState> getDefs() const { return Defs; }
538 SmallVectorImpl<ReadState> &getUses() { return Uses; }
539 ArrayRef<ReadState> getUses() const { return Uses; }
540 const InstrDesc &getDesc() const { return Desc; }
541
542 unsigned getLatency() const { return Desc.MaxLatency; }
543 unsigned getNumMicroOps() const { return Desc.NumMicroOps; }
544 unsigned getOpcode() const { return Opcode; }
545 bool isALoadBarrier() const { return IsALoadBarrier; }
546 bool isAStoreBarrier() const { return IsAStoreBarrier; }
547 void setLoadBarrier(bool IsBarrier) { IsALoadBarrier = IsBarrier; }
548 void setStoreBarrier(bool IsBarrier) { IsAStoreBarrier = IsBarrier; }
549
550 /// Return the MCAOperand which corresponds to index Idx within the original
551 /// MCInst.
552 const MCAOperand *getOperand(const unsigned Idx) const {
553 auto It = llvm::find_if(Range: Operands, P: [&Idx](const MCAOperand &Op) {
554 return Op.getIndex() == Idx;
555 });
556 if (It == Operands.end())
557 return nullptr;
558 return &(*It);
559 }
560 unsigned getNumOperands() const { return Operands.size(); }
561 void addOperand(const MCAOperand Op) { Operands.push_back(x: Op); }
562
563 bool hasDependentUsers() const {
564 return any_of(Range: Defs,
565 P: [](const WriteState &Def) { return Def.getNumUsers() > 0; });
566 }
567
568 unsigned getNumUsers() const {
569 unsigned NumUsers = 0;
570 for (const WriteState &Def : Defs)
571 NumUsers += Def.getNumUsers();
572 return NumUsers;
573 }
574
575 // Returns true if this instruction is a candidate for move elimination.
576 bool isOptimizableMove() const { return IsOptimizableMove; }
577 void setOptimizableMove() { IsOptimizableMove = true; }
578 void clearOptimizableMove() { IsOptimizableMove = false; }
579 bool isMemOp() const { return MayLoad || MayStore; }
580
581 // Getters and setters for general instruction flags.
582 void setMayLoad(bool newVal) { MayLoad = newVal; }
583 void setMayStore(bool newVal) { MayStore = newVal; }
584 void setHasSideEffects(bool newVal) { HasSideEffects = newVal; }
585 void setBeginGroup(bool newVal) { BeginGroup = newVal; }
586 void setEndGroup(bool newVal) { EndGroup = newVal; }
587 void setRetireOOO(bool newVal) { RetireOOO = newVal; }
588
589 bool getMayLoad() const { return MayLoad; }
590 bool getMayStore() const { return MayStore; }
591 bool getHasSideEffects() const { return HasSideEffects; }
592 bool getBeginGroup() const { return BeginGroup; }
593 bool getEndGroup() const { return EndGroup; }
594 bool getRetireOOO() const { return RetireOOO; }
595};
596
597/// An instruction propagated through the simulated instruction pipeline.
598///
599/// This class is used to monitor changes to the internal state of instructions
600/// that are sent to the various components of the simulated hardware pipeline.
601class Instruction : public InstructionBase {
602 enum InstrStage {
603 IS_INVALID, // Instruction in an invalid state.
604 IS_DISPATCHED, // Instruction dispatched but operands are not ready.
605 IS_PENDING, // Instruction is not ready, but operand latency is known.
606 IS_READY, // Instruction dispatched and operands ready.
607 IS_EXECUTING, // Instruction issued.
608 IS_EXECUTED, // Instruction executed. Values are written back.
609 IS_RETIRED // Instruction retired.
610 };
611
612 // The current instruction stage.
613 enum InstrStage Stage;
614
615 // This value defaults to the instruction latency. This instruction is
616 // considered executed when field CyclesLeft goes to zero.
617 int CyclesLeft;
618
619 // Retire Unit token ID for this instruction.
620 unsigned RCUTokenID;
621
622 // LS token ID for this instruction.
623 // This field is set to the invalid null token if this is not a memory
624 // operation.
625 unsigned LSUTokenID;
626
627 // A resource mask which identifies buffered resources consumed by this
628 // instruction at dispatch stage. In the absence of macro-fusion, this value
629 // should always match the value of field `UsedBuffers` from the instruction
630 // descriptor (see field InstrBase::Desc).
631 uint64_t UsedBuffers;
632
633 // Critical register dependency.
634 CriticalDependency CriticalRegDep;
635
636 // Critical memory dependency.
637 CriticalDependency CriticalMemDep;
638
639 // A bitmask of busy processor resource units.
640 // This field is set to zero only if execution is not delayed during this
641 // cycle because of unavailable pipeline resources.
642 uint64_t CriticalResourceMask;
643
644 // True if this instruction has been optimized at register renaming stage.
645 bool IsEliminated;
646
647public:
648 Instruction(const InstrDesc &D, const unsigned Opcode)
649 : InstructionBase(D, Opcode), Stage(IS_INVALID),
650 CyclesLeft(UNKNOWN_CYCLES), RCUTokenID(0), LSUTokenID(0),
651 UsedBuffers(D.UsedBuffers), CriticalRegDep(), CriticalMemDep(),
652 CriticalResourceMask(0), IsEliminated(false) {}
653
654 LLVM_ABI void reset();
655
656 unsigned getRCUTokenID() const { return RCUTokenID; }
657 unsigned getLSUTokenID() const { return LSUTokenID; }
658 void setLSUTokenID(unsigned LSUTok) { LSUTokenID = LSUTok; }
659
660 uint64_t getUsedBuffers() const { return UsedBuffers; }
661 void setUsedBuffers(uint64_t Mask) { UsedBuffers = Mask; }
662 void clearUsedBuffers() { UsedBuffers = 0ULL; }
663
664 int getCyclesLeft() const { return CyclesLeft; }
665
666 // Transition to the dispatch stage, and assign a RCUToken to this
667 // instruction. The RCUToken is used to track the completion of every
668 // register write performed by this instruction.
669 LLVM_ABI void dispatch(unsigned RCUTokenID);
670
671 // Instruction issued. Transition to the IS_EXECUTING state, and update
672 // all the register definitions.
673 LLVM_ABI void execute(unsigned IID);
674
675 // Force a transition from the IS_DISPATCHED state to the IS_READY or
676 // IS_PENDING state. State transitions normally occur either at the beginning
677 // of a new cycle (see method cycleEvent()), or as a result of another issue
678 // event. This method is called every time the instruction might have changed
679 // in state. It internally delegates to method updateDispatched() and
680 // updateWaiting().
681 LLVM_ABI void update();
682 LLVM_ABI bool updateDispatched();
683 LLVM_ABI bool updatePending();
684
685 bool isInvalid() const { return Stage == IS_INVALID; }
686 bool isDispatched() const { return Stage == IS_DISPATCHED; }
687 bool isPending() const { return Stage == IS_PENDING; }
688 bool isReady() const { return Stage == IS_READY; }
689 bool isExecuting() const { return Stage == IS_EXECUTING; }
690 bool isExecuted() const { return Stage == IS_EXECUTED; }
691 bool isRetired() const { return Stage == IS_RETIRED; }
692 bool isEliminated() const { return IsEliminated; }
693
694 // Forces a transition from state IS_DISPATCHED to state IS_EXECUTED.
695 LLVM_ABI void forceExecuted();
696 void setEliminated() { IsEliminated = true; }
697
698 void retire() {
699 assert(isExecuted() && "Instruction is in an invalid state!");
700 Stage = IS_RETIRED;
701 }
702
703 const CriticalDependency &getCriticalRegDep() const { return CriticalRegDep; }
704 const CriticalDependency &getCriticalMemDep() const { return CriticalMemDep; }
705 LLVM_ABI const CriticalDependency &computeCriticalRegDep();
706 void setCriticalMemDep(const CriticalDependency &MemDep) {
707 CriticalMemDep = MemDep;
708 }
709
710 uint64_t getCriticalResourceMask() const { return CriticalResourceMask; }
711 void setCriticalResourceMask(uint64_t ResourceMask) {
712 CriticalResourceMask = ResourceMask;
713 }
714
715 LLVM_ABI void cycleEvent();
716};
717
718/// An InstRef contains both a SourceMgr index and Instruction pair. The index
719/// is used as a unique identifier for the instruction. MCA will make use of
720/// this index as a key throughout MCA.
721class InstRef {
722 std::pair<unsigned, Instruction *> Data;
723
724public:
725 InstRef() : Data(std::make_pair(x: 0, y: nullptr)) {}
726 InstRef(unsigned Index, Instruction *I) : Data(std::make_pair(x&: Index, y&: I)) {}
727
728 bool operator==(const InstRef &Other) const { return Data == Other.Data; }
729 bool operator!=(const InstRef &Other) const { return Data != Other.Data; }
730 bool operator<(const InstRef &Other) const {
731 return Data.first < Other.Data.first;
732 }
733
734 unsigned getSourceIndex() const { return Data.first; }
735 Instruction *getInstruction() { return Data.second; }
736 const Instruction *getInstruction() const { return Data.second; }
737
738 /// Returns true if this references a valid instruction.
739 explicit operator bool() const { return Data.second != nullptr; }
740
741 /// Invalidate this reference.
742 void invalidate() { Data.second = nullptr; }
743
744#ifndef NDEBUG
745 void print(raw_ostream &OS) const { OS << getSourceIndex(); }
746#endif
747};
748
749#ifndef NDEBUG
750inline raw_ostream &operator<<(raw_ostream &OS, const InstRef &IR) {
751 IR.print(OS);
752 return OS;
753}
754#endif
755
756} // namespace mca
757} // namespace llvm
758
759#endif // LLVM_MCA_INSTRUCTION_H
760