]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/lib/MCA/Stages/ExecuteStage.cpp
Merge llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and openmp
[FreeBSD/FreeBSD.git] / contrib / llvm / lib / MCA / Stages / ExecuteStage.cpp
1 //===---------------------- ExecuteStage.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 defines the execution stage of an instruction pipeline.
12 ///
13 /// The ExecuteStage is responsible for managing the hardware scheduler
14 /// and issuing notifications that an instruction has been executed.
15 ///
16 //===----------------------------------------------------------------------===//
17
18 #include "llvm/MCA/Stages/ExecuteStage.h"
19 #include "llvm/ADT/SmallVector.h"
20 #include "llvm/Support/Debug.h"
21
22 #define DEBUG_TYPE "llvm-mca"
23
24 namespace llvm {
25 namespace mca {
26
27 HWStallEvent::GenericEventType toHWStallEventType(Scheduler::Status Status) {
28   switch (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;
39   }
40
41   llvm_unreachable("Don't know how to process this StallKind!");
42 }
43
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));
48     return false;
49   }
50
51   return true;
52 }
53
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);
58
59   notifyReservedOrReleasedBuffers(IR, /* Reserved */ false);
60
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))
66       return S;
67   }
68
69   for (const InstRef &I : Ready)
70     notifyInstructionReady(I);
71   return ErrorSuccess();
72 }
73
74 Error ExecuteStage::issueReadyInstructions() {
75   InstRef IR = HWS.select();
76   while (IR) {
77     if (Error Err = issueInstruction(IR))
78       return Err;
79
80     // Select the next instruction to issue.
81     IR = HWS.select();
82   }
83
84   return ErrorSuccess();
85 }
86
87 Error ExecuteStage::cycleStart() {
88   SmallVector<ResourceRef, 8> Freed;
89   SmallVector<InstRef, 4> Executed;
90   SmallVector<InstRef, 4> Ready;
91
92   HWS.cycleEvent(Freed, Executed, Ready);
93
94   for (const ResourceRef &RR : Freed)
95     notifyResourceAvailable(RR);
96
97   for (InstRef &IR : Executed) {
98     notifyInstructionExecuted(IR);
99     // FIXME: add a buffer of executed instructions.
100     if (Error S = moveToTheNextStage(IR))
101       return S;
102   }
103
104   for (const InstRef &IR : Ready)
105     notifyInstructionReady(IR);
106
107   return issueReadyInstructions();
108 }
109
110 #ifndef NDEBUG
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!");
115
116   // Ensure that instructions eliminated at register renaming stage are in a
117   // consistent state.
118   const InstrDesc &Desc = Inst.getDesc();
119   assert(!Desc.MayLoad && !Desc.MayStore && "Cannot eliminate a memory op!");
120 }
121 #endif
122
123 Error ExecuteStage::handleInstructionEliminated(InstRef &IR) {
124 #ifndef NDEBUG
125   verifyInstructionEliminated(IR);
126 #endif
127   notifyInstructionReady(IR);
128   notifyInstructionIssued(IR, {});
129   IR.getInstruction()->forceExecuted();
130   notifyInstructionExecuted(IR);
131   return moveToTheNextStage(IR);
132 }
133
134 // Schedule the instruction for execution on the hardware.
135 Error ExecuteStage::execute(InstRef &IR) {
136   assert(isAvailable(IR) && "Scheduler is not available!");
137
138 #ifndef NDEBUG
139   // Ensure that the HWS has not stored this instruction in its queues.
140   HWS.sanityCheck(IR);
141 #endif
142
143   if (IR.getInstruction()->isEliminated())
144     return handleInstructionEliminated(IR);
145
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.
150   HWS.dispatch(IR);
151   notifyReservedOrReleasedBuffers(IR, /* Reserved */ true);
152   if (!HWS.isReady(IR))
153     return ErrorSuccess();
154
155   // If we did not return early, then the scheduler is ready for execution.
156   notifyInstructionReady(IR);
157
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();
162
163   // Issue IR to the underlying pipelines.
164   return issueInstruction(IR);
165 }
166
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));
171 }
172
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));
177 }
178
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);
184 }
185
186 void ExecuteStage::notifyInstructionIssued(
187     const InstRef &IR,
188     MutableArrayRef<std::pair<ResourceRef, ResourceCycles>> Used) const {
189   LLVM_DEBUG({
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';
195     }
196   });
197
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);
201
202   notifyEvent<HWInstructionEvent>(HWInstructionIssuedEvent(IR, Used));
203 }
204
205 void ExecuteStage::notifyReservedOrReleasedBuffers(const InstRef &IR,
206                                                    bool Reserved) const {
207   const InstrDesc &Desc = IR.getInstruction()->getDesc();
208   if (Desc.Buffers.empty())
209     return;
210
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); });
214   if (Reserved) {
215     for (HWEventListener *Listener : getListeners())
216       Listener->onReservedBuffers(IR, BufferIDs);
217     return;
218   }
219
220   for (HWEventListener *Listener : getListeners())
221     Listener->onReleasedBuffers(IR, BufferIDs);
222 }
223
224 } // namespace mca
225 } // namespace llvm