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