1 //===---------------------- InOrderIssueStage.cpp ---------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
10 /// InOrderIssueStage implements an in-order execution pipeline.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/MCA/Stages/InOrderIssueStage.h"
15 #include "llvm/MCA/HardwareUnits/LSUnit.h"
16 #include "llvm/MCA/HardwareUnits/RegisterFile.h"
17 #include "llvm/MCA/HardwareUnits/RetireControlUnit.h"
18 #include "llvm/MCA/Instruction.h"
20 #define DEBUG_TYPE "llvm-mca"
24 void StallInfo::clear() {
27 Kind
= StallKind::DEFAULT
;
30 void StallInfo::update(const InstRef
&Inst
, unsigned Cycles
, StallKind SK
) {
36 void StallInfo::cycleEnd() {
46 InOrderIssueStage::InOrderIssueStage(const MCSubtargetInfo
&STI
,
47 RegisterFile
&PRF
, CustomBehaviour
&CB
,
49 : STI(STI
), PRF(PRF
), RM(STI
.getSchedModel()), CB(CB
), LSU(LSU
),
50 NumIssued(), CarryOver(), Bandwidth(), LastWriteBackCycle() {}
52 unsigned InOrderIssueStage::getIssueWidth() const {
53 return STI
.getSchedModel().IssueWidth
;
56 bool InOrderIssueStage::hasWorkToComplete() const {
57 return !IssuedInst
.empty() || SI
.isValid() || CarriedOver
;
60 bool InOrderIssueStage::isAvailable(const InstRef
&IR
) const {
61 if (SI
.isValid() || CarriedOver
)
64 const Instruction
&Inst
= *IR
.getInstruction();
65 unsigned NumMicroOps
= Inst
.getNumMicroOps();
67 bool ShouldCarryOver
= NumMicroOps
> getIssueWidth();
68 if (Bandwidth
< NumMicroOps
&& !ShouldCarryOver
)
71 // Instruction with BeginGroup must be the first instruction to be issued in a
73 if (Inst
.getBeginGroup() && NumIssued
!= 0)
79 static bool hasResourceHazard(const ResourceManager
&RM
, const InstRef
&IR
) {
80 if (RM
.checkAvailability(IR
.getInstruction()->getDesc())) {
81 LLVM_DEBUG(dbgs() << "[E] Stall #" << IR
<< '\n');
88 static unsigned findFirstWriteBackCycle(const InstRef
&IR
) {
89 unsigned FirstWBCycle
= IR
.getInstruction()->getLatency();
90 for (const WriteState
&WS
: IR
.getInstruction()->getDefs()) {
91 int CyclesLeft
= WS
.getCyclesLeft();
92 if (CyclesLeft
== UNKNOWN_CYCLES
)
93 CyclesLeft
= WS
.getLatency();
96 FirstWBCycle
= std::min(FirstWBCycle
, (unsigned)CyclesLeft
);
101 /// Return a number of cycles left until register requirements of the
102 /// instructions are met.
103 static unsigned checkRegisterHazard(const RegisterFile
&PRF
,
104 const MCSubtargetInfo
&STI
,
106 for (const ReadState
&RS
: IR
.getInstruction()->getUses()) {
107 RegisterFile::RAWHazard Hazard
= PRF
.checkRAWHazards(STI
, RS
);
108 if (Hazard
.isValid())
109 return Hazard
.hasUnknownCycles() ? 1U : Hazard
.CyclesLeft
;
115 bool InOrderIssueStage::canExecute(const InstRef
&IR
) {
116 assert(!SI
.getCyclesLeft() && "Should not have reached this code!");
117 assert(!SI
.isValid() && "Should not have reached this code!");
119 if (unsigned Cycles
= checkRegisterHazard(PRF
, STI
, IR
)) {
120 SI
.update(IR
, Cycles
, StallInfo::StallKind::REGISTER_DEPS
);
124 if (hasResourceHazard(RM
, IR
)) {
125 SI
.update(IR
, /* delay */ 1, StallInfo::StallKind::DISPATCH
);
129 if (IR
.getInstruction()->isMemOp() && !LSU
.isReady(IR
)) {
130 // This load (store) aliases with a preceding store (load). Delay
131 // it until the depenency is cleared.
132 SI
.update(IR
, /* delay */ 1, StallInfo::StallKind::LOAD_STORE
);
136 if (unsigned CustomStallCycles
= CB
.checkCustomHazard(IssuedInst
, IR
)) {
137 SI
.update(IR
, CustomStallCycles
, StallInfo::StallKind::CUSTOM_STALL
);
141 if (LastWriteBackCycle
) {
142 if (!IR
.getInstruction()->getRetireOOO()) {
143 unsigned NextWriteBackCycle
= findFirstWriteBackCycle(IR
);
144 // Delay the instruction to ensure that writes happen in program order.
145 if (NextWriteBackCycle
< LastWriteBackCycle
) {
146 SI
.update(IR
, LastWriteBackCycle
- NextWriteBackCycle
,
147 StallInfo::StallKind::DELAY
);
156 static void addRegisterReadWrite(RegisterFile
&PRF
, Instruction
&IS
,
157 unsigned SourceIndex
,
158 const MCSubtargetInfo
&STI
,
159 SmallVectorImpl
<unsigned> &UsedRegs
) {
160 assert(!IS
.isEliminated());
162 for (ReadState
&RS
: IS
.getUses())
163 PRF
.addRegisterRead(RS
, STI
);
165 for (WriteState
&WS
: IS
.getDefs())
166 PRF
.addRegisterWrite(WriteRef(SourceIndex
, &WS
), UsedRegs
);
169 void InOrderIssueStage::notifyInstructionIssued(const InstRef
&IR
,
170 ArrayRef
<ResourceUse
> UsedRes
) {
171 notifyEvent
<HWInstructionEvent
>(
172 HWInstructionEvent(HWInstructionEvent::Ready
, IR
));
173 notifyEvent
<HWInstructionEvent
>(HWInstructionIssuedEvent(IR
, UsedRes
));
175 LLVM_DEBUG(dbgs() << "[E] Issued #" << IR
<< "\n");
178 void InOrderIssueStage::notifyInstructionDispatched(
179 const InstRef
&IR
, unsigned Ops
, ArrayRef
<unsigned> UsedRegs
) {
180 notifyEvent
<HWInstructionEvent
>(
181 HWInstructionDispatchedEvent(IR
, UsedRegs
, Ops
));
183 LLVM_DEBUG(dbgs() << "[E] Dispatched #" << IR
<< "\n");
186 void InOrderIssueStage::notifyInstructionExecuted(const InstRef
&IR
) {
187 notifyEvent
<HWInstructionEvent
>(
188 HWInstructionEvent(HWInstructionEvent::Executed
, IR
));
189 LLVM_DEBUG(dbgs() << "[E] Instruction #" << IR
<< " is executed\n");
192 void InOrderIssueStage::notifyInstructionRetired(const InstRef
&IR
,
193 ArrayRef
<unsigned> FreedRegs
) {
194 notifyEvent
<HWInstructionEvent
>(HWInstructionRetiredEvent(IR
, FreedRegs
));
195 LLVM_DEBUG(dbgs() << "[E] Retired #" << IR
<< " \n");
198 llvm::Error
InOrderIssueStage::execute(InstRef
&IR
) {
199 Instruction
&IS
= *IR
.getInstruction();
201 IS
.setLSUTokenID(LSU
.dispatch(IR
));
203 if (llvm::Error E
= tryIssue(IR
))
209 return llvm::ErrorSuccess();
212 llvm::Error
InOrderIssueStage::tryIssue(InstRef
&IR
) {
213 Instruction
&IS
= *IR
.getInstruction();
214 unsigned SourceIndex
= IR
.getSourceIndex();
215 const InstrDesc
&Desc
= IS
.getDesc();
217 if (!canExecute(IR
)) {
218 LLVM_DEBUG(dbgs() << "[N] Stalled #" << SI
.getInstruction() << " for "
219 << SI
.getCyclesLeft() << " cycles\n");
221 return llvm::ErrorSuccess();
224 unsigned RCUTokenID
= RetireControlUnit::UnhandledTokenID
;
225 IS
.dispatch(RCUTokenID
);
227 SmallVector
<unsigned, 4> UsedRegs(PRF
.getNumRegisterFiles());
228 addRegisterReadWrite(PRF
, IS
, SourceIndex
, STI
, UsedRegs
);
230 unsigned NumMicroOps
= IS
.getNumMicroOps();
231 notifyInstructionDispatched(IR
, NumMicroOps
, UsedRegs
);
233 SmallVector
<ResourceUse
, 4> UsedResources
;
234 RM
.issueInstruction(Desc
, UsedResources
);
235 IS
.execute(SourceIndex
);
238 LSU
.onInstructionIssued(IR
);
240 // Replace resource masks with valid resource processor IDs.
241 for (ResourceUse
&Use
: UsedResources
) {
242 uint64_t Mask
= Use
.first
.first
;
243 Use
.first
.first
= RM
.resolveResourceMask(Mask
);
245 notifyInstructionIssued(IR
, UsedResources
);
247 bool ShouldCarryOver
= NumMicroOps
> Bandwidth
;
248 if (ShouldCarryOver
) {
249 CarryOver
= NumMicroOps
- Bandwidth
;
252 NumIssued
+= Bandwidth
;
253 LLVM_DEBUG(dbgs() << "[N] Carry over #" << IR
<< " \n");
255 NumIssued
+= NumMicroOps
;
256 Bandwidth
= IS
.getEndGroup() ? 0 : Bandwidth
- NumMicroOps
;
259 // If the instruction has a latency of 0, we need to handle
260 // the execution and retirement now.
261 if (IS
.isExecuted()) {
262 PRF
.onInstructionExecuted(&IS
);
263 LSU
.onInstructionExecuted(IR
);
264 notifyEvent
<HWInstructionEvent
>(
265 HWInstructionEvent(HWInstructionEvent::Executed
, IR
));
266 LLVM_DEBUG(dbgs() << "[E] Instruction #" << IR
<< " is executed\n");
268 retireInstruction(IR
);
269 return llvm::ErrorSuccess();
272 IssuedInst
.push_back(IR
);
274 if (!IR
.getInstruction()->getRetireOOO())
275 LastWriteBackCycle
= IS
.getCyclesLeft();
277 return llvm::ErrorSuccess();
280 void InOrderIssueStage::updateIssuedInst() {
281 // Update other instructions. Executed instructions will be retired during the
283 unsigned NumExecuted
= 0;
284 for (auto I
= IssuedInst
.begin(), E
= IssuedInst
.end();
285 I
!= (E
- NumExecuted
);) {
287 Instruction
&IS
= *IR
.getInstruction();
290 if (!IS
.isExecuted()) {
291 LLVM_DEBUG(dbgs() << "[N] Instruction #" << IR
292 << " is still executing\n");
297 PRF
.onInstructionExecuted(&IS
);
298 LSU
.onInstructionExecuted(IR
);
299 notifyInstructionExecuted(IR
);
302 retireInstruction(*I
);
304 std::iter_swap(I
, E
- NumExecuted
);
308 IssuedInst
.resize(IssuedInst
.size() - NumExecuted
);
311 void InOrderIssueStage::updateCarriedOver() {
315 assert(!SI
.isValid() && "A stalled instruction cannot be carried over.");
317 if (CarryOver
> Bandwidth
) {
318 CarryOver
-= Bandwidth
;
320 LLVM_DEBUG(dbgs() << "[N] Carry over (" << CarryOver
<< "uops left) #"
321 << CarriedOver
<< " \n");
325 LLVM_DEBUG(dbgs() << "[N] Carry over (complete) #" << CarriedOver
<< " \n");
327 if (CarriedOver
.getInstruction()->getEndGroup())
330 Bandwidth
-= CarryOver
;
332 CarriedOver
= InstRef();
336 void InOrderIssueStage::retireInstruction(InstRef
&IR
) {
337 Instruction
&IS
= *IR
.getInstruction();
340 llvm::SmallVector
<unsigned, 4> FreedRegs(PRF
.getNumRegisterFiles());
341 for (const WriteState
&WS
: IS
.getDefs())
342 PRF
.removeRegisterWrite(WS
, FreedRegs
);
345 LSU
.onInstructionRetired(IR
);
347 notifyInstructionRetired(IR
, FreedRegs
);
350 void InOrderIssueStage::notifyStallEvent() {
351 assert(SI
.getCyclesLeft() && "A zero cycles stall?");
352 assert(SI
.isValid() && "Invalid stall information found!");
354 const InstRef
&IR
= SI
.getInstruction();
356 switch (SI
.getStallKind()) {
359 case StallInfo::StallKind::REGISTER_DEPS
: {
360 notifyEvent
<HWStallEvent
>(
361 HWStallEvent(HWStallEvent::RegisterFileStall
, IR
));
362 notifyEvent
<HWPressureEvent
>(
363 HWPressureEvent(HWPressureEvent::REGISTER_DEPS
, IR
));
366 case StallInfo::StallKind::DISPATCH
: {
367 notifyEvent
<HWStallEvent
>(
368 HWStallEvent(HWStallEvent::DispatchGroupStall
, IR
));
369 notifyEvent
<HWPressureEvent
>(
370 HWPressureEvent(HWPressureEvent::RESOURCES
, IR
));
373 case StallInfo::StallKind::CUSTOM_STALL
: {
374 notifyEvent
<HWStallEvent
>(
375 HWStallEvent(HWStallEvent::CustomBehaviourStall
, IR
));
381 llvm::Error
InOrderIssueStage::cycleStart() {
383 Bandwidth
= getIssueWidth();
388 // Release consumed resources.
389 SmallVector
<ResourceRef
, 4> Freed
;
390 RM
.cycleEvent(Freed
);
394 // Continue to issue the instruction carried over from the previous cycle
397 // Issue instructions scheduled for this cycle
399 if (!SI
.getCyclesLeft()) {
400 // Make a copy of the reference, and try issue it again.
401 // Do not take the instruction reference because SI.clear() will
403 InstRef IR
= SI
.getInstruction();
406 if (llvm::Error E
= tryIssue(IR
))
410 if (SI
.getCyclesLeft()) {
411 // The instruction is still stalled, cannot issue any new instructions in
415 return llvm::ErrorSuccess();
419 assert((NumIssued
<= getIssueWidth()) && "Overflow.");
420 return llvm::ErrorSuccess();
423 llvm::Error
InOrderIssueStage::cycleEnd() {
427 if (LastWriteBackCycle
> 0)
428 --LastWriteBackCycle
;
430 return llvm::ErrorSuccess();