xref: /freebsd/contrib/llvm-project/llvm/include/llvm/MCA/Instruction.h (revision 700637cbb5e582861067a11aaca4d053546871d2)
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 
31 namespace llvm {
32 
33 namespace mca {
34 
35 constexpr int UNKNOWN_CYCLES = -512;
36 
37 /// A representation of an mca::Instruction operand
38 /// for use in mca::CustomBehaviour.
39 class 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 
65 public:
MCAOperand()66   MCAOperand() : Kind(kInvalid), FPImmVal(), Index() {}
67 
isValid()68   bool isValid() const { return Kind != kInvalid; }
isReg()69   bool isReg() const { return Kind == kRegister; }
isImm()70   bool isImm() const { return Kind == kImmediate; }
isSFPImm()71   bool isSFPImm() const { return Kind == kSFPImmediate; }
isDFPImm()72   bool isDFPImm() const { return Kind == kDFPImmediate; }
73 
74   /// Returns the register number.
getReg()75   unsigned getReg() const {
76     assert(isReg() && "This is not a register operand!");
77     return RegVal;
78   }
79 
getImm()80   int64_t getImm() const {
81     assert(isImm() && "This is not an immediate");
82     return ImmVal;
83   }
84 
getSFPImm()85   uint32_t getSFPImm() const {
86     assert(isSFPImm() && "This is not an SFP immediate");
87     return SFPImmVal;
88   }
89 
getDFPImm()90   uint64_t getDFPImm() const {
91     assert(isDFPImm() && "This is not an FP immediate");
92     return FPImmVal;
93   }
94 
setIndex(const unsigned Idx)95   void setIndex(const unsigned Idx) { Index = Idx; }
96 
getIndex()97   unsigned getIndex() const { return Index; }
98 
createReg(unsigned Reg)99   static MCAOperand createReg(unsigned Reg) {
100     MCAOperand Op;
101     Op.Kind = kRegister;
102     Op.RegVal = Reg;
103     return Op;
104   }
105 
createImm(int64_t Val)106   static MCAOperand createImm(int64_t Val) {
107     MCAOperand Op;
108     Op.Kind = kImmediate;
109     Op.ImmVal = Val;
110     return Op;
111   }
112 
createSFPImm(uint32_t Val)113   static MCAOperand createSFPImm(uint32_t Val) {
114     MCAOperand Op;
115     Op.Kind = kSFPImmediate;
116     Op.SFPImmVal = Val;
117     return Op;
118   }
119 
createDFPImm(uint64_t Val)120   static MCAOperand createDFPImm(uint64_t Val) {
121     MCAOperand Op;
122     Op.Kind = kDFPImmediate;
123     Op.FPImmVal = Val;
124     return Op;
125   }
126 
createInvalid()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.
136 struct 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 
isImplicitWriteWriteDescriptor160   bool isImplicitWrite() const { return OpIndex < 0; };
161 };
162 
163 /// A register read descriptor.
164 struct 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 
isImplicitReadReadDescriptor178   bool isImplicitRead() const { return OpIndex < 0; };
179 };
180 
181 class ReadState;
182 
183 /// A critical data dependency descriptor.
184 ///
185 /// Field RegID is set to the invalid register for memory dependencies.
186 struct 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.
198 class 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 
248 public:
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 
getCyclesLeft()259   int getCyclesLeft() const { return CyclesLeft; }
getWriteResourceID()260   unsigned getWriteResourceID() const { return WD->SClassOrWriteResourceID; }
getRegisterID()261   MCPhysReg getRegisterID() const { return RegisterID; }
setRegisterID(const MCPhysReg RegID)262   void setRegisterID(const MCPhysReg RegID) { RegisterID = RegID; }
getRegisterFileID()263   unsigned getRegisterFileID() const { return PRFID; }
getLatency()264   unsigned getLatency() const { return WD->Latency; }
getDependentWriteCyclesLeft()265   unsigned getDependentWriteCyclesLeft() const {
266     return DependentWriteCyclesLeft;
267   }
getDependentWrite()268   const WriteState *getDependentWrite() const { return DependentWrite; }
getCriticalRegDep()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 
getNumUsers()281   unsigned getNumUsers() const {
282     unsigned NumUsers = Users.size();
283     if (PartialWrite)
284       ++NumUsers;
285     return NumUsers;
286   }
287 
clearsSuperRegisters()288   bool clearsSuperRegisters() const { return ClearsSuperRegs; }
isWriteZero()289   bool isWriteZero() const { return WritesZero; }
isEliminated()290   bool isEliminated() const { return IsEliminated; }
291 
isReady()292   bool isReady() const {
293     if (DependentWrite)
294       return false;
295     unsigned CyclesLeft = getDependentWriteCyclesLeft();
296     return !CyclesLeft || CyclesLeft < getLatency();
297   }
298 
isExecuted()299   bool isExecuted() const {
300     return CyclesLeft != UNKNOWN_CYCLES && CyclesLeft <= 0;
301   }
302 
setDependentWrite(const WriteState * Other)303   void setDependentWrite(const WriteState *Other) { DependentWrite = Other; }
304   LLVM_ABI void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
setWriteZero()305   void setWriteZero() { WritesZero = true; }
setEliminated()306   void setEliminated() {
307     assert(Users.empty() && "Write is in an inconsistent state.");
308     CyclesLeft = 0;
309     IsEliminated = true;
310   }
311 
setPRF(unsigned PRF)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.
327 class 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 
356 public:
ReadState(const ReadDescriptor & Desc,MCPhysReg RegID)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 
getDescriptor()362   const ReadDescriptor &getDescriptor() const { return *RD; }
getSchedClass()363   unsigned getSchedClass() const { return RD->SchedClassID; }
getRegisterID()364   MCPhysReg getRegisterID() const { return RegisterID; }
getRegisterFileID()365   unsigned getRegisterFileID() const { return PRFID; }
getCriticalRegDep()366   const CriticalDependency &getCriticalRegDep() const { return CRD; }
367 
isPending()368   bool isPending() const { return !IndependentFromDef && CyclesLeft > 0; }
isReady()369   bool isReady() const { return IsReady; }
isImplicitRead()370   bool isImplicitRead() const { return RD->isImplicitRead(); }
371 
isIndependentFromDef()372   bool isIndependentFromDef() const { return IndependentFromDef; }
setIndependentFromDef()373   void setIndependentFromDef() { IndependentFromDef = true; }
374 
375   LLVM_ABI void cycleEvent();
376   LLVM_ABI void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
setDependentWrites(unsigned Writes)377   void setDependentWrites(unsigned Writes) {
378     DependentWrites = Writes;
379     IsReady = !Writes;
380   }
381 
isReadZero()382   bool isReadZero() const { return IsZero; }
setReadZero()383   void setReadZero() { IsZero = true; }
setPRF(unsigned ID)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.
390 class CycleSegment {
391   unsigned Begin; // Inclusive.
392   unsigned End;   // Exclusive.
393   bool Reserved;  // Resources associated to this segment must be reserved.
394 
395 public:
396   CycleSegment(unsigned StartCycle, unsigned EndCycle, bool IsReserved = false)
Begin(StartCycle)397       : Begin(StartCycle), End(EndCycle), Reserved(IsReserved) {}
398 
contains(unsigned Cycle)399   bool contains(unsigned Cycle) const { return Cycle >= Begin && Cycle < End; }
startsAfter(const CycleSegment & CS)400   bool startsAfter(const CycleSegment &CS) const { return End <= CS.Begin; }
endsBefore(const CycleSegment & CS)401   bool endsBefore(const CycleSegment &CS) const { return Begin >= CS.End; }
overlaps(const CycleSegment & CS)402   bool overlaps(const CycleSegment &CS) const {
403     return !startsAfter(CS) && !endsBefore(CS);
404   }
isExecuting()405   bool isExecuting() const { return Begin == 0 && End != 0; }
isExecuted()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 
isValid()418   bool isValid() const { return Begin <= End; }
size()419   unsigned size() const { return End - Begin; };
subtract(unsigned Cycles)420   void subtract(unsigned Cycles) {
421     assert(End >= Cycles);
422     End -= Cycles;
423   }
424 
begin()425   unsigned begin() const { return Begin; }
end()426   unsigned end() const { return End; }
setEnd(unsigned NewEnd)427   void setEnd(unsigned NewEnd) { End = NewEnd; }
isReserved()428   bool isReserved() const { return Reserved; }
setReserved()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.
437 struct ResourceUsage {
438   CycleSegment CS;
439   unsigned NumUnits;
440   ResourceUsage(CycleSegment Cycles, unsigned Units = 1)
CSResourceUsage441       : CS(Cycles), NumUnits(Units) {}
sizeResourceUsage442   unsigned size() const { return CS.size(); }
isReservedResourceUsage443   bool isReserved() const { return CS.isReserved(); }
setReservedResourceUsage444   void setReserved() { CS.setReserved(); }
445 };
446 
447 /// An instruction descriptor
448 struct 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.
isZeroLatencyInstrDesc486   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.
497 class 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 
531 public:
InstructionBase(const InstrDesc & D,const unsigned Opcode)532   InstructionBase(const InstrDesc &D, const unsigned Opcode)
533       : Desc(D), IsOptimizableMove(false), Operands(0), Opcode(Opcode),
534         IsALoadBarrier(false), IsAStoreBarrier(false) {}
535 
getDefs()536   SmallVectorImpl<WriteState> &getDefs() { return Defs; }
getDefs()537   ArrayRef<WriteState> getDefs() const { return Defs; }
getUses()538   SmallVectorImpl<ReadState> &getUses() { return Uses; }
getUses()539   ArrayRef<ReadState> getUses() const { return Uses; }
getDesc()540   const InstrDesc &getDesc() const { return Desc; }
541 
getLatency()542   unsigned getLatency() const { return Desc.MaxLatency; }
getNumMicroOps()543   unsigned getNumMicroOps() const { return Desc.NumMicroOps; }
getOpcode()544   unsigned getOpcode() const { return Opcode; }
isALoadBarrier()545   bool isALoadBarrier() const { return IsALoadBarrier; }
isAStoreBarrier()546   bool isAStoreBarrier() const { return IsAStoreBarrier; }
setLoadBarrier(bool IsBarrier)547   void setLoadBarrier(bool IsBarrier) { IsALoadBarrier = IsBarrier; }
setStoreBarrier(bool IsBarrier)548   void setStoreBarrier(bool IsBarrier) { IsAStoreBarrier = IsBarrier; }
549 
550   /// Return the MCAOperand which corresponds to index Idx within the original
551   /// MCInst.
getOperand(const unsigned Idx)552   const MCAOperand *getOperand(const unsigned Idx) const {
553     auto It = llvm::find_if(Operands, [&Idx](const MCAOperand &Op) {
554       return Op.getIndex() == Idx;
555     });
556     if (It == Operands.end())
557       return nullptr;
558     return &(*It);
559   }
getNumOperands()560   unsigned getNumOperands() const { return Operands.size(); }
addOperand(const MCAOperand Op)561   void addOperand(const MCAOperand Op) { Operands.push_back(Op); }
562 
hasDependentUsers()563   bool hasDependentUsers() const {
564     return any_of(Defs,
565                   [](const WriteState &Def) { return Def.getNumUsers() > 0; });
566   }
567 
getNumUsers()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.
isOptimizableMove()576   bool isOptimizableMove() const { return IsOptimizableMove; }
setOptimizableMove()577   void setOptimizableMove() { IsOptimizableMove = true; }
clearOptimizableMove()578   void clearOptimizableMove() { IsOptimizableMove = false; }
isMemOp()579   bool isMemOp() const { return MayLoad || MayStore; }
580 
581   // Getters and setters for general instruction flags.
setMayLoad(bool newVal)582   void setMayLoad(bool newVal) { MayLoad = newVal; }
setMayStore(bool newVal)583   void setMayStore(bool newVal) { MayStore = newVal; }
setHasSideEffects(bool newVal)584   void setHasSideEffects(bool newVal) { HasSideEffects = newVal; }
setBeginGroup(bool newVal)585   void setBeginGroup(bool newVal) { BeginGroup = newVal; }
setEndGroup(bool newVal)586   void setEndGroup(bool newVal) { EndGroup = newVal; }
setRetireOOO(bool newVal)587   void setRetireOOO(bool newVal) { RetireOOO = newVal; }
588 
getMayLoad()589   bool getMayLoad() const { return MayLoad; }
getMayStore()590   bool getMayStore() const { return MayStore; }
getHasSideEffects()591   bool getHasSideEffects() const { return HasSideEffects; }
getBeginGroup()592   bool getBeginGroup() const { return BeginGroup; }
getEndGroup()593   bool getEndGroup() const { return EndGroup; }
getRetireOOO()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.
601 class 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 
647 public:
Instruction(const InstrDesc & D,const unsigned Opcode)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 
getRCUTokenID()656   unsigned getRCUTokenID() const { return RCUTokenID; }
getLSUTokenID()657   unsigned getLSUTokenID() const { return LSUTokenID; }
setLSUTokenID(unsigned LSUTok)658   void setLSUTokenID(unsigned LSUTok) { LSUTokenID = LSUTok; }
659 
getUsedBuffers()660   uint64_t getUsedBuffers() const { return UsedBuffers; }
setUsedBuffers(uint64_t Mask)661   void setUsedBuffers(uint64_t Mask) { UsedBuffers = Mask; }
clearUsedBuffers()662   void clearUsedBuffers() { UsedBuffers = 0ULL; }
663 
getCyclesLeft()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 
isInvalid()685   bool isInvalid() const { return Stage == IS_INVALID; }
isDispatched()686   bool isDispatched() const { return Stage == IS_DISPATCHED; }
isPending()687   bool isPending() const { return Stage == IS_PENDING; }
isReady()688   bool isReady() const { return Stage == IS_READY; }
isExecuting()689   bool isExecuting() const { return Stage == IS_EXECUTING; }
isExecuted()690   bool isExecuted() const { return Stage == IS_EXECUTED; }
isRetired()691   bool isRetired() const { return Stage == IS_RETIRED; }
isEliminated()692   bool isEliminated() const { return IsEliminated; }
693 
694   // Forces a transition from state IS_DISPATCHED to state IS_EXECUTED.
695   LLVM_ABI void forceExecuted();
setEliminated()696   void setEliminated() { IsEliminated = true; }
697 
retire()698   void retire() {
699     assert(isExecuted() && "Instruction is in an invalid state!");
700     Stage = IS_RETIRED;
701   }
702 
getCriticalRegDep()703   const CriticalDependency &getCriticalRegDep() const { return CriticalRegDep; }
getCriticalMemDep()704   const CriticalDependency &getCriticalMemDep() const { return CriticalMemDep; }
705   LLVM_ABI const CriticalDependency &computeCriticalRegDep();
setCriticalMemDep(const CriticalDependency & MemDep)706   void setCriticalMemDep(const CriticalDependency &MemDep) {
707     CriticalMemDep = MemDep;
708   }
709 
getCriticalResourceMask()710   uint64_t getCriticalResourceMask() const { return CriticalResourceMask; }
setCriticalResourceMask(uint64_t ResourceMask)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.
721 class InstRef {
722   std::pair<unsigned, Instruction *> Data;
723 
724 public:
InstRef()725   InstRef() : Data(std::make_pair(0, nullptr)) {}
InstRef(unsigned Index,Instruction * I)726   InstRef(unsigned Index, Instruction *I) : Data(std::make_pair(Index, 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 
getSourceIndex()734   unsigned getSourceIndex() const { return Data.first; }
getInstruction()735   Instruction *getInstruction() { return Data.second; }
getInstruction()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.
invalidate()742   void invalidate() { Data.second = nullptr; }
743 
744 #ifndef NDEBUG
print(raw_ostream & OS)745   void print(raw_ostream &OS) const { OS << getSourceIndex(); }
746 #endif
747 };
748 
749 #ifndef NDEBUG
750 inline 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