#include "llvm/MCA/HardwareUnits/LSUnit.h"
#include "llvm/MCA/Instruction.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
#define DEBUG_TYPE "llvm-mca"
namespace llvm {
namespace mca {
LSUnitBase::LSUnitBase(const MCSchedModel &SM, unsigned LQ, unsigned SQ,
bool AssumeNoAlias)
: LQSize(LQ), SQSize(SQ), UsedLQEntries(0), UsedSQEntries(0),
NoAlias(AssumeNoAlias), NextGroupID(1) {
if (SM.hasExtraProcessorInfo()) {
const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo();
if (!LQSize && EPI.LoadQueueID) {
const MCProcResourceDesc &LdQDesc = *SM.getProcResource(EPI.LoadQueueID);
LQSize = std::max(0, LdQDesc.BufferSize);
}
if (!SQSize && EPI.StoreQueueID) {
const MCProcResourceDesc &StQDesc = *SM.getProcResource(EPI.StoreQueueID);
SQSize = std::max(0, StQDesc.BufferSize);
}
}
}
LSUnitBase::~LSUnitBase() = default;
void LSUnitBase::cycleEvent() {
for (const std::pair<unsigned, std::unique_ptr<MemoryGroup>> &G : Groups)
G.second->cycleEvent();
}
#ifndef NDEBUG
void LSUnitBase::dump() const {
dbgs() << "[LSUnit] LQ_Size = " << getLoadQueueSize() << '\n';
dbgs() << "[LSUnit] SQ_Size = " << getStoreQueueSize() << '\n';
dbgs() << "[LSUnit] NextLQSlotIdx = " << getUsedLQEntries() << '\n';
dbgs() << "[LSUnit] NextSQSlotIdx = " << getUsedSQEntries() << '\n';
dbgs() << "\n";
for (const auto &GroupIt : Groups) {
const MemoryGroup &Group = *GroupIt.second;
dbgs() << "[LSUnit] Group (" << GroupIt.first << "): "
<< "[ #Preds = " << Group.getNumPredecessors()
<< ", #GIssued = " << Group.getNumExecutingPredecessors()
<< ", #GExecuted = " << Group.getNumExecutedPredecessors()
<< ", #Inst = " << Group.getNumInstructions()
<< ", #IIssued = " << Group.getNumExecuting()
<< ", #IExecuted = " << Group.getNumExecuted() << '\n';
}
}
#endif
unsigned LSUnit::dispatch(const InstRef &IR) {
const Instruction &IS = *IR.getInstruction();
bool IsStoreBarrier = IS.isAStoreBarrier();
bool IsLoadBarrier = IS.isALoadBarrier();
assert((IS.getMayLoad() || IS.getMayStore()) && "Not a memory operation!");
if (IS.getMayLoad())
acquireLQSlot();
if (IS.getMayStore())
acquireSQSlot();
if (IS.getMayStore()) {
unsigned NewGID = createMemoryGroup();
MemoryGroup &NewGroup = getGroup(NewGID);
NewGroup.addInstruction();
unsigned ImmediateLoadDominator =
std::max(CurrentLoadGroupID, CurrentLoadBarrierGroupID);
if (ImmediateLoadDominator) {
MemoryGroup &IDom = getGroup(ImmediateLoadDominator);
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << ImmediateLoadDominator
<< ") --> (" << NewGID << ")\n");
IDom.addSuccessor(&NewGroup, !assumeNoAlias());
}
if (CurrentStoreBarrierGroupID) {
MemoryGroup &StoreGroup = getGroup(CurrentStoreBarrierGroupID);
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: ("
<< CurrentStoreBarrierGroupID
<< ") --> (" << NewGID << ")\n");
StoreGroup.addSuccessor(&NewGroup, true);
}
if (CurrentStoreGroupID &&
(CurrentStoreGroupID != CurrentStoreBarrierGroupID)) {
MemoryGroup &StoreGroup = getGroup(CurrentStoreGroupID);
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID
<< ") --> (" << NewGID << ")\n");
StoreGroup.addSuccessor(&NewGroup, !assumeNoAlias());
}
CurrentStoreGroupID = NewGID;
if (IsStoreBarrier)
CurrentStoreBarrierGroupID = NewGID;
if (IS.getMayLoad()) {
CurrentLoadGroupID = NewGID;
if (IsLoadBarrier)
CurrentLoadBarrierGroupID = NewGID;
}
return NewGID;
}
assert(IS.getMayLoad() && "Expected a load!");
unsigned ImmediateLoadDominator =
std::max(CurrentLoadGroupID, CurrentLoadBarrierGroupID);
bool ShouldCreateANewGroup =
IsLoadBarrier || !ImmediateLoadDominator ||
CurrentLoadBarrierGroupID == ImmediateLoadDominator ||
ImmediateLoadDominator <= CurrentStoreGroupID ||
getGroup(ImmediateLoadDominator).isExecuting();
if (ShouldCreateANewGroup) {
unsigned NewGID = createMemoryGroup();
MemoryGroup &NewGroup = getGroup(NewGID);
NewGroup.addInstruction();
if (!assumeNoAlias() && CurrentStoreGroupID) {
MemoryGroup &StoreGroup = getGroup(CurrentStoreGroupID);
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID
<< ") --> (" << NewGID << ")\n");
StoreGroup.addSuccessor(&NewGroup, true);
}
if (IsLoadBarrier) {
if (ImmediateLoadDominator) {
MemoryGroup &LoadGroup = getGroup(ImmediateLoadDominator);
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: ("
<< ImmediateLoadDominator
<< ") --> (" << NewGID << ")\n");
LoadGroup.addSuccessor(&NewGroup, true);
}
} else {
if (CurrentLoadBarrierGroupID) {
MemoryGroup &LoadGroup = getGroup(CurrentLoadBarrierGroupID);
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: ("
<< CurrentLoadBarrierGroupID
<< ") --> (" << NewGID << ")\n");
LoadGroup.addSuccessor(&NewGroup, true);
}
}
CurrentLoadGroupID = NewGID;
if (IsLoadBarrier)
CurrentLoadBarrierGroupID = NewGID;
return NewGID;
}
MemoryGroup &Group = getGroup(CurrentLoadGroupID);
Group.addInstruction();
return CurrentLoadGroupID;
}
LSUnit::Status LSUnit::isAvailable(const InstRef &IR) const {
const Instruction &IS = *IR.getInstruction();
if (IS.getMayLoad() && isLQFull())
return LSUnit::LSU_LQUEUE_FULL;
if (IS.getMayStore() && isSQFull())
return LSUnit::LSU_SQUEUE_FULL;
return LSUnit::LSU_AVAILABLE;
}
void LSUnitBase::onInstructionExecuted(const InstRef &IR) {
unsigned GroupID = IR.getInstruction()->getLSUTokenID();
auto It = Groups.find(GroupID);
assert(It != Groups.end() && "Instruction not dispatched to the LS unit");
It->second->onInstructionExecuted(IR);
if (It->second->isExecuted())
Groups.erase(It);
}
void LSUnitBase::onInstructionRetired(const InstRef &IR) {
const Instruction &IS = *IR.getInstruction();
bool IsALoad = IS.getMayLoad();
bool IsAStore = IS.getMayStore();
assert((IsALoad || IsAStore) && "Expected a memory operation!");
if (IsALoad) {
releaseLQSlot();
LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex()
<< " has been removed from the load queue.\n");
}
if (IsAStore) {
releaseSQSlot();
LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex()
<< " has been removed from the store queue.\n");
}
}
void LSUnit::onInstructionExecuted(const InstRef &IR) {
const Instruction &IS = *IR.getInstruction();
if (!IS.isMemOp())
return;
LSUnitBase::onInstructionExecuted(IR);
unsigned GroupID = IS.getLSUTokenID();
if (!isValidGroupID(GroupID)) {
if (GroupID == CurrentLoadGroupID)
CurrentLoadGroupID = 0;
if (GroupID == CurrentStoreGroupID)
CurrentStoreGroupID = 0;
if (GroupID == CurrentLoadBarrierGroupID)
CurrentLoadBarrierGroupID = 0;
if (GroupID == CurrentStoreBarrierGroupID)
CurrentStoreBarrierGroupID = 0;
}
}
} }