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 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 420b57cec5SDimitry Andric LSUnitBase::~LSUnitBase() {} 430b57cec5SDimitry Andric 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 500b57cec5SDimitry 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 690b57cec5SDimitry Andric unsigned LSUnit::dispatch(const InstRef &IR) { 700b57cec5SDimitry Andric const InstrDesc &Desc = IR.getInstruction()->getDesc(); 71*04eeddc0SDimitry Andric bool IsStoreBarrier = IR.getInstruction()->isAStoreBarrier(); 72*04eeddc0SDimitry Andric bool IsLoadBarrier = IR.getInstruction()->isALoadBarrier(); 730b57cec5SDimitry Andric assert((Desc.MayLoad || Desc.MayStore) && "Not a memory operation!"); 740b57cec5SDimitry Andric 750b57cec5SDimitry Andric if (Desc.MayLoad) 768bcb0991SDimitry Andric acquireLQSlot(); 770b57cec5SDimitry Andric if (Desc.MayStore) 788bcb0991SDimitry Andric acquireSQSlot(); 790b57cec5SDimitry Andric 800b57cec5SDimitry Andric if (Desc.MayStore) { 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; 115*04eeddc0SDimitry Andric if (IsStoreBarrier) 1165ffd83dbSDimitry Andric CurrentStoreBarrierGroupID = NewGID; 1175ffd83dbSDimitry Andric 1180b57cec5SDimitry Andric if (Desc.MayLoad) { 1190b57cec5SDimitry Andric CurrentLoadGroupID = NewGID; 120*04eeddc0SDimitry Andric if (IsLoadBarrier) 1210b57cec5SDimitry Andric CurrentLoadBarrierGroupID = NewGID; 1220b57cec5SDimitry Andric } 1230b57cec5SDimitry Andric 1240b57cec5SDimitry Andric return NewGID; 1250b57cec5SDimitry Andric } 1260b57cec5SDimitry Andric 1270b57cec5SDimitry Andric assert(Desc.MayLoad && "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 = 145*04eeddc0SDimitry 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. 165*04eeddc0SDimitry 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; 185*04eeddc0SDimitry 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 1960b57cec5SDimitry Andric LSUnit::Status LSUnit::isAvailable(const InstRef &IR) const { 1970b57cec5SDimitry Andric const InstrDesc &Desc = IR.getInstruction()->getDesc(); 1980b57cec5SDimitry Andric if (Desc.MayLoad && isLQFull()) 1990b57cec5SDimitry Andric return LSUnit::LSU_LQUEUE_FULL; 2000b57cec5SDimitry Andric if (Desc.MayStore && isSQFull()) 2010b57cec5SDimitry Andric return LSUnit::LSU_SQUEUE_FULL; 2020b57cec5SDimitry Andric return LSUnit::LSU_AVAILABLE; 2030b57cec5SDimitry Andric } 2040b57cec5SDimitry Andric 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 2148bcb0991SDimitry Andric void LSUnitBase::onInstructionRetired(const InstRef &IR) { 2150b57cec5SDimitry Andric const InstrDesc &Desc = IR.getInstruction()->getDesc(); 2160b57cec5SDimitry Andric bool IsALoad = Desc.MayLoad; 2170b57cec5SDimitry Andric bool IsAStore = Desc.MayStore; 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 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