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