1 //===--------------------- DispatchStage.cpp --------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
11 /// This file models the dispatch component of an instruction pipeline.
13 /// The DispatchStage is responsible for updating instruction dependencies
14 /// and communicating to the simulated instruction scheduler that an instruction
15 /// is ready to be scheduled for execution.
17 //===----------------------------------------------------------------------===//
19 #include "llvm/MCA/Stages/DispatchStage.h"
20 #include "llvm/MCA/HWEventListener.h"
21 #include "llvm/MCA/HardwareUnits/Scheduler.h"
22 #include "llvm/Support/Debug.h"
24 #define DEBUG_TYPE "llvm-mca"
29 void DispatchStage::notifyInstructionDispatched(const InstRef &IR,
30 ArrayRef<unsigned> UsedRegs,
31 unsigned UOps) const {
32 LLVM_DEBUG(dbgs() << "[E] Instruction Dispatched: #" << IR << '\n');
33 notifyEvent<HWInstructionEvent>(
34 HWInstructionDispatchedEvent(IR, UsedRegs, UOps));
37 bool DispatchStage::checkPRF(const InstRef &IR) const {
38 SmallVector<unsigned, 4> RegDefs;
39 for (const WriteState &RegDef : IR.getInstruction()->getDefs())
40 RegDefs.emplace_back(RegDef.getRegisterID());
42 const unsigned RegisterMask = PRF.isAvailable(RegDefs);
43 // A mask with all zeroes means: register files are available.
45 notifyEvent<HWStallEvent>(
46 HWStallEvent(HWStallEvent::RegisterFileStall, IR));
53 bool DispatchStage::checkRCU(const InstRef &IR) const {
54 const unsigned NumMicroOps = IR.getInstruction()->getDesc().NumMicroOps;
55 if (RCU.isAvailable(NumMicroOps))
57 notifyEvent<HWStallEvent>(
58 HWStallEvent(HWStallEvent::RetireControlUnitStall, IR));
62 bool DispatchStage::canDispatch(const InstRef &IR) const {
63 return checkRCU(IR) && checkPRF(IR) && checkNextStage(IR);
66 void DispatchStage::updateRAWDependencies(ReadState &RS,
67 const MCSubtargetInfo &STI) {
68 SmallVector<WriteRef, 4> DependentWrites;
70 // Collect all the dependent writes, and update RS internal state.
71 PRF.addRegisterRead(RS, DependentWrites);
73 // We know that this read depends on all the writes in DependentWrites.
74 // For each write, check if we have ReadAdvance information, and use it
75 // to figure out in how many cycles this read becomes available.
76 const ReadDescriptor &RD = RS.getDescriptor();
77 const MCSchedModel &SM = STI.getSchedModel();
78 const MCSchedClassDesc *SC = SM.getSchedClassDesc(RD.SchedClassID);
79 for (WriteRef &WR : DependentWrites) {
80 WriteState &WS = *WR.getWriteState();
81 unsigned WriteResID = WS.getWriteResourceID();
82 int ReadAdvance = STI.getReadAdvanceCycles(SC, RD.UseIndex, WriteResID);
83 WS.addUser(&RS, ReadAdvance);
87 Error DispatchStage::dispatch(InstRef IR) {
88 assert(!CarryOver && "Cannot dispatch another instruction!");
89 Instruction &IS = *IR.getInstruction();
90 const InstrDesc &Desc = IS.getDesc();
91 const unsigned NumMicroOps = Desc.NumMicroOps;
92 if (NumMicroOps > DispatchWidth) {
93 assert(AvailableEntries == DispatchWidth);
95 CarryOver = NumMicroOps - DispatchWidth;
98 assert(AvailableEntries >= NumMicroOps);
99 AvailableEntries -= NumMicroOps;
102 // Check if this instructions ends the dispatch group.
104 AvailableEntries = 0;
106 // Check if this is an optimizable reg-reg move.
107 bool IsEliminated = false;
108 if (IS.isOptimizableMove()) {
109 assert(IS.getDefs().size() == 1 && "Expected a single input!");
110 assert(IS.getUses().size() == 1 && "Expected a single output!");
111 IsEliminated = PRF.tryEliminateMove(IS.getDefs()[0], IS.getUses()[0]);
114 // A dependency-breaking instruction doesn't have to wait on the register
115 // input operands, and it is often optimized at register renaming stage.
116 // Update RAW dependencies if this instruction is not a dependency-breaking
117 // instruction. A dependency-breaking instruction is a zero-latency
118 // instruction that doesn't consume hardware resources.
119 // An example of dependency-breaking instruction on X86 is a zero-idiom XOR.
121 // We also don't update data dependencies for instructions that have been
122 // eliminated at register renaming stage.
124 for (ReadState &RS : IS.getUses())
125 updateRAWDependencies(RS, STI);
128 // By default, a dependency-breaking zero-idiom is expected to be optimized
129 // at register renaming stage. That means, no physical register is allocated
130 // to the instruction.
131 SmallVector<unsigned, 4> RegisterFiles(PRF.getNumRegisterFiles());
132 for (WriteState &WS : IS.getDefs())
133 PRF.addRegisterWrite(WriteRef(IR.getSourceIndex(), &WS), RegisterFiles);
135 // Reserve slots in the RCU, and notify the instruction that it has been
136 // dispatched to the schedulers for execution.
137 IS.dispatch(RCU.reserveSlot(IR, NumMicroOps));
139 // Notify listeners of the "instruction dispatched" event,
140 // and move IR to the next stage.
141 notifyInstructionDispatched(IR, RegisterFiles,
142 std::min(DispatchWidth, NumMicroOps));
143 return moveToTheNextStage(IR);
146 Error DispatchStage::cycleStart() {
150 AvailableEntries = DispatchWidth;
151 return ErrorSuccess();
154 AvailableEntries = CarryOver >= DispatchWidth ? 0 : DispatchWidth - CarryOver;
155 unsigned DispatchedOpcodes = DispatchWidth - AvailableEntries;
156 CarryOver -= DispatchedOpcodes;
157 assert(CarriedOver && "Invalid dispatched instruction");
159 SmallVector<unsigned, 8> RegisterFiles(PRF.getNumRegisterFiles(), 0U);
160 notifyInstructionDispatched(CarriedOver, RegisterFiles, DispatchedOpcodes);
162 CarriedOver = InstRef();
163 return ErrorSuccess();
166 bool DispatchStage::isAvailable(const InstRef &IR) const {
167 const InstrDesc &Desc = IR.getInstruction()->getDesc();
168 unsigned Required = std::min(Desc.NumMicroOps, DispatchWidth);
169 if (Required > AvailableEntries)
172 if (Desc.BeginGroup && AvailableEntries != DispatchWidth)
175 // The dispatch logic doesn't internally buffer instructions. It only accepts
176 // instructions that can be successfully moved to the next stage during this
178 return canDispatch(IR);
181 Error DispatchStage::execute(InstRef &IR) {
182 assert(canDispatch(IR) && "Cannot dispatch another instruction!");
187 void DispatchStage::dump() const {