147
|
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 = LdQDesc.BufferSize;
|
|
33 }
|
|
34
|
|
35 if (!SQSize && EPI.StoreQueueID) {
|
|
36 const MCProcResourceDesc &StQDesc = *SM.getProcResource(EPI.StoreQueueID);
|
|
37 SQSize = 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 assignLQSlot();
|
|
76 if (Desc.MayStore)
|
|
77 assignSQSlot();
|
|
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 const InstrDesc &Desc = IR.getInstruction()->getDesc();
|
|
164 bool IsALoad = Desc.MayLoad;
|
|
165 bool IsAStore = Desc.MayStore;
|
|
166 assert((IsALoad || IsAStore) && "Expected a memory operation!");
|
|
167
|
|
168 unsigned GroupID = IR.getInstruction()->getLSUTokenID();
|
|
169 auto It = Groups.find(GroupID);
|
|
170 It->second->onInstructionExecuted();
|
|
171 if (It->second->isExecuted()) {
|
|
172 Groups.erase(It);
|
|
173 }
|
|
174
|
|
175 if (IsALoad) {
|
|
176 UsedLQEntries--;
|
|
177 LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex()
|
|
178 << " has been removed from the load queue.\n");
|
|
179 }
|
|
180
|
|
181 if (IsAStore) {
|
|
182 UsedSQEntries--;
|
|
183 LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex()
|
|
184 << " has been removed from the store queue.\n");
|
|
185 }
|
|
186 }
|
|
187
|
|
188 void LSUnit::onInstructionExecuted(const InstRef &IR) {
|
|
189 const Instruction &IS = *IR.getInstruction();
|
|
190 if (!IS.isMemOp())
|
|
191 return;
|
|
192
|
|
193 LSUnitBase::onInstructionExecuted(IR);
|
|
194 unsigned GroupID = IS.getLSUTokenID();
|
|
195 if (!isValidGroupID(GroupID)) {
|
|
196 if (GroupID == CurrentLoadGroupID)
|
|
197 CurrentLoadGroupID = 0;
|
|
198 if (GroupID == CurrentStoreGroupID)
|
|
199 CurrentStoreGroupID = 0;
|
|
200 if (GroupID == CurrentLoadBarrierGroupID)
|
|
201 CurrentLoadBarrierGroupID = 0;
|
|
202 }
|
|
203 }
|
|
204
|
|
205 } // namespace mca
|
|
206 } // namespace llvm
|