xref: /freebsd/contrib/llvm-project/llvm/lib/MCA/HardwareUnits/LSUnit.cpp (revision 0b57cec536236d46e3dba9bd041533462f33dbb7)
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