xref: /freebsd-src/contrib/llvm-project/llvm/lib/MCA/HardwareUnits/LSUnit.cpp (revision 81ad626541db97eb356e2c1d4a20eb2a26a766ab)
10b57cec5SDimitry Andric //===----------------------- LSUnit.cpp --------------------------*- C++-*-===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric /// \file
90b57cec5SDimitry Andric ///
100b57cec5SDimitry Andric /// A Load-Store Unit for the llvm-mca tool.
110b57cec5SDimitry Andric ///
120b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
130b57cec5SDimitry Andric 
140b57cec5SDimitry Andric #include "llvm/MCA/HardwareUnits/LSUnit.h"
150b57cec5SDimitry Andric #include "llvm/MCA/Instruction.h"
160b57cec5SDimitry Andric #include "llvm/Support/Debug.h"
170b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
180b57cec5SDimitry Andric 
190b57cec5SDimitry Andric #define DEBUG_TYPE "llvm-mca"
200b57cec5SDimitry Andric 
210b57cec5SDimitry Andric namespace llvm {
220b57cec5SDimitry Andric namespace mca {
230b57cec5SDimitry Andric 
LSUnitBase(const MCSchedModel & SM,unsigned LQ,unsigned SQ,bool AssumeNoAlias)240b57cec5SDimitry Andric LSUnitBase::LSUnitBase(const MCSchedModel &SM, unsigned LQ, unsigned SQ,
250b57cec5SDimitry Andric                        bool AssumeNoAlias)
260b57cec5SDimitry Andric     : LQSize(LQ), SQSize(SQ), UsedLQEntries(0), UsedSQEntries(0),
270b57cec5SDimitry Andric       NoAlias(AssumeNoAlias), NextGroupID(1) {
280b57cec5SDimitry Andric   if (SM.hasExtraProcessorInfo()) {
290b57cec5SDimitry Andric     const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo();
300b57cec5SDimitry Andric     if (!LQSize && EPI.LoadQueueID) {
310b57cec5SDimitry Andric       const MCProcResourceDesc &LdQDesc = *SM.getProcResource(EPI.LoadQueueID);
328bcb0991SDimitry Andric       LQSize = std::max(0, LdQDesc.BufferSize);
330b57cec5SDimitry Andric     }
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric     if (!SQSize && EPI.StoreQueueID) {
360b57cec5SDimitry Andric       const MCProcResourceDesc &StQDesc = *SM.getProcResource(EPI.StoreQueueID);
378bcb0991SDimitry Andric       SQSize = std::max(0, StQDesc.BufferSize);
380b57cec5SDimitry Andric     }
390b57cec5SDimitry Andric   }
400b57cec5SDimitry Andric }
410b57cec5SDimitry Andric 
42*81ad6265SDimitry Andric LSUnitBase::~LSUnitBase() = default;
430b57cec5SDimitry Andric 
cycleEvent()440b57cec5SDimitry Andric void LSUnitBase::cycleEvent() {
450b57cec5SDimitry Andric   for (const std::pair<unsigned, std::unique_ptr<MemoryGroup>> &G : Groups)
460b57cec5SDimitry Andric     G.second->cycleEvent();
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric 
490b57cec5SDimitry Andric #ifndef NDEBUG
dump() const500b57cec5SDimitry Andric void LSUnitBase::dump() const {
510b57cec5SDimitry Andric   dbgs() << "[LSUnit] LQ_Size = " << getLoadQueueSize() << '\n';
520b57cec5SDimitry Andric   dbgs() << "[LSUnit] SQ_Size = " << getStoreQueueSize() << '\n';
530b57cec5SDimitry Andric   dbgs() << "[LSUnit] NextLQSlotIdx = " << getUsedLQEntries() << '\n';
540b57cec5SDimitry Andric   dbgs() << "[LSUnit] NextSQSlotIdx = " << getUsedSQEntries() << '\n';
550b57cec5SDimitry Andric   dbgs() << "\n";
560b57cec5SDimitry Andric   for (const auto &GroupIt : Groups) {
570b57cec5SDimitry Andric     const MemoryGroup &Group = *GroupIt.second;
580b57cec5SDimitry Andric     dbgs() << "[LSUnit] Group (" << GroupIt.first << "): "
590b57cec5SDimitry Andric            << "[ #Preds = " << Group.getNumPredecessors()
600b57cec5SDimitry Andric            << ", #GIssued = " << Group.getNumExecutingPredecessors()
610b57cec5SDimitry Andric            << ", #GExecuted = " << Group.getNumExecutedPredecessors()
620b57cec5SDimitry Andric            << ", #Inst = " << Group.getNumInstructions()
630b57cec5SDimitry Andric            << ", #IIssued = " << Group.getNumExecuting()
640b57cec5SDimitry Andric            << ", #IExecuted = " << Group.getNumExecuted() << '\n';
650b57cec5SDimitry Andric   }
660b57cec5SDimitry Andric }
670b57cec5SDimitry Andric #endif
680b57cec5SDimitry Andric 
dispatch(const InstRef & IR)690b57cec5SDimitry Andric unsigned LSUnit::dispatch(const InstRef &IR) {
70*81ad6265SDimitry Andric   const Instruction &IS = *IR.getInstruction();
71*81ad6265SDimitry Andric   bool IsStoreBarrier = IS.isAStoreBarrier();
72*81ad6265SDimitry Andric   bool IsLoadBarrier = IS.isALoadBarrier();
73*81ad6265SDimitry Andric   assert((IS.getMayLoad() || IS.getMayStore()) && "Not a memory operation!");
740b57cec5SDimitry Andric 
75*81ad6265SDimitry Andric   if (IS.getMayLoad())
768bcb0991SDimitry Andric     acquireLQSlot();
77*81ad6265SDimitry Andric   if (IS.getMayStore())
788bcb0991SDimitry Andric     acquireSQSlot();
790b57cec5SDimitry Andric 
80*81ad6265SDimitry Andric   if (IS.getMayStore()) {
810b57cec5SDimitry Andric     unsigned NewGID = createMemoryGroup();
820b57cec5SDimitry Andric     MemoryGroup &NewGroup = getGroup(NewGID);
830b57cec5SDimitry Andric     NewGroup.addInstruction();
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric     // A store may not pass a previous load or load barrier.
860b57cec5SDimitry Andric     unsigned ImmediateLoadDominator =
870b57cec5SDimitry Andric         std::max(CurrentLoadGroupID, CurrentLoadBarrierGroupID);
880b57cec5SDimitry Andric     if (ImmediateLoadDominator) {
890b57cec5SDimitry Andric       MemoryGroup &IDom = getGroup(ImmediateLoadDominator);
900b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << ImmediateLoadDominator
910b57cec5SDimitry Andric                         << ") --> (" << NewGID << ")\n");
925ffd83dbSDimitry Andric       IDom.addSuccessor(&NewGroup, !assumeNoAlias());
930b57cec5SDimitry Andric     }
945ffd83dbSDimitry Andric 
955ffd83dbSDimitry Andric     // A store may not pass a previous store barrier.
965ffd83dbSDimitry Andric     if (CurrentStoreBarrierGroupID) {
975ffd83dbSDimitry Andric       MemoryGroup &StoreGroup = getGroup(CurrentStoreBarrierGroupID);
985ffd83dbSDimitry Andric       LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: ("
995ffd83dbSDimitry Andric                         << CurrentStoreBarrierGroupID
1005ffd83dbSDimitry Andric                         << ") --> (" << NewGID << ")\n");
1015ffd83dbSDimitry Andric       StoreGroup.addSuccessor(&NewGroup, true);
1025ffd83dbSDimitry Andric     }
1035ffd83dbSDimitry Andric 
1045ffd83dbSDimitry Andric     // A store may not pass a previous store.
1055ffd83dbSDimitry Andric     if (CurrentStoreGroupID &&
1065ffd83dbSDimitry Andric         (CurrentStoreGroupID != CurrentStoreBarrierGroupID)) {
1070b57cec5SDimitry Andric       MemoryGroup &StoreGroup = getGroup(CurrentStoreGroupID);
1080b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID
1090b57cec5SDimitry Andric                         << ") --> (" << NewGID << ")\n");
1105ffd83dbSDimitry Andric       StoreGroup.addSuccessor(&NewGroup, !assumeNoAlias());
1110b57cec5SDimitry Andric     }
1120b57cec5SDimitry Andric 
1135ffd83dbSDimitry Andric 
1140b57cec5SDimitry Andric     CurrentStoreGroupID = NewGID;
11504eeddc0SDimitry Andric     if (IsStoreBarrier)
1165ffd83dbSDimitry Andric       CurrentStoreBarrierGroupID = NewGID;
1175ffd83dbSDimitry Andric 
118*81ad6265SDimitry Andric     if (IS.getMayLoad()) {
1190b57cec5SDimitry Andric       CurrentLoadGroupID = NewGID;
12004eeddc0SDimitry Andric       if (IsLoadBarrier)
1210b57cec5SDimitry Andric         CurrentLoadBarrierGroupID = NewGID;
1220b57cec5SDimitry Andric     }
1230b57cec5SDimitry Andric 
1240b57cec5SDimitry Andric     return NewGID;
1250b57cec5SDimitry Andric   }
1260b57cec5SDimitry Andric 
127*81ad6265SDimitry Andric   assert(IS.getMayLoad() && "Expected a load!");
1280b57cec5SDimitry Andric 
1295ffd83dbSDimitry Andric   unsigned ImmediateLoadDominator =
1305ffd83dbSDimitry Andric       std::max(CurrentLoadGroupID, CurrentLoadBarrierGroupID);
1310b57cec5SDimitry Andric 
1325ffd83dbSDimitry Andric   // A new load group is created if we are in one of the following situations:
1335ffd83dbSDimitry Andric   // 1) This is a load barrier (by construction, a load barrier is always
1345ffd83dbSDimitry Andric   //    assigned to a different memory group).
1355ffd83dbSDimitry Andric   // 2) There is no load in flight (by construction we always keep loads and
1365ffd83dbSDimitry Andric   //    stores into separate memory groups).
1375ffd83dbSDimitry Andric   // 3) There is a load barrier in flight. This load depends on it.
1385ffd83dbSDimitry Andric   // 4) There is an intervening store between the last load dispatched to the
1395ffd83dbSDimitry Andric   //    LSU and this load. We always create a new group even if this load
1405ffd83dbSDimitry Andric   //    does not alias the last dispatched store.
1415ffd83dbSDimitry Andric   // 5) There is no intervening store and there is an active load group.
1425ffd83dbSDimitry Andric   //    However that group has already started execution, so we cannot add
1435ffd83dbSDimitry Andric   //    this load to it.
1445ffd83dbSDimitry Andric   bool ShouldCreateANewGroup =
14504eeddc0SDimitry Andric       IsLoadBarrier || !ImmediateLoadDominator ||
1465ffd83dbSDimitry Andric       CurrentLoadBarrierGroupID == ImmediateLoadDominator ||
1475ffd83dbSDimitry Andric       ImmediateLoadDominator <= CurrentStoreGroupID ||
1485ffd83dbSDimitry Andric       getGroup(ImmediateLoadDominator).isExecuting();
1495ffd83dbSDimitry Andric 
1500b57cec5SDimitry Andric   if (ShouldCreateANewGroup) {
1510b57cec5SDimitry Andric     unsigned NewGID = createMemoryGroup();
1520b57cec5SDimitry Andric     MemoryGroup &NewGroup = getGroup(NewGID);
1530b57cec5SDimitry Andric     NewGroup.addInstruction();
1540b57cec5SDimitry Andric 
1555ffd83dbSDimitry Andric     // A load may not pass a previous store or store barrier
1565ffd83dbSDimitry Andric     // unless flag 'NoAlias' is set.
1570b57cec5SDimitry Andric     if (!assumeNoAlias() && CurrentStoreGroupID) {
1585ffd83dbSDimitry Andric       MemoryGroup &StoreGroup = getGroup(CurrentStoreGroupID);
1590b57cec5SDimitry Andric       LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID
1600b57cec5SDimitry Andric                         << ") --> (" << NewGID << ")\n");
1615ffd83dbSDimitry Andric       StoreGroup.addSuccessor(&NewGroup, true);
1620b57cec5SDimitry Andric     }
1635ffd83dbSDimitry Andric 
1645ffd83dbSDimitry Andric     // A load barrier may not pass a previous load or load barrier.
16504eeddc0SDimitry Andric     if (IsLoadBarrier) {
1665ffd83dbSDimitry Andric       if (ImmediateLoadDominator) {
1675ffd83dbSDimitry Andric         MemoryGroup &LoadGroup = getGroup(ImmediateLoadDominator);
1685ffd83dbSDimitry Andric         LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: ("
1695ffd83dbSDimitry Andric                           << ImmediateLoadDominator
1700b57cec5SDimitry Andric                           << ") --> (" << NewGID << ")\n");
1715ffd83dbSDimitry Andric         LoadGroup.addSuccessor(&NewGroup, true);
1725ffd83dbSDimitry Andric       }
1735ffd83dbSDimitry Andric     } else {
1745ffd83dbSDimitry Andric       // A younger load cannot pass a older load barrier.
1755ffd83dbSDimitry Andric       if (CurrentLoadBarrierGroupID) {
1765ffd83dbSDimitry Andric         MemoryGroup &LoadGroup = getGroup(CurrentLoadBarrierGroupID);
1775ffd83dbSDimitry Andric         LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: ("
1785ffd83dbSDimitry Andric                           << CurrentLoadBarrierGroupID
1795ffd83dbSDimitry Andric                           << ") --> (" << NewGID << ")\n");
1805ffd83dbSDimitry Andric         LoadGroup.addSuccessor(&NewGroup, true);
1815ffd83dbSDimitry Andric       }
1820b57cec5SDimitry Andric     }
1830b57cec5SDimitry Andric 
1840b57cec5SDimitry Andric     CurrentLoadGroupID = NewGID;
18504eeddc0SDimitry Andric     if (IsLoadBarrier)
1860b57cec5SDimitry Andric       CurrentLoadBarrierGroupID = NewGID;
1870b57cec5SDimitry Andric     return NewGID;
1880b57cec5SDimitry Andric   }
1890b57cec5SDimitry Andric 
1905ffd83dbSDimitry Andric   // A load may pass a previous load.
1910b57cec5SDimitry Andric   MemoryGroup &Group = getGroup(CurrentLoadGroupID);
1920b57cec5SDimitry Andric   Group.addInstruction();
1930b57cec5SDimitry Andric   return CurrentLoadGroupID;
1940b57cec5SDimitry Andric }
1950b57cec5SDimitry Andric 
isAvailable(const InstRef & IR) const1960b57cec5SDimitry Andric LSUnit::Status LSUnit::isAvailable(const InstRef &IR) const {
197*81ad6265SDimitry Andric   const Instruction &IS = *IR.getInstruction();
198*81ad6265SDimitry Andric   if (IS.getMayLoad() && isLQFull())
1990b57cec5SDimitry Andric     return LSUnit::LSU_LQUEUE_FULL;
200*81ad6265SDimitry Andric   if (IS.getMayStore() && isSQFull())
2010b57cec5SDimitry Andric     return LSUnit::LSU_SQUEUE_FULL;
2020b57cec5SDimitry Andric   return LSUnit::LSU_AVAILABLE;
2030b57cec5SDimitry Andric }
2040b57cec5SDimitry Andric 
onInstructionExecuted(const InstRef & IR)2050b57cec5SDimitry Andric void LSUnitBase::onInstructionExecuted(const InstRef &IR) {
2068bcb0991SDimitry Andric   unsigned GroupID = IR.getInstruction()->getLSUTokenID();
2078bcb0991SDimitry Andric   auto It = Groups.find(GroupID);
2088bcb0991SDimitry Andric   assert(It != Groups.end() && "Instruction not dispatched to the LS unit");
209fe6060f1SDimitry Andric   It->second->onInstructionExecuted(IR);
2108bcb0991SDimitry Andric   if (It->second->isExecuted())
2118bcb0991SDimitry Andric     Groups.erase(It);
2128bcb0991SDimitry Andric }
2138bcb0991SDimitry Andric 
onInstructionRetired(const InstRef & IR)2148bcb0991SDimitry Andric void LSUnitBase::onInstructionRetired(const InstRef &IR) {
215*81ad6265SDimitry Andric   const Instruction &IS = *IR.getInstruction();
216*81ad6265SDimitry Andric   bool IsALoad = IS.getMayLoad();
217*81ad6265SDimitry Andric   bool IsAStore = IS.getMayStore();
2180b57cec5SDimitry Andric   assert((IsALoad || IsAStore) && "Expected a memory operation!");
2190b57cec5SDimitry Andric 
2200b57cec5SDimitry Andric   if (IsALoad) {
2218bcb0991SDimitry Andric     releaseLQSlot();
2220b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex()
2230b57cec5SDimitry Andric                       << " has been removed from the load queue.\n");
2240b57cec5SDimitry Andric   }
2250b57cec5SDimitry Andric 
2260b57cec5SDimitry Andric   if (IsAStore) {
2278bcb0991SDimitry Andric     releaseSQSlot();
2280b57cec5SDimitry Andric     LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex()
2290b57cec5SDimitry Andric                       << " has been removed from the store queue.\n");
2300b57cec5SDimitry Andric   }
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric 
onInstructionExecuted(const InstRef & IR)2330b57cec5SDimitry Andric void LSUnit::onInstructionExecuted(const InstRef &IR) {
2340b57cec5SDimitry Andric   const Instruction &IS = *IR.getInstruction();
2350b57cec5SDimitry Andric   if (!IS.isMemOp())
2360b57cec5SDimitry Andric     return;
2370b57cec5SDimitry Andric 
2380b57cec5SDimitry Andric   LSUnitBase::onInstructionExecuted(IR);
2390b57cec5SDimitry Andric   unsigned GroupID = IS.getLSUTokenID();
2400b57cec5SDimitry Andric   if (!isValidGroupID(GroupID)) {
2410b57cec5SDimitry Andric     if (GroupID == CurrentLoadGroupID)
2420b57cec5SDimitry Andric       CurrentLoadGroupID = 0;
2430b57cec5SDimitry Andric     if (GroupID == CurrentStoreGroupID)
2440b57cec5SDimitry Andric       CurrentStoreGroupID = 0;
2450b57cec5SDimitry Andric     if (GroupID == CurrentLoadBarrierGroupID)
2460b57cec5SDimitry Andric       CurrentLoadBarrierGroupID = 0;
247eaeb601bSDimitry Andric     if (GroupID == CurrentStoreBarrierGroupID)
248eaeb601bSDimitry Andric       CurrentStoreBarrierGroupID = 0;
2490b57cec5SDimitry Andric   }
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric 
2520b57cec5SDimitry Andric } // namespace mca
2530b57cec5SDimitry Andric } // namespace llvm
254