Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/lib/MCA/HardwareUnits/LSUnit.cpp
35292 views
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() = default;
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 Instruction &IS = *IR.getInstruction();
71
bool IsStoreBarrier = IS.isAStoreBarrier();
72
bool IsLoadBarrier = IS.isALoadBarrier();
73
assert((IS.getMayLoad() || IS.getMayStore()) && "Not a memory operation!");
74
75
if (IS.getMayLoad())
76
acquireLQSlot();
77
if (IS.getMayStore())
78
acquireSQSlot();
79
80
if (IS.getMayStore()) {
81
unsigned NewGID = createMemoryGroup();
82
MemoryGroup &NewGroup = getGroup(NewGID);
83
NewGroup.addInstruction();
84
85
// A store may not pass a previous load or load barrier.
86
unsigned ImmediateLoadDominator =
87
std::max(CurrentLoadGroupID, CurrentLoadBarrierGroupID);
88
if (ImmediateLoadDominator) {
89
MemoryGroup &IDom = getGroup(ImmediateLoadDominator);
90
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << ImmediateLoadDominator
91
<< ") --> (" << NewGID << ")\n");
92
IDom.addSuccessor(&NewGroup, !assumeNoAlias());
93
}
94
95
// A store may not pass a previous store barrier.
96
if (CurrentStoreBarrierGroupID) {
97
MemoryGroup &StoreGroup = getGroup(CurrentStoreBarrierGroupID);
98
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: ("
99
<< CurrentStoreBarrierGroupID
100
<< ") --> (" << NewGID << ")\n");
101
StoreGroup.addSuccessor(&NewGroup, true);
102
}
103
104
// A store may not pass a previous store.
105
if (CurrentStoreGroupID &&
106
(CurrentStoreGroupID != CurrentStoreBarrierGroupID)) {
107
MemoryGroup &StoreGroup = getGroup(CurrentStoreGroupID);
108
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID
109
<< ") --> (" << NewGID << ")\n");
110
StoreGroup.addSuccessor(&NewGroup, !assumeNoAlias());
111
}
112
113
114
CurrentStoreGroupID = NewGID;
115
if (IsStoreBarrier)
116
CurrentStoreBarrierGroupID = NewGID;
117
118
if (IS.getMayLoad()) {
119
CurrentLoadGroupID = NewGID;
120
if (IsLoadBarrier)
121
CurrentLoadBarrierGroupID = NewGID;
122
}
123
124
return NewGID;
125
}
126
127
assert(IS.getMayLoad() && "Expected a load!");
128
129
unsigned ImmediateLoadDominator =
130
std::max(CurrentLoadGroupID, CurrentLoadBarrierGroupID);
131
132
// A new load group is created if we are in one of the following situations:
133
// 1) This is a load barrier (by construction, a load barrier is always
134
// assigned to a different memory group).
135
// 2) There is no load in flight (by construction we always keep loads and
136
// stores into separate memory groups).
137
// 3) There is a load barrier in flight. This load depends on it.
138
// 4) There is an intervening store between the last load dispatched to the
139
// LSU and this load. We always create a new group even if this load
140
// does not alias the last dispatched store.
141
// 5) There is no intervening store and there is an active load group.
142
// However that group has already started execution, so we cannot add
143
// this load to it.
144
bool ShouldCreateANewGroup =
145
IsLoadBarrier || !ImmediateLoadDominator ||
146
CurrentLoadBarrierGroupID == ImmediateLoadDominator ||
147
ImmediateLoadDominator <= CurrentStoreGroupID ||
148
getGroup(ImmediateLoadDominator).isExecuting();
149
150
if (ShouldCreateANewGroup) {
151
unsigned NewGID = createMemoryGroup();
152
MemoryGroup &NewGroup = getGroup(NewGID);
153
NewGroup.addInstruction();
154
155
// A load may not pass a previous store or store barrier
156
// unless flag 'NoAlias' is set.
157
if (!assumeNoAlias() && CurrentStoreGroupID) {
158
MemoryGroup &StoreGroup = getGroup(CurrentStoreGroupID);
159
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID
160
<< ") --> (" << NewGID << ")\n");
161
StoreGroup.addSuccessor(&NewGroup, true);
162
}
163
164
// A load barrier may not pass a previous load or load barrier.
165
if (IsLoadBarrier) {
166
if (ImmediateLoadDominator) {
167
MemoryGroup &LoadGroup = getGroup(ImmediateLoadDominator);
168
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: ("
169
<< ImmediateLoadDominator
170
<< ") --> (" << NewGID << ")\n");
171
LoadGroup.addSuccessor(&NewGroup, true);
172
}
173
} else {
174
// A younger load cannot pass a older load barrier.
175
if (CurrentLoadBarrierGroupID) {
176
MemoryGroup &LoadGroup = getGroup(CurrentLoadBarrierGroupID);
177
LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: ("
178
<< CurrentLoadBarrierGroupID
179
<< ") --> (" << NewGID << ")\n");
180
LoadGroup.addSuccessor(&NewGroup, true);
181
}
182
}
183
184
CurrentLoadGroupID = NewGID;
185
if (IsLoadBarrier)
186
CurrentLoadBarrierGroupID = NewGID;
187
return NewGID;
188
}
189
190
// A load may pass a previous load.
191
MemoryGroup &Group = getGroup(CurrentLoadGroupID);
192
Group.addInstruction();
193
return CurrentLoadGroupID;
194
}
195
196
LSUnit::Status LSUnit::isAvailable(const InstRef &IR) const {
197
const Instruction &IS = *IR.getInstruction();
198
if (IS.getMayLoad() && isLQFull())
199
return LSUnit::LSU_LQUEUE_FULL;
200
if (IS.getMayStore() && isSQFull())
201
return LSUnit::LSU_SQUEUE_FULL;
202
return LSUnit::LSU_AVAILABLE;
203
}
204
205
void LSUnitBase::onInstructionExecuted(const InstRef &IR) {
206
unsigned GroupID = IR.getInstruction()->getLSUTokenID();
207
auto It = Groups.find(GroupID);
208
assert(It != Groups.end() && "Instruction not dispatched to the LS unit");
209
It->second->onInstructionExecuted(IR);
210
if (It->second->isExecuted())
211
Groups.erase(It);
212
}
213
214
void LSUnitBase::onInstructionRetired(const InstRef &IR) {
215
const Instruction &IS = *IR.getInstruction();
216
bool IsALoad = IS.getMayLoad();
217
bool IsAStore = IS.getMayStore();
218
assert((IsALoad || IsAStore) && "Expected a memory operation!");
219
220
if (IsALoad) {
221
releaseLQSlot();
222
LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex()
223
<< " has been removed from the load queue.\n");
224
}
225
226
if (IsAStore) {
227
releaseSQSlot();
228
LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex()
229
<< " has been removed from the store queue.\n");
230
}
231
}
232
233
void LSUnit::onInstructionExecuted(const InstRef &IR) {
234
const Instruction &IS = *IR.getInstruction();
235
if (!IS.isMemOp())
236
return;
237
238
LSUnitBase::onInstructionExecuted(IR);
239
unsigned GroupID = IS.getLSUTokenID();
240
if (!isValidGroupID(GroupID)) {
241
if (GroupID == CurrentLoadGroupID)
242
CurrentLoadGroupID = 0;
243
if (GroupID == CurrentStoreGroupID)
244
CurrentStoreGroupID = 0;
245
if (GroupID == CurrentLoadBarrierGroupID)
246
CurrentLoadBarrierGroupID = 0;
247
if (GroupID == CurrentStoreBarrierGroupID)
248
CurrentStoreBarrierGroupID = 0;
249
}
250
}
251
252
} // namespace mca
253
} // namespace llvm
254
255