1 //===--------------------- DispatchStage.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 /// This file models the dispatch component of an instruction pipeline.
12 /// The DispatchStage is responsible for updating instruction dependencies
13 /// and communicating to the simulated instruction scheduler that an instruction
14 /// is ready to be scheduled for execution.
16 //===----------------------------------------------------------------------===//
18 #include "llvm/MCA/Stages/DispatchStage.h"
19 #include "llvm/MCA/HWEventListener.h"
20 #include "llvm/MCA/HardwareUnits/Scheduler.h"
21 #include "llvm/Support/Debug.h"
23 #define DEBUG_TYPE "llvm-mca"
28 DispatchStage::DispatchStage(const MCSubtargetInfo
&Subtarget
,
29 const MCRegisterInfo
&MRI
,
30 unsigned MaxDispatchWidth
, RetireControlUnit
&R
,
32 : DispatchWidth(MaxDispatchWidth
), AvailableEntries(MaxDispatchWidth
),
33 CarryOver(0U), CarriedOver(), STI(Subtarget
), RCU(R
), PRF(F
) {
35 DispatchWidth
= Subtarget
.getSchedModel().IssueWidth
;
38 void DispatchStage::notifyInstructionDispatched(const InstRef
&IR
,
39 ArrayRef
<unsigned> UsedRegs
,
40 unsigned UOps
) const {
41 LLVM_DEBUG(dbgs() << "[E] Instruction Dispatched: #" << IR
<< '\n');
42 notifyEvent
<HWInstructionEvent
>(
43 HWInstructionDispatchedEvent(IR
, UsedRegs
, UOps
));
46 bool DispatchStage::checkPRF(const InstRef
&IR
) const {
47 SmallVector
<MCPhysReg
, 4> RegDefs
;
48 for (const WriteState
&RegDef
: IR
.getInstruction()->getDefs())
49 RegDefs
.emplace_back(RegDef
.getRegisterID());
51 const unsigned RegisterMask
= PRF
.isAvailable(RegDefs
);
52 // A mask with all zeroes means: register files are available.
54 notifyEvent
<HWStallEvent
>(
55 HWStallEvent(HWStallEvent::RegisterFileStall
, IR
));
62 bool DispatchStage::checkRCU(const InstRef
&IR
) const {
63 const unsigned NumMicroOps
= IR
.getInstruction()->getNumMicroOps();
64 if (RCU
.isAvailable(NumMicroOps
))
66 notifyEvent
<HWStallEvent
>(
67 HWStallEvent(HWStallEvent::RetireControlUnitStall
, IR
));
71 bool DispatchStage::canDispatch(const InstRef
&IR
) const {
72 bool CanDispatch
= checkRCU(IR
);
73 CanDispatch
&= checkPRF(IR
);
74 CanDispatch
&= checkNextStage(IR
);
78 Error
DispatchStage::dispatch(InstRef IR
) {
79 assert(!CarryOver
&& "Cannot dispatch another instruction!");
80 Instruction
&IS
= *IR
.getInstruction();
81 const InstrDesc
&Desc
= IS
.getDesc();
82 const unsigned NumMicroOps
= IS
.getNumMicroOps();
83 if (NumMicroOps
> DispatchWidth
) {
84 assert(AvailableEntries
== DispatchWidth
);
86 CarryOver
= NumMicroOps
- DispatchWidth
;
89 assert(AvailableEntries
>= NumMicroOps
);
90 AvailableEntries
-= NumMicroOps
;
93 // Check if this instructions ends the dispatch group.
97 // Check if this is an optimizable reg-reg move.
98 if (IS
.isOptimizableMove()) {
99 assert(IS
.getDefs().size() == 1 && "Expected a single input!");
100 assert(IS
.getUses().size() == 1 && "Expected a single output!");
101 if (PRF
.tryEliminateMove(IS
.getDefs()[0], IS
.getUses()[0]))
105 // A dependency-breaking instruction doesn't have to wait on the register
106 // input operands, and it is often optimized at register renaming stage.
107 // Update RAW dependencies if this instruction is not a dependency-breaking
108 // instruction. A dependency-breaking instruction is a zero-latency
109 // instruction that doesn't consume hardware resources.
110 // An example of dependency-breaking instruction on X86 is a zero-idiom XOR.
112 // We also don't update data dependencies for instructions that have been
113 // eliminated at register renaming stage.
114 if (!IS
.isEliminated()) {
115 for (ReadState
&RS
: IS
.getUses())
116 PRF
.addRegisterRead(RS
, STI
);
119 // By default, a dependency-breaking zero-idiom is expected to be optimized
120 // at register renaming stage. That means, no physical register is allocated
121 // to the instruction.
122 SmallVector
<unsigned, 4> RegisterFiles(PRF
.getNumRegisterFiles());
123 for (WriteState
&WS
: IS
.getDefs())
124 PRF
.addRegisterWrite(WriteRef(IR
.getSourceIndex(), &WS
), RegisterFiles
);
126 // Reserve entries in the reorder buffer.
127 unsigned RCUTokenID
= RCU
.dispatch(IR
);
128 // Notify the instruction that it has been dispatched.
129 IS
.dispatch(RCUTokenID
);
131 // Notify listeners of the "instruction dispatched" event,
132 // and move IR to the next stage.
133 notifyInstructionDispatched(IR
, RegisterFiles
,
134 std::min(DispatchWidth
, NumMicroOps
));
135 return moveToTheNextStage(IR
);
138 Error
DispatchStage::cycleStart() {
142 AvailableEntries
= DispatchWidth
;
143 return ErrorSuccess();
146 AvailableEntries
= CarryOver
>= DispatchWidth
? 0 : DispatchWidth
- CarryOver
;
147 unsigned DispatchedOpcodes
= DispatchWidth
- AvailableEntries
;
148 CarryOver
-= DispatchedOpcodes
;
149 assert(CarriedOver
&& "Invalid dispatched instruction");
151 SmallVector
<unsigned, 8> RegisterFiles(PRF
.getNumRegisterFiles(), 0U);
152 notifyInstructionDispatched(CarriedOver
, RegisterFiles
, DispatchedOpcodes
);
154 CarriedOver
= InstRef();
155 return ErrorSuccess();
158 bool DispatchStage::isAvailable(const InstRef
&IR
) const {
159 const Instruction
&Inst
= *IR
.getInstruction();
160 unsigned NumMicroOps
= Inst
.getNumMicroOps();
161 const InstrDesc
&Desc
= Inst
.getDesc();
162 unsigned Required
= std::min(NumMicroOps
, DispatchWidth
);
163 if (Required
> AvailableEntries
)
166 if (Desc
.BeginGroup
&& AvailableEntries
!= DispatchWidth
)
169 // The dispatch logic doesn't internally buffer instructions. It only accepts
170 // instructions that can be successfully moved to the next stage during this
172 return canDispatch(IR
);
175 Error
DispatchStage::execute(InstRef
&IR
) {
176 assert(canDispatch(IR
) && "Cannot dispatch another instruction!");
181 void DispatchStage::dump() const {