1*0b57cec5SDimitry Andric //===----------------------- LSUnit.cpp --------------------------*- C++-*-===// 2*0b57cec5SDimitry Andric // 3*0b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0b57cec5SDimitry Andric // 7*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 8*0b57cec5SDimitry Andric /// \file 9*0b57cec5SDimitry Andric /// 10*0b57cec5SDimitry Andric /// A Load-Store Unit for the llvm-mca tool. 11*0b57cec5SDimitry Andric /// 12*0b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 13*0b57cec5SDimitry Andric 14*0b57cec5SDimitry Andric #include "llvm/MCA/HardwareUnits/LSUnit.h" 15*0b57cec5SDimitry Andric #include "llvm/MCA/Instruction.h" 16*0b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 17*0b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 18*0b57cec5SDimitry Andric 19*0b57cec5SDimitry Andric #define DEBUG_TYPE "llvm-mca" 20*0b57cec5SDimitry Andric 21*0b57cec5SDimitry Andric namespace llvm { 22*0b57cec5SDimitry Andric namespace mca { 23*0b57cec5SDimitry Andric 24*0b57cec5SDimitry Andric LSUnitBase::LSUnitBase(const MCSchedModel &SM, unsigned LQ, unsigned SQ, 25*0b57cec5SDimitry Andric bool AssumeNoAlias) 26*0b57cec5SDimitry Andric : LQSize(LQ), SQSize(SQ), UsedLQEntries(0), UsedSQEntries(0), 27*0b57cec5SDimitry Andric NoAlias(AssumeNoAlias), NextGroupID(1) { 28*0b57cec5SDimitry Andric if (SM.hasExtraProcessorInfo()) { 29*0b57cec5SDimitry Andric const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo(); 30*0b57cec5SDimitry Andric if (!LQSize && EPI.LoadQueueID) { 31*0b57cec5SDimitry Andric const MCProcResourceDesc &LdQDesc = *SM.getProcResource(EPI.LoadQueueID); 32*0b57cec5SDimitry Andric LQSize = LdQDesc.BufferSize; 33*0b57cec5SDimitry Andric } 34*0b57cec5SDimitry Andric 35*0b57cec5SDimitry Andric if (!SQSize && EPI.StoreQueueID) { 36*0b57cec5SDimitry Andric const MCProcResourceDesc &StQDesc = *SM.getProcResource(EPI.StoreQueueID); 37*0b57cec5SDimitry Andric SQSize = StQDesc.BufferSize; 38*0b57cec5SDimitry Andric } 39*0b57cec5SDimitry Andric } 40*0b57cec5SDimitry Andric } 41*0b57cec5SDimitry Andric 42*0b57cec5SDimitry Andric LSUnitBase::~LSUnitBase() {} 43*0b57cec5SDimitry Andric 44*0b57cec5SDimitry Andric void LSUnitBase::cycleEvent() { 45*0b57cec5SDimitry Andric for (const std::pair<unsigned, std::unique_ptr<MemoryGroup>> &G : Groups) 46*0b57cec5SDimitry Andric G.second->cycleEvent(); 47*0b57cec5SDimitry Andric } 48*0b57cec5SDimitry Andric 49*0b57cec5SDimitry Andric #ifndef NDEBUG 50*0b57cec5SDimitry Andric void LSUnitBase::dump() const { 51*0b57cec5SDimitry Andric dbgs() << "[LSUnit] LQ_Size = " << getLoadQueueSize() << '\n'; 52*0b57cec5SDimitry Andric dbgs() << "[LSUnit] SQ_Size = " << getStoreQueueSize() << '\n'; 53*0b57cec5SDimitry Andric dbgs() << "[LSUnit] NextLQSlotIdx = " << getUsedLQEntries() << '\n'; 54*0b57cec5SDimitry Andric dbgs() << "[LSUnit] NextSQSlotIdx = " << getUsedSQEntries() << '\n'; 55*0b57cec5SDimitry Andric dbgs() << "\n"; 56*0b57cec5SDimitry Andric for (const auto &GroupIt : Groups) { 57*0b57cec5SDimitry Andric const MemoryGroup &Group = *GroupIt.second; 58*0b57cec5SDimitry Andric dbgs() << "[LSUnit] Group (" << GroupIt.first << "): " 59*0b57cec5SDimitry Andric << "[ #Preds = " << Group.getNumPredecessors() 60*0b57cec5SDimitry Andric << ", #GIssued = " << Group.getNumExecutingPredecessors() 61*0b57cec5SDimitry Andric << ", #GExecuted = " << Group.getNumExecutedPredecessors() 62*0b57cec5SDimitry Andric << ", #Inst = " << Group.getNumInstructions() 63*0b57cec5SDimitry Andric << ", #IIssued = " << Group.getNumExecuting() 64*0b57cec5SDimitry Andric << ", #IExecuted = " << Group.getNumExecuted() << '\n'; 65*0b57cec5SDimitry Andric } 66*0b57cec5SDimitry Andric } 67*0b57cec5SDimitry Andric #endif 68*0b57cec5SDimitry Andric 69*0b57cec5SDimitry Andric unsigned LSUnit::dispatch(const InstRef &IR) { 70*0b57cec5SDimitry Andric const InstrDesc &Desc = IR.getInstruction()->getDesc(); 71*0b57cec5SDimitry Andric unsigned IsMemBarrier = Desc.HasSideEffects; 72*0b57cec5SDimitry Andric assert((Desc.MayLoad || Desc.MayStore) && "Not a memory operation!"); 73*0b57cec5SDimitry Andric 74*0b57cec5SDimitry Andric if (Desc.MayLoad) 75*0b57cec5SDimitry Andric assignLQSlot(); 76*0b57cec5SDimitry Andric if (Desc.MayStore) 77*0b57cec5SDimitry Andric assignSQSlot(); 78*0b57cec5SDimitry Andric 79*0b57cec5SDimitry Andric if (Desc.MayStore) { 80*0b57cec5SDimitry Andric // Always create a new group for store operations. 81*0b57cec5SDimitry Andric 82*0b57cec5SDimitry Andric // A store may not pass a previous store or store barrier. 83*0b57cec5SDimitry Andric unsigned NewGID = createMemoryGroup(); 84*0b57cec5SDimitry Andric MemoryGroup &NewGroup = getGroup(NewGID); 85*0b57cec5SDimitry Andric NewGroup.addInstruction(); 86*0b57cec5SDimitry Andric 87*0b57cec5SDimitry Andric // A store may not pass a previous load or load barrier. 88*0b57cec5SDimitry Andric unsigned ImmediateLoadDominator = 89*0b57cec5SDimitry Andric std::max(CurrentLoadGroupID, CurrentLoadBarrierGroupID); 90*0b57cec5SDimitry Andric if (ImmediateLoadDominator) { 91*0b57cec5SDimitry Andric MemoryGroup &IDom = getGroup(ImmediateLoadDominator); 92*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << ImmediateLoadDominator 93*0b57cec5SDimitry Andric << ") --> (" << NewGID << ")\n"); 94*0b57cec5SDimitry Andric IDom.addSuccessor(&NewGroup); 95*0b57cec5SDimitry Andric } 96*0b57cec5SDimitry Andric if (CurrentStoreGroupID) { 97*0b57cec5SDimitry Andric MemoryGroup &StoreGroup = getGroup(CurrentStoreGroupID); 98*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID 99*0b57cec5SDimitry Andric << ") --> (" << NewGID << ")\n"); 100*0b57cec5SDimitry Andric StoreGroup.addSuccessor(&NewGroup); 101*0b57cec5SDimitry Andric } 102*0b57cec5SDimitry Andric 103*0b57cec5SDimitry Andric CurrentStoreGroupID = NewGID; 104*0b57cec5SDimitry Andric if (Desc.MayLoad) { 105*0b57cec5SDimitry Andric CurrentLoadGroupID = NewGID; 106*0b57cec5SDimitry Andric if (IsMemBarrier) 107*0b57cec5SDimitry Andric CurrentLoadBarrierGroupID = NewGID; 108*0b57cec5SDimitry Andric } 109*0b57cec5SDimitry Andric 110*0b57cec5SDimitry Andric return NewGID; 111*0b57cec5SDimitry Andric } 112*0b57cec5SDimitry Andric 113*0b57cec5SDimitry Andric assert(Desc.MayLoad && "Expected a load!"); 114*0b57cec5SDimitry Andric 115*0b57cec5SDimitry Andric // Always create a new memory group if this is the first load of the sequence. 116*0b57cec5SDimitry Andric 117*0b57cec5SDimitry Andric // A load may not pass a previous store unless flag 'NoAlias' is set. 118*0b57cec5SDimitry Andric // A load may pass a previous load. 119*0b57cec5SDimitry Andric // A younger load cannot pass a older load barrier. 120*0b57cec5SDimitry Andric // A load barrier cannot pass a older load. 121*0b57cec5SDimitry Andric bool ShouldCreateANewGroup = !CurrentLoadGroupID || IsMemBarrier || 122*0b57cec5SDimitry Andric CurrentLoadGroupID <= CurrentStoreGroupID || 123*0b57cec5SDimitry Andric CurrentLoadGroupID <= CurrentLoadBarrierGroupID; 124*0b57cec5SDimitry Andric if (ShouldCreateANewGroup) { 125*0b57cec5SDimitry Andric unsigned NewGID = createMemoryGroup(); 126*0b57cec5SDimitry Andric MemoryGroup &NewGroup = getGroup(NewGID); 127*0b57cec5SDimitry Andric NewGroup.addInstruction(); 128*0b57cec5SDimitry Andric 129*0b57cec5SDimitry Andric if (!assumeNoAlias() && CurrentStoreGroupID) { 130*0b57cec5SDimitry Andric MemoryGroup &StGroup = getGroup(CurrentStoreGroupID); 131*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID 132*0b57cec5SDimitry Andric << ") --> (" << NewGID << ")\n"); 133*0b57cec5SDimitry Andric StGroup.addSuccessor(&NewGroup); 134*0b57cec5SDimitry Andric } 135*0b57cec5SDimitry Andric if (CurrentLoadBarrierGroupID) { 136*0b57cec5SDimitry Andric MemoryGroup &LdGroup = getGroup(CurrentLoadBarrierGroupID); 137*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentLoadBarrierGroupID 138*0b57cec5SDimitry Andric << ") --> (" << NewGID << ")\n"); 139*0b57cec5SDimitry Andric LdGroup.addSuccessor(&NewGroup); 140*0b57cec5SDimitry Andric } 141*0b57cec5SDimitry Andric 142*0b57cec5SDimitry Andric CurrentLoadGroupID = NewGID; 143*0b57cec5SDimitry Andric if (IsMemBarrier) 144*0b57cec5SDimitry Andric CurrentLoadBarrierGroupID = NewGID; 145*0b57cec5SDimitry Andric return NewGID; 146*0b57cec5SDimitry Andric } 147*0b57cec5SDimitry Andric 148*0b57cec5SDimitry Andric MemoryGroup &Group = getGroup(CurrentLoadGroupID); 149*0b57cec5SDimitry Andric Group.addInstruction(); 150*0b57cec5SDimitry Andric return CurrentLoadGroupID; 151*0b57cec5SDimitry Andric } 152*0b57cec5SDimitry Andric 153*0b57cec5SDimitry Andric LSUnit::Status LSUnit::isAvailable(const InstRef &IR) const { 154*0b57cec5SDimitry Andric const InstrDesc &Desc = IR.getInstruction()->getDesc(); 155*0b57cec5SDimitry Andric if (Desc.MayLoad && isLQFull()) 156*0b57cec5SDimitry Andric return LSUnit::LSU_LQUEUE_FULL; 157*0b57cec5SDimitry Andric if (Desc.MayStore && isSQFull()) 158*0b57cec5SDimitry Andric return LSUnit::LSU_SQUEUE_FULL; 159*0b57cec5SDimitry Andric return LSUnit::LSU_AVAILABLE; 160*0b57cec5SDimitry Andric } 161*0b57cec5SDimitry Andric 162*0b57cec5SDimitry Andric void LSUnitBase::onInstructionExecuted(const InstRef &IR) { 163*0b57cec5SDimitry Andric const InstrDesc &Desc = IR.getInstruction()->getDesc(); 164*0b57cec5SDimitry Andric bool IsALoad = Desc.MayLoad; 165*0b57cec5SDimitry Andric bool IsAStore = Desc.MayStore; 166*0b57cec5SDimitry Andric assert((IsALoad || IsAStore) && "Expected a memory operation!"); 167*0b57cec5SDimitry Andric 168*0b57cec5SDimitry Andric unsigned GroupID = IR.getInstruction()->getLSUTokenID(); 169*0b57cec5SDimitry Andric auto It = Groups.find(GroupID); 170*0b57cec5SDimitry Andric It->second->onInstructionExecuted(); 171*0b57cec5SDimitry Andric if (It->second->isExecuted()) { 172*0b57cec5SDimitry Andric Groups.erase(It); 173*0b57cec5SDimitry Andric } 174*0b57cec5SDimitry Andric 175*0b57cec5SDimitry Andric if (IsALoad) { 176*0b57cec5SDimitry Andric UsedLQEntries--; 177*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex() 178*0b57cec5SDimitry Andric << " has been removed from the load queue.\n"); 179*0b57cec5SDimitry Andric } 180*0b57cec5SDimitry Andric 181*0b57cec5SDimitry Andric if (IsAStore) { 182*0b57cec5SDimitry Andric UsedSQEntries--; 183*0b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex() 184*0b57cec5SDimitry Andric << " has been removed from the store queue.\n"); 185*0b57cec5SDimitry Andric } 186*0b57cec5SDimitry Andric } 187*0b57cec5SDimitry Andric 188*0b57cec5SDimitry Andric void LSUnit::onInstructionExecuted(const InstRef &IR) { 189*0b57cec5SDimitry Andric const Instruction &IS = *IR.getInstruction(); 190*0b57cec5SDimitry Andric if (!IS.isMemOp()) 191*0b57cec5SDimitry Andric return; 192*0b57cec5SDimitry Andric 193*0b57cec5SDimitry Andric LSUnitBase::onInstructionExecuted(IR); 194*0b57cec5SDimitry Andric unsigned GroupID = IS.getLSUTokenID(); 195*0b57cec5SDimitry Andric if (!isValidGroupID(GroupID)) { 196*0b57cec5SDimitry Andric if (GroupID == CurrentLoadGroupID) 197*0b57cec5SDimitry Andric CurrentLoadGroupID = 0; 198*0b57cec5SDimitry Andric if (GroupID == CurrentStoreGroupID) 199*0b57cec5SDimitry Andric CurrentStoreGroupID = 0; 200*0b57cec5SDimitry Andric if (GroupID == CurrentLoadBarrierGroupID) 201*0b57cec5SDimitry Andric CurrentLoadBarrierGroupID = 0; 202*0b57cec5SDimitry Andric } 203*0b57cec5SDimitry Andric } 204*0b57cec5SDimitry Andric 205*0b57cec5SDimitry Andric } // namespace mca 206*0b57cec5SDimitry Andric } // namespace llvm 207