Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:44:16

0001 //===--------------------- Instruction.h ------------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 /// \file
0009 ///
0010 /// This file defines abstractions used by the Pipeline to model register reads,
0011 /// register writes and instructions.
0012 ///
0013 //===----------------------------------------------------------------------===//
0014 
0015 #ifndef LLVM_MCA_INSTRUCTION_H
0016 #define LLVM_MCA_INSTRUCTION_H
0017 
0018 #include "llvm/ADT/ArrayRef.h"
0019 #include "llvm/ADT/STLExtras.h"
0020 #include "llvm/ADT/SmallVector.h"
0021 #include "llvm/MC/MCRegister.h" // definition of MCPhysReg.
0022 #include "llvm/Support/MathExtras.h"
0023 
0024 #ifndef NDEBUG
0025 #include "llvm/Support/raw_ostream.h"
0026 #endif
0027 
0028 #include <memory>
0029 
0030 namespace llvm {
0031 
0032 namespace mca {
0033 
0034 constexpr int UNKNOWN_CYCLES = -512;
0035 
0036 /// A representation of an mca::Instruction operand
0037 /// for use in mca::CustomBehaviour.
0038 class MCAOperand {
0039   // This class is mostly copied from MCOperand within
0040   // MCInst.h except that we don't keep track of
0041   // expressions or sub-instructions.
0042   enum MCAOperandType : unsigned char {
0043     kInvalid,   ///< Uninitialized, Relocatable immediate, or Sub-instruction.
0044     kRegister,  ///< Register operand.
0045     kImmediate, ///< Immediate operand.
0046     kSFPImmediate, ///< Single-floating-point immediate operand.
0047     kDFPImmediate, ///< Double-Floating-point immediate operand.
0048   };
0049   MCAOperandType Kind;
0050 
0051   union {
0052     unsigned RegVal;
0053     int64_t ImmVal;
0054     uint32_t SFPImmVal;
0055     uint64_t FPImmVal;
0056   };
0057 
0058   // We only store specific operands for specific instructions
0059   // so an instruction's operand 3 may be stored within the list
0060   // of MCAOperand as element 0. This Index attribute keeps track
0061   // of the original index (3 for this example).
0062   unsigned Index;
0063 
0064 public:
0065   MCAOperand() : Kind(kInvalid), FPImmVal(), Index() {}
0066 
0067   bool isValid() const { return Kind != kInvalid; }
0068   bool isReg() const { return Kind == kRegister; }
0069   bool isImm() const { return Kind == kImmediate; }
0070   bool isSFPImm() const { return Kind == kSFPImmediate; }
0071   bool isDFPImm() const { return Kind == kDFPImmediate; }
0072 
0073   /// Returns the register number.
0074   unsigned getReg() const {
0075     assert(isReg() && "This is not a register operand!");
0076     return RegVal;
0077   }
0078 
0079   int64_t getImm() const {
0080     assert(isImm() && "This is not an immediate");
0081     return ImmVal;
0082   }
0083 
0084   uint32_t getSFPImm() const {
0085     assert(isSFPImm() && "This is not an SFP immediate");
0086     return SFPImmVal;
0087   }
0088 
0089   uint64_t getDFPImm() const {
0090     assert(isDFPImm() && "This is not an FP immediate");
0091     return FPImmVal;
0092   }
0093 
0094   void setIndex(const unsigned Idx) { Index = Idx; }
0095 
0096   unsigned getIndex() const { return Index; }
0097 
0098   static MCAOperand createReg(unsigned Reg) {
0099     MCAOperand Op;
0100     Op.Kind = kRegister;
0101     Op.RegVal = Reg;
0102     return Op;
0103   }
0104 
0105   static MCAOperand createImm(int64_t Val) {
0106     MCAOperand Op;
0107     Op.Kind = kImmediate;
0108     Op.ImmVal = Val;
0109     return Op;
0110   }
0111 
0112   static MCAOperand createSFPImm(uint32_t Val) {
0113     MCAOperand Op;
0114     Op.Kind = kSFPImmediate;
0115     Op.SFPImmVal = Val;
0116     return Op;
0117   }
0118 
0119   static MCAOperand createDFPImm(uint64_t Val) {
0120     MCAOperand Op;
0121     Op.Kind = kDFPImmediate;
0122     Op.FPImmVal = Val;
0123     return Op;
0124   }
0125 
0126   static MCAOperand createInvalid() {
0127     MCAOperand Op;
0128     Op.Kind = kInvalid;
0129     Op.FPImmVal = 0;
0130     return Op;
0131   }
0132 };
0133 
0134 /// A register write descriptor.
0135 struct WriteDescriptor {
0136   // Operand index. The index is negative for implicit writes only.
0137   // For implicit writes, the actual operand index is computed performing
0138   // a bitwise not of the OpIndex.
0139   int OpIndex;
0140   // Write latency. Number of cycles before write-back stage.
0141   unsigned Latency;
0142   // This field is set to a value different than zero only if this
0143   // is an implicit definition.
0144   MCPhysReg RegisterID;
0145   // Instruction itineraries would set this field to the SchedClass ID.
0146   // Otherwise, it defaults to the WriteResourceID from the MCWriteLatencyEntry
0147   // element associated to this write.
0148   // When computing read latencies, this value is matched against the
0149   // "ReadAdvance" information. The hardware backend may implement
0150   // dedicated forwarding paths to quickly propagate write results to dependent
0151   // instructions waiting in the reservation station (effectively bypassing the
0152   // write-back stage).
0153   unsigned SClassOrWriteResourceID;
0154   // True only if this is a write obtained from an optional definition.
0155   // Optional definitions are allowed to reference regID zero (i.e. "no
0156   // register").
0157   bool IsOptionalDef;
0158 
0159   bool isImplicitWrite() const { return OpIndex < 0; };
0160 };
0161 
0162 /// A register read descriptor.
0163 struct ReadDescriptor {
0164   // A MCOperand index. This is used by the Dispatch logic to identify register
0165   // reads. Implicit reads have negative indices. The actual operand index of an
0166   // implicit read is the bitwise not of field OpIndex.
0167   int OpIndex;
0168   // The actual "UseIdx". This is used to query the ReadAdvance table. Explicit
0169   // uses always come first in the sequence of uses.
0170   unsigned UseIndex;
0171   // This field is only set if this is an implicit read.
0172   MCPhysReg RegisterID;
0173   // Scheduling Class Index. It is used to query the scheduling model for the
0174   // MCSchedClassDesc object.
0175   unsigned SchedClassID;
0176 
0177   bool isImplicitRead() const { return OpIndex < 0; };
0178 };
0179 
0180 class ReadState;
0181 
0182 /// A critical data dependency descriptor.
0183 ///
0184 /// Field RegID is set to the invalid register for memory dependencies.
0185 struct CriticalDependency {
0186   unsigned IID;
0187   MCPhysReg RegID;
0188   unsigned Cycles;
0189 };
0190 
0191 /// Tracks uses of a register definition (e.g. register write).
0192 ///
0193 /// Each implicit/explicit register write is associated with an instance of
0194 /// this class. A WriteState object tracks the dependent users of a
0195 /// register write. It also tracks how many cycles are left before the write
0196 /// back stage.
0197 class WriteState {
0198   const WriteDescriptor *WD;
0199   // On instruction issue, this field is set equal to the write latency.
0200   // Before instruction issue, this field defaults to -512, a special
0201   // value that represents an "unknown" number of cycles.
0202   int CyclesLeft;
0203 
0204   // Actual register defined by this write. This field is only used
0205   // to speedup queries on the register file.
0206   // For implicit writes, this field always matches the value of
0207   // field RegisterID from WD.
0208   MCPhysReg RegisterID;
0209 
0210   // Physical register file that serves register RegisterID.
0211   unsigned PRFID;
0212 
0213   // True if this write implicitly clears the upper portion of RegisterID's
0214   // super-registers.
0215   bool ClearsSuperRegs;
0216 
0217   // True if this write is from a dependency breaking zero-idiom instruction.
0218   bool WritesZero;
0219 
0220   // True if this write has been eliminated at register renaming stage.
0221   // Example: a register move doesn't consume scheduler/pipleline resources if
0222   // it is eliminated at register renaming stage. It still consumes
0223   // decode bandwidth, and ROB entries.
0224   bool IsEliminated;
0225 
0226   // This field is set if this is a partial register write, and it has a false
0227   // dependency on any previous write of the same register (or a portion of it).
0228   // DependentWrite must be able to complete before this write completes, so
0229   // that we don't break the WAW, and the two writes can be merged together.
0230   const WriteState *DependentWrite;
0231 
0232   // A partial write that is in a false dependency with this write.
0233   WriteState *PartialWrite;
0234   unsigned DependentWriteCyclesLeft;
0235 
0236   // Critical register dependency for this write.
0237   CriticalDependency CRD;
0238 
0239   // A list of dependent reads. Users is a set of dependent
0240   // reads. A dependent read is added to the set only if CyclesLeft
0241   // is "unknown". As soon as CyclesLeft is 'known', each user in the set
0242   // gets notified with the actual CyclesLeft.
0243 
0244   // The 'second' element of a pair is a "ReadAdvance" number of cycles.
0245   SmallVector<std::pair<ReadState *, int>, 4> Users;
0246 
0247 public:
0248   WriteState(const WriteDescriptor &Desc, MCPhysReg RegID,
0249              bool clearsSuperRegs = false, bool writesZero = false)
0250       : WD(&Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID), PRFID(0),
0251         ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero),
0252         IsEliminated(false), DependentWrite(nullptr), PartialWrite(nullptr),
0253         DependentWriteCyclesLeft(0), CRD() {}
0254 
0255   WriteState(const WriteState &Other) = default;
0256   WriteState &operator=(const WriteState &Other) = default;
0257 
0258   int getCyclesLeft() const { return CyclesLeft; }
0259   unsigned getWriteResourceID() const { return WD->SClassOrWriteResourceID; }
0260   MCPhysReg getRegisterID() const { return RegisterID; }
0261   void setRegisterID(const MCPhysReg RegID) { RegisterID = RegID; }
0262   unsigned getRegisterFileID() const { return PRFID; }
0263   unsigned getLatency() const { return WD->Latency; }
0264   unsigned getDependentWriteCyclesLeft() const {
0265     return DependentWriteCyclesLeft;
0266   }
0267   const WriteState *getDependentWrite() const { return DependentWrite; }
0268   const CriticalDependency &getCriticalRegDep() const { return CRD; }
0269 
0270   // This method adds Use to the set of data dependent reads. IID is the
0271   // instruction identifier associated with this write. ReadAdvance is the
0272   // number of cycles to subtract from the latency of this data dependency.
0273   // Use is in a RAW dependency with this write.
0274   void addUser(unsigned IID, ReadState *Use, int ReadAdvance);
0275 
0276   // Use is a younger register write that is in a false dependency with this
0277   // write. IID is the instruction identifier associated with this write.
0278   void addUser(unsigned IID, WriteState *Use);
0279 
0280   unsigned getNumUsers() const {
0281     unsigned NumUsers = Users.size();
0282     if (PartialWrite)
0283       ++NumUsers;
0284     return NumUsers;
0285   }
0286 
0287   bool clearsSuperRegisters() const { return ClearsSuperRegs; }
0288   bool isWriteZero() const { return WritesZero; }
0289   bool isEliminated() const { return IsEliminated; }
0290 
0291   bool isReady() const {
0292     if (DependentWrite)
0293       return false;
0294     unsigned CyclesLeft = getDependentWriteCyclesLeft();
0295     return !CyclesLeft || CyclesLeft < getLatency();
0296   }
0297 
0298   bool isExecuted() const {
0299     return CyclesLeft != UNKNOWN_CYCLES && CyclesLeft <= 0;
0300   }
0301 
0302   void setDependentWrite(const WriteState *Other) { DependentWrite = Other; }
0303   void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
0304   void setWriteZero() { WritesZero = true; }
0305   void setEliminated() {
0306     assert(Users.empty() && "Write is in an inconsistent state.");
0307     CyclesLeft = 0;
0308     IsEliminated = true;
0309   }
0310 
0311   void setPRF(unsigned PRF) { PRFID = PRF; }
0312 
0313   // On every cycle, update CyclesLeft and notify dependent users.
0314   void cycleEvent();
0315   void onInstructionIssued(unsigned IID);
0316 
0317 #ifndef NDEBUG
0318   void dump() const;
0319 #endif
0320 };
0321 
0322 /// Tracks register operand latency in cycles.
0323 ///
0324 /// A read may be dependent on more than one write. This occurs when some
0325 /// writes only partially update the register associated to this read.
0326 class ReadState {
0327   const ReadDescriptor *RD;
0328   // Physical register identified associated to this read.
0329   MCPhysReg RegisterID;
0330   // Physical register file that serves register RegisterID.
0331   unsigned PRFID;
0332   // Number of writes that contribute to the definition of RegisterID.
0333   // In the absence of partial register updates, the number of DependentWrites
0334   // cannot be more than one.
0335   unsigned DependentWrites;
0336   // Number of cycles left before RegisterID can be read. This value depends on
0337   // the latency of all the dependent writes. It defaults to UNKNOWN_CYCLES.
0338   // It gets set to the value of field TotalCycles only when the 'CyclesLeft' of
0339   // every dependent write is known.
0340   int CyclesLeft;
0341   // This field is updated on every writeStartEvent(). When the number of
0342   // dependent writes (i.e. field DependentWrite) is zero, this value is
0343   // propagated to field CyclesLeft.
0344   unsigned TotalCycles;
0345   // Longest register dependency.
0346   CriticalDependency CRD;
0347   // This field is set to true only if there are no dependent writes, and
0348   // there are no `CyclesLeft' to wait.
0349   bool IsReady;
0350   // True if this is a read from a known zero register.
0351   bool IsZero;
0352   // True if this register read is from a dependency-breaking instruction.
0353   bool IndependentFromDef;
0354 
0355 public:
0356   ReadState(const ReadDescriptor &Desc, MCPhysReg RegID)
0357       : RD(&Desc), RegisterID(RegID), PRFID(0), DependentWrites(0),
0358         CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), CRD(), IsReady(true),
0359         IsZero(false), IndependentFromDef(false) {}
0360 
0361   const ReadDescriptor &getDescriptor() const { return *RD; }
0362   unsigned getSchedClass() const { return RD->SchedClassID; }
0363   MCPhysReg getRegisterID() const { return RegisterID; }
0364   unsigned getRegisterFileID() const { return PRFID; }
0365   const CriticalDependency &getCriticalRegDep() const { return CRD; }
0366 
0367   bool isPending() const { return !IndependentFromDef && CyclesLeft > 0; }
0368   bool isReady() const { return IsReady; }
0369   bool isImplicitRead() const { return RD->isImplicitRead(); }
0370 
0371   bool isIndependentFromDef() const { return IndependentFromDef; }
0372   void setIndependentFromDef() { IndependentFromDef = true; }
0373 
0374   void cycleEvent();
0375   void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
0376   void setDependentWrites(unsigned Writes) {
0377     DependentWrites = Writes;
0378     IsReady = !Writes;
0379   }
0380 
0381   bool isReadZero() const { return IsZero; }
0382   void setReadZero() { IsZero = true; }
0383   void setPRF(unsigned ID) { PRFID = ID; }
0384 };
0385 
0386 /// A sequence of cycles.
0387 ///
0388 /// This class can be used as a building block to construct ranges of cycles.
0389 class CycleSegment {
0390   unsigned Begin; // Inclusive.
0391   unsigned End;   // Exclusive.
0392   bool Reserved;  // Resources associated to this segment must be reserved.
0393 
0394 public:
0395   CycleSegment(unsigned StartCycle, unsigned EndCycle, bool IsReserved = false)
0396       : Begin(StartCycle), End(EndCycle), Reserved(IsReserved) {}
0397 
0398   bool contains(unsigned Cycle) const { return Cycle >= Begin && Cycle < End; }
0399   bool startsAfter(const CycleSegment &CS) const { return End <= CS.Begin; }
0400   bool endsBefore(const CycleSegment &CS) const { return Begin >= CS.End; }
0401   bool overlaps(const CycleSegment &CS) const {
0402     return !startsAfter(CS) && !endsBefore(CS);
0403   }
0404   bool isExecuting() const { return Begin == 0 && End != 0; }
0405   bool isExecuted() const { return End == 0; }
0406   bool operator<(const CycleSegment &Other) const {
0407     return Begin < Other.Begin;
0408   }
0409   CycleSegment &operator--() {
0410     if (Begin)
0411       Begin--;
0412     if (End)
0413       End--;
0414     return *this;
0415   }
0416 
0417   bool isValid() const { return Begin <= End; }
0418   unsigned size() const { return End - Begin; };
0419   void subtract(unsigned Cycles) {
0420     assert(End >= Cycles);
0421     End -= Cycles;
0422   }
0423 
0424   unsigned begin() const { return Begin; }
0425   unsigned end() const { return End; }
0426   void setEnd(unsigned NewEnd) { End = NewEnd; }
0427   bool isReserved() const { return Reserved; }
0428   void setReserved() { Reserved = true; }
0429 };
0430 
0431 /// Helper used by class InstrDesc to describe how hardware resources
0432 /// are used.
0433 ///
0434 /// This class describes how many resource units of a specific resource kind
0435 /// (and how many cycles) are "used" by an instruction.
0436 struct ResourceUsage {
0437   CycleSegment CS;
0438   unsigned NumUnits;
0439   ResourceUsage(CycleSegment Cycles, unsigned Units = 1)
0440       : CS(Cycles), NumUnits(Units) {}
0441   unsigned size() const { return CS.size(); }
0442   bool isReserved() const { return CS.isReserved(); }
0443   void setReserved() { CS.setReserved(); }
0444 };
0445 
0446 /// An instruction descriptor
0447 struct InstrDesc {
0448   SmallVector<WriteDescriptor, 2> Writes; // Implicit writes are at the end.
0449   SmallVector<ReadDescriptor, 4> Reads;   // Implicit reads are at the end.
0450 
0451   // For every resource used by an instruction of this kind, this vector
0452   // reports the number of "consumed cycles".
0453   SmallVector<std::pair<uint64_t, ResourceUsage>, 4> Resources;
0454 
0455   // A bitmask of used hardware buffers.
0456   uint64_t UsedBuffers;
0457 
0458   // A bitmask of used processor resource units.
0459   uint64_t UsedProcResUnits;
0460 
0461   // A bitmask of used processor resource groups.
0462   uint64_t UsedProcResGroups;
0463 
0464   unsigned MaxLatency;
0465   // Number of MicroOps for this instruction.
0466   unsigned NumMicroOps;
0467   // SchedClassID used to construct this InstrDesc.
0468   // This information is currently used by views to do fast queries on the
0469   // subtarget when computing the reciprocal throughput.
0470   unsigned SchedClassID;
0471 
0472   // True if all buffered resources are in-order, and there is at least one
0473   // buffer which is a dispatch hazard (BufferSize = 0).
0474   unsigned MustIssueImmediately : 1;
0475 
0476   // True if the corresponding mca::Instruction can be recycled. Currently only
0477   // instructions that are neither variadic nor have any variant can be
0478   // recycled.
0479   unsigned IsRecyclable : 1;
0480 
0481   // True if some of the consumed group resources are partially overlapping.
0482   unsigned HasPartiallyOverlappingGroups : 1;
0483 
0484   // A zero latency instruction doesn't consume any scheduler resources.
0485   bool isZeroLatency() const { return !MaxLatency && Resources.empty(); }
0486 
0487   InstrDesc() = default;
0488   InstrDesc(const InstrDesc &Other) = delete;
0489   InstrDesc &operator=(const InstrDesc &Other) = delete;
0490 };
0491 
0492 /// Base class for instructions consumed by the simulation pipeline.
0493 ///
0494 /// This class tracks data dependencies as well as generic properties
0495 /// of the instruction.
0496 class InstructionBase {
0497   const InstrDesc &Desc;
0498 
0499   // This field is set for instructions that are candidates for move
0500   // elimination. For more information about move elimination, see the
0501   // definition of RegisterMappingTracker in RegisterFile.h
0502   bool IsOptimizableMove;
0503 
0504   // Output dependencies.
0505   // One entry per each implicit and explicit register definition.
0506   SmallVector<WriteState, 2> Defs;
0507 
0508   // Input dependencies.
0509   // One entry per each implicit and explicit register use.
0510   SmallVector<ReadState, 4> Uses;
0511 
0512   // List of operands which can be used by mca::CustomBehaviour
0513   std::vector<MCAOperand> Operands;
0514 
0515   // Instruction opcode which can be used by mca::CustomBehaviour
0516   unsigned Opcode;
0517 
0518   // Flags used by the LSUnit.
0519   bool IsALoadBarrier : 1;
0520   bool IsAStoreBarrier : 1;
0521   // Flags copied from the InstrDesc and potentially modified by
0522   // CustomBehaviour or (more likely) InstrPostProcess.
0523   bool MayLoad : 1;
0524   bool MayStore : 1;
0525   bool HasSideEffects : 1;
0526   bool BeginGroup : 1;
0527   bool EndGroup : 1;
0528   bool RetireOOO : 1;
0529 
0530 public:
0531   InstructionBase(const InstrDesc &D, const unsigned Opcode)
0532       : Desc(D), IsOptimizableMove(false), Operands(0), Opcode(Opcode),
0533         IsALoadBarrier(false), IsAStoreBarrier(false) {}
0534 
0535   SmallVectorImpl<WriteState> &getDefs() { return Defs; }
0536   ArrayRef<WriteState> getDefs() const { return Defs; }
0537   SmallVectorImpl<ReadState> &getUses() { return Uses; }
0538   ArrayRef<ReadState> getUses() const { return Uses; }
0539   const InstrDesc &getDesc() const { return Desc; }
0540 
0541   unsigned getLatency() const { return Desc.MaxLatency; }
0542   unsigned getNumMicroOps() const { return Desc.NumMicroOps; }
0543   unsigned getOpcode() const { return Opcode; }
0544   bool isALoadBarrier() const { return IsALoadBarrier; }
0545   bool isAStoreBarrier() const { return IsAStoreBarrier; }
0546   void setLoadBarrier(bool IsBarrier) { IsALoadBarrier = IsBarrier; }
0547   void setStoreBarrier(bool IsBarrier) { IsAStoreBarrier = IsBarrier; }
0548 
0549   /// Return the MCAOperand which corresponds to index Idx within the original
0550   /// MCInst.
0551   const MCAOperand *getOperand(const unsigned Idx) const {
0552     auto It = llvm::find_if(Operands, [&Idx](const MCAOperand &Op) {
0553       return Op.getIndex() == Idx;
0554     });
0555     if (It == Operands.end())
0556       return nullptr;
0557     return &(*It);
0558   }
0559   unsigned getNumOperands() const { return Operands.size(); }
0560   void addOperand(const MCAOperand Op) { Operands.push_back(Op); }
0561 
0562   bool hasDependentUsers() const {
0563     return any_of(Defs,
0564                   [](const WriteState &Def) { return Def.getNumUsers() > 0; });
0565   }
0566 
0567   unsigned getNumUsers() const {
0568     unsigned NumUsers = 0;
0569     for (const WriteState &Def : Defs)
0570       NumUsers += Def.getNumUsers();
0571     return NumUsers;
0572   }
0573 
0574   // Returns true if this instruction is a candidate for move elimination.
0575   bool isOptimizableMove() const { return IsOptimizableMove; }
0576   void setOptimizableMove() { IsOptimizableMove = true; }
0577   void clearOptimizableMove() { IsOptimizableMove = false; }
0578   bool isMemOp() const { return MayLoad || MayStore; }
0579 
0580   // Getters and setters for general instruction flags.
0581   void setMayLoad(bool newVal) { MayLoad = newVal; }
0582   void setMayStore(bool newVal) { MayStore = newVal; }
0583   void setHasSideEffects(bool newVal) { HasSideEffects = newVal; }
0584   void setBeginGroup(bool newVal) { BeginGroup = newVal; }
0585   void setEndGroup(bool newVal) { EndGroup = newVal; }
0586   void setRetireOOO(bool newVal) { RetireOOO = newVal; }
0587 
0588   bool getMayLoad() const { return MayLoad; }
0589   bool getMayStore() const { return MayStore; }
0590   bool getHasSideEffects() const { return HasSideEffects; }
0591   bool getBeginGroup() const { return BeginGroup; }
0592   bool getEndGroup() const { return EndGroup; }
0593   bool getRetireOOO() const { return RetireOOO; }
0594 };
0595 
0596 /// An instruction propagated through the simulated instruction pipeline.
0597 ///
0598 /// This class is used to monitor changes to the internal state of instructions
0599 /// that are sent to the various components of the simulated hardware pipeline.
0600 class Instruction : public InstructionBase {
0601   enum InstrStage {
0602     IS_INVALID,    // Instruction in an invalid state.
0603     IS_DISPATCHED, // Instruction dispatched but operands are not ready.
0604     IS_PENDING,    // Instruction is not ready, but operand latency is known.
0605     IS_READY,      // Instruction dispatched and operands ready.
0606     IS_EXECUTING,  // Instruction issued.
0607     IS_EXECUTED,   // Instruction executed. Values are written back.
0608     IS_RETIRED     // Instruction retired.
0609   };
0610 
0611   // The current instruction stage.
0612   enum InstrStage Stage;
0613 
0614   // This value defaults to the instruction latency. This instruction is
0615   // considered executed when field CyclesLeft goes to zero.
0616   int CyclesLeft;
0617 
0618   // Retire Unit token ID for this instruction.
0619   unsigned RCUTokenID;
0620 
0621   // LS token ID for this instruction.
0622   // This field is set to the invalid null token if this is not a memory
0623   // operation.
0624   unsigned LSUTokenID;
0625 
0626   // A resource mask which identifies buffered resources consumed by this
0627   // instruction at dispatch stage. In the absence of macro-fusion, this value
0628   // should always match the value of field `UsedBuffers` from the instruction
0629   // descriptor (see field InstrBase::Desc).
0630   uint64_t UsedBuffers;
0631 
0632   // Critical register dependency.
0633   CriticalDependency CriticalRegDep;
0634 
0635   // Critical memory dependency.
0636   CriticalDependency CriticalMemDep;
0637 
0638   // A bitmask of busy processor resource units.
0639   // This field is set to zero only if execution is not delayed during this
0640   // cycle because of unavailable pipeline resources.
0641   uint64_t CriticalResourceMask;
0642 
0643   // True if this instruction has been optimized at register renaming stage.
0644   bool IsEliminated;
0645 
0646 public:
0647   Instruction(const InstrDesc &D, const unsigned Opcode)
0648       : InstructionBase(D, Opcode), Stage(IS_INVALID),
0649         CyclesLeft(UNKNOWN_CYCLES), RCUTokenID(0), LSUTokenID(0),
0650         UsedBuffers(D.UsedBuffers), CriticalRegDep(), CriticalMemDep(),
0651         CriticalResourceMask(0), IsEliminated(false) {}
0652 
0653   void reset();
0654 
0655   unsigned getRCUTokenID() const { return RCUTokenID; }
0656   unsigned getLSUTokenID() const { return LSUTokenID; }
0657   void setLSUTokenID(unsigned LSUTok) { LSUTokenID = LSUTok; }
0658 
0659   uint64_t getUsedBuffers() const { return UsedBuffers; }
0660   void setUsedBuffers(uint64_t Mask) { UsedBuffers = Mask; }
0661   void clearUsedBuffers() { UsedBuffers = 0ULL; }
0662 
0663   int getCyclesLeft() const { return CyclesLeft; }
0664 
0665   // Transition to the dispatch stage, and assign a RCUToken to this
0666   // instruction. The RCUToken is used to track the completion of every
0667   // register write performed by this instruction.
0668   void dispatch(unsigned RCUTokenID);
0669 
0670   // Instruction issued. Transition to the IS_EXECUTING state, and update
0671   // all the register definitions.
0672   void execute(unsigned IID);
0673 
0674   // Force a transition from the IS_DISPATCHED state to the IS_READY or
0675   // IS_PENDING state. State transitions normally occur either at the beginning
0676   // of a new cycle (see method cycleEvent()), or as a result of another issue
0677   // event. This method is called every time the instruction might have changed
0678   // in state. It internally delegates to method updateDispatched() and
0679   // updateWaiting().
0680   void update();
0681   bool updateDispatched();
0682   bool updatePending();
0683 
0684   bool isInvalid() const { return Stage == IS_INVALID; }
0685   bool isDispatched() const { return Stage == IS_DISPATCHED; }
0686   bool isPending() const { return Stage == IS_PENDING; }
0687   bool isReady() const { return Stage == IS_READY; }
0688   bool isExecuting() const { return Stage == IS_EXECUTING; }
0689   bool isExecuted() const { return Stage == IS_EXECUTED; }
0690   bool isRetired() const { return Stage == IS_RETIRED; }
0691   bool isEliminated() const { return IsEliminated; }
0692 
0693   // Forces a transition from state IS_DISPATCHED to state IS_EXECUTED.
0694   void forceExecuted();
0695   void setEliminated() { IsEliminated = true; }
0696 
0697   void retire() {
0698     assert(isExecuted() && "Instruction is in an invalid state!");
0699     Stage = IS_RETIRED;
0700   }
0701 
0702   const CriticalDependency &getCriticalRegDep() const { return CriticalRegDep; }
0703   const CriticalDependency &getCriticalMemDep() const { return CriticalMemDep; }
0704   const CriticalDependency &computeCriticalRegDep();
0705   void setCriticalMemDep(const CriticalDependency &MemDep) {
0706     CriticalMemDep = MemDep;
0707   }
0708 
0709   uint64_t getCriticalResourceMask() const { return CriticalResourceMask; }
0710   void setCriticalResourceMask(uint64_t ResourceMask) {
0711     CriticalResourceMask = ResourceMask;
0712   }
0713 
0714   void cycleEvent();
0715 };
0716 
0717 /// An InstRef contains both a SourceMgr index and Instruction pair.  The index
0718 /// is used as a unique identifier for the instruction.  MCA will make use of
0719 /// this index as a key throughout MCA.
0720 class InstRef {
0721   std::pair<unsigned, Instruction *> Data;
0722 
0723 public:
0724   InstRef() : Data(std::make_pair(0, nullptr)) {}
0725   InstRef(unsigned Index, Instruction *I) : Data(std::make_pair(Index, I)) {}
0726 
0727   bool operator==(const InstRef &Other) const { return Data == Other.Data; }
0728   bool operator!=(const InstRef &Other) const { return Data != Other.Data; }
0729   bool operator<(const InstRef &Other) const {
0730     return Data.first < Other.Data.first;
0731   }
0732 
0733   unsigned getSourceIndex() const { return Data.first; }
0734   Instruction *getInstruction() { return Data.second; }
0735   const Instruction *getInstruction() const { return Data.second; }
0736 
0737   /// Returns true if this references a valid instruction.
0738   explicit operator bool() const { return Data.second != nullptr; }
0739 
0740   /// Invalidate this reference.
0741   void invalidate() { Data.second = nullptr; }
0742 
0743 #ifndef NDEBUG
0744   void print(raw_ostream &OS) const { OS << getSourceIndex(); }
0745 #endif
0746 };
0747 
0748 #ifndef NDEBUG
0749 inline raw_ostream &operator<<(raw_ostream &OS, const InstRef &IR) {
0750   IR.print(OS);
0751   return OS;
0752 }
0753 #endif
0754 
0755 } // namespace mca
0756 } // namespace llvm
0757 
0758 #endif // LLVM_MCA_INSTRUCTION_H