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