blob: d4d3f22797f7efcb89edd2ed84d614fafd78f75e [file] [log] [blame]
Andrew Walbran16937d02019-10-22 13:54:20 +01001//===--------------------- 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
29namespace llvm {
30
31namespace mca {
32
33constexpr int UNKNOWN_CYCLES = -512;
34
35/// A register write descriptor.
36struct 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.
64struct 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
81class ReadState;
82
Andrew Walbran3d2c1972020-04-07 12:24:26 +010083/// A critical data dependency descriptor.
84///
85/// Field RegID is set to the invalid register for memory dependencies.
86struct CriticalDependency {
87 unsigned IID;
88 unsigned RegID;
89 unsigned Cycles;
90};
91
Andrew Walbran16937d02019-10-22 13:54:20 +010092/// Tracks uses of a register definition (e.g. register write).
93///
94/// Each implicit/explicit register write is associated with an instance of
95/// this class. A WriteState object tracks the dependent users of a
96/// register write. It also tracks how many cycles are left before the write
97/// back stage.
98class WriteState {
99 const WriteDescriptor *WD;
100 // On instruction issue, this field is set equal to the write latency.
101 // Before instruction issue, this field defaults to -512, a special
102 // value that represents an "unknown" number of cycles.
103 int CyclesLeft;
104
105 // Actual register defined by this write. This field is only used
106 // to speedup queries on the register file.
107 // For implicit writes, this field always matches the value of
108 // field RegisterID from WD.
109 unsigned RegisterID;
110
111 // Physical register file that serves register RegisterID.
112 unsigned PRFID;
113
114 // True if this write implicitly clears the upper portion of RegisterID's
115 // super-registers.
116 bool ClearsSuperRegs;
117
118 // True if this write is from a dependency breaking zero-idiom instruction.
119 bool WritesZero;
120
121 // True if this write has been eliminated at register renaming stage.
122 // Example: a register move doesn't consume scheduler/pipleline resources if
123 // it is eliminated at register renaming stage. It still consumes
124 // decode bandwidth, and ROB entries.
125 bool IsEliminated;
126
127 // This field is set if this is a partial register write, and it has a false
128 // dependency on any previous write of the same register (or a portion of it).
129 // DependentWrite must be able to complete before this write completes, so
130 // that we don't break the WAW, and the two writes can be merged together.
131 const WriteState *DependentWrite;
132
133 // A partial write that is in a false dependency with this write.
134 WriteState *PartialWrite;
Andrew Walbran16937d02019-10-22 13:54:20 +0100135 unsigned DependentWriteCyclesLeft;
136
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100137 // Critical register dependency for this write.
138 CriticalDependency CRD;
139
Andrew Walbran16937d02019-10-22 13:54:20 +0100140 // A list of dependent reads. Users is a set of dependent
141 // reads. A dependent read is added to the set only if CyclesLeft
142 // is "unknown". As soon as CyclesLeft is 'known', each user in the set
143 // gets notified with the actual CyclesLeft.
144
145 // The 'second' element of a pair is a "ReadAdvance" number of cycles.
146 SmallVector<std::pair<ReadState *, int>, 4> Users;
147
148public:
149 WriteState(const WriteDescriptor &Desc, unsigned RegID,
150 bool clearsSuperRegs = false, bool writesZero = false)
151 : WD(&Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID), PRFID(0),
152 ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero),
153 IsEliminated(false), DependentWrite(nullptr), PartialWrite(nullptr),
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100154 DependentWriteCyclesLeft(0), CRD() {}
Andrew Walbran16937d02019-10-22 13:54:20 +0100155
156 WriteState(const WriteState &Other) = default;
157 WriteState &operator=(const WriteState &Other) = default;
158
159 int getCyclesLeft() const { return CyclesLeft; }
160 unsigned getWriteResourceID() const { return WD->SClassOrWriteResourceID; }
161 unsigned getRegisterID() const { return RegisterID; }
162 unsigned getRegisterFileID() const { return PRFID; }
163 unsigned getLatency() const { return WD->Latency; }
Andrew Walbran16937d02019-10-22 13:54:20 +0100164 unsigned getDependentWriteCyclesLeft() const {
165 return DependentWriteCyclesLeft;
166 }
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100167 const WriteState *getDependentWrite() const { return DependentWrite; }
168 const CriticalDependency &getCriticalRegDep() const { return CRD; }
169
170 // This method adds Use to the set of data dependent reads. IID is the
171 // instruction identifier associated with this write. ReadAdvance is the
172 // number of cycles to subtract from the latency of this data dependency.
173 // Use is in a RAW dependency with this write.
174 void addUser(unsigned IID, ReadState *Use, int ReadAdvance);
175
176 // Use is a younger register write that is in a false dependency with this
177 // write. IID is the instruction identifier associated with this write.
178 void addUser(unsigned IID, WriteState *Use);
Andrew Walbran16937d02019-10-22 13:54:20 +0100179
180 unsigned getNumUsers() const {
181 unsigned NumUsers = Users.size();
182 if (PartialWrite)
183 ++NumUsers;
184 return NumUsers;
185 }
186
187 bool clearsSuperRegisters() const { return ClearsSuperRegs; }
188 bool isWriteZero() const { return WritesZero; }
189 bool isEliminated() const { return IsEliminated; }
190
191 bool isReady() const {
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100192 if (DependentWrite)
Andrew Walbran16937d02019-10-22 13:54:20 +0100193 return false;
194 unsigned CyclesLeft = getDependentWriteCyclesLeft();
195 return !CyclesLeft || CyclesLeft < getLatency();
196 }
197
198 bool isExecuted() const {
199 return CyclesLeft != UNKNOWN_CYCLES && CyclesLeft <= 0;
200 }
201
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100202 void setDependentWrite(const WriteState *Other) { DependentWrite = Other; }
203 void writeStartEvent(unsigned IID, unsigned RegID, unsigned Cycles);
Andrew Walbran16937d02019-10-22 13:54:20 +0100204 void setWriteZero() { WritesZero = true; }
205 void setEliminated() {
206 assert(Users.empty() && "Write is in an inconsistent state.");
207 CyclesLeft = 0;
208 IsEliminated = true;
209 }
210
211 void setPRF(unsigned PRF) { PRFID = PRF; }
212
213 // On every cycle, update CyclesLeft and notify dependent users.
214 void cycleEvent();
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100215 void onInstructionIssued(unsigned IID);
Andrew Walbran16937d02019-10-22 13:54:20 +0100216
217#ifndef NDEBUG
218 void dump() const;
219#endif
220};
221
222/// Tracks register operand latency in cycles.
223///
224/// A read may be dependent on more than one write. This occurs when some
225/// writes only partially update the register associated to this read.
226class ReadState {
227 const ReadDescriptor *RD;
228 // Physical register identified associated to this read.
229 unsigned RegisterID;
230 // Physical register file that serves register RegisterID.
231 unsigned PRFID;
232 // Number of writes that contribute to the definition of RegisterID.
233 // In the absence of partial register updates, the number of DependentWrites
234 // cannot be more than one.
235 unsigned DependentWrites;
236 // Number of cycles left before RegisterID can be read. This value depends on
237 // the latency of all the dependent writes. It defaults to UNKNOWN_CYCLES.
238 // It gets set to the value of field TotalCycles only when the 'CyclesLeft' of
239 // every dependent write is known.
240 int CyclesLeft;
241 // This field is updated on every writeStartEvent(). When the number of
242 // dependent writes (i.e. field DependentWrite) is zero, this value is
243 // propagated to field CyclesLeft.
244 unsigned TotalCycles;
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100245 // Longest register dependency.
246 CriticalDependency CRD;
Andrew Walbran16937d02019-10-22 13:54:20 +0100247 // This field is set to true only if there are no dependent writes, and
248 // there are no `CyclesLeft' to wait.
249 bool IsReady;
250 // True if this is a read from a known zero register.
251 bool IsZero;
252 // True if this register read is from a dependency-breaking instruction.
253 bool IndependentFromDef;
254
255public:
256 ReadState(const ReadDescriptor &Desc, unsigned RegID)
257 : RD(&Desc), RegisterID(RegID), PRFID(0), DependentWrites(0),
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100258 CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), CRD(), IsReady(true),
Andrew Walbran16937d02019-10-22 13:54:20 +0100259 IsZero(false), IndependentFromDef(false) {}
260
261 const ReadDescriptor &getDescriptor() const { return *RD; }
262 unsigned getSchedClass() const { return RD->SchedClassID; }
263 unsigned getRegisterID() const { return RegisterID; }
264 unsigned getRegisterFileID() const { return PRFID; }
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100265 const CriticalDependency &getCriticalRegDep() const { return CRD; }
Andrew Walbran16937d02019-10-22 13:54:20 +0100266
267 bool isPending() const { return !IndependentFromDef && CyclesLeft > 0; }
268 bool isReady() const { return IsReady; }
269 bool isImplicitRead() const { return RD->isImplicitRead(); }
270
271 bool isIndependentFromDef() const { return IndependentFromDef; }
272 void setIndependentFromDef() { IndependentFromDef = true; }
273
274 void cycleEvent();
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100275 void writeStartEvent(unsigned IID, unsigned RegID, unsigned Cycles);
Andrew Walbran16937d02019-10-22 13:54:20 +0100276 void setDependentWrites(unsigned Writes) {
277 DependentWrites = Writes;
278 IsReady = !Writes;
279 }
280
281 bool isReadZero() const { return IsZero; }
282 void setReadZero() { IsZero = true; }
283 void setPRF(unsigned ID) { PRFID = ID; }
284};
285
286/// A sequence of cycles.
287///
288/// This class can be used as a building block to construct ranges of cycles.
289class CycleSegment {
290 unsigned Begin; // Inclusive.
291 unsigned End; // Exclusive.
292 bool Reserved; // Resources associated to this segment must be reserved.
293
294public:
295 CycleSegment(unsigned StartCycle, unsigned EndCycle, bool IsReserved = false)
296 : Begin(StartCycle), End(EndCycle), Reserved(IsReserved) {}
297
298 bool contains(unsigned Cycle) const { return Cycle >= Begin && Cycle < End; }
299 bool startsAfter(const CycleSegment &CS) const { return End <= CS.Begin; }
300 bool endsBefore(const CycleSegment &CS) const { return Begin >= CS.End; }
301 bool overlaps(const CycleSegment &CS) const {
302 return !startsAfter(CS) && !endsBefore(CS);
303 }
304 bool isExecuting() const { return Begin == 0 && End != 0; }
305 bool isExecuted() const { return End == 0; }
306 bool operator<(const CycleSegment &Other) const {
307 return Begin < Other.Begin;
308 }
309 CycleSegment &operator--(void) {
310 if (Begin)
311 Begin--;
312 if (End)
313 End--;
314 return *this;
315 }
316
317 bool isValid() const { return Begin <= End; }
318 unsigned size() const { return End - Begin; };
319 void subtract(unsigned Cycles) {
320 assert(End >= Cycles);
321 End -= Cycles;
322 }
323
324 unsigned begin() const { return Begin; }
325 unsigned end() const { return End; }
326 void setEnd(unsigned NewEnd) { End = NewEnd; }
327 bool isReserved() const { return Reserved; }
328 void setReserved() { Reserved = true; }
329};
330
331/// Helper used by class InstrDesc to describe how hardware resources
332/// are used.
333///
334/// This class describes how many resource units of a specific resource kind
335/// (and how many cycles) are "used" by an instruction.
336struct ResourceUsage {
337 CycleSegment CS;
338 unsigned NumUnits;
339 ResourceUsage(CycleSegment Cycles, unsigned Units = 1)
340 : CS(Cycles), NumUnits(Units) {}
341 unsigned size() const { return CS.size(); }
342 bool isReserved() const { return CS.isReserved(); }
343 void setReserved() { CS.setReserved(); }
344};
345
346/// An instruction descriptor
347struct InstrDesc {
348 SmallVector<WriteDescriptor, 4> Writes; // Implicit writes are at the end.
349 SmallVector<ReadDescriptor, 4> Reads; // Implicit reads are at the end.
350
351 // For every resource used by an instruction of this kind, this vector
352 // reports the number of "consumed cycles".
353 SmallVector<std::pair<uint64_t, ResourceUsage>, 4> Resources;
354
355 // A list of buffered resources consumed by this instruction.
356 SmallVector<uint64_t, 4> Buffers;
357
358 unsigned UsedProcResUnits;
359 unsigned UsedProcResGroups;
360
361 unsigned MaxLatency;
362 // Number of MicroOps for this instruction.
363 unsigned NumMicroOps;
364 // SchedClassID used to construct this InstrDesc.
365 // This information is currently used by views to do fast queries on the
366 // subtarget when computing the reciprocal throughput.
367 unsigned SchedClassID;
368
369 bool MayLoad;
370 bool MayStore;
371 bool HasSideEffects;
372 bool BeginGroup;
373 bool EndGroup;
374
375 // True if all buffered resources are in-order, and there is at least one
376 // buffer which is a dispatch hazard (BufferSize = 0).
377 bool MustIssueImmediately;
378
379 // A zero latency instruction doesn't consume any scheduler resources.
380 bool isZeroLatency() const { return !MaxLatency && Resources.empty(); }
381
382 InstrDesc() = default;
383 InstrDesc(const InstrDesc &Other) = delete;
384 InstrDesc &operator=(const InstrDesc &Other) = delete;
385};
386
387/// Base class for instructions consumed by the simulation pipeline.
388///
389/// This class tracks data dependencies as well as generic properties
390/// of the instruction.
391class InstructionBase {
392 const InstrDesc &Desc;
393
394 // This field is set for instructions that are candidates for move
395 // elimination. For more information about move elimination, see the
396 // definition of RegisterMappingTracker in RegisterFile.h
397 bool IsOptimizableMove;
398
399 // Output dependencies.
400 // One entry per each implicit and explicit register definition.
401 SmallVector<WriteState, 4> Defs;
402
403 // Input dependencies.
404 // One entry per each implicit and explicit register use.
405 SmallVector<ReadState, 4> Uses;
406
407public:
408 InstructionBase(const InstrDesc &D) : Desc(D), IsOptimizableMove(false) {}
409
410 SmallVectorImpl<WriteState> &getDefs() { return Defs; }
411 const ArrayRef<WriteState> getDefs() const { return Defs; }
412 SmallVectorImpl<ReadState> &getUses() { return Uses; }
413 const ArrayRef<ReadState> getUses() const { return Uses; }
414 const InstrDesc &getDesc() const { return Desc; }
415
416 unsigned getLatency() const { return Desc.MaxLatency; }
417
418 bool hasDependentUsers() const {
419 return any_of(Defs,
420 [](const WriteState &Def) { return Def.getNumUsers() > 0; });
421 }
422
423 unsigned getNumUsers() const {
424 unsigned NumUsers = 0;
425 for (const WriteState &Def : Defs)
426 NumUsers += Def.getNumUsers();
427 return NumUsers;
428 }
429
430 // Returns true if this instruction is a candidate for move elimination.
431 bool isOptimizableMove() const { return IsOptimizableMove; }
432 void setOptimizableMove() { IsOptimizableMove = true; }
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100433 bool isMemOp() const { return Desc.MayLoad || Desc.MayStore; }
Andrew Walbran16937d02019-10-22 13:54:20 +0100434};
435
436/// An instruction propagated through the simulated instruction pipeline.
437///
438/// This class is used to monitor changes to the internal state of instructions
439/// that are sent to the various components of the simulated hardware pipeline.
440class Instruction : public InstructionBase {
441 enum InstrStage {
442 IS_INVALID, // Instruction in an invalid state.
443 IS_DISPATCHED, // Instruction dispatched but operands are not ready.
444 IS_PENDING, // Instruction is not ready, but operand latency is known.
445 IS_READY, // Instruction dispatched and operands ready.
446 IS_EXECUTING, // Instruction issued.
447 IS_EXECUTED, // Instruction executed. Values are written back.
448 IS_RETIRED // Instruction retired.
449 };
450
451 // The current instruction stage.
452 enum InstrStage Stage;
453
454 // This value defaults to the instruction latency. This instruction is
455 // considered executed when field CyclesLeft goes to zero.
456 int CyclesLeft;
457
458 // Retire Unit token ID for this instruction.
459 unsigned RCUTokenID;
460
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100461 // LS token ID for this instruction.
462 // This field is set to the invalid null token if this is not a memory
463 // operation.
464 unsigned LSUTokenID;
465
466 // Critical register dependency.
467 CriticalDependency CriticalRegDep;
468
469 // Critical memory dependency.
470 CriticalDependency CriticalMemDep;
471
472 // A bitmask of busy processor resource units.
473 // This field is set to zero only if execution is not delayed during this
474 // cycle because of unavailable pipeline resources.
475 uint64_t CriticalResourceMask;
476
477 // True if this instruction has been optimized at register renaming stage.
478 bool IsEliminated;
479
Andrew Walbran16937d02019-10-22 13:54:20 +0100480public:
481 Instruction(const InstrDesc &D)
482 : InstructionBase(D), Stage(IS_INVALID), CyclesLeft(UNKNOWN_CYCLES),
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100483 RCUTokenID(0), LSUTokenID(0), CriticalRegDep(), CriticalMemDep(),
484 CriticalResourceMask(0), IsEliminated(false) {}
Andrew Walbran16937d02019-10-22 13:54:20 +0100485
486 unsigned getRCUTokenID() const { return RCUTokenID; }
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100487 unsigned getLSUTokenID() const { return LSUTokenID; }
488 void setLSUTokenID(unsigned LSUTok) { LSUTokenID = LSUTok; }
Andrew Walbran16937d02019-10-22 13:54:20 +0100489 int getCyclesLeft() const { return CyclesLeft; }
490
491 // Transition to the dispatch stage, and assign a RCUToken to this
492 // instruction. The RCUToken is used to track the completion of every
493 // register write performed by this instruction.
494 void dispatch(unsigned RCUTokenID);
495
496 // Instruction issued. Transition to the IS_EXECUTING state, and update
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100497 // all the register definitions.
498 void execute(unsigned IID);
Andrew Walbran16937d02019-10-22 13:54:20 +0100499
500 // Force a transition from the IS_DISPATCHED state to the IS_READY or
501 // IS_PENDING state. State transitions normally occur either at the beginning
502 // of a new cycle (see method cycleEvent()), or as a result of another issue
503 // event. This method is called every time the instruction might have changed
504 // in state. It internally delegates to method updateDispatched() and
505 // updateWaiting().
506 void update();
507 bool updateDispatched();
508 bool updatePending();
509
510 bool isDispatched() const { return Stage == IS_DISPATCHED; }
511 bool isPending() const { return Stage == IS_PENDING; }
512 bool isReady() const { return Stage == IS_READY; }
513 bool isExecuting() const { return Stage == IS_EXECUTING; }
514 bool isExecuted() const { return Stage == IS_EXECUTED; }
515 bool isRetired() const { return Stage == IS_RETIRED; }
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100516 bool isEliminated() const { return IsEliminated; }
Andrew Walbran16937d02019-10-22 13:54:20 +0100517
518 // Forces a transition from state IS_DISPATCHED to state IS_EXECUTED.
519 void forceExecuted();
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100520 void setEliminated() { IsEliminated = true; }
Andrew Walbran16937d02019-10-22 13:54:20 +0100521
522 void retire() {
523 assert(isExecuted() && "Instruction is in an invalid state!");
524 Stage = IS_RETIRED;
525 }
526
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100527 const CriticalDependency &getCriticalRegDep() const { return CriticalRegDep; }
528 const CriticalDependency &getCriticalMemDep() const { return CriticalMemDep; }
529 const CriticalDependency &computeCriticalRegDep();
530 void setCriticalMemDep(const CriticalDependency &MemDep) {
531 CriticalMemDep = MemDep;
532 }
533
534 uint64_t getCriticalResourceMask() const { return CriticalResourceMask; }
535 void setCriticalResourceMask(uint64_t ResourceMask) {
536 CriticalResourceMask = ResourceMask;
537 }
538
Andrew Walbran16937d02019-10-22 13:54:20 +0100539 void cycleEvent();
540};
541
542/// An InstRef contains both a SourceMgr index and Instruction pair. The index
543/// is used as a unique identifier for the instruction. MCA will make use of
544/// this index as a key throughout MCA.
545class InstRef {
546 std::pair<unsigned, Instruction *> Data;
547
548public:
549 InstRef() : Data(std::make_pair(0, nullptr)) {}
550 InstRef(unsigned Index, Instruction *I) : Data(std::make_pair(Index, I)) {}
551
552 bool operator==(const InstRef &Other) const { return Data == Other.Data; }
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100553 bool operator!=(const InstRef &Other) const { return Data != Other.Data; }
554 bool operator<(const InstRef &Other) const {
555 return Data.first < Other.Data.first;
556 }
Andrew Walbran16937d02019-10-22 13:54:20 +0100557
558 unsigned getSourceIndex() const { return Data.first; }
559 Instruction *getInstruction() { return Data.second; }
560 const Instruction *getInstruction() const { return Data.second; }
561
562 /// Returns true if this references a valid instruction.
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100563 explicit operator bool() const { return Data.second != nullptr; }
Andrew Walbran16937d02019-10-22 13:54:20 +0100564
565 /// Invalidate this reference.
566 void invalidate() { Data.second = nullptr; }
567
568#ifndef NDEBUG
569 void print(raw_ostream &OS) const { OS << getSourceIndex(); }
570#endif
571};
572
573#ifndef NDEBUG
574inline raw_ostream &operator<<(raw_ostream &OS, const InstRef &IR) {
575 IR.print(OS);
576 return OS;
577}
578#endif
579
580/// A reference to a register write.
581///
582/// This class is mainly used by the register file to describe register
583/// mappings. It correlates a register write to the source index of the
584/// defining instruction.
585class WriteRef {
586 std::pair<unsigned, WriteState *> Data;
587 static const unsigned INVALID_IID;
588
589public:
590 WriteRef() : Data(INVALID_IID, nullptr) {}
591 WriteRef(unsigned SourceIndex, WriteState *WS) : Data(SourceIndex, WS) {}
592
593 unsigned getSourceIndex() const { return Data.first; }
594 const WriteState *getWriteState() const { return Data.second; }
595 WriteState *getWriteState() { return Data.second; }
596 void invalidate() { Data.second = nullptr; }
597 bool isWriteZero() const {
598 assert(isValid() && "Invalid null WriteState found!");
599 return getWriteState()->isWriteZero();
600 }
601
602 /// Returns true if this register write has been executed, and the new
603 /// register value is therefore available to users.
604 bool isAvailable() const {
605 if (getSourceIndex() == INVALID_IID)
606 return false;
607 const WriteState *WS = getWriteState();
608 return !WS || WS->isExecuted();
609 }
610
Andrew Walbran3d2c1972020-04-07 12:24:26 +0100611 bool isValid() const { return Data.second && Data.first != INVALID_IID; }
Andrew Walbran16937d02019-10-22 13:54:20 +0100612 bool operator==(const WriteRef &Other) const { return Data == Other.Data; }
613
614#ifndef NDEBUG
615 void dump() const;
616#endif
617};
618
619} // namespace mca
620} // namespace llvm
621
622#endif // LLVM_MCA_INSTRUCTION_H