File indexing completed on 2026-05-10 08:44:16
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef LLVM_MCA_INSTRUCTION_H
0016 #define LLVM_MCA_INSTRUCTION_H
0017
0018 #include "llvm/ADT/ArrayRef.h"
0019 #include "llvm/ADT/STLExtras.h"
0020 #include "llvm/ADT/SmallVector.h"
0021 #include "llvm/MC/MCRegister.h" // definition of MCPhysReg.
0022 #include "llvm/Support/MathExtras.h"
0023
0024 #ifndef NDEBUG
0025 #include "llvm/Support/raw_ostream.h"
0026 #endif
0027
0028 #include <memory>
0029
0030 namespace llvm {
0031
0032 namespace mca {
0033
0034 constexpr int UNKNOWN_CYCLES = -512;
0035
0036
0037
0038 class MCAOperand {
0039
0040
0041
0042 enum MCAOperandType : unsigned char {
0043 kInvalid,
0044 kRegister,
0045 kImmediate,
0046 kSFPImmediate,
0047 kDFPImmediate,
0048 };
0049 MCAOperandType Kind;
0050
0051 union {
0052 unsigned RegVal;
0053 int64_t ImmVal;
0054 uint32_t SFPImmVal;
0055 uint64_t FPImmVal;
0056 };
0057
0058
0059
0060
0061
0062 unsigned Index;
0063
0064 public:
0065 MCAOperand() : Kind(kInvalid), FPImmVal(), Index() {}
0066
0067 bool isValid() const { return Kind != kInvalid; }
0068 bool isReg() const { return Kind == kRegister; }
0069 bool isImm() const { return Kind == kImmediate; }
0070 bool isSFPImm() const { return Kind == kSFPImmediate; }
0071 bool isDFPImm() const { return Kind == kDFPImmediate; }
0072
0073
0074 unsigned getReg() const {
0075 assert(isReg() && "This is not a register operand!");
0076 return RegVal;
0077 }
0078
0079 int64_t getImm() const {
0080 assert(isImm() && "This is not an immediate");
0081 return ImmVal;
0082 }
0083
0084 uint32_t getSFPImm() const {
0085 assert(isSFPImm() && "This is not an SFP immediate");
0086 return SFPImmVal;
0087 }
0088
0089 uint64_t getDFPImm() const {
0090 assert(isDFPImm() && "This is not an FP immediate");
0091 return FPImmVal;
0092 }
0093
0094 void setIndex(const unsigned Idx) { Index = Idx; }
0095
0096 unsigned getIndex() const { return Index; }
0097
0098 static MCAOperand createReg(unsigned Reg) {
0099 MCAOperand Op;
0100 Op.Kind = kRegister;
0101 Op.RegVal = Reg;
0102 return Op;
0103 }
0104
0105 static MCAOperand createImm(int64_t Val) {
0106 MCAOperand Op;
0107 Op.Kind = kImmediate;
0108 Op.ImmVal = Val;
0109 return Op;
0110 }
0111
0112 static MCAOperand createSFPImm(uint32_t Val) {
0113 MCAOperand Op;
0114 Op.Kind = kSFPImmediate;
0115 Op.SFPImmVal = Val;
0116 return Op;
0117 }
0118
0119 static MCAOperand createDFPImm(uint64_t Val) {
0120 MCAOperand Op;
0121 Op.Kind = kDFPImmediate;
0122 Op.FPImmVal = Val;
0123 return Op;
0124 }
0125
0126 static MCAOperand createInvalid() {
0127 MCAOperand Op;
0128 Op.Kind = kInvalid;
0129 Op.FPImmVal = 0;
0130 return Op;
0131 }
0132 };
0133
0134
0135 struct WriteDescriptor {
0136
0137
0138
0139 int OpIndex;
0140
0141 unsigned Latency;
0142
0143
0144 MCPhysReg RegisterID;
0145
0146
0147
0148
0149
0150
0151
0152
0153 unsigned SClassOrWriteResourceID;
0154
0155
0156
0157 bool IsOptionalDef;
0158
0159 bool isImplicitWrite() const { return OpIndex < 0; };
0160 };
0161
0162
0163 struct ReadDescriptor {
0164
0165
0166
0167 int OpIndex;
0168
0169
0170 unsigned UseIndex;
0171
0172 MCPhysReg RegisterID;
0173
0174
0175 unsigned SchedClassID;
0176
0177 bool isImplicitRead() const { return OpIndex < 0; };
0178 };
0179
0180 class ReadState;
0181
0182
0183
0184
0185 struct CriticalDependency {
0186 unsigned IID;
0187 MCPhysReg RegID;
0188 unsigned Cycles;
0189 };
0190
0191
0192
0193
0194
0195
0196
0197 class WriteState {
0198 const WriteDescriptor *WD;
0199
0200
0201
0202 int CyclesLeft;
0203
0204
0205
0206
0207
0208 MCPhysReg RegisterID;
0209
0210
0211 unsigned PRFID;
0212
0213
0214
0215 bool ClearsSuperRegs;
0216
0217
0218 bool WritesZero;
0219
0220
0221
0222
0223
0224 bool IsEliminated;
0225
0226
0227
0228
0229
0230 const WriteState *DependentWrite;
0231
0232
0233 WriteState *PartialWrite;
0234 unsigned DependentWriteCyclesLeft;
0235
0236
0237 CriticalDependency CRD;
0238
0239
0240
0241
0242
0243
0244
0245 SmallVector<std::pair<ReadState *, int>, 4> Users;
0246
0247 public:
0248 WriteState(const WriteDescriptor &Desc, MCPhysReg RegID,
0249 bool clearsSuperRegs = false, bool writesZero = false)
0250 : WD(&Desc), CyclesLeft(UNKNOWN_CYCLES), RegisterID(RegID), PRFID(0),
0251 ClearsSuperRegs(clearsSuperRegs), WritesZero(writesZero),
0252 IsEliminated(false), DependentWrite(nullptr), PartialWrite(nullptr),
0253 DependentWriteCyclesLeft(0), CRD() {}
0254
0255 WriteState(const WriteState &Other) = default;
0256 WriteState &operator=(const WriteState &Other) = default;
0257
0258 int getCyclesLeft() const { return CyclesLeft; }
0259 unsigned getWriteResourceID() const { return WD->SClassOrWriteResourceID; }
0260 MCPhysReg getRegisterID() const { return RegisterID; }
0261 void setRegisterID(const MCPhysReg RegID) { RegisterID = RegID; }
0262 unsigned getRegisterFileID() const { return PRFID; }
0263 unsigned getLatency() const { return WD->Latency; }
0264 unsigned getDependentWriteCyclesLeft() const {
0265 return DependentWriteCyclesLeft;
0266 }
0267 const WriteState *getDependentWrite() const { return DependentWrite; }
0268 const CriticalDependency &getCriticalRegDep() const { return CRD; }
0269
0270
0271
0272
0273
0274 void addUser(unsigned IID, ReadState *Use, int ReadAdvance);
0275
0276
0277
0278 void addUser(unsigned IID, WriteState *Use);
0279
0280 unsigned getNumUsers() const {
0281 unsigned NumUsers = Users.size();
0282 if (PartialWrite)
0283 ++NumUsers;
0284 return NumUsers;
0285 }
0286
0287 bool clearsSuperRegisters() const { return ClearsSuperRegs; }
0288 bool isWriteZero() const { return WritesZero; }
0289 bool isEliminated() const { return IsEliminated; }
0290
0291 bool isReady() const {
0292 if (DependentWrite)
0293 return false;
0294 unsigned CyclesLeft = getDependentWriteCyclesLeft();
0295 return !CyclesLeft || CyclesLeft < getLatency();
0296 }
0297
0298 bool isExecuted() const {
0299 return CyclesLeft != UNKNOWN_CYCLES && CyclesLeft <= 0;
0300 }
0301
0302 void setDependentWrite(const WriteState *Other) { DependentWrite = Other; }
0303 void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
0304 void setWriteZero() { WritesZero = true; }
0305 void setEliminated() {
0306 assert(Users.empty() && "Write is in an inconsistent state.");
0307 CyclesLeft = 0;
0308 IsEliminated = true;
0309 }
0310
0311 void setPRF(unsigned PRF) { PRFID = PRF; }
0312
0313
0314 void cycleEvent();
0315 void onInstructionIssued(unsigned IID);
0316
0317 #ifndef NDEBUG
0318 void dump() const;
0319 #endif
0320 };
0321
0322
0323
0324
0325
0326 class ReadState {
0327 const ReadDescriptor *RD;
0328
0329 MCPhysReg RegisterID;
0330
0331 unsigned PRFID;
0332
0333
0334
0335 unsigned DependentWrites;
0336
0337
0338
0339
0340 int CyclesLeft;
0341
0342
0343
0344 unsigned TotalCycles;
0345
0346 CriticalDependency CRD;
0347
0348
0349 bool IsReady;
0350
0351 bool IsZero;
0352
0353 bool IndependentFromDef;
0354
0355 public:
0356 ReadState(const ReadDescriptor &Desc, MCPhysReg RegID)
0357 : RD(&Desc), RegisterID(RegID), PRFID(0), DependentWrites(0),
0358 CyclesLeft(UNKNOWN_CYCLES), TotalCycles(0), CRD(), IsReady(true),
0359 IsZero(false), IndependentFromDef(false) {}
0360
0361 const ReadDescriptor &getDescriptor() const { return *RD; }
0362 unsigned getSchedClass() const { return RD->SchedClassID; }
0363 MCPhysReg getRegisterID() const { return RegisterID; }
0364 unsigned getRegisterFileID() const { return PRFID; }
0365 const CriticalDependency &getCriticalRegDep() const { return CRD; }
0366
0367 bool isPending() const { return !IndependentFromDef && CyclesLeft > 0; }
0368 bool isReady() const { return IsReady; }
0369 bool isImplicitRead() const { return RD->isImplicitRead(); }
0370
0371 bool isIndependentFromDef() const { return IndependentFromDef; }
0372 void setIndependentFromDef() { IndependentFromDef = true; }
0373
0374 void cycleEvent();
0375 void writeStartEvent(unsigned IID, MCPhysReg RegID, unsigned Cycles);
0376 void setDependentWrites(unsigned Writes) {
0377 DependentWrites = Writes;
0378 IsReady = !Writes;
0379 }
0380
0381 bool isReadZero() const { return IsZero; }
0382 void setReadZero() { IsZero = true; }
0383 void setPRF(unsigned ID) { PRFID = ID; }
0384 };
0385
0386
0387
0388
0389 class CycleSegment {
0390 unsigned Begin;
0391 unsigned End;
0392 bool Reserved;
0393
0394 public:
0395 CycleSegment(unsigned StartCycle, unsigned EndCycle, bool IsReserved = false)
0396 : Begin(StartCycle), End(EndCycle), Reserved(IsReserved) {}
0397
0398 bool contains(unsigned Cycle) const { return Cycle >= Begin && Cycle < End; }
0399 bool startsAfter(const CycleSegment &CS) const { return End <= CS.Begin; }
0400 bool endsBefore(const CycleSegment &CS) const { return Begin >= CS.End; }
0401 bool overlaps(const CycleSegment &CS) const {
0402 return !startsAfter(CS) && !endsBefore(CS);
0403 }
0404 bool isExecuting() const { return Begin == 0 && End != 0; }
0405 bool isExecuted() const { return End == 0; }
0406 bool operator<(const CycleSegment &Other) const {
0407 return Begin < Other.Begin;
0408 }
0409 CycleSegment &operator--() {
0410 if (Begin)
0411 Begin--;
0412 if (End)
0413 End--;
0414 return *this;
0415 }
0416
0417 bool isValid() const { return Begin <= End; }
0418 unsigned size() const { return End - Begin; };
0419 void subtract(unsigned Cycles) {
0420 assert(End >= Cycles);
0421 End -= Cycles;
0422 }
0423
0424 unsigned begin() const { return Begin; }
0425 unsigned end() const { return End; }
0426 void setEnd(unsigned NewEnd) { End = NewEnd; }
0427 bool isReserved() const { return Reserved; }
0428 void setReserved() { Reserved = true; }
0429 };
0430
0431
0432
0433
0434
0435
0436 struct ResourceUsage {
0437 CycleSegment CS;
0438 unsigned NumUnits;
0439 ResourceUsage(CycleSegment Cycles, unsigned Units = 1)
0440 : CS(Cycles), NumUnits(Units) {}
0441 unsigned size() const { return CS.size(); }
0442 bool isReserved() const { return CS.isReserved(); }
0443 void setReserved() { CS.setReserved(); }
0444 };
0445
0446
0447 struct InstrDesc {
0448 SmallVector<WriteDescriptor, 2> Writes;
0449 SmallVector<ReadDescriptor, 4> Reads;
0450
0451
0452
0453 SmallVector<std::pair<uint64_t, ResourceUsage>, 4> Resources;
0454
0455
0456 uint64_t UsedBuffers;
0457
0458
0459 uint64_t UsedProcResUnits;
0460
0461
0462 uint64_t UsedProcResGroups;
0463
0464 unsigned MaxLatency;
0465
0466 unsigned NumMicroOps;
0467
0468
0469
0470 unsigned SchedClassID;
0471
0472
0473
0474 unsigned MustIssueImmediately : 1;
0475
0476
0477
0478
0479 unsigned IsRecyclable : 1;
0480
0481
0482 unsigned HasPartiallyOverlappingGroups : 1;
0483
0484
0485 bool isZeroLatency() const { return !MaxLatency && Resources.empty(); }
0486
0487 InstrDesc() = default;
0488 InstrDesc(const InstrDesc &Other) = delete;
0489 InstrDesc &operator=(const InstrDesc &Other) = delete;
0490 };
0491
0492
0493
0494
0495
0496 class InstructionBase {
0497 const InstrDesc &Desc;
0498
0499
0500
0501
0502 bool IsOptimizableMove;
0503
0504
0505
0506 SmallVector<WriteState, 2> Defs;
0507
0508
0509
0510 SmallVector<ReadState, 4> Uses;
0511
0512
0513 std::vector<MCAOperand> Operands;
0514
0515
0516 unsigned Opcode;
0517
0518
0519 bool IsALoadBarrier : 1;
0520 bool IsAStoreBarrier : 1;
0521
0522
0523 bool MayLoad : 1;
0524 bool MayStore : 1;
0525 bool HasSideEffects : 1;
0526 bool BeginGroup : 1;
0527 bool EndGroup : 1;
0528 bool RetireOOO : 1;
0529
0530 public:
0531 InstructionBase(const InstrDesc &D, const unsigned Opcode)
0532 : Desc(D), IsOptimizableMove(false), Operands(0), Opcode(Opcode),
0533 IsALoadBarrier(false), IsAStoreBarrier(false) {}
0534
0535 SmallVectorImpl<WriteState> &getDefs() { return Defs; }
0536 ArrayRef<WriteState> getDefs() const { return Defs; }
0537 SmallVectorImpl<ReadState> &getUses() { return Uses; }
0538 ArrayRef<ReadState> getUses() const { return Uses; }
0539 const InstrDesc &getDesc() const { return Desc; }
0540
0541 unsigned getLatency() const { return Desc.MaxLatency; }
0542 unsigned getNumMicroOps() const { return Desc.NumMicroOps; }
0543 unsigned getOpcode() const { return Opcode; }
0544 bool isALoadBarrier() const { return IsALoadBarrier; }
0545 bool isAStoreBarrier() const { return IsAStoreBarrier; }
0546 void setLoadBarrier(bool IsBarrier) { IsALoadBarrier = IsBarrier; }
0547 void setStoreBarrier(bool IsBarrier) { IsAStoreBarrier = IsBarrier; }
0548
0549
0550
0551 const MCAOperand *getOperand(const unsigned Idx) const {
0552 auto It = llvm::find_if(Operands, [&Idx](const MCAOperand &Op) {
0553 return Op.getIndex() == Idx;
0554 });
0555 if (It == Operands.end())
0556 return nullptr;
0557 return &(*It);
0558 }
0559 unsigned getNumOperands() const { return Operands.size(); }
0560 void addOperand(const MCAOperand Op) { Operands.push_back(Op); }
0561
0562 bool hasDependentUsers() const {
0563 return any_of(Defs,
0564 [](const WriteState &Def) { return Def.getNumUsers() > 0; });
0565 }
0566
0567 unsigned getNumUsers() const {
0568 unsigned NumUsers = 0;
0569 for (const WriteState &Def : Defs)
0570 NumUsers += Def.getNumUsers();
0571 return NumUsers;
0572 }
0573
0574
0575 bool isOptimizableMove() const { return IsOptimizableMove; }
0576 void setOptimizableMove() { IsOptimizableMove = true; }
0577 void clearOptimizableMove() { IsOptimizableMove = false; }
0578 bool isMemOp() const { return MayLoad || MayStore; }
0579
0580
0581 void setMayLoad(bool newVal) { MayLoad = newVal; }
0582 void setMayStore(bool newVal) { MayStore = newVal; }
0583 void setHasSideEffects(bool newVal) { HasSideEffects = newVal; }
0584 void setBeginGroup(bool newVal) { BeginGroup = newVal; }
0585 void setEndGroup(bool newVal) { EndGroup = newVal; }
0586 void setRetireOOO(bool newVal) { RetireOOO = newVal; }
0587
0588 bool getMayLoad() const { return MayLoad; }
0589 bool getMayStore() const { return MayStore; }
0590 bool getHasSideEffects() const { return HasSideEffects; }
0591 bool getBeginGroup() const { return BeginGroup; }
0592 bool getEndGroup() const { return EndGroup; }
0593 bool getRetireOOO() const { return RetireOOO; }
0594 };
0595
0596
0597
0598
0599
0600 class Instruction : public InstructionBase {
0601 enum InstrStage {
0602 IS_INVALID,
0603 IS_DISPATCHED,
0604 IS_PENDING,
0605 IS_READY,
0606 IS_EXECUTING,
0607 IS_EXECUTED,
0608 IS_RETIRED
0609 };
0610
0611
0612 enum InstrStage Stage;
0613
0614
0615
0616 int CyclesLeft;
0617
0618
0619 unsigned RCUTokenID;
0620
0621
0622
0623
0624 unsigned LSUTokenID;
0625
0626
0627
0628
0629
0630 uint64_t UsedBuffers;
0631
0632
0633 CriticalDependency CriticalRegDep;
0634
0635
0636 CriticalDependency CriticalMemDep;
0637
0638
0639
0640
0641 uint64_t CriticalResourceMask;
0642
0643
0644 bool IsEliminated;
0645
0646 public:
0647 Instruction(const InstrDesc &D, const unsigned Opcode)
0648 : InstructionBase(D, Opcode), Stage(IS_INVALID),
0649 CyclesLeft(UNKNOWN_CYCLES), RCUTokenID(0), LSUTokenID(0),
0650 UsedBuffers(D.UsedBuffers), CriticalRegDep(), CriticalMemDep(),
0651 CriticalResourceMask(0), IsEliminated(false) {}
0652
0653 void reset();
0654
0655 unsigned getRCUTokenID() const { return RCUTokenID; }
0656 unsigned getLSUTokenID() const { return LSUTokenID; }
0657 void setLSUTokenID(unsigned LSUTok) { LSUTokenID = LSUTok; }
0658
0659 uint64_t getUsedBuffers() const { return UsedBuffers; }
0660 void setUsedBuffers(uint64_t Mask) { UsedBuffers = Mask; }
0661 void clearUsedBuffers() { UsedBuffers = 0ULL; }
0662
0663 int getCyclesLeft() const { return CyclesLeft; }
0664
0665
0666
0667
0668 void dispatch(unsigned RCUTokenID);
0669
0670
0671
0672 void execute(unsigned IID);
0673
0674
0675
0676
0677
0678
0679
0680 void update();
0681 bool updateDispatched();
0682 bool updatePending();
0683
0684 bool isInvalid() const { return Stage == IS_INVALID; }
0685 bool isDispatched() const { return Stage == IS_DISPATCHED; }
0686 bool isPending() const { return Stage == IS_PENDING; }
0687 bool isReady() const { return Stage == IS_READY; }
0688 bool isExecuting() const { return Stage == IS_EXECUTING; }
0689 bool isExecuted() const { return Stage == IS_EXECUTED; }
0690 bool isRetired() const { return Stage == IS_RETIRED; }
0691 bool isEliminated() const { return IsEliminated; }
0692
0693
0694 void forceExecuted();
0695 void setEliminated() { IsEliminated = true; }
0696
0697 void retire() {
0698 assert(isExecuted() && "Instruction is in an invalid state!");
0699 Stage = IS_RETIRED;
0700 }
0701
0702 const CriticalDependency &getCriticalRegDep() const { return CriticalRegDep; }
0703 const CriticalDependency &getCriticalMemDep() const { return CriticalMemDep; }
0704 const CriticalDependency &computeCriticalRegDep();
0705 void setCriticalMemDep(const CriticalDependency &MemDep) {
0706 CriticalMemDep = MemDep;
0707 }
0708
0709 uint64_t getCriticalResourceMask() const { return CriticalResourceMask; }
0710 void setCriticalResourceMask(uint64_t ResourceMask) {
0711 CriticalResourceMask = ResourceMask;
0712 }
0713
0714 void cycleEvent();
0715 };
0716
0717
0718
0719
0720 class InstRef {
0721 std::pair<unsigned, Instruction *> Data;
0722
0723 public:
0724 InstRef() : Data(std::make_pair(0, nullptr)) {}
0725 InstRef(unsigned Index, Instruction *I) : Data(std::make_pair(Index, I)) {}
0726
0727 bool operator==(const InstRef &Other) const { return Data == Other.Data; }
0728 bool operator!=(const InstRef &Other) const { return Data != Other.Data; }
0729 bool operator<(const InstRef &Other) const {
0730 return Data.first < Other.Data.first;
0731 }
0732
0733 unsigned getSourceIndex() const { return Data.first; }
0734 Instruction *getInstruction() { return Data.second; }
0735 const Instruction *getInstruction() const { return Data.second; }
0736
0737
0738 explicit operator bool() const { return Data.second != nullptr; }
0739
0740
0741 void invalidate() { Data.second = nullptr; }
0742
0743 #ifndef NDEBUG
0744 void print(raw_ostream &OS) const { OS << getSourceIndex(); }
0745 #endif
0746 };
0747
0748 #ifndef NDEBUG
0749 inline raw_ostream &operator<<(raw_ostream &OS, const InstRef &IR) {
0750 IR.print(OS);
0751 return OS;
0752 }
0753 #endif
0754
0755 }
0756 }
0757
0758 #endif