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