1 //===--------------------- DispatchStage.cpp --------------------*- C++ -*-===//
2 //
3 // The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 /// \file
10 ///
11 /// This file models the dispatch component of an instruction pipeline.
12 ///
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.
16 ///
17 //===----------------------------------------------------------------------===//
18
19 #include "DispatchStage.h"
20 #include "HWEventListener.h"
21 #include "Scheduler.h"
22 #include "llvm/Support/Debug.h"
23
24 using namespace llvm;
25
26 #define DEBUG_TYPE "llvm-mca"
27
28 namespace mca {
29
notifyInstructionDispatched(const InstRef & IR,ArrayRef<unsigned> UsedRegs)30 void DispatchStage::notifyInstructionDispatched(const InstRef &IR,
31 ArrayRef<unsigned> UsedRegs) {
32 LLVM_DEBUG(dbgs() << "[E] Instruction Dispatched: #" << IR << '\n');
33 notifyEvent<HWInstructionEvent>(HWInstructionDispatchedEvent(IR, UsedRegs));
34 }
35
checkPRF(const InstRef & IR)36 bool DispatchStage::checkPRF(const InstRef &IR) {
37 SmallVector<unsigned, 4> RegDefs;
38 for (const std::unique_ptr<WriteState> &RegDef :
39 IR.getInstruction()->getDefs())
40 RegDefs.emplace_back(RegDef->getRegisterID());
41
42 const unsigned RegisterMask = PRF.isAvailable(RegDefs);
43 // A mask with all zeroes means: register files are available.
44 if (RegisterMask) {
45 notifyEvent<HWStallEvent>(
46 HWStallEvent(HWStallEvent::RegisterFileStall, IR));
47 return false;
48 }
49
50 return true;
51 }
52
checkRCU(const InstRef & IR)53 bool DispatchStage::checkRCU(const InstRef &IR) {
54 const unsigned NumMicroOps = IR.getInstruction()->getDesc().NumMicroOps;
55 if (RCU.isAvailable(NumMicroOps))
56 return true;
57 notifyEvent<HWStallEvent>(
58 HWStallEvent(HWStallEvent::RetireControlUnitStall, IR));
59 return false;
60 }
61
checkScheduler(const InstRef & IR)62 bool DispatchStage::checkScheduler(const InstRef &IR) {
63 HWStallEvent::GenericEventType Event;
64 const bool Ready = SC.canBeDispatched(IR, Event);
65 if (!Ready)
66 notifyEvent<HWStallEvent>(HWStallEvent(Event, IR));
67 return Ready;
68 }
69
updateRAWDependencies(ReadState & RS,const MCSubtargetInfo & STI)70 void DispatchStage::updateRAWDependencies(ReadState &RS,
71 const MCSubtargetInfo &STI) {
72 SmallVector<WriteRef, 4> DependentWrites;
73
74 collectWrites(DependentWrites, RS.getRegisterID());
75 RS.setDependentWrites(DependentWrites.size());
76 // We know that this read depends on all the writes in DependentWrites.
77 // For each write, check if we have ReadAdvance information, and use it
78 // to figure out in how many cycles this read becomes available.
79 const ReadDescriptor &RD = RS.getDescriptor();
80 const MCSchedModel &SM = STI.getSchedModel();
81 const MCSchedClassDesc *SC = SM.getSchedClassDesc(RD.SchedClassID);
82 for (WriteRef &WR : DependentWrites) {
83 WriteState &WS = *WR.getWriteState();
84 unsigned WriteResID = WS.getWriteResourceID();
85 int ReadAdvance = STI.getReadAdvanceCycles(SC, RD.UseIndex, WriteResID);
86 WS.addUser(&RS, ReadAdvance);
87 }
88 }
89
dispatch(InstRef IR)90 void DispatchStage::dispatch(InstRef IR) {
91 assert(!CarryOver && "Cannot dispatch another instruction!");
92 Instruction &IS = *IR.getInstruction();
93 const InstrDesc &Desc = IS.getDesc();
94 const unsigned NumMicroOps = Desc.NumMicroOps;
95 if (NumMicroOps > DispatchWidth) {
96 assert(AvailableEntries == DispatchWidth);
97 AvailableEntries = 0;
98 CarryOver = NumMicroOps - DispatchWidth;
99 } else {
100 assert(AvailableEntries >= NumMicroOps);
101 AvailableEntries -= NumMicroOps;
102 }
103
104 // A dependency-breaking instruction doesn't have to wait on the register
105 // input operands, and it is often optimized at register renaming stage.
106 // Update RAW dependencies if this instruction is not a dependency-breaking
107 // instruction. A dependency-breaking instruction is a zero-latency
108 // instruction that doesn't consume hardware resources.
109 // An example of dependency-breaking instruction on X86 is a zero-idiom XOR.
110 bool IsDependencyBreaking = IS.isDependencyBreaking();
111 for (std::unique_ptr<ReadState> &RS : IS.getUses())
112 if (RS->isImplicitRead() || !IsDependencyBreaking)
113 updateRAWDependencies(*RS, STI);
114
115 // By default, a dependency-breaking zero-latency instruction is expected to
116 // be optimized at register renaming stage. That means, no physical register
117 // is allocated to the instruction.
118 bool ShouldAllocateRegisters =
119 !(Desc.isZeroLatency() && IsDependencyBreaking);
120 SmallVector<unsigned, 4> RegisterFiles(PRF.getNumRegisterFiles());
121 for (std::unique_ptr<WriteState> &WS : IS.getDefs()) {
122 PRF.addRegisterWrite(WriteRef(IR.first, WS.get()), RegisterFiles,
123 ShouldAllocateRegisters);
124 }
125
126 // Reserve slots in the RCU, and notify the instruction that it has been
127 // dispatched to the schedulers for execution.
128 IS.dispatch(RCU.reserveSlot(IR, NumMicroOps));
129
130 // Notify listeners of the "instruction dispatched" event.
131 notifyInstructionDispatched(IR, RegisterFiles);
132 }
133
cycleStart()134 void DispatchStage::cycleStart() {
135 AvailableEntries = CarryOver >= DispatchWidth ? 0 : DispatchWidth - CarryOver;
136 CarryOver = CarryOver >= DispatchWidth ? CarryOver - DispatchWidth : 0U;
137 }
138
execute(InstRef & IR)139 bool DispatchStage::execute(InstRef &IR) {
140 const InstrDesc &Desc = IR.getInstruction()->getDesc();
141 if (!isAvailable(Desc.NumMicroOps) || !canDispatch(IR))
142 return false;
143 dispatch(IR);
144 return true;
145 }
146
147 #ifndef NDEBUG
dump() const148 void DispatchStage::dump() const {
149 PRF.dump();
150 RCU.dump();
151 }
152 #endif
153 } // namespace mca
154