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--(void) { 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 implicit uses of processor resource units. 462 uint64_t ImplicitlyUsedProcResUnits; 463 464 // A bitmask of used processor resource groups. 465 uint64_t UsedProcResGroups; 466 467 unsigned MaxLatency; 468 // Number of MicroOps for this instruction. 469 unsigned NumMicroOps; 470 // SchedClassID used to construct this InstrDesc. 471 // This information is currently used by views to do fast queries on the 472 // subtarget when computing the reciprocal throughput. 473 unsigned SchedClassID; 474 475 unsigned MayLoad : 1; 476 unsigned MayStore : 1; 477 unsigned HasSideEffects : 1; 478 unsigned BeginGroup : 1; 479 unsigned EndGroup : 1; 480 unsigned RetireOOO : 1; 481 482 // True if all buffered resources are in-order, and there is at least one 483 // buffer which is a dispatch hazard (BufferSize = 0). 484 unsigned MustIssueImmediately : 1; 485 486 // A zero latency instruction doesn't consume any scheduler resources. isZeroLatencyInstrDesc487 bool isZeroLatency() const { return !MaxLatency && Resources.empty(); } 488 489 InstrDesc() = default; 490 InstrDesc(const InstrDesc &Other) = delete; 491 InstrDesc &operator=(const InstrDesc &Other) = delete; 492 }; 493 494 /// Base class for instructions consumed by the simulation pipeline. 495 /// 496 /// This class tracks data dependencies as well as generic properties 497 /// of the instruction. 498 class InstructionBase { 499 const InstrDesc &Desc; 500 501 // This field is set for instructions that are candidates for move 502 // elimination. For more information about move elimination, see the 503 // definition of RegisterMappingTracker in RegisterFile.h 504 bool IsOptimizableMove; 505 506 // Output dependencies. 507 // One entry per each implicit and explicit register definition. 508 SmallVector<WriteState, 2> Defs; 509 510 // Input dependencies. 511 // One entry per each implicit and explicit register use. 512 SmallVector<ReadState, 4> Uses; 513 514 // List of operands which can be used by mca::CustomBehaviour 515 std::vector<MCAOperand> Operands; 516 517 // Instruction opcode which can be used by mca::CustomBehaviour 518 unsigned Opcode; 519 520 public: InstructionBase(const InstrDesc & D,const unsigned Opcode)521 InstructionBase(const InstrDesc &D, const unsigned Opcode) 522 : Desc(D), IsOptimizableMove(false), Operands(0), Opcode(Opcode) {} 523 getDefs()524 SmallVectorImpl<WriteState> &getDefs() { return Defs; } getDefs()525 ArrayRef<WriteState> getDefs() const { return Defs; } getUses()526 SmallVectorImpl<ReadState> &getUses() { return Uses; } getUses()527 ArrayRef<ReadState> getUses() const { return Uses; } getDesc()528 const InstrDesc &getDesc() const { return Desc; } 529 getLatency()530 unsigned getLatency() const { return Desc.MaxLatency; } getNumMicroOps()531 unsigned getNumMicroOps() const { return Desc.NumMicroOps; } getOpcode()532 unsigned getOpcode() const { return Opcode; } 533 534 /// Return the MCAOperand which corresponds to index Idx within the original 535 /// MCInst. getOperand(const unsigned Idx)536 const MCAOperand *getOperand(const unsigned Idx) const { 537 auto It = std::find_if( 538 Operands.begin(), Operands.end(), 539 [&Idx](const MCAOperand &Op) { return Op.getIndex() == Idx; }); 540 if (It == Operands.end()) 541 return nullptr; 542 return &(*It); 543 } getNumOperands()544 unsigned getNumOperands() const { return Operands.size(); } addOperand(const MCAOperand Op)545 void addOperand(const MCAOperand Op) { Operands.push_back(Op); } 546 hasDependentUsers()547 bool hasDependentUsers() const { 548 return any_of(Defs, 549 [](const WriteState &Def) { return Def.getNumUsers() > 0; }); 550 } 551 getNumUsers()552 unsigned getNumUsers() const { 553 unsigned NumUsers = 0; 554 for (const WriteState &Def : Defs) 555 NumUsers += Def.getNumUsers(); 556 return NumUsers; 557 } 558 559 // Returns true if this instruction is a candidate for move elimination. isOptimizableMove()560 bool isOptimizableMove() const { return IsOptimizableMove; } setOptimizableMove()561 void setOptimizableMove() { IsOptimizableMove = true; } isMemOp()562 bool isMemOp() const { return Desc.MayLoad || Desc.MayStore; } 563 }; 564 565 /// An instruction propagated through the simulated instruction pipeline. 566 /// 567 /// This class is used to monitor changes to the internal state of instructions 568 /// that are sent to the various components of the simulated hardware pipeline. 569 class Instruction : public InstructionBase { 570 enum InstrStage { 571 IS_INVALID, // Instruction in an invalid state. 572 IS_DISPATCHED, // Instruction dispatched but operands are not ready. 573 IS_PENDING, // Instruction is not ready, but operand latency is known. 574 IS_READY, // Instruction dispatched and operands ready. 575 IS_EXECUTING, // Instruction issued. 576 IS_EXECUTED, // Instruction executed. Values are written back. 577 IS_RETIRED // Instruction retired. 578 }; 579 580 // The current instruction stage. 581 enum InstrStage Stage; 582 583 // This value defaults to the instruction latency. This instruction is 584 // considered executed when field CyclesLeft goes to zero. 585 int CyclesLeft; 586 587 // Retire Unit token ID for this instruction. 588 unsigned RCUTokenID; 589 590 // LS token ID for this instruction. 591 // This field is set to the invalid null token if this is not a memory 592 // operation. 593 unsigned LSUTokenID; 594 595 // A resource mask which identifies buffered resources consumed by this 596 // instruction at dispatch stage. In the absence of macro-fusion, this value 597 // should always match the value of field `UsedBuffers` from the instruction 598 // descriptor (see field InstrBase::Desc). 599 uint64_t UsedBuffers; 600 601 // Critical register dependency. 602 CriticalDependency CriticalRegDep; 603 604 // Critical memory dependency. 605 CriticalDependency CriticalMemDep; 606 607 // A bitmask of busy processor resource units. 608 // This field is set to zero only if execution is not delayed during this 609 // cycle because of unavailable pipeline resources. 610 uint64_t CriticalResourceMask; 611 612 // True if this instruction has been optimized at register renaming stage. 613 bool IsEliminated; 614 615 public: Instruction(const InstrDesc & D,const unsigned Opcode)616 Instruction(const InstrDesc &D, const unsigned Opcode) 617 : InstructionBase(D, Opcode), Stage(IS_INVALID), 618 CyclesLeft(UNKNOWN_CYCLES), RCUTokenID(0), LSUTokenID(0), 619 UsedBuffers(D.UsedBuffers), CriticalRegDep(), CriticalMemDep(), 620 CriticalResourceMask(0), IsEliminated(false) {} 621 getRCUTokenID()622 unsigned getRCUTokenID() const { return RCUTokenID; } getLSUTokenID()623 unsigned getLSUTokenID() const { return LSUTokenID; } setLSUTokenID(unsigned LSUTok)624 void setLSUTokenID(unsigned LSUTok) { LSUTokenID = LSUTok; } 625 getUsedBuffers()626 uint64_t getUsedBuffers() const { return UsedBuffers; } setUsedBuffers(uint64_t Mask)627 void setUsedBuffers(uint64_t Mask) { UsedBuffers = Mask; } clearUsedBuffers()628 void clearUsedBuffers() { UsedBuffers = 0ULL; } 629 getCyclesLeft()630 int getCyclesLeft() const { return CyclesLeft; } 631 632 // Transition to the dispatch stage, and assign a RCUToken to this 633 // instruction. The RCUToken is used to track the completion of every 634 // register write performed by this instruction. 635 void dispatch(unsigned RCUTokenID); 636 637 // Instruction issued. Transition to the IS_EXECUTING state, and update 638 // all the register definitions. 639 void execute(unsigned IID); 640 641 // Force a transition from the IS_DISPATCHED state to the IS_READY or 642 // IS_PENDING state. State transitions normally occur either at the beginning 643 // of a new cycle (see method cycleEvent()), or as a result of another issue 644 // event. This method is called every time the instruction might have changed 645 // in state. It internally delegates to method updateDispatched() and 646 // updateWaiting(). 647 void update(); 648 bool updateDispatched(); 649 bool updatePending(); 650 isDispatched()651 bool isDispatched() const { return Stage == IS_DISPATCHED; } isPending()652 bool isPending() const { return Stage == IS_PENDING; } isReady()653 bool isReady() const { return Stage == IS_READY; } isExecuting()654 bool isExecuting() const { return Stage == IS_EXECUTING; } isExecuted()655 bool isExecuted() const { return Stage == IS_EXECUTED; } isRetired()656 bool isRetired() const { return Stage == IS_RETIRED; } isEliminated()657 bool isEliminated() const { return IsEliminated; } 658 659 // Forces a transition from state IS_DISPATCHED to state IS_EXECUTED. 660 void forceExecuted(); setEliminated()661 void setEliminated() { IsEliminated = true; } 662 retire()663 void retire() { 664 assert(isExecuted() && "Instruction is in an invalid state!"); 665 Stage = IS_RETIRED; 666 } 667 getCriticalRegDep()668 const CriticalDependency &getCriticalRegDep() const { return CriticalRegDep; } getCriticalMemDep()669 const CriticalDependency &getCriticalMemDep() const { return CriticalMemDep; } 670 const CriticalDependency &computeCriticalRegDep(); setCriticalMemDep(const CriticalDependency & MemDep)671 void setCriticalMemDep(const CriticalDependency &MemDep) { 672 CriticalMemDep = MemDep; 673 } 674 getCriticalResourceMask()675 uint64_t getCriticalResourceMask() const { return CriticalResourceMask; } setCriticalResourceMask(uint64_t ResourceMask)676 void setCriticalResourceMask(uint64_t ResourceMask) { 677 CriticalResourceMask = ResourceMask; 678 } 679 680 void cycleEvent(); 681 }; 682 683 /// An InstRef contains both a SourceMgr index and Instruction pair. The index 684 /// is used as a unique identifier for the instruction. MCA will make use of 685 /// this index as a key throughout MCA. 686 class InstRef { 687 std::pair<unsigned, Instruction *> Data; 688 689 public: InstRef()690 InstRef() : Data(std::make_pair(0, nullptr)) {} InstRef(unsigned Index,Instruction * I)691 InstRef(unsigned Index, Instruction *I) : Data(std::make_pair(Index, I)) {} 692 693 bool operator==(const InstRef &Other) const { return Data == Other.Data; } 694 bool operator!=(const InstRef &Other) const { return Data != Other.Data; } 695 bool operator<(const InstRef &Other) const { 696 return Data.first < Other.Data.first; 697 } 698 getSourceIndex()699 unsigned getSourceIndex() const { return Data.first; } getInstruction()700 Instruction *getInstruction() { return Data.second; } getInstruction()701 const Instruction *getInstruction() const { return Data.second; } 702 703 /// Returns true if this references a valid instruction. 704 explicit operator bool() const { return Data.second != nullptr; } 705 706 /// Invalidate this reference. invalidate()707 void invalidate() { Data.second = nullptr; } 708 709 #ifndef NDEBUG print(raw_ostream & OS)710 void print(raw_ostream &OS) const { OS << getSourceIndex(); } 711 #endif 712 }; 713 714 #ifndef NDEBUG 715 inline raw_ostream &operator<<(raw_ostream &OS, const InstRef &IR) { 716 IR.print(OS); 717 return OS; 718 } 719 #endif 720 721 } // namespace mca 722 } // namespace llvm 723 724 #endif // LLVM_MCA_INSTRUCTION_H 725