xref: /llvm-project/llvm/lib/MCA/HardwareUnits/LSUnit.cpp (revision 5ad52e35a8e40aacb77cdb59c10f1b19c6ca1ee2)
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 LSUnit::LSUnit(const MCSchedModel &SM, unsigned LQ, unsigned SQ,
25                bool AssumeNoAlias)
26     : LQ_Size(LQ), SQ_Size(SQ), NoAlias(AssumeNoAlias) {
27   if (SM.hasExtraProcessorInfo()) {
28     const MCExtraProcessorInfo &EPI = SM.getExtraProcessorInfo();
29     if (!LQ_Size && EPI.LoadQueueID) {
30       const MCProcResourceDesc &LdQDesc = *SM.getProcResource(EPI.LoadQueueID);
31       LQ_Size = LdQDesc.BufferSize;
32     }
33 
34     if (!SQ_Size && EPI.StoreQueueID) {
35       const MCProcResourceDesc &StQDesc = *SM.getProcResource(EPI.StoreQueueID);
36       SQ_Size = StQDesc.BufferSize;
37     }
38   }
39 }
40 
41 #ifndef NDEBUG
42 void LSUnit::dump() const {
43   dbgs() << "[LSUnit] LQ_Size = " << LQ_Size << '\n';
44   dbgs() << "[LSUnit] SQ_Size = " << SQ_Size << '\n';
45   dbgs() << "[LSUnit] NextLQSlotIdx = " << LoadQueue.size() << '\n';
46   dbgs() << "[LSUnit] NextSQSlotIdx = " << StoreQueue.size() << '\n';
47 }
48 #endif
49 
50 void LSUnit::assignLQSlot(unsigned Index) {
51   assert(!isLQFull());
52   assert(LoadQueue.count(Index) == 0);
53 
54   LLVM_DEBUG(dbgs() << "[LSUnit] - AssignLQSlot <Idx=" << Index
55                     << ",slot=" << LoadQueue.size() << ">\n");
56   LoadQueue.insert(Index);
57 }
58 
59 void LSUnit::assignSQSlot(unsigned Index) {
60   assert(!isSQFull());
61   assert(StoreQueue.count(Index) == 0);
62 
63   LLVM_DEBUG(dbgs() << "[LSUnit] - AssignSQSlot <Idx=" << Index
64                     << ",slot=" << StoreQueue.size() << ">\n");
65   StoreQueue.insert(Index);
66 }
67 
68 void LSUnit::dispatch(const InstRef &IR) {
69   const InstrDesc &Desc = IR.getInstruction()->getDesc();
70   unsigned IsMemBarrier = Desc.HasSideEffects;
71   assert((Desc.MayLoad || Desc.MayStore) && "Not a memory operation!");
72 
73   const unsigned Index = IR.getSourceIndex();
74   if (Desc.MayLoad) {
75     if (IsMemBarrier)
76       LoadBarriers.insert(Index);
77     assignLQSlot(Index);
78   }
79 
80   if (Desc.MayStore) {
81     if (IsMemBarrier)
82       StoreBarriers.insert(Index);
83     assignSQSlot(Index);
84   }
85 }
86 
87 LSUnit::Status LSUnit::isAvailable(const InstRef &IR) const {
88   const InstrDesc &Desc = IR.getInstruction()->getDesc();
89   if (Desc.MayLoad && isLQFull())
90     return LSUnit::LSU_LQUEUE_FULL;
91   if (Desc.MayStore && isSQFull())
92     return LSUnit::LSU_SQUEUE_FULL;
93   return LSUnit::LSU_AVAILABLE;
94 }
95 
96 unsigned LSUnit::isReady(const InstRef &IR) const {
97   const InstrDesc &Desc = IR.getInstruction()->getDesc();
98   const unsigned Index = IR.getSourceIndex();
99   bool IsALoad = Desc.MayLoad;
100   bool IsAStore = Desc.MayStore;
101   assert((IsALoad || IsAStore) && "Not a memory operation!");
102   assert((!IsALoad || LoadQueue.count(Index) == 1) && "Load not in queue!");
103   assert((!IsAStore || StoreQueue.count(Index) == 1) && "Store not in queue!");
104 
105   if (IsALoad && !LoadBarriers.empty()) {
106     unsigned LoadBarrierIndex = *LoadBarriers.begin();
107     // A younger load cannot pass a older load barrier.
108     if (Index > LoadBarrierIndex)
109       return LoadBarrierIndex;
110     // A load barrier cannot pass a older load.
111     if (Index == LoadBarrierIndex && Index != *LoadQueue.begin())
112       return *LoadQueue.begin();
113   }
114 
115   if (IsAStore && !StoreBarriers.empty()) {
116     unsigned StoreBarrierIndex = *StoreBarriers.begin();
117     // A younger store cannot pass a older store barrier.
118     if (Index > StoreBarrierIndex)
119       return StoreBarrierIndex;
120     // A store barrier cannot pass a older store.
121     if (Index == StoreBarrierIndex && Index != *StoreQueue.begin())
122       return *StoreQueue.begin();
123   }
124 
125   // A load may not pass a previous store unless flag 'NoAlias' is set.
126   // A load may pass a previous load.
127   if (NoAlias && IsALoad)
128     return Index;
129 
130   if (StoreQueue.size()) {
131     // A load may not pass a previous store.
132     // A store may not pass a previous store.
133     if (Index > *StoreQueue.begin())
134       return *StoreQueue.begin();
135   }
136 
137   // Okay, we are older than the oldest store in the queue.
138   // If there are no pending loads, then we can say for sure that this
139   // instruction is ready.
140   if (isLQEmpty())
141     return Index;
142 
143   // Check if there are no older loads.
144   if (Index <= *LoadQueue.begin())
145     return Index;
146 
147   // There is at least one younger load.
148   //
149   // A load may pass a previous load.
150   if (IsALoad)
151     return Index;
152 
153   // A store may not pass a previous load.
154   return *LoadQueue.begin();
155 }
156 
157 void LSUnit::onInstructionExecuted(const InstRef &IR) {
158   const InstrDesc &Desc = IR.getInstruction()->getDesc();
159   const unsigned Index = IR.getSourceIndex();
160   bool IsALoad = Desc.MayLoad;
161   bool IsAStore = Desc.MayStore;
162 
163   if (IsALoad) {
164     if (LoadQueue.erase(Index)) {
165       LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index
166                         << " has been removed from the load queue.\n");
167     }
168     if (!LoadBarriers.empty() && Index == *LoadBarriers.begin()) {
169       LLVM_DEBUG(
170           dbgs() << "[LSUnit]: Instruction idx=" << Index
171                  << " has been removed from the set of load barriers.\n");
172       LoadBarriers.erase(Index);
173     }
174   }
175 
176   if (IsAStore) {
177     if (StoreQueue.erase(Index)) {
178       LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index
179                         << " has been removed from the store queue.\n");
180     }
181 
182     if (!StoreBarriers.empty() && Index == *StoreBarriers.begin()) {
183       LLVM_DEBUG(
184           dbgs() << "[LSUnit]: Instruction idx=" << Index
185                  << " has been removed from the set of store barriers.\n");
186       StoreBarriers.erase(Index);
187     }
188   }
189 }
190 
191 } // namespace mca
192 } // namespace llvm
193