1 //===---------------------- ExecuteStage.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 defines the execution stage of an instruction pipeline.
13 /// The ExecuteStage is responsible for managing the hardware scheduler
14 /// and issuing notifications that an instruction has been executed.
16 //===----------------------------------------------------------------------===//
18 #include "llvm/MCA/Stages/ExecuteStage.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/Support/Debug.h"
22 #define DEBUG_TYPE "llvm-mca"
27 HWStallEvent::GenericEventType toHWStallEventType(Scheduler::Status Status) {
29 case Scheduler::SC_LOAD_QUEUE_FULL:
30 return HWStallEvent::LoadQueueFull;
31 case Scheduler::SC_STORE_QUEUE_FULL:
32 return HWStallEvent::StoreQueueFull;
33 case Scheduler::SC_BUFFERS_FULL:
34 return HWStallEvent::SchedulerQueueFull;
35 case Scheduler::SC_DISPATCH_GROUP_STALL:
36 return HWStallEvent::DispatchGroupStall;
37 case Scheduler::SC_AVAILABLE:
38 return HWStallEvent::Invalid;
41 llvm_unreachable("Don't know how to process this StallKind!");
44 bool ExecuteStage::isAvailable(const InstRef &IR) const {
45 if (Scheduler::Status S = HWS.isAvailable(IR)) {
46 HWStallEvent::GenericEventType ET = toHWStallEventType(S);
47 notifyEvent<HWStallEvent>(HWStallEvent(ET, IR));
54 Error ExecuteStage::issueInstruction(InstRef &IR) {
55 SmallVector<std::pair<ResourceRef, ResourceCycles>, 4> Used;
56 SmallVector<InstRef, 4> Ready;
57 HWS.issueInstruction(IR, Used, Ready);
59 notifyReservedOrReleasedBuffers(IR, /* Reserved */ false);
61 notifyInstructionIssued(IR, Used);
62 if (IR.getInstruction()->isExecuted()) {
63 notifyInstructionExecuted(IR);
64 // FIXME: add a buffer of executed instructions.
65 if (Error S = moveToTheNextStage(IR))
69 for (const InstRef &I : Ready)
70 notifyInstructionReady(I);
71 return ErrorSuccess();
74 Error ExecuteStage::issueReadyInstructions() {
75 InstRef IR = HWS.select();
77 if (Error Err = issueInstruction(IR))
80 // Select the next instruction to issue.
84 return ErrorSuccess();
87 Error ExecuteStage::cycleStart() {
88 SmallVector<ResourceRef, 8> Freed;
89 SmallVector<InstRef, 4> Executed;
90 SmallVector<InstRef, 4> Ready;
92 HWS.cycleEvent(Freed, Executed, Ready);
94 for (const ResourceRef &RR : Freed)
95 notifyResourceAvailable(RR);
97 for (InstRef &IR : Executed) {
98 notifyInstructionExecuted(IR);
99 // FIXME: add a buffer of executed instructions.
100 if (Error S = moveToTheNextStage(IR))
104 for (const InstRef &IR : Ready)
105 notifyInstructionReady(IR);
107 return issueReadyInstructions();
111 static void verifyInstructionEliminated(const InstRef &IR) {
112 const Instruction &Inst = *IR.getInstruction();
113 assert(Inst.isEliminated() && "Instruction was not eliminated!");
114 assert(Inst.isReady() && "Instruction in an inconsistent state!");
116 // Ensure that instructions eliminated at register renaming stage are in a
118 const InstrDesc &Desc = Inst.getDesc();
119 assert(!Desc.MayLoad && !Desc.MayStore && "Cannot eliminate a memory op!");
123 Error ExecuteStage::handleInstructionEliminated(InstRef &IR) {
125 verifyInstructionEliminated(IR);
127 notifyInstructionReady(IR);
128 notifyInstructionIssued(IR, {});
129 IR.getInstruction()->forceExecuted();
130 notifyInstructionExecuted(IR);
131 return moveToTheNextStage(IR);
134 // Schedule the instruction for execution on the hardware.
135 Error ExecuteStage::execute(InstRef &IR) {
136 assert(isAvailable(IR) && "Scheduler is not available!");
139 // Ensure that the HWS has not stored this instruction in its queues.
143 if (IR.getInstruction()->isEliminated())
144 return handleInstructionEliminated(IR);
146 // Reserve a slot in each buffered resource. Also, mark units with
147 // BufferSize=0 as reserved. Resources with a buffer size of zero will only
148 // be released after MCIS is issued, and all the ResourceCycles for those
149 // units have been consumed.
151 notifyReservedOrReleasedBuffers(IR, /* Reserved */ true);
152 if (!HWS.isReady(IR))
153 return ErrorSuccess();
155 // If we did not return early, then the scheduler is ready for execution.
156 notifyInstructionReady(IR);
158 // If we cannot issue immediately, the HWS will add IR to its ready queue for
159 // execution later, so we must return early here.
160 if (!HWS.mustIssueImmediately(IR))
161 return ErrorSuccess();
163 // Issue IR to the underlying pipelines.
164 return issueInstruction(IR);
167 void ExecuteStage::notifyInstructionExecuted(const InstRef &IR) const {
168 LLVM_DEBUG(dbgs() << "[E] Instruction Executed: #" << IR << '\n');
169 notifyEvent<HWInstructionEvent>(
170 HWInstructionEvent(HWInstructionEvent::Executed, IR));
173 void ExecuteStage::notifyInstructionReady(const InstRef &IR) const {
174 LLVM_DEBUG(dbgs() << "[E] Instruction Ready: #" << IR << '\n');
175 notifyEvent<HWInstructionEvent>(
176 HWInstructionEvent(HWInstructionEvent::Ready, IR));
179 void ExecuteStage::notifyResourceAvailable(const ResourceRef &RR) const {
180 LLVM_DEBUG(dbgs() << "[E] Resource Available: [" << RR.first << '.'
181 << RR.second << "]\n");
182 for (HWEventListener *Listener : getListeners())
183 Listener->onResourceAvailable(RR);
186 void ExecuteStage::notifyInstructionIssued(
188 MutableArrayRef<std::pair<ResourceRef, ResourceCycles>> Used) const {
190 dbgs() << "[E] Instruction Issued: #" << IR << '\n';
191 for (const std::pair<ResourceRef, ResourceCycles> &Resource : Used) {
192 dbgs() << "[E] Resource Used: [" << Resource.first.first << '.'
193 << Resource.first.second << "], ";
194 dbgs() << "cycles: " << Resource.second << '\n';
198 // Replace resource masks with valid resource processor IDs.
199 for (std::pair<ResourceRef, ResourceCycles> &Use : Used)
200 Use.first.first = HWS.getResourceID(Use.first.first);
202 notifyEvent<HWInstructionEvent>(HWInstructionIssuedEvent(IR, Used));
205 void ExecuteStage::notifyReservedOrReleasedBuffers(const InstRef &IR,
206 bool Reserved) const {
207 const InstrDesc &Desc = IR.getInstruction()->getDesc();
208 if (Desc.Buffers.empty())
211 SmallVector<unsigned, 4> BufferIDs(Desc.Buffers.begin(), Desc.Buffers.end());
212 std::transform(Desc.Buffers.begin(), Desc.Buffers.end(), BufferIDs.begin(),
213 [&](uint64_t Op) { return HWS.getResourceID(Op); });
215 for (HWEventListener *Listener : getListeners())
216 Listener->onReservedBuffers(IR, BufferIDs);
220 for (HWEventListener *Listener : getListeners())
221 Listener->onReleasedBuffers(IR, BufferIDs);