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); 32*8bcb0991SDimitry 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); 37*8bcb0991SDimitry 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(); 710b57cec5SDimitry Andric unsigned IsMemBarrier = Desc.HasSideEffects; 720b57cec5SDimitry Andric assert((Desc.MayLoad || Desc.MayStore) && "Not a memory operation!"); 730b57cec5SDimitry Andric 740b57cec5SDimitry Andric if (Desc.MayLoad) 75*8bcb0991SDimitry Andric acquireLQSlot(); 760b57cec5SDimitry Andric if (Desc.MayStore) 77*8bcb0991SDimitry Andric acquireSQSlot(); 780b57cec5SDimitry Andric 790b57cec5SDimitry Andric if (Desc.MayStore) { 800b57cec5SDimitry Andric // Always create a new group for store operations. 810b57cec5SDimitry Andric 820b57cec5SDimitry Andric // A store may not pass a previous store or store barrier. 830b57cec5SDimitry Andric unsigned NewGID = createMemoryGroup(); 840b57cec5SDimitry Andric MemoryGroup &NewGroup = getGroup(NewGID); 850b57cec5SDimitry Andric NewGroup.addInstruction(); 860b57cec5SDimitry Andric 870b57cec5SDimitry Andric // A store may not pass a previous load or load barrier. 880b57cec5SDimitry Andric unsigned ImmediateLoadDominator = 890b57cec5SDimitry Andric std::max(CurrentLoadGroupID, CurrentLoadBarrierGroupID); 900b57cec5SDimitry Andric if (ImmediateLoadDominator) { 910b57cec5SDimitry Andric MemoryGroup &IDom = getGroup(ImmediateLoadDominator); 920b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << ImmediateLoadDominator 930b57cec5SDimitry Andric << ") --> (" << NewGID << ")\n"); 940b57cec5SDimitry Andric IDom.addSuccessor(&NewGroup); 950b57cec5SDimitry Andric } 960b57cec5SDimitry Andric if (CurrentStoreGroupID) { 970b57cec5SDimitry Andric MemoryGroup &StoreGroup = getGroup(CurrentStoreGroupID); 980b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID 990b57cec5SDimitry Andric << ") --> (" << NewGID << ")\n"); 1000b57cec5SDimitry Andric StoreGroup.addSuccessor(&NewGroup); 1010b57cec5SDimitry Andric } 1020b57cec5SDimitry Andric 1030b57cec5SDimitry Andric CurrentStoreGroupID = NewGID; 1040b57cec5SDimitry Andric if (Desc.MayLoad) { 1050b57cec5SDimitry Andric CurrentLoadGroupID = NewGID; 1060b57cec5SDimitry Andric if (IsMemBarrier) 1070b57cec5SDimitry Andric CurrentLoadBarrierGroupID = NewGID; 1080b57cec5SDimitry Andric } 1090b57cec5SDimitry Andric 1100b57cec5SDimitry Andric return NewGID; 1110b57cec5SDimitry Andric } 1120b57cec5SDimitry Andric 1130b57cec5SDimitry Andric assert(Desc.MayLoad && "Expected a load!"); 1140b57cec5SDimitry Andric 1150b57cec5SDimitry Andric // Always create a new memory group if this is the first load of the sequence. 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric // A load may not pass a previous store unless flag 'NoAlias' is set. 1180b57cec5SDimitry Andric // A load may pass a previous load. 1190b57cec5SDimitry Andric // A younger load cannot pass a older load barrier. 1200b57cec5SDimitry Andric // A load barrier cannot pass a older load. 1210b57cec5SDimitry Andric bool ShouldCreateANewGroup = !CurrentLoadGroupID || IsMemBarrier || 1220b57cec5SDimitry Andric CurrentLoadGroupID <= CurrentStoreGroupID || 1230b57cec5SDimitry Andric CurrentLoadGroupID <= CurrentLoadBarrierGroupID; 1240b57cec5SDimitry Andric if (ShouldCreateANewGroup) { 1250b57cec5SDimitry Andric unsigned NewGID = createMemoryGroup(); 1260b57cec5SDimitry Andric MemoryGroup &NewGroup = getGroup(NewGID); 1270b57cec5SDimitry Andric NewGroup.addInstruction(); 1280b57cec5SDimitry Andric 1290b57cec5SDimitry Andric if (!assumeNoAlias() && CurrentStoreGroupID) { 1300b57cec5SDimitry Andric MemoryGroup &StGroup = getGroup(CurrentStoreGroupID); 1310b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID 1320b57cec5SDimitry Andric << ") --> (" << NewGID << ")\n"); 1330b57cec5SDimitry Andric StGroup.addSuccessor(&NewGroup); 1340b57cec5SDimitry Andric } 1350b57cec5SDimitry Andric if (CurrentLoadBarrierGroupID) { 1360b57cec5SDimitry Andric MemoryGroup &LdGroup = getGroup(CurrentLoadBarrierGroupID); 1370b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentLoadBarrierGroupID 1380b57cec5SDimitry Andric << ") --> (" << NewGID << ")\n"); 1390b57cec5SDimitry Andric LdGroup.addSuccessor(&NewGroup); 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric CurrentLoadGroupID = NewGID; 1430b57cec5SDimitry Andric if (IsMemBarrier) 1440b57cec5SDimitry Andric CurrentLoadBarrierGroupID = NewGID; 1450b57cec5SDimitry Andric return NewGID; 1460b57cec5SDimitry Andric } 1470b57cec5SDimitry Andric 1480b57cec5SDimitry Andric MemoryGroup &Group = getGroup(CurrentLoadGroupID); 1490b57cec5SDimitry Andric Group.addInstruction(); 1500b57cec5SDimitry Andric return CurrentLoadGroupID; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric LSUnit::Status LSUnit::isAvailable(const InstRef &IR) const { 1540b57cec5SDimitry Andric const InstrDesc &Desc = IR.getInstruction()->getDesc(); 1550b57cec5SDimitry Andric if (Desc.MayLoad && isLQFull()) 1560b57cec5SDimitry Andric return LSUnit::LSU_LQUEUE_FULL; 1570b57cec5SDimitry Andric if (Desc.MayStore && isSQFull()) 1580b57cec5SDimitry Andric return LSUnit::LSU_SQUEUE_FULL; 1590b57cec5SDimitry Andric return LSUnit::LSU_AVAILABLE; 1600b57cec5SDimitry Andric } 1610b57cec5SDimitry Andric 1620b57cec5SDimitry Andric void LSUnitBase::onInstructionExecuted(const InstRef &IR) { 163*8bcb0991SDimitry Andric unsigned GroupID = IR.getInstruction()->getLSUTokenID(); 164*8bcb0991SDimitry Andric auto It = Groups.find(GroupID); 165*8bcb0991SDimitry Andric assert(It != Groups.end() && "Instruction not dispatched to the LS unit"); 166*8bcb0991SDimitry Andric It->second->onInstructionExecuted(); 167*8bcb0991SDimitry Andric if (It->second->isExecuted()) 168*8bcb0991SDimitry Andric Groups.erase(It); 169*8bcb0991SDimitry Andric } 170*8bcb0991SDimitry Andric 171*8bcb0991SDimitry Andric void LSUnitBase::onInstructionRetired(const InstRef &IR) { 1720b57cec5SDimitry Andric const InstrDesc &Desc = IR.getInstruction()->getDesc(); 1730b57cec5SDimitry Andric bool IsALoad = Desc.MayLoad; 1740b57cec5SDimitry Andric bool IsAStore = Desc.MayStore; 1750b57cec5SDimitry Andric assert((IsALoad || IsAStore) && "Expected a memory operation!"); 1760b57cec5SDimitry Andric 1770b57cec5SDimitry Andric if (IsALoad) { 178*8bcb0991SDimitry Andric releaseLQSlot(); 1790b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex() 1800b57cec5SDimitry Andric << " has been removed from the load queue.\n"); 1810b57cec5SDimitry Andric } 1820b57cec5SDimitry Andric 1830b57cec5SDimitry Andric if (IsAStore) { 184*8bcb0991SDimitry Andric releaseSQSlot(); 1850b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex() 1860b57cec5SDimitry Andric << " has been removed from the store queue.\n"); 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric } 1890b57cec5SDimitry Andric 1900b57cec5SDimitry Andric void LSUnit::onInstructionExecuted(const InstRef &IR) { 1910b57cec5SDimitry Andric const Instruction &IS = *IR.getInstruction(); 1920b57cec5SDimitry Andric if (!IS.isMemOp()) 1930b57cec5SDimitry Andric return; 1940b57cec5SDimitry Andric 1950b57cec5SDimitry Andric LSUnitBase::onInstructionExecuted(IR); 1960b57cec5SDimitry Andric unsigned GroupID = IS.getLSUTokenID(); 1970b57cec5SDimitry Andric if (!isValidGroupID(GroupID)) { 1980b57cec5SDimitry Andric if (GroupID == CurrentLoadGroupID) 1990b57cec5SDimitry Andric CurrentLoadGroupID = 0; 2000b57cec5SDimitry Andric if (GroupID == CurrentStoreGroupID) 2010b57cec5SDimitry Andric CurrentStoreGroupID = 0; 2020b57cec5SDimitry Andric if (GroupID == CurrentLoadBarrierGroupID) 2030b57cec5SDimitry Andric CurrentLoadBarrierGroupID = 0; 2040b57cec5SDimitry Andric } 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric 2070b57cec5SDimitry Andric } // namespace mca 2080b57cec5SDimitry Andric } // namespace llvm 209