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