1343171Sdim//===----------------------- LSUnit.cpp --------------------------*- C++-*-===// 2343171Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343171Sdim// 7343171Sdim//===----------------------------------------------------------------------===// 8343171Sdim/// \file 9343171Sdim/// 10343171Sdim/// A Load-Store Unit for the llvm-mca tool. 11343171Sdim/// 12343171Sdim//===----------------------------------------------------------------------===// 13343171Sdim 14343171Sdim#include "llvm/MCA/HardwareUnits/LSUnit.h" 15343171Sdim#include "llvm/MCA/Instruction.h" 16343171Sdim#include "llvm/Support/Debug.h" 17343171Sdim#include "llvm/Support/raw_ostream.h" 18343171Sdim 19343171Sdim#define DEBUG_TYPE "llvm-mca" 20343171Sdim 21343171Sdimnamespace llvm { 22343171Sdimnamespace mca { 23343171Sdim 24353358SdimLSUnitBase::LSUnitBase(const MCSchedModel &SM, unsigned LQ, unsigned SQ, 25353358Sdim bool AssumeNoAlias) 26353358Sdim : LQSize(LQ), SQSize(SQ), UsedLQEntries(0), UsedSQEntries(0), 27353358Sdim NoAlias(AssumeNoAlias), NextGroupID(1) { 28343171Sdim if (SM.hasExtraProcessorInfo()) { 29343171Sdim const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo(); 30353358Sdim if (!LQSize && EPI.LoadQueueID) { 31343171Sdim const MCProcResourceDesc &LdQDesc = *SM.getProcResource(EPI.LoadQueueID); 32360784Sdim LQSize = std::max(0, LdQDesc.BufferSize); 33343171Sdim } 34343171Sdim 35353358Sdim if (!SQSize && EPI.StoreQueueID) { 36343171Sdim const MCProcResourceDesc &StQDesc = *SM.getProcResource(EPI.StoreQueueID); 37360784Sdim SQSize = std::max(0, StQDesc.BufferSize); 38343171Sdim } 39343171Sdim } 40343171Sdim} 41343171Sdim 42353358SdimLSUnitBase::~LSUnitBase() {} 43343171Sdim 44353358Sdimvoid LSUnitBase::cycleEvent() { 45353358Sdim for (const std::pair<unsigned, std::unique_ptr<MemoryGroup>> &G : Groups) 46353358Sdim G.second->cycleEvent(); 47343171Sdim} 48343171Sdim 49353358Sdim#ifndef NDEBUG 50353358Sdimvoid LSUnitBase::dump() const { 51353358Sdim dbgs() << "[LSUnit] LQ_Size = " << getLoadQueueSize() << '\n'; 52353358Sdim dbgs() << "[LSUnit] SQ_Size = " << getStoreQueueSize() << '\n'; 53353358Sdim dbgs() << "[LSUnit] NextLQSlotIdx = " << getUsedLQEntries() << '\n'; 54353358Sdim dbgs() << "[LSUnit] NextSQSlotIdx = " << getUsedSQEntries() << '\n'; 55353358Sdim dbgs() << "\n"; 56353358Sdim for (const auto &GroupIt : Groups) { 57353358Sdim const MemoryGroup &Group = *GroupIt.second; 58353358Sdim dbgs() << "[LSUnit] Group (" << GroupIt.first << "): " 59353358Sdim << "[ #Preds = " << Group.getNumPredecessors() 60353358Sdim << ", #GIssued = " << Group.getNumExecutingPredecessors() 61353358Sdim << ", #GExecuted = " << Group.getNumExecutedPredecessors() 62353358Sdim << ", #Inst = " << Group.getNumInstructions() 63353358Sdim << ", #IIssued = " << Group.getNumExecuting() 64353358Sdim << ", #IExecuted = " << Group.getNumExecuted() << '\n'; 65353358Sdim } 66343171Sdim} 67353358Sdim#endif 68343171Sdim 69353358Sdimunsigned LSUnit::dispatch(const InstRef &IR) { 70343171Sdim const InstrDesc &Desc = IR.getInstruction()->getDesc(); 71343171Sdim unsigned IsMemBarrier = Desc.HasSideEffects; 72343171Sdim assert((Desc.MayLoad || Desc.MayStore) && "Not a memory operation!"); 73343171Sdim 74353358Sdim if (Desc.MayLoad) 75360784Sdim acquireLQSlot(); 76353358Sdim if (Desc.MayStore) 77360784Sdim acquireSQSlot(); 78353358Sdim 79353358Sdim if (Desc.MayStore) { 80353358Sdim // Always create a new group for store operations. 81353358Sdim 82353358Sdim // A store may not pass a previous store or store barrier. 83353358Sdim unsigned NewGID = createMemoryGroup(); 84353358Sdim MemoryGroup &NewGroup = getGroup(NewGID); 85353358Sdim NewGroup.addInstruction(); 86353358Sdim 87353358Sdim // A store may not pass a previous load or load barrier. 88353358Sdim unsigned ImmediateLoadDominator = 89353358Sdim std::max(CurrentLoadGroupID, CurrentLoadBarrierGroupID); 90353358Sdim if (ImmediateLoadDominator) { 91353358Sdim MemoryGroup &IDom = getGroup(ImmediateLoadDominator); 92353358Sdim LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << ImmediateLoadDominator 93353358Sdim << ") --> (" << NewGID << ")\n"); 94353358Sdim IDom.addSuccessor(&NewGroup); 95353358Sdim } 96353358Sdim if (CurrentStoreGroupID) { 97353358Sdim MemoryGroup &StoreGroup = getGroup(CurrentStoreGroupID); 98353358Sdim LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID 99353358Sdim << ") --> (" << NewGID << ")\n"); 100353358Sdim StoreGroup.addSuccessor(&NewGroup); 101353358Sdim } 102353358Sdim 103353358Sdim CurrentStoreGroupID = NewGID; 104353358Sdim if (Desc.MayLoad) { 105353358Sdim CurrentLoadGroupID = NewGID; 106353358Sdim if (IsMemBarrier) 107353358Sdim CurrentLoadBarrierGroupID = NewGID; 108353358Sdim } 109353358Sdim 110353358Sdim return NewGID; 111343171Sdim } 112343171Sdim 113353358Sdim assert(Desc.MayLoad && "Expected a load!"); 114353358Sdim 115353358Sdim // Always create a new memory group if this is the first load of the sequence. 116353358Sdim 117353358Sdim // A load may not pass a previous store unless flag 'NoAlias' is set. 118353358Sdim // A load may pass a previous load. 119353358Sdim // A younger load cannot pass a older load barrier. 120353358Sdim // A load barrier cannot pass a older load. 121353358Sdim bool ShouldCreateANewGroup = !CurrentLoadGroupID || IsMemBarrier || 122353358Sdim CurrentLoadGroupID <= CurrentStoreGroupID || 123353358Sdim CurrentLoadGroupID <= CurrentLoadBarrierGroupID; 124353358Sdim if (ShouldCreateANewGroup) { 125353358Sdim unsigned NewGID = createMemoryGroup(); 126353358Sdim MemoryGroup &NewGroup = getGroup(NewGID); 127353358Sdim NewGroup.addInstruction(); 128353358Sdim 129353358Sdim if (!assumeNoAlias() && CurrentStoreGroupID) { 130353358Sdim MemoryGroup &StGroup = getGroup(CurrentStoreGroupID); 131353358Sdim LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID 132353358Sdim << ") --> (" << NewGID << ")\n"); 133353358Sdim StGroup.addSuccessor(&NewGroup); 134353358Sdim } 135353358Sdim if (CurrentLoadBarrierGroupID) { 136353358Sdim MemoryGroup &LdGroup = getGroup(CurrentLoadBarrierGroupID); 137353358Sdim LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentLoadBarrierGroupID 138353358Sdim << ") --> (" << NewGID << ")\n"); 139353358Sdim LdGroup.addSuccessor(&NewGroup); 140353358Sdim } 141353358Sdim 142353358Sdim CurrentLoadGroupID = NewGID; 143343171Sdim if (IsMemBarrier) 144353358Sdim CurrentLoadBarrierGroupID = NewGID; 145353358Sdim return NewGID; 146343171Sdim } 147353358Sdim 148353358Sdim MemoryGroup &Group = getGroup(CurrentLoadGroupID); 149353358Sdim Group.addInstruction(); 150353358Sdim return CurrentLoadGroupID; 151343171Sdim} 152343171Sdim 153343171SdimLSUnit::Status LSUnit::isAvailable(const InstRef &IR) const { 154343171Sdim const InstrDesc &Desc = IR.getInstruction()->getDesc(); 155343171Sdim if (Desc.MayLoad && isLQFull()) 156343171Sdim return LSUnit::LSU_LQUEUE_FULL; 157343171Sdim if (Desc.MayStore && isSQFull()) 158343171Sdim return LSUnit::LSU_SQUEUE_FULL; 159343171Sdim return LSUnit::LSU_AVAILABLE; 160343171Sdim} 161343171Sdim 162353358Sdimvoid LSUnitBase::onInstructionExecuted(const InstRef &IR) { 163360784Sdim unsigned GroupID = IR.getInstruction()->getLSUTokenID(); 164360784Sdim auto It = Groups.find(GroupID); 165360784Sdim assert(It != Groups.end() && "Instruction not dispatched to the LS unit"); 166360784Sdim It->second->onInstructionExecuted(); 167360784Sdim if (It->second->isExecuted()) 168360784Sdim Groups.erase(It); 169360784Sdim} 170360784Sdim 171360784Sdimvoid LSUnitBase::onInstructionRetired(const InstRef &IR) { 172343171Sdim const InstrDesc &Desc = IR.getInstruction()->getDesc(); 173343171Sdim bool IsALoad = Desc.MayLoad; 174343171Sdim bool IsAStore = Desc.MayStore; 175353358Sdim assert((IsALoad || IsAStore) && "Expected a memory operation!"); 176343171Sdim 177353358Sdim if (IsALoad) { 178360784Sdim releaseLQSlot(); 179353358Sdim LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex() 180353358Sdim << " has been removed from the load queue.\n"); 181343171Sdim } 182343171Sdim 183353358Sdim if (IsAStore) { 184360784Sdim releaseSQSlot(); 185353358Sdim LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex() 186353358Sdim << " has been removed from the store queue.\n"); 187343171Sdim } 188343171Sdim} 189343171Sdim 190343171Sdimvoid LSUnit::onInstructionExecuted(const InstRef &IR) { 191353358Sdim const Instruction &IS = *IR.getInstruction(); 192353358Sdim if (!IS.isMemOp()) 193353358Sdim return; 194343171Sdim 195353358Sdim LSUnitBase::onInstructionExecuted(IR); 196353358Sdim unsigned GroupID = IS.getLSUTokenID(); 197353358Sdim if (!isValidGroupID(GroupID)) { 198353358Sdim if (GroupID == CurrentLoadGroupID) 199353358Sdim CurrentLoadGroupID = 0; 200353358Sdim if (GroupID == CurrentStoreGroupID) 201353358Sdim CurrentStoreGroupID = 0; 202353358Sdim if (GroupID == CurrentLoadBarrierGroupID) 203353358Sdim CurrentLoadBarrierGroupID = 0; 204343171Sdim } 205343171Sdim} 206343171Sdim 207343171Sdim} // namespace mca 208343171Sdim} // namespace llvm 209