[InstCombine] Signed saturation patterns
[llvm-complete.git] / lib / MCA / HardwareUnits / LSUnit.cpp
blob0ee084c7ce1a927c27925880d10e7d9cfbe8aab5
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 //===----------------------------------------------------------------------===//
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"
19 #define DEBUG_TYPE "llvm-mca"
21 namespace llvm {
22 namespace mca {
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);
35 if (!SQSize && EPI.StoreQueueID) {
36 const MCProcResourceDesc &StQDesc = *SM.getProcResource(EPI.StoreQueueID);
37 SQSize = std::max(0, StQDesc.BufferSize);
42 LSUnitBase::~LSUnitBase() {}
44 void LSUnitBase::cycleEvent() {
45 for (const std::pair<unsigned, std::unique_ptr<MemoryGroup>> &G : Groups)
46 G.second->cycleEvent();
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';
67 #endif
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!");
74 if (Desc.MayLoad)
75 acquireLQSlot();
76 if (Desc.MayStore)
77 acquireSQSlot();
79 if (Desc.MayStore) {
80 // Always create a new group for store operations.
82 // A store may not pass a previous store or store barrier.
83 unsigned NewGID = createMemoryGroup();
84 MemoryGroup &NewGroup = getGroup(NewGID);
85 NewGroup.addInstruction();
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);
96 if (CurrentStoreGroupID) {
97 MemoryGroup &StoreGroup = getGroup(CurrentStoreGroupID);
98 LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID
99 << ") --> (" << NewGID << ")\n");
100 StoreGroup.addSuccessor(&NewGroup);
103 CurrentStoreGroupID = NewGID;
104 if (Desc.MayLoad) {
105 CurrentLoadGroupID = NewGID;
106 if (IsMemBarrier)
107 CurrentLoadBarrierGroupID = NewGID;
110 return NewGID;
113 assert(Desc.MayLoad && "Expected a load!");
115 // Always create a new memory group if this is the first load of the sequence.
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();
129 if (!assumeNoAlias() && CurrentStoreGroupID) {
130 MemoryGroup &StGroup = getGroup(CurrentStoreGroupID);
131 LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentStoreGroupID
132 << ") --> (" << NewGID << ")\n");
133 StGroup.addSuccessor(&NewGroup);
135 if (CurrentLoadBarrierGroupID) {
136 MemoryGroup &LdGroup = getGroup(CurrentLoadBarrierGroupID);
137 LLVM_DEBUG(dbgs() << "[LSUnit]: GROUP DEP: (" << CurrentLoadBarrierGroupID
138 << ") --> (" << NewGID << ")\n");
139 LdGroup.addSuccessor(&NewGroup);
142 CurrentLoadGroupID = NewGID;
143 if (IsMemBarrier)
144 CurrentLoadBarrierGroupID = NewGID;
145 return NewGID;
148 MemoryGroup &Group = getGroup(CurrentLoadGroupID);
149 Group.addInstruction();
150 return CurrentLoadGroupID;
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;
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);
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!");
177 if (IsALoad) {
178 releaseLQSlot();
179 LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex()
180 << " has been removed from the load queue.\n");
183 if (IsAStore) {
184 releaseSQSlot();
185 LLVM_DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << IR.getSourceIndex()
186 << " has been removed from the store queue.\n");
190 void LSUnit::onInstructionExecuted(const InstRef &IR) {
191 const Instruction &IS = *IR.getInstruction();
192 if (!IS.isMemOp())
193 return;
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;
207 } // namespace mca
208 } // namespace llvm