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