xref: /freebsd-src/contrib/llvm-project/llvm/include/llvm/MCA/Instruction.h (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
10b57cec5SDimitry Andric //===--------------------- Instruction.h ------------------------*- C++ -*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// This file defines abstractions used by the Pipeline to model register reads,
110b57cec5SDimitry Andric /// register writes and instructions.
120b57cec5SDimitry Andric ///
130b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
140b57cec5SDimitry Andric 
150b57cec5SDimitry Andric #ifndef LLVM_MCA_INSTRUCTION_H
160b57cec5SDimitry Andric #define LLVM_MCA_INSTRUCTION_H
170b57cec5SDimitry Andric 
180b57cec5SDimitry Andric #include "llvm/ADT/ArrayRef.h"
190b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
200b57cec5SDimitry Andric #include "llvm/ADT/SmallVector.h"
218bcb0991SDimitry Andric #include "llvm/MC/MCRegister.h" // definition of MCPhysReg.
220b57cec5SDimitry Andric #include "llvm/Support/MathExtras.h"
230b57cec5SDimitry Andric 
240b57cec5SDimitry Andric #ifndef NDEBUG
250b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
260b57cec5SDimitry Andric #endif
270b57cec5SDimitry Andric 
280b57cec5SDimitry Andric #include <memory>
290b57cec5SDimitry Andric 
300b57cec5SDimitry Andric namespace llvm {
310b57cec5SDimitry Andric 
320b57cec5SDimitry Andric namespace mca {
330b57cec5SDimitry Andric 
340b57cec5SDimitry Andric constexpr int UNKNOWN_CYCLES = -512;
350b57cec5SDimitry Andric 
36fe6060f1SDimitry Andric /// A representation of an mca::Instruction operand
37fe6060f1SDimitry Andric /// for use in mca::CustomBehaviour.
38fe6060f1SDimitry Andric class MCAOperand {
39fe6060f1SDimitry Andric   // This class is mostly copied from MCOperand within
40fe6060f1SDimitry Andric   // MCInst.h except that we don't keep track of
41fe6060f1SDimitry Andric   // expressions or sub-instructions.
42fe6060f1SDimitry Andric   enum MCAOperandType : unsigned char {
43fe6060f1SDimitry Andric     kInvalid,   ///< Uninitialized, Relocatable immediate, or Sub-instruction.
44fe6060f1SDimitry Andric     kRegister,  ///< Register operand.
45fe6060f1SDimitry Andric     kImmediate, ///< Immediate operand.
46fe6060f1SDimitry Andric     kSFPImmediate, ///< Single-floating-point immediate operand.
47fe6060f1SDimitry Andric     kDFPImmediate, ///< Double-Floating-point immediate operand.
48fe6060f1SDimitry Andric   };
49349cc55cSDimitry Andric   MCAOperandType Kind;
50fe6060f1SDimitry Andric 
51fe6060f1SDimitry Andric   union {
52fe6060f1SDimitry Andric     unsigned RegVal;
53fe6060f1SDimitry Andric     int64_t ImmVal;
54fe6060f1SDimitry Andric     uint32_t SFPImmVal;
55fe6060f1SDimitry Andric     uint64_t FPImmVal;
56fe6060f1SDimitry Andric   };
57fe6060f1SDimitry Andric 
58fe6060f1SDimitry Andric   // We only store specific operands for specific instructions
59fe6060f1SDimitry Andric   // so an instruction's operand 3 may be stored within the list
60fe6060f1SDimitry Andric   // of MCAOperand as element 0. This Index attribute keeps track
61fe6060f1SDimitry Andric   // of the original index (3 for this example).
62fe6060f1SDimitry Andric   unsigned Index;
63fe6060f1SDimitry Andric 
64fe6060f1SDimitry Andric public:
MCAOperand()65349cc55cSDimitry Andric   MCAOperand() : Kind(kInvalid), FPImmVal(), Index() {}
66fe6060f1SDimitry Andric 
isValid()67fe6060f1SDimitry Andric   bool isValid() const { return Kind != kInvalid; }
isReg()68fe6060f1SDimitry Andric   bool isReg() const { return Kind == kRegister; }
isImm()69fe6060f1SDimitry Andric   bool isImm() const { return Kind == kImmediate; }
isSFPImm()70fe6060f1SDimitry Andric   bool isSFPImm() const { return Kind == kSFPImmediate; }
isDFPImm()71fe6060f1SDimitry Andric   bool isDFPImm() const { return Kind == kDFPImmediate; }
72fe6060f1SDimitry Andric 
73fe6060f1SDimitry Andric   /// Returns the register number.
getReg()74fe6060f1SDimitry Andric   unsigned getReg() const {
75fe6060f1SDimitry Andric     assert(isReg() && "This is not a register operand!");
76fe6060f1SDimitry Andric     return RegVal;
77fe6060f1SDimitry Andric   }
78fe6060f1SDimitry Andric 
getImm()79fe6060f1SDimitry Andric   int64_t getImm() const {
80fe6060f1SDimitry Andric     assert(isImm() && "This is not an immediate");
81fe6060f1SDimitry Andric     return ImmVal;
82fe6060f1SDimitry Andric   }
83fe6060f1SDimitry Andric 
getSFPImm()84fe6060f1SDimitry Andric   uint32_t getSFPImm() const {
85fe6060f1SDimitry Andric     assert(isSFPImm() && "This is not an SFP immediate");
86fe6060f1SDimitry Andric     return SFPImmVal;
87fe6060f1SDimitry Andric   }
88fe6060f1SDimitry Andric 
getDFPImm()89fe6060f1SDimitry Andric   uint64_t getDFPImm() const {
90fe6060f1SDimitry Andric     assert(isDFPImm() && "This is not an FP immediate");
91fe6060f1SDimitry Andric     return FPImmVal;
92fe6060f1SDimitry Andric   }
93fe6060f1SDimitry Andric 
setIndex(const unsigned Idx)94fe6060f1SDimitry Andric   void setIndex(const unsigned Idx) { Index = Idx; }
95fe6060f1SDimitry Andric 
getIndex()96fe6060f1SDimitry Andric   unsigned getIndex() const { return Index; }
97fe6060f1SDimitry Andric 
createReg(unsigned Reg)98fe6060f1SDimitry Andric   static MCAOperand createReg(unsigned Reg) {
99fe6060f1SDimitry Andric     MCAOperand Op;
100fe6060f1SDimitry Andric     Op.Kind = kRegister;
101fe6060f1SDimitry Andric     Op.RegVal = Reg;
102fe6060f1SDimitry Andric     return Op;
103fe6060f1SDimitry Andric   }
104fe6060f1SDimitry Andric 
createImm(int64_t Val)105fe6060f1SDimitry Andric   static MCAOperand createImm(int64_t Val) {
106fe6060f1SDimitry Andric     MCAOperand Op;
107fe6060f1SDimitry Andric     Op.Kind = kImmediate;
108fe6060f1SDimitry Andric     Op.ImmVal = Val;
109fe6060f1SDimitry Andric     return Op;
110fe6060f1SDimitry Andric   }
111fe6060f1SDimitry Andric 
createSFPImm(uint32_t Val)112fe6060f1SDimitry Andric   static MCAOperand createSFPImm(uint32_t Val) {
113fe6060f1SDimitry Andric     MCAOperand Op;
114fe6060f1SDimitry Andric     Op.Kind = kSFPImmediate;
115fe6060f1SDimitry Andric     Op.SFPImmVal = Val;
116fe6060f1SDimitry Andric     return Op;
117fe6060f1SDimitry Andric   }
118fe6060f1SDimitry Andric 
createDFPImm(uint64_t Val)119fe6060f1SDimitry Andric   static MCAOperand createDFPImm(uint64_t Val) {
120fe6060f1SDimitry Andric     MCAOperand Op;
121fe6060f1SDimitry Andric     Op.Kind = kDFPImmediate;
122fe6060f1SDimitry Andric     Op.FPImmVal = Val;
123fe6060f1SDimitry Andric     return Op;
124fe6060f1SDimitry Andric   }
125fe6060f1SDimitry Andric 
createInvalid()126fe6060f1SDimitry Andric   static MCAOperand createInvalid() {
127fe6060f1SDimitry Andric     MCAOperand Op;
128fe6060f1SDimitry Andric     Op.Kind = kInvalid;
129fe6060f1SDimitry Andric     Op.FPImmVal = 0;
130fe6060f1SDimitry Andric     return Op;
131fe6060f1SDimitry Andric   }
132fe6060f1SDimitry Andric };
133fe6060f1SDimitry Andric 
1340b57cec5SDimitry Andric /// A register write descriptor.
1350b57cec5SDimitry Andric struct WriteDescriptor {
1360b57cec5SDimitry Andric   // Operand index. The index is negative for implicit writes only.
1370b57cec5SDimitry Andric   // For implicit writes, the actual operand index is computed performing
1380b57cec5SDimitry Andric   // a bitwise not of the OpIndex.
1390b57cec5SDimitry Andric   int OpIndex;
1400b57cec5SDimitry Andric   // Write latency. Number of cycles before write-back stage.
1410b57cec5SDimitry Andric   unsigned Latency;
1420b57cec5SDimitry Andric   // This field is set to a value different than zero only if this
1430b57cec5SDimitry Andric   // is an implicit definition.
1448bcb0991SDimitry Andric   MCPhysReg RegisterID;
1450b57cec5SDimitry Andric   // Instruction itineraries would set this field to the SchedClass ID.
1460b57cec5SDimitry Andric   // Otherwise, it defaults to the WriteResourceID from the MCWriteLatencyEntry
1470b57cec5SDimitry Andric   // element associated to this write.
1480b57cec5SDimitry Andric   // When computing read latencies, this value is matched against the
1490b57cec5SDimitry Andric   // "ReadAdvance" information. The hardware backend may implement
1500b57cec5SDimitry Andric   // dedicated forwarding paths to quickly propagate write results to dependent
1510b57cec5SDimitry Andric   // instructions waiting in the reservation station (effectively bypassing the
1520b57cec5SDimitry Andric   // write-back stage).
1530b57cec5SDimitry Andric   unsigned SClassOrWriteResourceID;
1540b57cec5SDimitry Andric   // True only if this is a write obtained from an optional definition.
1550b57cec5SDimitry Andric   // Optional definitions are allowed to reference regID zero (i.e. "no
1560b57cec5SDimitry Andric   // register").
1570b57cec5SDimitry Andric   bool IsOptionalDef;
1580b57cec5SDimitry Andric 
isImplicitWriteWriteDescriptor1590b57cec5SDimitry Andric   bool isImplicitWrite() const { return OpIndex < 0; };
1600b57cec5SDimitry Andric };
1610b57cec5SDimitry Andric 
1620b57cec5SDimitry Andric /// A register read descriptor.
1630b57cec5SDimitry Andric struct ReadDescriptor {
1640b57cec5SDimitry Andric   // A MCOperand index. This is used by the Dispatch logic to identify register
1650b57cec5SDimitry Andric   // reads. Implicit reads have negative indices. The actual operand index of an
1660b57cec5SDimitry Andric   // implicit read is the bitwise not of field OpIndex.
1670b57cec5SDimitry Andric   int OpIndex;
1680b57cec5SDimitry Andric   // The actual "UseIdx". This is used to query the ReadAdvance table. Explicit
1690b57cec5SDimitry Andric   // uses always come first in the sequence of uses.
1700b57cec5SDimitry Andric   unsigned UseIndex;
1710b57cec5SDimitry Andric   // This field is only set if this is an implicit read.
1728bcb0991SDimitry Andric   MCPhysReg RegisterID;
1730b57cec5SDimitry Andric   // Scheduling Class Index. It is used to query the scheduling model for the
1740b57cec5SDimitry Andric   // MCSchedClassDesc object.
1750b57cec5SDimitry Andric   unsigned SchedClassID;
1760b57cec5SDimitry Andric 
isImplicitReadReadDescriptor1770b57cec5SDimitry Andric   bool isImplicitRead() const { return OpIndex < 0; };
1780b57cec5SDimitry Andric };
1790b57cec5SDimitry Andric 
1800b57cec5SDimitry Andric class ReadState;
1810b57cec5SDimitry Andric 
1820b57cec5SDimitry Andric /// A critical data dependency descriptor.
1830b57cec5SDimitry Andric ///
1840b57cec5SDimitry Andric /// Field RegID is set to the invalid register for memory dependencies.
1850b57cec5SDimitry Andric struct CriticalDependency {
1860b57cec5SDimitry Andric   unsigned IID;
1878bcb0991SDimitry Andric   MCPhysReg RegID;
1880b57cec5SDimitry Andric   unsigned Cycles;
1890b57cec5SDimitry Andric };
1900b57cec5SDimitry Andric 
1910b57cec5SDimitry Andric /// Tracks uses of a register definition (e.g. register write).
1920b57cec5SDimitry Andric ///
1930b57cec5SDimitry Andric /// Each implicit/explicit register write is associated with an instance of
1940b57cec5SDimitry Andric /// this class. A WriteState object tracks the dependent users of a
1950b57cec5SDimitry Andric /// register write. It also tracks how many cycles are left before the write
1960b57cec5SDimitry Andric /// back stage.
1970b57cec5SDimitry Andric class WriteState {
1980b57cec5SDimitry Andric   const WriteDescriptor *WD;
1990b57cec5SDimitry Andric   // On instruction issue, this field is set equal to the write latency.
2000b57cec5SDimitry Andric   // Before instruction issue, this field defaults to -512, a special
2010b57cec5SDimitry Andric   // value that represents an "unknown" number of cycles.
2020b57cec5SDimitry Andric   int CyclesLeft;
2030b57cec5SDimitry Andric 
2040b57cec5SDimitry Andric   // Actual register defined by this write. This field is only used
2050b57cec5SDimitry Andric   // to speedup queries on the register file.
2060b57cec5SDimitry Andric   // For implicit writes, this field always matches the value of
2070b57cec5SDimitry Andric   // field RegisterID from WD.
2088bcb0991SDimitry Andric   MCPhysReg RegisterID;
2090b57cec5SDimitry Andric 
2100b57cec5SDimitry Andric   // Physical register file that serves register RegisterID.
2110b57cec5SDimitry Andric   unsigned PRFID;
2120b57cec5SDimitry Andric 
2130b57cec5SDimitry Andric   // True if this write implicitly clears the upper portion of RegisterID's
2140b57cec5SDimitry Andric   // super-registers.
2150b57cec5SDimitry Andric   bool ClearsSuperRegs;
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric   // True if this write is from a dependency breaking zero-idiom instruction.
2180b57cec5SDimitry Andric   bool WritesZero;
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   // True if this write has been eliminated at register renaming stage.
2210b57cec5SDimitry Andric   // Example: a register move doesn't consume scheduler/pipleline resources if
2220b57cec5SDimitry Andric   // it is eliminated at register renaming stage. It still consumes
2230b57cec5SDimitry Andric   // decode bandwidth, and ROB entries.
2240b57cec5SDimitry Andric   bool IsEliminated;
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   // This field is set if this is a partial register write, and it has a false
2270b57cec5SDimitry Andric   // dependency on any previous write of the same register (or a portion of it).
2280b57cec5SDimitry Andric   // DependentWrite must be able to complete before this write completes, so
2290b57cec5SDimitry Andric   // that we don't break the WAW, and the two writes can be merged together.
2300b57cec5SDimitry Andric   const WriteState *DependentWrite;
2310b57cec5SDimitry Andric 
2320b57cec5SDimitry Andric   // A partial write that is in a false dependency with this write.
2330b57cec5SDimitry Andric   WriteState *PartialWrite;
2340b57cec5SDimitry Andric   unsigned DependentWriteCyclesLeft;
2350b57cec5SDimitry Andric 
2360b57cec5SDimitry Andric   // Critical register dependency for this write.
2370b57cec5SDimitry Andric   CriticalDependency CRD;
2380b57cec5SDimitry Andric 
2390b57cec5SDimitry Andric   // A list of dependent reads. Users is a set of dependent
2400b57cec5SDimitry Andric   // reads. A dependent read is added to the set only if CyclesLeft
2410b57cec5SDimitry Andric   // is "unknown". As soon as CyclesLeft is 'known', each user in the set
2420b57cec5SDimitry Andric   // gets notified with the actual CyclesLeft.
2430b57cec5SDimitry Andric 
2440b57cec5SDimitry Andric   // The 'second' element of a pair is a "ReadAdvance" number of cycles.
2450b57cec5SDimitry Andric   SmallVector<std::pair<ReadState *, int>, 4> Users;
2460b57cec5SDimitry Andric 
2470b57cec5SDimitry Andric public:
2488bcb0991SDimitry Andric   WriteState(const WriteDescriptor &Desc, MCPhysReg RegID,
2490b57cec5SDimitry Andric              bool clearsSuperRegs = false, bool writesZero = false)
2500b57cec5SDimitry Andric       : WD(&Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID), PRFID(0),
2510b57cec5SDimitry Andric         ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero),
2520b57cec5SDimitry Andric         IsEliminated(false), DependentWrite(nullptr), PartialWrite(nullptr),
2530b57cec5SDimitry Andric         DependentWriteCyclesLeft(0), CRD() {}
2540b57cec5SDimitry Andric 
2550b57cec5SDimitry Andric   WriteState(const WriteState &Other) = default;
2560b57cec5SDimitry Andric   WriteState &operator=(const WriteState &Other) = default;
2570b57cec5SDimitry Andric 
getCyclesLeft()2580b57cec5SDimitry Andric   int getCyclesLeft() const { return CyclesLeft; }
getWriteResourceID()2590b57cec5SDimitry Andric   unsigned getWriteResourceID() const { return WD->SClassOrWriteResourceID; }
getRegisterID()2608bcb0991SDimitry Andric   MCPhysReg getRegisterID() const { return RegisterID; }
setRegisterID(const MCPhysReg RegID)261fe6060f1SDimitry Andric   void setRegisterID(const MCPhysReg RegID) { RegisterID = RegID; }
getRegisterFileID()2620b57cec5SDimitry Andric   unsigned getRegisterFileID() const { return PRFID; }
getLatency()2630b57cec5SDimitry Andric   unsigned getLatency() const { return WD->Latency; }
getDependentWriteCyclesLeft()2640b57cec5SDimitry Andric   unsigned getDependentWriteCyclesLeft() const {
2650b57cec5SDimitry Andric     return DependentWriteCyclesLeft;
2660b57cec5SDimitry Andric   }
getDependentWrite()2670b57cec5SDimitry Andric   const WriteState *getDependentWrite() const { return DependentWrite; }
getCriticalRegDep()2680b57cec5SDimitry Andric   const CriticalDependency &getCriticalRegDep() const { return CRD; }
2690b57cec5SDimitry Andric 
2700b57cec5SDimitry Andric   // This method adds Use to the set of data dependent reads. IID is the
2710b57cec5SDimitry Andric   // instruction identifier associated with this write. ReadAdvance is the
2720b57cec5SDimitry Andric   // number of cycles to subtract from the latency of this data dependency.
2730b57cec5SDimitry Andric   // Use is in a RAW dependency with this write.
2740b57cec5SDimitry Andric   void addUser(unsigned IID, ReadState *Use, int ReadAdvance);
2750b57cec5SDimitry Andric 
2760b57cec5SDimitry Andric   // Use is a younger register write that is in a false dependency with this
2770b57cec5SDimitry Andric   // write. IID is the instruction identifier associated with this write.
2780b57cec5SDimitry Andric   void addUser(unsigned IID, WriteState *Use);
2790b57cec5SDimitry Andric 
getNumUsers()2800b57cec5SDimitry Andric   unsigned getNumUsers() const {
2810b57cec5SDimitry Andric     unsigned NumUsers = Users.size();
2820b57cec5SDimitry Andric     if (PartialWrite)
2830b57cec5SDimitry Andric       ++NumUsers;
2840b57cec5SDimitry Andric     return NumUsers;
2850b57cec5SDimitry Andric   }
2860b57cec5SDimitry Andric 
clearsSuperRegisters()2870b57cec5SDimitry Andric   bool clearsSuperRegisters() const { return ClearsSuperRegs; }
isWriteZero()2880b57cec5SDimitry Andric   bool isWriteZero() const { return WritesZero; }
isEliminated()2890b57cec5SDimitry Andric   bool isEliminated() const { return IsEliminated; }
2900b57cec5SDimitry Andric 
isReady()2910b57cec5SDimitry Andric   bool isReady() const {
2920b57cec5SDimitry Andric     if (DependentWrite)
2930b57cec5SDimitry Andric       return false;
2940b57cec5SDimitry Andric     unsigned CyclesLeft = getDependentWriteCyclesLeft();
2950b57cec5SDimitry Andric     return !CyclesLeft || CyclesLeft < getLatency();
2960b57cec5SDimitry Andric   }
2970b57cec5SDimitry Andric 
isExecuted()2980b57cec5SDimitry Andric   bool isExecuted() const {
2990b57cec5SDimitry Andric     return CyclesLeft != UNKNOWN_CYCLES && CyclesLeft <= 0;
3000b57cec5SDimitry Andric   }
3010b57cec5SDimitry Andric 
setDependentWrite(const WriteState * Other)3020b57cec5SDimitry Andric   void setDependentWrite(const WriteState *Other) { DependentWrite = Other; }
3038bcb0991SDimitry Andric   void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
setWriteZero()3040b57cec5SDimitry Andric   void setWriteZero() { WritesZero = true; }
setEliminated()3050b57cec5SDimitry Andric   void setEliminated() {
3060b57cec5SDimitry Andric     assert(Users.empty() && "Write is in an inconsistent state.");
3070b57cec5SDimitry Andric     CyclesLeft = 0;
3080b57cec5SDimitry Andric     IsEliminated = true;
3090b57cec5SDimitry Andric   }
3100b57cec5SDimitry Andric 
setPRF(unsigned PRF)3110b57cec5SDimitry Andric   void setPRF(unsigned PRF) { PRFID = PRF; }
3120b57cec5SDimitry Andric 
3130b57cec5SDimitry Andric   // On every cycle, update CyclesLeft and notify dependent users.
3140b57cec5SDimitry Andric   void cycleEvent();
3150b57cec5SDimitry Andric   void onInstructionIssued(unsigned IID);
3160b57cec5SDimitry Andric 
3170b57cec5SDimitry Andric #ifndef NDEBUG
3180b57cec5SDimitry Andric   void dump() const;
3190b57cec5SDimitry Andric #endif
3200b57cec5SDimitry Andric };
3210b57cec5SDimitry Andric 
3220b57cec5SDimitry Andric /// Tracks register operand latency in cycles.
3230b57cec5SDimitry Andric ///
3240b57cec5SDimitry Andric /// A read may be dependent on more than one write. This occurs when some
3250b57cec5SDimitry Andric /// writes only partially update the register associated to this read.
3260b57cec5SDimitry Andric class ReadState {
3270b57cec5SDimitry Andric   const ReadDescriptor *RD;
3280b57cec5SDimitry Andric   // Physical register identified associated to this read.
3298bcb0991SDimitry Andric   MCPhysReg RegisterID;
3300b57cec5SDimitry Andric   // Physical register file that serves register RegisterID.
3310b57cec5SDimitry Andric   unsigned PRFID;
3320b57cec5SDimitry Andric   // Number of writes that contribute to the definition of RegisterID.
3330b57cec5SDimitry Andric   // In the absence of partial register updates, the number of DependentWrites
3340b57cec5SDimitry Andric   // cannot be more than one.
3350b57cec5SDimitry Andric   unsigned DependentWrites;
3360b57cec5SDimitry Andric   // Number of cycles left before RegisterID can be read. This value depends on
3370b57cec5SDimitry Andric   // the latency of all the dependent writes. It defaults to UNKNOWN_CYCLES.
3380b57cec5SDimitry Andric   // It gets set to the value of field TotalCycles only when the 'CyclesLeft' of
3390b57cec5SDimitry Andric   // every dependent write is known.
3400b57cec5SDimitry Andric   int CyclesLeft;
3410b57cec5SDimitry Andric   // This field is updated on every writeStartEvent(). When the number of
3420b57cec5SDimitry Andric   // dependent writes (i.e. field DependentWrite) is zero, this value is
3430b57cec5SDimitry Andric   // propagated to field CyclesLeft.
3440b57cec5SDimitry Andric   unsigned TotalCycles;
3450b57cec5SDimitry Andric   // Longest register dependency.
3460b57cec5SDimitry Andric   CriticalDependency CRD;
3470b57cec5SDimitry Andric   // This field is set to true only if there are no dependent writes, and
3480b57cec5SDimitry Andric   // there are no `CyclesLeft' to wait.
3490b57cec5SDimitry Andric   bool IsReady;
3500b57cec5SDimitry Andric   // True if this is a read from a known zero register.
3510b57cec5SDimitry Andric   bool IsZero;
3520b57cec5SDimitry Andric   // True if this register read is from a dependency-breaking instruction.
3530b57cec5SDimitry Andric   bool IndependentFromDef;
3540b57cec5SDimitry Andric 
3550b57cec5SDimitry Andric public:
ReadState(const ReadDescriptor & Desc,MCPhysReg RegID)3568bcb0991SDimitry Andric   ReadState(const ReadDescriptor &Desc, MCPhysReg RegID)
3570b57cec5SDimitry Andric       : RD(&Desc), RegisterID(RegID), PRFID(0), DependentWrites(0),
3580b57cec5SDimitry Andric         CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), CRD(), IsReady(true),
3590b57cec5SDimitry Andric         IsZero(false), IndependentFromDef(false) {}
3600b57cec5SDimitry Andric 
getDescriptor()3610b57cec5SDimitry Andric   const ReadDescriptor &getDescriptor() const { return *RD; }
getSchedClass()3620b57cec5SDimitry Andric   unsigned getSchedClass() const { return RD->SchedClassID; }
getRegisterID()3638bcb0991SDimitry Andric   MCPhysReg getRegisterID() const { return RegisterID; }
getRegisterFileID()3640b57cec5SDimitry Andric   unsigned getRegisterFileID() const { return PRFID; }
getCriticalRegDep()3650b57cec5SDimitry Andric   const CriticalDependency &getCriticalRegDep() const { return CRD; }
3660b57cec5SDimitry Andric 
isPending()3670b57cec5SDimitry Andric   bool isPending() const { return !IndependentFromDef && CyclesLeft > 0; }
isReady()3680b57cec5SDimitry Andric   bool isReady() const { return IsReady; }
isImplicitRead()3690b57cec5SDimitry Andric   bool isImplicitRead() const { return RD->isImplicitRead(); }
3700b57cec5SDimitry Andric 
isIndependentFromDef()3710b57cec5SDimitry Andric   bool isIndependentFromDef() const { return IndependentFromDef; }
setIndependentFromDef()3720b57cec5SDimitry Andric   void setIndependentFromDef() { IndependentFromDef = true; }
3730b57cec5SDimitry Andric 
3740b57cec5SDimitry Andric   void cycleEvent();
3758bcb0991SDimitry Andric   void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
setDependentWrites(unsigned Writes)3760b57cec5SDimitry Andric   void setDependentWrites(unsigned Writes) {
3770b57cec5SDimitry Andric     DependentWrites = Writes;
3780b57cec5SDimitry Andric     IsReady = !Writes;
3790b57cec5SDimitry Andric   }
3800b57cec5SDimitry Andric 
isReadZero()3810b57cec5SDimitry Andric   bool isReadZero() const { return IsZero; }
setReadZero()3820b57cec5SDimitry Andric   void setReadZero() { IsZero = true; }
setPRF(unsigned ID)3830b57cec5SDimitry Andric   void setPRF(unsigned ID) { PRFID = ID; }
3840b57cec5SDimitry Andric };
3850b57cec5SDimitry Andric 
3860b57cec5SDimitry Andric /// A sequence of cycles.
3870b57cec5SDimitry Andric ///
3880b57cec5SDimitry Andric /// This class can be used as a building block to construct ranges of cycles.
3890b57cec5SDimitry Andric class CycleSegment {
3900b57cec5SDimitry Andric   unsigned Begin; // Inclusive.
3910b57cec5SDimitry Andric   unsigned End;   // Exclusive.
3920b57cec5SDimitry Andric   bool Reserved;  // Resources associated to this segment must be reserved.
3930b57cec5SDimitry Andric 
3940b57cec5SDimitry Andric public:
3950b57cec5SDimitry Andric   CycleSegment(unsigned StartCycle, unsigned EndCycle, bool IsReserved = false)
Begin(StartCycle)3960b57cec5SDimitry Andric       : Begin(StartCycle), End(EndCycle), Reserved(IsReserved) {}
3970b57cec5SDimitry Andric 
contains(unsigned Cycle)3980b57cec5SDimitry Andric   bool contains(unsigned Cycle) const { return Cycle >= Begin && Cycle < End; }
startsAfter(const CycleSegment & CS)3990b57cec5SDimitry Andric   bool startsAfter(const CycleSegment &CS) const { return End <= CS.Begin; }
endsBefore(const CycleSegment & CS)4000b57cec5SDimitry Andric   bool endsBefore(const CycleSegment &CS) const { return Begin >= CS.End; }
overlaps(const CycleSegment & CS)4010b57cec5SDimitry Andric   bool overlaps(const CycleSegment &CS) const {
4020b57cec5SDimitry Andric     return !startsAfter(CS) && !endsBefore(CS);
4030b57cec5SDimitry Andric   }
isExecuting()4040b57cec5SDimitry Andric   bool isExecuting() const { return Begin == 0 && End != 0; }
isExecuted()4050b57cec5SDimitry Andric   bool isExecuted() const { return End == 0; }
4060b57cec5SDimitry Andric   bool operator<(const CycleSegment &Other) const {
4070b57cec5SDimitry Andric     return Begin < Other.Begin;
4080b57cec5SDimitry Andric   }
40904eeddc0SDimitry Andric   CycleSegment &operator--() {
4100b57cec5SDimitry Andric     if (Begin)
4110b57cec5SDimitry Andric       Begin--;
4120b57cec5SDimitry Andric     if (End)
4130b57cec5SDimitry Andric       End--;
4140b57cec5SDimitry Andric     return *this;
4150b57cec5SDimitry Andric   }
4160b57cec5SDimitry Andric 
isValid()4170b57cec5SDimitry Andric   bool isValid() const { return Begin <= End; }
size()4180b57cec5SDimitry Andric   unsigned size() const { return End - Begin; };
subtract(unsigned Cycles)4190b57cec5SDimitry Andric   void subtract(unsigned Cycles) {
4200b57cec5SDimitry Andric     assert(End >= Cycles);
4210b57cec5SDimitry Andric     End -= Cycles;
4220b57cec5SDimitry Andric   }
4230b57cec5SDimitry Andric 
begin()4240b57cec5SDimitry Andric   unsigned begin() const { return Begin; }
end()4250b57cec5SDimitry Andric   unsigned end() const { return End; }
setEnd(unsigned NewEnd)4260b57cec5SDimitry Andric   void setEnd(unsigned NewEnd) { End = NewEnd; }
isReserved()4270b57cec5SDimitry Andric   bool isReserved() const { return Reserved; }
setReserved()4280b57cec5SDimitry Andric   void setReserved() { Reserved = true; }
4290b57cec5SDimitry Andric };
4300b57cec5SDimitry Andric 
4310b57cec5SDimitry Andric /// Helper used by class InstrDesc to describe how hardware resources
4320b57cec5SDimitry Andric /// are used.
4330b57cec5SDimitry Andric ///
4340b57cec5SDimitry Andric /// This class describes how many resource units of a specific resource kind
4350b57cec5SDimitry Andric /// (and how many cycles) are "used" by an instruction.
4360b57cec5SDimitry Andric struct ResourceUsage {
4370b57cec5SDimitry Andric   CycleSegment CS;
4380b57cec5SDimitry Andric   unsigned NumUnits;
4390b57cec5SDimitry Andric   ResourceUsage(CycleSegment Cycles, unsigned Units = 1)
CSResourceUsage4400b57cec5SDimitry Andric       : CS(Cycles), NumUnits(Units) {}
sizeResourceUsage4410b57cec5SDimitry Andric   unsigned size() const { return CS.size(); }
isReservedResourceUsage4420b57cec5SDimitry Andric   bool isReserved() const { return CS.isReserved(); }
setReservedResourceUsage4430b57cec5SDimitry Andric   void setReserved() { CS.setReserved(); }
4440b57cec5SDimitry Andric };
4450b57cec5SDimitry Andric 
4460b57cec5SDimitry Andric /// An instruction descriptor
4470b57cec5SDimitry Andric struct InstrDesc {
448fe6060f1SDimitry Andric   SmallVector<WriteDescriptor, 2> Writes; // Implicit writes are at the end.
4490b57cec5SDimitry Andric   SmallVector<ReadDescriptor, 4> Reads;   // Implicit reads are at the end.
4500b57cec5SDimitry Andric 
4510b57cec5SDimitry Andric   // For every resource used by an instruction of this kind, this vector
4520b57cec5SDimitry Andric   // reports the number of "consumed cycles".
4530b57cec5SDimitry Andric   SmallVector<std::pair<uint64_t, ResourceUsage>, 4> Resources;
4540b57cec5SDimitry Andric 
4558bcb0991SDimitry Andric   // A bitmask of used hardware buffers.
4568bcb0991SDimitry Andric   uint64_t UsedBuffers;
4570b57cec5SDimitry Andric 
4588bcb0991SDimitry Andric   // A bitmask of used processor resource units.
4598bcb0991SDimitry Andric   uint64_t UsedProcResUnits;
4608bcb0991SDimitry Andric 
4618bcb0991SDimitry Andric   // A bitmask of used processor resource groups.
4628bcb0991SDimitry Andric   uint64_t UsedProcResGroups;
4630b57cec5SDimitry Andric 
4640b57cec5SDimitry Andric   unsigned MaxLatency;
4650b57cec5SDimitry Andric   // Number of MicroOps for this instruction.
4660b57cec5SDimitry Andric   unsigned NumMicroOps;
4670b57cec5SDimitry Andric   // SchedClassID used to construct this InstrDesc.
4680b57cec5SDimitry Andric   // This information is currently used by views to do fast queries on the
4690b57cec5SDimitry Andric   // subtarget when computing the reciprocal throughput.
4700b57cec5SDimitry Andric   unsigned SchedClassID;
4710b57cec5SDimitry Andric 
4720b57cec5SDimitry Andric   // True if all buffered resources are in-order, and there is at least one
4730b57cec5SDimitry Andric   // buffer which is a dispatch hazard (BufferSize = 0).
474fe6060f1SDimitry Andric   unsigned MustIssueImmediately : 1;
4750b57cec5SDimitry Andric 
47681ad6265SDimitry Andric   // True if the corresponding mca::Instruction can be recycled. Currently only
47781ad6265SDimitry Andric   // instructions that are neither variadic nor have any variant can be
47881ad6265SDimitry Andric   // recycled.
47981ad6265SDimitry Andric   unsigned IsRecyclable : 1;
48081ad6265SDimitry Andric 
481*bdd1243dSDimitry Andric   // True if some of the consumed group resources are partially overlapping.
482*bdd1243dSDimitry Andric   unsigned HasPartiallyOverlappingGroups : 1;
483*bdd1243dSDimitry Andric 
4840b57cec5SDimitry Andric   // A zero latency instruction doesn't consume any scheduler resources.
isZeroLatencyInstrDesc4850b57cec5SDimitry Andric   bool isZeroLatency() const { return !MaxLatency && Resources.empty(); }
4860b57cec5SDimitry Andric 
4870b57cec5SDimitry Andric   InstrDesc() = default;
4880b57cec5SDimitry Andric   InstrDesc(const InstrDesc &Other) = delete;
4890b57cec5SDimitry Andric   InstrDesc &operator=(const InstrDesc &Other) = delete;
4900b57cec5SDimitry Andric };
4910b57cec5SDimitry Andric 
4920b57cec5SDimitry Andric /// Base class for instructions consumed by the simulation pipeline.
4930b57cec5SDimitry Andric ///
4940b57cec5SDimitry Andric /// This class tracks data dependencies as well as generic properties
4950b57cec5SDimitry Andric /// of the instruction.
4960b57cec5SDimitry Andric class InstructionBase {
4970b57cec5SDimitry Andric   const InstrDesc &Desc;
4980b57cec5SDimitry Andric 
4990b57cec5SDimitry Andric   // This field is set for instructions that are candidates for move
5000b57cec5SDimitry Andric   // elimination. For more information about move elimination, see the
5010b57cec5SDimitry Andric   // definition of RegisterMappingTracker in RegisterFile.h
5020b57cec5SDimitry Andric   bool IsOptimizableMove;
5030b57cec5SDimitry Andric 
5040b57cec5SDimitry Andric   // Output dependencies.
5050b57cec5SDimitry Andric   // One entry per each implicit and explicit register definition.
506fe6060f1SDimitry Andric   SmallVector<WriteState, 2> Defs;
5070b57cec5SDimitry Andric 
5080b57cec5SDimitry Andric   // Input dependencies.
5090b57cec5SDimitry Andric   // One entry per each implicit and explicit register use.
5100b57cec5SDimitry Andric   SmallVector<ReadState, 4> Uses;
5110b57cec5SDimitry Andric 
512fe6060f1SDimitry Andric   // List of operands which can be used by mca::CustomBehaviour
513fe6060f1SDimitry Andric   std::vector<MCAOperand> Operands;
514fe6060f1SDimitry Andric 
515fe6060f1SDimitry Andric   // Instruction opcode which can be used by mca::CustomBehaviour
516fe6060f1SDimitry Andric   unsigned Opcode;
517fe6060f1SDimitry Andric 
51804eeddc0SDimitry Andric   // Flags used by the LSUnit.
51981ad6265SDimitry Andric   bool IsALoadBarrier : 1;
52081ad6265SDimitry Andric   bool IsAStoreBarrier : 1;
52181ad6265SDimitry Andric   // Flags copied from the InstrDesc and potentially modified by
52281ad6265SDimitry Andric   // CustomBehaviour or (more likely) InstrPostProcess.
52381ad6265SDimitry Andric   bool MayLoad : 1;
52481ad6265SDimitry Andric   bool MayStore : 1;
52581ad6265SDimitry Andric   bool HasSideEffects : 1;
52681ad6265SDimitry Andric   bool BeginGroup : 1;
52781ad6265SDimitry Andric   bool EndGroup : 1;
52881ad6265SDimitry Andric   bool RetireOOO : 1;
52904eeddc0SDimitry Andric 
5300b57cec5SDimitry Andric public:
InstructionBase(const InstrDesc & D,const unsigned Opcode)531fe6060f1SDimitry Andric   InstructionBase(const InstrDesc &D, const unsigned Opcode)
53204eeddc0SDimitry Andric       : Desc(D), IsOptimizableMove(false), Operands(0), Opcode(Opcode),
53304eeddc0SDimitry Andric         IsALoadBarrier(false), IsAStoreBarrier(false) {}
5340b57cec5SDimitry Andric 
getDefs()5350b57cec5SDimitry Andric   SmallVectorImpl<WriteState> &getDefs() { return Defs; }
getDefs()536fe6060f1SDimitry Andric   ArrayRef<WriteState> getDefs() const { return Defs; }
getUses()5370b57cec5SDimitry Andric   SmallVectorImpl<ReadState> &getUses() { return Uses; }
getUses()538fe6060f1SDimitry Andric   ArrayRef<ReadState> getUses() const { return Uses; }
getDesc()5390b57cec5SDimitry Andric   const InstrDesc &getDesc() const { return Desc; }
5400b57cec5SDimitry Andric 
getLatency()5410b57cec5SDimitry Andric   unsigned getLatency() const { return Desc.MaxLatency; }
getNumMicroOps()5428bcb0991SDimitry Andric   unsigned getNumMicroOps() const { return Desc.NumMicroOps; }
getOpcode()543fe6060f1SDimitry Andric   unsigned getOpcode() const { return Opcode; }
isALoadBarrier()54404eeddc0SDimitry Andric   bool isALoadBarrier() const { return IsALoadBarrier; }
isAStoreBarrier()54504eeddc0SDimitry Andric   bool isAStoreBarrier() const { return IsAStoreBarrier; }
setLoadBarrier(bool IsBarrier)54604eeddc0SDimitry Andric   void setLoadBarrier(bool IsBarrier) { IsALoadBarrier = IsBarrier; }
setStoreBarrier(bool IsBarrier)54704eeddc0SDimitry Andric   void setStoreBarrier(bool IsBarrier) { IsAStoreBarrier = IsBarrier; }
548fe6060f1SDimitry Andric 
549fe6060f1SDimitry Andric   /// Return the MCAOperand which corresponds to index Idx within the original
550fe6060f1SDimitry Andric   /// MCInst.
getOperand(const unsigned Idx)551fe6060f1SDimitry Andric   const MCAOperand *getOperand(const unsigned Idx) const {
552*bdd1243dSDimitry Andric     auto It = llvm::find_if(Operands, [&Idx](const MCAOperand &Op) {
553*bdd1243dSDimitry Andric       return Op.getIndex() == Idx;
554*bdd1243dSDimitry Andric     });
555fe6060f1SDimitry Andric     if (It == Operands.end())
556fe6060f1SDimitry Andric       return nullptr;
557fe6060f1SDimitry Andric     return &(*It);
558fe6060f1SDimitry Andric   }
getNumOperands()559fe6060f1SDimitry Andric   unsigned getNumOperands() const { return Operands.size(); }
addOperand(const MCAOperand Op)560fe6060f1SDimitry Andric   void addOperand(const MCAOperand Op) { Operands.push_back(Op); }
5610b57cec5SDimitry Andric 
hasDependentUsers()5620b57cec5SDimitry Andric   bool hasDependentUsers() const {
5630b57cec5SDimitry Andric     return any_of(Defs,
5640b57cec5SDimitry Andric                   [](const WriteState &Def) { return Def.getNumUsers() > 0; });
5650b57cec5SDimitry Andric   }
5660b57cec5SDimitry Andric 
getNumUsers()5670b57cec5SDimitry Andric   unsigned getNumUsers() const {
5680b57cec5SDimitry Andric     unsigned NumUsers = 0;
5690b57cec5SDimitry Andric     for (const WriteState &Def : Defs)
5700b57cec5SDimitry Andric       NumUsers += Def.getNumUsers();
5710b57cec5SDimitry Andric     return NumUsers;
5720b57cec5SDimitry Andric   }
5730b57cec5SDimitry Andric 
5740b57cec5SDimitry Andric   // Returns true if this instruction is a candidate for move elimination.
isOptimizableMove()5750b57cec5SDimitry Andric   bool isOptimizableMove() const { return IsOptimizableMove; }
setOptimizableMove()5760b57cec5SDimitry Andric   void setOptimizableMove() { IsOptimizableMove = true; }
clearOptimizableMove()57781ad6265SDimitry Andric   void clearOptimizableMove() { IsOptimizableMove = false; }
isMemOp()57881ad6265SDimitry Andric   bool isMemOp() const { return MayLoad || MayStore; }
57981ad6265SDimitry Andric 
58081ad6265SDimitry Andric   // Getters and setters for general instruction flags.
setMayLoad(bool newVal)58181ad6265SDimitry Andric   void setMayLoad(bool newVal) { MayLoad = newVal; }
setMayStore(bool newVal)58281ad6265SDimitry Andric   void setMayStore(bool newVal) { MayStore = newVal; }
setHasSideEffects(bool newVal)58381ad6265SDimitry Andric   void setHasSideEffects(bool newVal) { HasSideEffects = newVal; }
setBeginGroup(bool newVal)58481ad6265SDimitry Andric   void setBeginGroup(bool newVal) { BeginGroup = newVal; }
setEndGroup(bool newVal)58581ad6265SDimitry Andric   void setEndGroup(bool newVal) { EndGroup = newVal; }
setRetireOOO(bool newVal)58681ad6265SDimitry Andric   void setRetireOOO(bool newVal) { RetireOOO = newVal; }
58781ad6265SDimitry Andric 
getMayLoad()58881ad6265SDimitry Andric   bool getMayLoad() const { return MayLoad; }
getMayStore()58981ad6265SDimitry Andric   bool getMayStore() const { return MayStore; }
getHasSideEffects()59081ad6265SDimitry Andric   bool getHasSideEffects() const { return HasSideEffects; }
getBeginGroup()59181ad6265SDimitry Andric   bool getBeginGroup() const { return BeginGroup; }
getEndGroup()59281ad6265SDimitry Andric   bool getEndGroup() const { return EndGroup; }
getRetireOOO()59381ad6265SDimitry Andric   bool getRetireOOO() const { return RetireOOO; }
5940b57cec5SDimitry Andric };
5950b57cec5SDimitry Andric 
5960b57cec5SDimitry Andric /// An instruction propagated through the simulated instruction pipeline.
5970b57cec5SDimitry Andric ///
5980b57cec5SDimitry Andric /// This class is used to monitor changes to the internal state of instructions
5990b57cec5SDimitry Andric /// that are sent to the various components of the simulated hardware pipeline.
6000b57cec5SDimitry Andric class Instruction : public InstructionBase {
6010b57cec5SDimitry Andric   enum InstrStage {
6020b57cec5SDimitry Andric     IS_INVALID,    // Instruction in an invalid state.
6030b57cec5SDimitry Andric     IS_DISPATCHED, // Instruction dispatched but operands are not ready.
6040b57cec5SDimitry Andric     IS_PENDING,    // Instruction is not ready, but operand latency is known.
6050b57cec5SDimitry Andric     IS_READY,      // Instruction dispatched and operands ready.
6060b57cec5SDimitry Andric     IS_EXECUTING,  // Instruction issued.
6070b57cec5SDimitry Andric     IS_EXECUTED,   // Instruction executed. Values are written back.
6080b57cec5SDimitry Andric     IS_RETIRED     // Instruction retired.
6090b57cec5SDimitry Andric   };
6100b57cec5SDimitry Andric 
6110b57cec5SDimitry Andric   // The current instruction stage.
6120b57cec5SDimitry Andric   enum InstrStage Stage;
6130b57cec5SDimitry Andric 
6140b57cec5SDimitry Andric   // This value defaults to the instruction latency. This instruction is
6150b57cec5SDimitry Andric   // considered executed when field CyclesLeft goes to zero.
6160b57cec5SDimitry Andric   int CyclesLeft;
6170b57cec5SDimitry Andric 
6180b57cec5SDimitry Andric   // Retire Unit token ID for this instruction.
6190b57cec5SDimitry Andric   unsigned RCUTokenID;
6200b57cec5SDimitry Andric 
6210b57cec5SDimitry Andric   // LS token ID for this instruction.
6220b57cec5SDimitry Andric   // This field is set to the invalid null token if this is not a memory
6230b57cec5SDimitry Andric   // operation.
6240b57cec5SDimitry Andric   unsigned LSUTokenID;
6250b57cec5SDimitry Andric 
6268bcb0991SDimitry Andric   // A resource mask which identifies buffered resources consumed by this
6278bcb0991SDimitry Andric   // instruction at dispatch stage. In the absence of macro-fusion, this value
6288bcb0991SDimitry Andric   // should always match the value of field `UsedBuffers` from the instruction
6298bcb0991SDimitry Andric   // descriptor (see field InstrBase::Desc).
6308bcb0991SDimitry Andric   uint64_t UsedBuffers;
6318bcb0991SDimitry Andric 
6320b57cec5SDimitry Andric   // Critical register dependency.
6330b57cec5SDimitry Andric   CriticalDependency CriticalRegDep;
6340b57cec5SDimitry Andric 
6350b57cec5SDimitry Andric   // Critical memory dependency.
6360b57cec5SDimitry Andric   CriticalDependency CriticalMemDep;
6370b57cec5SDimitry Andric 
6380b57cec5SDimitry Andric   // A bitmask of busy processor resource units.
6390b57cec5SDimitry Andric   // This field is set to zero only if execution is not delayed during this
6400b57cec5SDimitry Andric   // cycle because of unavailable pipeline resources.
6410b57cec5SDimitry Andric   uint64_t CriticalResourceMask;
6420b57cec5SDimitry Andric 
6430b57cec5SDimitry Andric   // True if this instruction has been optimized at register renaming stage.
6440b57cec5SDimitry Andric   bool IsEliminated;
6450b57cec5SDimitry Andric 
6460b57cec5SDimitry Andric public:
Instruction(const InstrDesc & D,const unsigned Opcode)647fe6060f1SDimitry Andric   Instruction(const InstrDesc &D, const unsigned Opcode)
648fe6060f1SDimitry Andric       : InstructionBase(D, Opcode), Stage(IS_INVALID),
649fe6060f1SDimitry Andric         CyclesLeft(UNKNOWN_CYCLES), RCUTokenID(0), LSUTokenID(0),
650fe6060f1SDimitry Andric         UsedBuffers(D.UsedBuffers), CriticalRegDep(), CriticalMemDep(),
651fe6060f1SDimitry Andric         CriticalResourceMask(0), IsEliminated(false) {}
6520b57cec5SDimitry Andric 
65381ad6265SDimitry Andric   void reset();
65481ad6265SDimitry Andric 
getRCUTokenID()6550b57cec5SDimitry Andric   unsigned getRCUTokenID() const { return RCUTokenID; }
getLSUTokenID()6560b57cec5SDimitry Andric   unsigned getLSUTokenID() const { return LSUTokenID; }
setLSUTokenID(unsigned LSUTok)6570b57cec5SDimitry Andric   void setLSUTokenID(unsigned LSUTok) { LSUTokenID = LSUTok; }
6588bcb0991SDimitry Andric 
getUsedBuffers()6598bcb0991SDimitry Andric   uint64_t getUsedBuffers() const { return UsedBuffers; }
setUsedBuffers(uint64_t Mask)6608bcb0991SDimitry Andric   void setUsedBuffers(uint64_t Mask) { UsedBuffers = Mask; }
clearUsedBuffers()6618bcb0991SDimitry Andric   void clearUsedBuffers() { UsedBuffers = 0ULL; }
6628bcb0991SDimitry Andric 
getCyclesLeft()6630b57cec5SDimitry Andric   int getCyclesLeft() const { return CyclesLeft; }
6640b57cec5SDimitry Andric 
6650b57cec5SDimitry Andric   // Transition to the dispatch stage, and assign a RCUToken to this
6660b57cec5SDimitry Andric   // instruction. The RCUToken is used to track the completion of every
6670b57cec5SDimitry Andric   // register write performed by this instruction.
6680b57cec5SDimitry Andric   void dispatch(unsigned RCUTokenID);
6690b57cec5SDimitry Andric 
6700b57cec5SDimitry Andric   // Instruction issued. Transition to the IS_EXECUTING state, and update
6710b57cec5SDimitry Andric   // all the register definitions.
6720b57cec5SDimitry Andric   void execute(unsigned IID);
6730b57cec5SDimitry Andric 
6740b57cec5SDimitry Andric   // Force a transition from the IS_DISPATCHED state to the IS_READY or
6750b57cec5SDimitry Andric   // IS_PENDING state. State transitions normally occur either at the beginning
6760b57cec5SDimitry Andric   // of a new cycle (see method cycleEvent()), or as a result of another issue
6770b57cec5SDimitry Andric   // event. This method is called every time the instruction might have changed
6780b57cec5SDimitry Andric   // in state. It internally delegates to method updateDispatched() and
6790b57cec5SDimitry Andric   // updateWaiting().
6800b57cec5SDimitry Andric   void update();
6810b57cec5SDimitry Andric   bool updateDispatched();
6820b57cec5SDimitry Andric   bool updatePending();
6830b57cec5SDimitry Andric 
isInvalid()68481ad6265SDimitry Andric   bool isInvalid() const { return Stage == IS_INVALID; }
isDispatched()6850b57cec5SDimitry Andric   bool isDispatched() const { return Stage == IS_DISPATCHED; }
isPending()6860b57cec5SDimitry Andric   bool isPending() const { return Stage == IS_PENDING; }
isReady()6870b57cec5SDimitry Andric   bool isReady() const { return Stage == IS_READY; }
isExecuting()6880b57cec5SDimitry Andric   bool isExecuting() const { return Stage == IS_EXECUTING; }
isExecuted()6890b57cec5SDimitry Andric   bool isExecuted() const { return Stage == IS_EXECUTED; }
isRetired()6900b57cec5SDimitry Andric   bool isRetired() const { return Stage == IS_RETIRED; }
isEliminated()6910b57cec5SDimitry Andric   bool isEliminated() const { return IsEliminated; }
6920b57cec5SDimitry Andric 
6930b57cec5SDimitry Andric   // Forces a transition from state IS_DISPATCHED to state IS_EXECUTED.
6940b57cec5SDimitry Andric   void forceExecuted();
setEliminated()6950b57cec5SDimitry Andric   void setEliminated() { IsEliminated = true; }
6960b57cec5SDimitry Andric 
retire()6970b57cec5SDimitry Andric   void retire() {
6980b57cec5SDimitry Andric     assert(isExecuted() && "Instruction is in an invalid state!");
6990b57cec5SDimitry Andric     Stage = IS_RETIRED;
7000b57cec5SDimitry Andric   }
7010b57cec5SDimitry Andric 
getCriticalRegDep()7020b57cec5SDimitry Andric   const CriticalDependency &getCriticalRegDep() const { return CriticalRegDep; }
getCriticalMemDep()7030b57cec5SDimitry Andric   const CriticalDependency &getCriticalMemDep() const { return CriticalMemDep; }
7040b57cec5SDimitry Andric   const CriticalDependency &computeCriticalRegDep();
setCriticalMemDep(const CriticalDependency & MemDep)7050b57cec5SDimitry Andric   void setCriticalMemDep(const CriticalDependency &MemDep) {
7060b57cec5SDimitry Andric     CriticalMemDep = MemDep;
7070b57cec5SDimitry Andric   }
7080b57cec5SDimitry Andric 
getCriticalResourceMask()7090b57cec5SDimitry Andric   uint64_t getCriticalResourceMask() const { return CriticalResourceMask; }
setCriticalResourceMask(uint64_t ResourceMask)7100b57cec5SDimitry Andric   void setCriticalResourceMask(uint64_t ResourceMask) {
7110b57cec5SDimitry Andric     CriticalResourceMask = ResourceMask;
7120b57cec5SDimitry Andric   }
7130b57cec5SDimitry Andric 
7140b57cec5SDimitry Andric   void cycleEvent();
7150b57cec5SDimitry Andric };
7160b57cec5SDimitry Andric 
7170b57cec5SDimitry Andric /// An InstRef contains both a SourceMgr index and Instruction pair.  The index
7180b57cec5SDimitry Andric /// is used as a unique identifier for the instruction.  MCA will make use of
7190b57cec5SDimitry Andric /// this index as a key throughout MCA.
7200b57cec5SDimitry Andric class InstRef {
7210b57cec5SDimitry Andric   std::pair<unsigned, Instruction *> Data;
7220b57cec5SDimitry Andric 
7230b57cec5SDimitry Andric public:
InstRef()7240b57cec5SDimitry Andric   InstRef() : Data(std::make_pair(0, nullptr)) {}
InstRef(unsigned Index,Instruction * I)7250b57cec5SDimitry Andric   InstRef(unsigned Index, Instruction *I) : Data(std::make_pair(Index, I)) {}
7260b57cec5SDimitry Andric 
7270b57cec5SDimitry Andric   bool operator==(const InstRef &Other) const { return Data == Other.Data; }
7280b57cec5SDimitry Andric   bool operator!=(const InstRef &Other) const { return Data != Other.Data; }
7290b57cec5SDimitry Andric   bool operator<(const InstRef &Other) const {
7300b57cec5SDimitry Andric     return Data.first < Other.Data.first;
7310b57cec5SDimitry Andric   }
7320b57cec5SDimitry Andric 
getSourceIndex()7330b57cec5SDimitry Andric   unsigned getSourceIndex() const { return Data.first; }
getInstruction()7340b57cec5SDimitry Andric   Instruction *getInstruction() { return Data.second; }
getInstruction()7350b57cec5SDimitry Andric   const Instruction *getInstruction() const { return Data.second; }
7360b57cec5SDimitry Andric 
7370b57cec5SDimitry Andric   /// Returns true if this references a valid instruction.
7380b57cec5SDimitry Andric   explicit operator bool() const { return Data.second != nullptr; }
7390b57cec5SDimitry Andric 
7400b57cec5SDimitry Andric   /// Invalidate this reference.
invalidate()7410b57cec5SDimitry Andric   void invalidate() { Data.second = nullptr; }
7420b57cec5SDimitry Andric 
7430b57cec5SDimitry Andric #ifndef NDEBUG
print(raw_ostream & OS)7440b57cec5SDimitry Andric   void print(raw_ostream &OS) const { OS << getSourceIndex(); }
7450b57cec5SDimitry Andric #endif
7460b57cec5SDimitry Andric };
7470b57cec5SDimitry Andric 
7480b57cec5SDimitry Andric #ifndef NDEBUG
7490b57cec5SDimitry Andric inline raw_ostream &operator<<(raw_ostream &OS, const InstRef &IR) {
7500b57cec5SDimitry Andric   IR.print(OS);
7510b57cec5SDimitry Andric   return OS;
7520b57cec5SDimitry Andric }
7530b57cec5SDimitry Andric #endif
7540b57cec5SDimitry Andric 
7550b57cec5SDimitry Andric } // namespace mca
7560b57cec5SDimitry Andric } // namespace llvm
7570b57cec5SDimitry Andric 
7580b57cec5SDimitry Andric #endif // LLVM_MCA_INSTRUCTION_H
759