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_HARDWAREUNITS_LSUNIT_H
0016 #define LLVM_MCA_HARDWAREUNITS_LSUNIT_H
0017
0018 #include "llvm/ADT/DenseMap.h"
0019 #include "llvm/ADT/SmallVector.h"
0020 #include "llvm/MC/MCSchedule.h"
0021 #include "llvm/MCA/HardwareUnits/HardwareUnit.h"
0022 #include "llvm/MCA/Instruction.h"
0023
0024 namespace llvm {
0025 namespace mca {
0026
0027
0028 class LSUnitBase : public HardwareUnit {
0029
0030
0031
0032
0033
0034
0035 unsigned LQSize;
0036
0037
0038
0039
0040
0041
0042
0043 unsigned SQSize;
0044
0045 unsigned UsedLQEntries;
0046 unsigned UsedSQEntries;
0047
0048
0049
0050
0051
0052
0053 const bool NoAlias;
0054
0055 public:
0056 LSUnitBase(const MCSchedModel &SM, unsigned LoadQueueSize,
0057 unsigned StoreQueueSize, bool AssumeNoAlias);
0058
0059 virtual ~LSUnitBase();
0060
0061
0062 unsigned getLoadQueueSize() const { return LQSize; }
0063
0064
0065 unsigned getStoreQueueSize() const { return SQSize; }
0066
0067 unsigned getUsedLQEntries() const { return UsedLQEntries; }
0068 unsigned getUsedSQEntries() const { return UsedSQEntries; }
0069 void acquireLQSlot() { ++UsedLQEntries; }
0070 void acquireSQSlot() { ++UsedSQEntries; }
0071 void releaseLQSlot() { --UsedLQEntries; }
0072 void releaseSQSlot() { --UsedSQEntries; }
0073
0074 bool assumeNoAlias() const { return NoAlias; }
0075
0076 enum Status {
0077 LSU_AVAILABLE = 0,
0078 LSU_LQUEUE_FULL,
0079 LSU_SQUEUE_FULL
0080 };
0081
0082
0083
0084
0085
0086
0087 virtual Status isAvailable(const InstRef &IR) const = 0;
0088
0089
0090
0091
0092
0093
0094
0095 virtual unsigned dispatch(const InstRef &IR) = 0;
0096
0097 bool isSQEmpty() const { return !UsedSQEntries; }
0098 bool isLQEmpty() const { return !UsedLQEntries; }
0099 bool isSQFull() const { return SQSize && SQSize == UsedSQEntries; }
0100 bool isLQFull() const { return LQSize && LQSize == UsedLQEntries; }
0101
0102
0103 virtual bool isReady(const InstRef &IR) const = 0;
0104
0105
0106
0107 virtual bool isPending(const InstRef &IR) const = 0;
0108
0109
0110
0111 virtual bool isWaiting(const InstRef &IR) const = 0;
0112
0113 virtual bool hasDependentUsers(const InstRef &IR) const = 0;
0114
0115 virtual const CriticalDependency getCriticalPredecessor(unsigned GroupId) = 0;
0116
0117 virtual void onInstructionExecuted(const InstRef &IR) = 0;
0118
0119
0120
0121
0122
0123 virtual void onInstructionRetired(const InstRef &IR) = 0;
0124
0125 virtual void onInstructionIssued(const InstRef &IR) = 0;
0126
0127 virtual void cycleEvent() = 0;
0128
0129 #ifndef NDEBUG
0130 virtual void dump() const = 0;
0131 #endif
0132 };
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195 class LSUnit : public LSUnitBase {
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218
0219
0220
0221
0222
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236 protected:
0237
0238
0239
0240
0241
0242
0243
0244
0245 class MemoryGroup {
0246 unsigned NumPredecessors = 0;
0247 unsigned NumExecutingPredecessors = 0;
0248 unsigned NumExecutedPredecessors = 0;
0249
0250 unsigned NumInstructions = 0;
0251 unsigned NumExecuting = 0;
0252 unsigned NumExecuted = 0;
0253
0254 SmallVector<MemoryGroup *, 4> OrderSucc;
0255
0256 SmallVector<MemoryGroup *, 4> DataSucc;
0257
0258 CriticalDependency CriticalPredecessor;
0259 InstRef CriticalMemoryInstruction;
0260
0261 MemoryGroup(const MemoryGroup &) = delete;
0262 MemoryGroup &operator=(const MemoryGroup &) = delete;
0263
0264 public:
0265 MemoryGroup() = default;
0266 MemoryGroup(MemoryGroup &&) = default;
0267
0268 size_t getNumSuccessors() const {
0269 return OrderSucc.size() + DataSucc.size();
0270 }
0271 unsigned getNumPredecessors() const { return NumPredecessors; }
0272 unsigned getNumExecutingPredecessors() const {
0273 return NumExecutingPredecessors;
0274 }
0275 unsigned getNumExecutedPredecessors() const {
0276 return NumExecutedPredecessors;
0277 }
0278 unsigned getNumInstructions() const { return NumInstructions; }
0279 unsigned getNumExecuting() const { return NumExecuting; }
0280 unsigned getNumExecuted() const { return NumExecuted; }
0281
0282 const InstRef &getCriticalMemoryInstruction() const {
0283 return CriticalMemoryInstruction;
0284 }
0285 const CriticalDependency &getCriticalPredecessor() const {
0286 return CriticalPredecessor;
0287 }
0288
0289 void addSuccessor(MemoryGroup *Group, bool IsDataDependent) {
0290
0291
0292
0293 if (!IsDataDependent && isExecuting())
0294 return;
0295
0296 Group->NumPredecessors++;
0297 assert(!isExecuted() && "Should have been removed!");
0298 if (isExecuting())
0299 Group->onGroupIssued(CriticalMemoryInstruction, IsDataDependent);
0300
0301 if (IsDataDependent)
0302 DataSucc.emplace_back(Group);
0303 else
0304 OrderSucc.emplace_back(Group);
0305 }
0306
0307 bool isWaiting() const {
0308 return NumPredecessors >
0309 (NumExecutingPredecessors + NumExecutedPredecessors);
0310 }
0311 bool isPending() const {
0312 return NumExecutingPredecessors &&
0313 ((NumExecutedPredecessors + NumExecutingPredecessors) ==
0314 NumPredecessors);
0315 }
0316 bool isReady() const { return NumExecutedPredecessors == NumPredecessors; }
0317 bool isExecuting() const {
0318 return NumExecuting && (NumExecuting == (NumInstructions - NumExecuted));
0319 }
0320 bool isExecuted() const { return NumInstructions == NumExecuted; }
0321
0322 void onGroupIssued(const InstRef &IR, bool ShouldUpdateCriticalDep) {
0323 assert(!isReady() && "Unexpected group-start event!");
0324 NumExecutingPredecessors++;
0325
0326 if (!ShouldUpdateCriticalDep)
0327 return;
0328
0329 unsigned Cycles = IR.getInstruction()->getCyclesLeft();
0330 if (CriticalPredecessor.Cycles < Cycles) {
0331 CriticalPredecessor.IID = IR.getSourceIndex();
0332 CriticalPredecessor.Cycles = Cycles;
0333 }
0334 }
0335
0336 void onGroupExecuted() {
0337 assert(!isReady() && "Inconsistent state found!");
0338 NumExecutingPredecessors--;
0339 NumExecutedPredecessors++;
0340 }
0341
0342 void onInstructionIssued(const InstRef &IR) {
0343 assert(!isExecuting() && "Invalid internal state!");
0344 ++NumExecuting;
0345
0346
0347 const Instruction &IS = *IR.getInstruction();
0348 if ((bool)CriticalMemoryInstruction) {
0349 const Instruction &OtherIS =
0350 *CriticalMemoryInstruction.getInstruction();
0351 if (OtherIS.getCyclesLeft() < IS.getCyclesLeft())
0352 CriticalMemoryInstruction = IR;
0353 } else {
0354 CriticalMemoryInstruction = IR;
0355 }
0356
0357 if (!isExecuting())
0358 return;
0359
0360
0361 for (MemoryGroup *MG : OrderSucc) {
0362 MG->onGroupIssued(CriticalMemoryInstruction, false);
0363
0364 MG->onGroupExecuted();
0365 }
0366
0367 for (MemoryGroup *MG : DataSucc)
0368 MG->onGroupIssued(CriticalMemoryInstruction, true);
0369 }
0370
0371 void onInstructionExecuted(const InstRef &IR) {
0372 assert(isReady() && !isExecuted() && "Invalid internal state!");
0373 --NumExecuting;
0374 ++NumExecuted;
0375
0376 if (CriticalMemoryInstruction &&
0377 CriticalMemoryInstruction.getSourceIndex() == IR.getSourceIndex()) {
0378 CriticalMemoryInstruction.invalidate();
0379 }
0380
0381 if (!isExecuted())
0382 return;
0383
0384
0385
0386 for (MemoryGroup *MG : DataSucc)
0387 MG->onGroupExecuted();
0388 }
0389
0390 void addInstruction() {
0391 assert(!getNumSuccessors() && "Cannot add instructions to this group!");
0392 ++NumInstructions;
0393 }
0394
0395 void cycleEvent() {
0396 if (isWaiting() && CriticalPredecessor.Cycles)
0397 CriticalPredecessor.Cycles--;
0398 }
0399 };
0400
0401 DenseMap<unsigned, std::unique_ptr<MemoryGroup>> Groups;
0402 unsigned NextGroupID = 1;
0403
0404 unsigned CurrentLoadGroupID;
0405 unsigned CurrentLoadBarrierGroupID;
0406 unsigned CurrentStoreGroupID;
0407 unsigned CurrentStoreBarrierGroupID;
0408
0409 public:
0410 LSUnit(const MCSchedModel &SM)
0411 : LSUnit(SM, 0, 0, false) {}
0412 LSUnit(const MCSchedModel &SM, unsigned LQ, unsigned SQ)
0413 : LSUnit(SM, LQ, SQ, false) {}
0414 LSUnit(const MCSchedModel &SM, unsigned LQ, unsigned SQ, bool AssumeNoAlias)
0415 : LSUnitBase(SM, LQ, SQ, AssumeNoAlias), CurrentLoadGroupID(0),
0416 CurrentLoadBarrierGroupID(0), CurrentStoreGroupID(0),
0417 CurrentStoreBarrierGroupID(0) {}
0418
0419
0420
0421 Status isAvailable(const InstRef &IR) const override;
0422
0423 bool isReady(const InstRef &IR) const override {
0424 unsigned GroupID = IR.getInstruction()->getLSUTokenID();
0425 const MemoryGroup &Group = getGroup(GroupID);
0426 return Group.isReady();
0427 }
0428
0429 bool isPending(const InstRef &IR) const override {
0430 unsigned GroupID = IR.getInstruction()->getLSUTokenID();
0431 const MemoryGroup &Group = getGroup(GroupID);
0432 return Group.isPending();
0433 }
0434
0435 bool isWaiting(const InstRef &IR) const override {
0436 unsigned GroupID = IR.getInstruction()->getLSUTokenID();
0437 const MemoryGroup &Group = getGroup(GroupID);
0438 return Group.isWaiting();
0439 }
0440
0441 bool hasDependentUsers(const InstRef &IR) const override {
0442 unsigned GroupID = IR.getInstruction()->getLSUTokenID();
0443 const MemoryGroup &Group = getGroup(GroupID);
0444 return !Group.isExecuted() && Group.getNumSuccessors();
0445 }
0446
0447 const CriticalDependency getCriticalPredecessor(unsigned GroupId) override {
0448 const MemoryGroup &Group = getGroup(GroupId);
0449 return Group.getCriticalPredecessor();
0450 }
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461
0462
0463
0464
0465 unsigned dispatch(const InstRef &IR) override;
0466
0467 virtual void onInstructionIssued(const InstRef &IR) override {
0468 unsigned GroupID = IR.getInstruction()->getLSUTokenID();
0469 Groups[GroupID]->onInstructionIssued(IR);
0470 }
0471
0472 virtual void onInstructionRetired(const InstRef &IR) override;
0473
0474 virtual void onInstructionExecuted(const InstRef &IR) override;
0475
0476 virtual void cycleEvent() override;
0477
0478 #ifndef NDEBUG
0479 virtual void dump() const override;
0480 #endif
0481
0482 private:
0483 bool isValidGroupID(unsigned Index) const {
0484 return Index && Groups.contains(Index);
0485 }
0486
0487 const MemoryGroup &getGroup(unsigned Index) const {
0488 assert(isValidGroupID(Index) && "Group doesn't exist!");
0489 return *Groups.find(Index)->second;
0490 }
0491
0492 MemoryGroup &getGroup(unsigned Index) {
0493 assert(isValidGroupID(Index) && "Group doesn't exist!");
0494 return *Groups.find(Index)->second;
0495 }
0496
0497 unsigned createMemoryGroup() {
0498 Groups.insert(std::make_pair(NextGroupID, std::make_unique<MemoryGroup>()));
0499 return NextGroupID++;
0500 }
0501 };
0502
0503 }
0504 }
0505
0506 #endif