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 register write descriptor. 37 struct WriteDescriptor { 38 // Operand index. The index is negative for implicit writes only. 39 // For implicit writes, the actual operand index is computed performing 40 // a bitwise not of the OpIndex. 41 int OpIndex; 42 // Write latency. Number of cycles before write-back stage. 43 unsigned Latency; 44 // This field is set to a value different than zero only if this 45 // is an implicit definition. 46 MCPhysReg RegisterID; 47 // Instruction itineraries would set this field to the SchedClass ID. 48 // Otherwise, it defaults to the WriteResourceID from the MCWriteLatencyEntry 49 // element associated to this write. 50 // When computing read latencies, this value is matched against the 51 // "ReadAdvance" information. The hardware backend may implement 52 // dedicated forwarding paths to quickly propagate write results to dependent 53 // instructions waiting in the reservation station (effectively bypassing the 54 // write-back stage). 55 unsigned SClassOrWriteResourceID; 56 // True only if this is a write obtained from an optional definition. 57 // Optional definitions are allowed to reference regID zero (i.e. "no 58 // register"). 59 bool IsOptionalDef; 60 isImplicitWriteWriteDescriptor61 bool isImplicitWrite() const { return OpIndex < 0; }; 62 }; 63 64 /// A register read descriptor. 65 struct ReadDescriptor { 66 // A MCOperand index. This is used by the Dispatch logic to identify register 67 // reads. Implicit reads have negative indices. The actual operand index of an 68 // implicit read is the bitwise not of field OpIndex. 69 int OpIndex; 70 // The actual "UseIdx". This is used to query the ReadAdvance table. Explicit 71 // uses always come first in the sequence of uses. 72 unsigned UseIndex; 73 // This field is only set if this is an implicit read. 74 MCPhysReg RegisterID; 75 // Scheduling Class Index. It is used to query the scheduling model for the 76 // MCSchedClassDesc object. 77 unsigned SchedClassID; 78 isImplicitReadReadDescriptor79 bool isImplicitRead() const { return OpIndex < 0; }; 80 }; 81 82 class ReadState; 83 84 /// A critical data dependency descriptor. 85 /// 86 /// Field RegID is set to the invalid register for memory dependencies. 87 struct CriticalDependency { 88 unsigned IID; 89 MCPhysReg RegID; 90 unsigned Cycles; 91 }; 92 93 /// Tracks uses of a register definition (e.g. register write). 94 /// 95 /// Each implicit/explicit register write is associated with an instance of 96 /// this class. A WriteState object tracks the dependent users of a 97 /// register write. It also tracks how many cycles are left before the write 98 /// back stage. 99 class WriteState { 100 const WriteDescriptor *WD; 101 // On instruction issue, this field is set equal to the write latency. 102 // Before instruction issue, this field defaults to -512, a special 103 // value that represents an "unknown" number of cycles. 104 int CyclesLeft; 105 106 // Actual register defined by this write. This field is only used 107 // to speedup queries on the register file. 108 // For implicit writes, this field always matches the value of 109 // field RegisterID from WD. 110 MCPhysReg RegisterID; 111 112 // Physical register file that serves register RegisterID. 113 unsigned PRFID; 114 115 // True if this write implicitly clears the upper portion of RegisterID's 116 // super-registers. 117 bool ClearsSuperRegs; 118 119 // True if this write is from a dependency breaking zero-idiom instruction. 120 bool WritesZero; 121 122 // True if this write has been eliminated at register renaming stage. 123 // Example: a register move doesn't consume scheduler/pipleline resources if 124 // it is eliminated at register renaming stage. It still consumes 125 // decode bandwidth, and ROB entries. 126 bool IsEliminated; 127 128 // This field is set if this is a partial register write, and it has a false 129 // dependency on any previous write of the same register (or a portion of it). 130 // DependentWrite must be able to complete before this write completes, so 131 // that we don't break the WAW, and the two writes can be merged together. 132 const WriteState *DependentWrite; 133 134 // A partial write that is in a false dependency with this write. 135 WriteState *PartialWrite; 136 unsigned DependentWriteCyclesLeft; 137 138 // Critical register dependency for this write. 139 CriticalDependency CRD; 140 141 // A list of dependent reads. Users is a set of dependent 142 // reads. A dependent read is added to the set only if CyclesLeft 143 // is "unknown". As soon as CyclesLeft is 'known', each user in the set 144 // gets notified with the actual CyclesLeft. 145 146 // The 'second' element of a pair is a "ReadAdvance" number of cycles. 147 SmallVector<std::pair<ReadState *, int>, 4> Users; 148 149 public: 150 WriteState(const WriteDescriptor &Desc, MCPhysReg RegID, 151 bool clearsSuperRegs = false, bool writesZero = false) 152 : WD(&Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID), PRFID(0), 153 ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero), 154 IsEliminated(false), DependentWrite(nullptr), PartialWrite(nullptr), 155 DependentWriteCyclesLeft(0), CRD() {} 156 157 WriteState(const WriteState &Other) = default; 158 WriteState &operator=(const WriteState &Other) = default; 159 getCyclesLeft()160 int getCyclesLeft() const { return CyclesLeft; } getWriteResourceID()161 unsigned getWriteResourceID() const { return WD->SClassOrWriteResourceID; } getRegisterID()162 MCPhysReg getRegisterID() const { return RegisterID; } getRegisterFileID()163 unsigned getRegisterFileID() const { return PRFID; } getLatency()164 unsigned getLatency() const { return WD->Latency; } getDependentWriteCyclesLeft()165 unsigned getDependentWriteCyclesLeft() const { 166 return DependentWriteCyclesLeft; 167 } getDependentWrite()168 const WriteState *getDependentWrite() const { return DependentWrite; } getCriticalRegDep()169 const CriticalDependency &getCriticalRegDep() const { return CRD; } 170 171 // This method adds Use to the set of data dependent reads. IID is the 172 // instruction identifier associated with this write. ReadAdvance is the 173 // number of cycles to subtract from the latency of this data dependency. 174 // Use is in a RAW dependency with this write. 175 void addUser(unsigned IID, ReadState *Use, int ReadAdvance); 176 177 // Use is a younger register write that is in a false dependency with this 178 // write. IID is the instruction identifier associated with this write. 179 void addUser(unsigned IID, WriteState *Use); 180 getNumUsers()181 unsigned getNumUsers() const { 182 unsigned NumUsers = Users.size(); 183 if (PartialWrite) 184 ++NumUsers; 185 return NumUsers; 186 } 187 clearsSuperRegisters()188 bool clearsSuperRegisters() const { return ClearsSuperRegs; } isWriteZero()189 bool isWriteZero() const { return WritesZero; } isEliminated()190 bool isEliminated() const { return IsEliminated; } 191 isReady()192 bool isReady() const { 193 if (DependentWrite) 194 return false; 195 unsigned CyclesLeft = getDependentWriteCyclesLeft(); 196 return !CyclesLeft || CyclesLeft < getLatency(); 197 } 198 isExecuted()199 bool isExecuted() const { 200 return CyclesLeft != UNKNOWN_CYCLES && CyclesLeft <= 0; 201 } 202 setDependentWrite(const WriteState * Other)203 void setDependentWrite(const WriteState *Other) { DependentWrite = Other; } 204 void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles); setWriteZero()205 void setWriteZero() { WritesZero = true; } setEliminated()206 void setEliminated() { 207 assert(Users.empty() && "Write is in an inconsistent state."); 208 CyclesLeft = 0; 209 IsEliminated = true; 210 } 211 setPRF(unsigned PRF)212 void setPRF(unsigned PRF) { PRFID = PRF; } 213 214 // On every cycle, update CyclesLeft and notify dependent users. 215 void cycleEvent(); 216 void onInstructionIssued(unsigned IID); 217 218 #ifndef NDEBUG 219 void dump() const; 220 #endif 221 }; 222 223 /// Tracks register operand latency in cycles. 224 /// 225 /// A read may be dependent on more than one write. This occurs when some 226 /// writes only partially update the register associated to this read. 227 class ReadState { 228 const ReadDescriptor *RD; 229 // Physical register identified associated to this read. 230 MCPhysReg RegisterID; 231 // Physical register file that serves register RegisterID. 232 unsigned PRFID; 233 // Number of writes that contribute to the definition of RegisterID. 234 // In the absence of partial register updates, the number of DependentWrites 235 // cannot be more than one. 236 unsigned DependentWrites; 237 // Number of cycles left before RegisterID can be read. This value depends on 238 // the latency of all the dependent writes. It defaults to UNKNOWN_CYCLES. 239 // It gets set to the value of field TotalCycles only when the 'CyclesLeft' of 240 // every dependent write is known. 241 int CyclesLeft; 242 // This field is updated on every writeStartEvent(). When the number of 243 // dependent writes (i.e. field DependentWrite) is zero, this value is 244 // propagated to field CyclesLeft. 245 unsigned TotalCycles; 246 // Longest register dependency. 247 CriticalDependency CRD; 248 // This field is set to true only if there are no dependent writes, and 249 // there are no `CyclesLeft' to wait. 250 bool IsReady; 251 // True if this is a read from a known zero register. 252 bool IsZero; 253 // True if this register read is from a dependency-breaking instruction. 254 bool IndependentFromDef; 255 256 public: ReadState(const ReadDescriptor & Desc,MCPhysReg RegID)257 ReadState(const ReadDescriptor &Desc, MCPhysReg RegID) 258 : RD(&Desc), RegisterID(RegID), PRFID(0), DependentWrites(0), 259 CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), CRD(), IsReady(true), 260 IsZero(false), IndependentFromDef(false) {} 261 getDescriptor()262 const ReadDescriptor &getDescriptor() const { return *RD; } getSchedClass()263 unsigned getSchedClass() const { return RD->SchedClassID; } getRegisterID()264 MCPhysReg getRegisterID() const { return RegisterID; } getRegisterFileID()265 unsigned getRegisterFileID() const { return PRFID; } getCriticalRegDep()266 const CriticalDependency &getCriticalRegDep() const { return CRD; } 267 isPending()268 bool isPending() const { return !IndependentFromDef && CyclesLeft > 0; } isReady()269 bool isReady() const { return IsReady; } isImplicitRead()270 bool isImplicitRead() const { return RD->isImplicitRead(); } 271 isIndependentFromDef()272 bool isIndependentFromDef() const { return IndependentFromDef; } setIndependentFromDef()273 void setIndependentFromDef() { IndependentFromDef = true; } 274 275 void cycleEvent(); 276 void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles); setDependentWrites(unsigned Writes)277 void setDependentWrites(unsigned Writes) { 278 DependentWrites = Writes; 279 IsReady = !Writes; 280 } 281 isReadZero()282 bool isReadZero() const { return IsZero; } setReadZero()283 void setReadZero() { IsZero = true; } setPRF(unsigned ID)284 void setPRF(unsigned ID) { PRFID = ID; } 285 }; 286 287 /// A sequence of cycles. 288 /// 289 /// This class can be used as a building block to construct ranges of cycles. 290 class CycleSegment { 291 unsigned Begin; // Inclusive. 292 unsigned End; // Exclusive. 293 bool Reserved; // Resources associated to this segment must be reserved. 294 295 public: 296 CycleSegment(unsigned StartCycle, unsigned EndCycle, bool IsReserved = false) Begin(StartCycle)297 : Begin(StartCycle), End(EndCycle), Reserved(IsReserved) {} 298 contains(unsigned Cycle)299 bool contains(unsigned Cycle) const { return Cycle >= Begin && Cycle < End; } startsAfter(const CycleSegment & CS)300 bool startsAfter(const CycleSegment &CS) const { return End <= CS.Begin; } endsBefore(const CycleSegment & CS)301 bool endsBefore(const CycleSegment &CS) const { return Begin >= CS.End; } overlaps(const CycleSegment & CS)302 bool overlaps(const CycleSegment &CS) const { 303 return !startsAfter(CS) && !endsBefore(CS); 304 } isExecuting()305 bool isExecuting() const { return Begin == 0 && End != 0; } isExecuted()306 bool isExecuted() const { return End == 0; } 307 bool operator<(const CycleSegment &Other) const { 308 return Begin < Other.Begin; 309 } 310 CycleSegment &operator--(void) { 311 if (Begin) 312 Begin--; 313 if (End) 314 End--; 315 return *this; 316 } 317 isValid()318 bool isValid() const { return Begin <= End; } size()319 unsigned size() const { return End - Begin; }; subtract(unsigned Cycles)320 void subtract(unsigned Cycles) { 321 assert(End >= Cycles); 322 End -= Cycles; 323 } 324 begin()325 unsigned begin() const { return Begin; } end()326 unsigned end() const { return End; } setEnd(unsigned NewEnd)327 void setEnd(unsigned NewEnd) { End = NewEnd; } isReserved()328 bool isReserved() const { return Reserved; } setReserved()329 void setReserved() { Reserved = true; } 330 }; 331 332 /// Helper used by class InstrDesc to describe how hardware resources 333 /// are used. 334 /// 335 /// This class describes how many resource units of a specific resource kind 336 /// (and how many cycles) are "used" by an instruction. 337 struct ResourceUsage { 338 CycleSegment CS; 339 unsigned NumUnits; 340 ResourceUsage(CycleSegment Cycles, unsigned Units = 1) CSResourceUsage341 : CS(Cycles), NumUnits(Units) {} sizeResourceUsage342 unsigned size() const { return CS.size(); } isReservedResourceUsage343 bool isReserved() const { return CS.isReserved(); } setReservedResourceUsage344 void setReserved() { CS.setReserved(); } 345 }; 346 347 /// An instruction descriptor 348 struct InstrDesc { 349 SmallVector<WriteDescriptor, 4> Writes; // Implicit writes are at the end. 350 SmallVector<ReadDescriptor, 4> Reads; // Implicit reads are at the end. 351 352 // For every resource used by an instruction of this kind, this vector 353 // reports the number of "consumed cycles". 354 SmallVector<std::pair<uint64_t, ResourceUsage>, 4> Resources; 355 356 // A bitmask of used hardware buffers. 357 uint64_t UsedBuffers; 358 359 // A bitmask of used processor resource units. 360 uint64_t UsedProcResUnits; 361 362 // A bitmask of used processor resource groups. 363 uint64_t UsedProcResGroups; 364 365 unsigned MaxLatency; 366 // Number of MicroOps for this instruction. 367 unsigned NumMicroOps; 368 // SchedClassID used to construct this InstrDesc. 369 // This information is currently used by views to do fast queries on the 370 // subtarget when computing the reciprocal throughput. 371 unsigned SchedClassID; 372 373 bool MayLoad; 374 bool MayStore; 375 bool HasSideEffects; 376 bool BeginGroup; 377 bool EndGroup; 378 bool RetireOOO; 379 380 // True if all buffered resources are in-order, and there is at least one 381 // buffer which is a dispatch hazard (BufferSize = 0). 382 bool MustIssueImmediately; 383 384 // A zero latency instruction doesn't consume any scheduler resources. isZeroLatencyInstrDesc385 bool isZeroLatency() const { return !MaxLatency && Resources.empty(); } 386 387 InstrDesc() = default; 388 InstrDesc(const InstrDesc &Other) = delete; 389 InstrDesc &operator=(const InstrDesc &Other) = delete; 390 }; 391 392 /// Base class for instructions consumed by the simulation pipeline. 393 /// 394 /// This class tracks data dependencies as well as generic properties 395 /// of the instruction. 396 class InstructionBase { 397 const InstrDesc &Desc; 398 399 // This field is set for instructions that are candidates for move 400 // elimination. For more information about move elimination, see the 401 // definition of RegisterMappingTracker in RegisterFile.h 402 bool IsOptimizableMove; 403 404 // Output dependencies. 405 // One entry per each implicit and explicit register definition. 406 SmallVector<WriteState, 4> Defs; 407 408 // Input dependencies. 409 // One entry per each implicit and explicit register use. 410 SmallVector<ReadState, 4> Uses; 411 412 public: InstructionBase(const InstrDesc & D)413 InstructionBase(const InstrDesc &D) : Desc(D), IsOptimizableMove(false) {} 414 getDefs()415 SmallVectorImpl<WriteState> &getDefs() { return Defs; } getDefs()416 ArrayRef<WriteState> getDefs() const { return Defs; } getUses()417 SmallVectorImpl<ReadState> &getUses() { return Uses; } getUses()418 ArrayRef<ReadState> getUses() const { return Uses; } getDesc()419 const InstrDesc &getDesc() const { return Desc; } 420 getLatency()421 unsigned getLatency() const { return Desc.MaxLatency; } getNumMicroOps()422 unsigned getNumMicroOps() const { return Desc.NumMicroOps; } 423 hasDependentUsers()424 bool hasDependentUsers() const { 425 return any_of(Defs, 426 [](const WriteState &Def) { return Def.getNumUsers() > 0; }); 427 } 428 getNumUsers()429 unsigned getNumUsers() const { 430 unsigned NumUsers = 0; 431 for (const WriteState &Def : Defs) 432 NumUsers += Def.getNumUsers(); 433 return NumUsers; 434 } 435 436 // Returns true if this instruction is a candidate for move elimination. isOptimizableMove()437 bool isOptimizableMove() const { return IsOptimizableMove; } setOptimizableMove()438 void setOptimizableMove() { IsOptimizableMove = true; } isMemOp()439 bool isMemOp() const { return Desc.MayLoad || Desc.MayStore; } 440 }; 441 442 /// An instruction propagated through the simulated instruction pipeline. 443 /// 444 /// This class is used to monitor changes to the internal state of instructions 445 /// that are sent to the various components of the simulated hardware pipeline. 446 class Instruction : public InstructionBase { 447 enum InstrStage { 448 IS_INVALID, // Instruction in an invalid state. 449 IS_DISPATCHED, // Instruction dispatched but operands are not ready. 450 IS_PENDING, // Instruction is not ready, but operand latency is known. 451 IS_READY, // Instruction dispatched and operands ready. 452 IS_EXECUTING, // Instruction issued. 453 IS_EXECUTED, // Instruction executed. Values are written back. 454 IS_RETIRED // Instruction retired. 455 }; 456 457 // The current instruction stage. 458 enum InstrStage Stage; 459 460 // This value defaults to the instruction latency. This instruction is 461 // considered executed when field CyclesLeft goes to zero. 462 int CyclesLeft; 463 464 // Retire Unit token ID for this instruction. 465 unsigned RCUTokenID; 466 467 // LS token ID for this instruction. 468 // This field is set to the invalid null token if this is not a memory 469 // operation. 470 unsigned LSUTokenID; 471 472 // A resource mask which identifies buffered resources consumed by this 473 // instruction at dispatch stage. In the absence of macro-fusion, this value 474 // should always match the value of field `UsedBuffers` from the instruction 475 // descriptor (see field InstrBase::Desc). 476 uint64_t UsedBuffers; 477 478 // Critical register dependency. 479 CriticalDependency CriticalRegDep; 480 481 // Critical memory dependency. 482 CriticalDependency CriticalMemDep; 483 484 // A bitmask of busy processor resource units. 485 // This field is set to zero only if execution is not delayed during this 486 // cycle because of unavailable pipeline resources. 487 uint64_t CriticalResourceMask; 488 489 // True if this instruction has been optimized at register renaming stage. 490 bool IsEliminated; 491 492 public: Instruction(const InstrDesc & D)493 Instruction(const InstrDesc &D) 494 : InstructionBase(D), Stage(IS_INVALID), CyclesLeft(UNKNOWN_CYCLES), 495 RCUTokenID(0), LSUTokenID(0), UsedBuffers(D.UsedBuffers), 496 CriticalRegDep(), CriticalMemDep(), CriticalResourceMask(0), 497 IsEliminated(false) {} 498 getRCUTokenID()499 unsigned getRCUTokenID() const { return RCUTokenID; } getLSUTokenID()500 unsigned getLSUTokenID() const { return LSUTokenID; } setLSUTokenID(unsigned LSUTok)501 void setLSUTokenID(unsigned LSUTok) { LSUTokenID = LSUTok; } 502 getUsedBuffers()503 uint64_t getUsedBuffers() const { return UsedBuffers; } setUsedBuffers(uint64_t Mask)504 void setUsedBuffers(uint64_t Mask) { UsedBuffers = Mask; } clearUsedBuffers()505 void clearUsedBuffers() { UsedBuffers = 0ULL; } 506 getCyclesLeft()507 int getCyclesLeft() const { return CyclesLeft; } 508 509 // Transition to the dispatch stage, and assign a RCUToken to this 510 // instruction. The RCUToken is used to track the completion of every 511 // register write performed by this instruction. 512 void dispatch(unsigned RCUTokenID); 513 514 // Instruction issued. Transition to the IS_EXECUTING state, and update 515 // all the register definitions. 516 void execute(unsigned IID); 517 518 // Force a transition from the IS_DISPATCHED state to the IS_READY or 519 // IS_PENDING state. State transitions normally occur either at the beginning 520 // of a new cycle (see method cycleEvent()), or as a result of another issue 521 // event. This method is called every time the instruction might have changed 522 // in state. It internally delegates to method updateDispatched() and 523 // updateWaiting(). 524 void update(); 525 bool updateDispatched(); 526 bool updatePending(); 527 isDispatched()528 bool isDispatched() const { return Stage == IS_DISPATCHED; } isPending()529 bool isPending() const { return Stage == IS_PENDING; } isReady()530 bool isReady() const { return Stage == IS_READY; } isExecuting()531 bool isExecuting() const { return Stage == IS_EXECUTING; } isExecuted()532 bool isExecuted() const { return Stage == IS_EXECUTED; } isRetired()533 bool isRetired() const { return Stage == IS_RETIRED; } isEliminated()534 bool isEliminated() const { return IsEliminated; } 535 536 // Forces a transition from state IS_DISPATCHED to state IS_EXECUTED. 537 void forceExecuted(); setEliminated()538 void setEliminated() { IsEliminated = true; } 539 retire()540 void retire() { 541 assert(isExecuted() && "Instruction is in an invalid state!"); 542 Stage = IS_RETIRED; 543 } 544 getCriticalRegDep()545 const CriticalDependency &getCriticalRegDep() const { return CriticalRegDep; } getCriticalMemDep()546 const CriticalDependency &getCriticalMemDep() const { return CriticalMemDep; } 547 const CriticalDependency &computeCriticalRegDep(); setCriticalMemDep(const CriticalDependency & MemDep)548 void setCriticalMemDep(const CriticalDependency &MemDep) { 549 CriticalMemDep = MemDep; 550 } 551 getCriticalResourceMask()552 uint64_t getCriticalResourceMask() const { return CriticalResourceMask; } setCriticalResourceMask(uint64_t ResourceMask)553 void setCriticalResourceMask(uint64_t ResourceMask) { 554 CriticalResourceMask = ResourceMask; 555 } 556 557 void cycleEvent(); 558 }; 559 560 /// An InstRef contains both a SourceMgr index and Instruction pair. The index 561 /// is used as a unique identifier for the instruction. MCA will make use of 562 /// this index as a key throughout MCA. 563 class InstRef { 564 std::pair<unsigned, Instruction *> Data; 565 566 public: InstRef()567 InstRef() : Data(std::make_pair(0, nullptr)) {} InstRef(unsigned Index,Instruction * I)568 InstRef(unsigned Index, Instruction *I) : Data(std::make_pair(Index, I)) {} 569 570 bool operator==(const InstRef &Other) const { return Data == Other.Data; } 571 bool operator!=(const InstRef &Other) const { return Data != Other.Data; } 572 bool operator<(const InstRef &Other) const { 573 return Data.first < Other.Data.first; 574 } 575 getSourceIndex()576 unsigned getSourceIndex() const { return Data.first; } getInstruction()577 Instruction *getInstruction() { return Data.second; } getInstruction()578 const Instruction *getInstruction() const { return Data.second; } 579 580 /// Returns true if this references a valid instruction. 581 explicit operator bool() const { return Data.second != nullptr; } 582 583 /// Invalidate this reference. invalidate()584 void invalidate() { Data.second = nullptr; } 585 586 #ifndef NDEBUG print(raw_ostream & OS)587 void print(raw_ostream &OS) const { OS << getSourceIndex(); } 588 #endif 589 }; 590 591 #ifndef NDEBUG 592 inline raw_ostream &operator<<(raw_ostream &OS, const InstRef &IR) { 593 IR.print(OS); 594 return OS; 595 } 596 #endif 597 598 } // namespace mca 599 } // namespace llvm 600 601 #endif // LLVM_MCA_INSTRUCTION_H 602