blob: b0b0d71d400cbb46ee959f1eeb800446654acd37 [file] [log] [blame]
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +00001//===--------------------- Scheduler.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//
10// A scheduler for processor resource units and processor resource groups.
11//
12//===----------------------------------------------------------------------===//
13
Andrea Di Biagio51dba7d2018-03-23 17:36:07 +000014#include "Scheduler.h"
Andrea Di Biagioeec6b812018-06-26 10:44:12 +000015#include "llvm/Support/Debug.h"
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000016#include "llvm/Support/raw_ostream.h"
17
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000018namespace mca {
19
20using namespace llvm;
21
Andrea Di Biagioeec6b812018-06-26 10:44:12 +000022#define DEBUG_TYPE "llvm-mca"
23
Matt Davis0f70bc02018-08-23 18:42:37 +000024void Scheduler::initializeStrategy(std::unique_ptr<SchedulerStrategy> S) {
25 // Ensure we have a valid (non-null) strategy object.
26 Strategy = S ? std::move(S) : llvm::make_unique<DefaultSchedulerStrategy>();
27}
28
Andrea Di Biagiof3374f02018-08-21 18:20:16 +000029// Anchor the vtable of SchedulerStrategy and DefaultSchedulerStrategy.
30SchedulerStrategy::~SchedulerStrategy() = default;
31DefaultSchedulerStrategy::~DefaultSchedulerStrategy() = default;
32
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000033#ifndef NDEBUG
34void Scheduler::dump() const {
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +000035 dbgs() << "[SCHEDULER]: WaitSet size is: " << WaitSet.size() << '\n';
36 dbgs() << "[SCHEDULER]: ReadySet size is: " << ReadySet.size() << '\n';
37 dbgs() << "[SCHEDULER]: IssuedSet size is: " << IssuedSet.size() << '\n';
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000038 Resources->dump();
39}
40#endif
41
Andrea Di Biagio0875e752018-08-20 14:41:36 +000042Scheduler::Status Scheduler::isAvailable(const InstRef &IR) const {
Matt Davis21a8d322018-05-07 18:29:15 +000043 const InstrDesc &Desc = IR.getInstruction()->getDesc();
Andrea Di Biagiof3374f02018-08-21 18:20:16 +000044
Andrea Di Biagio163419f2018-08-17 15:01:37 +000045 switch (Resources->canBeDispatched(Desc.Buffers)) {
46 case ResourceStateEvent::RS_BUFFER_UNAVAILABLE:
Andrea Di Biagio0875e752018-08-20 14:41:36 +000047 return Scheduler::SC_BUFFERS_FULL;
Andrea Di Biagio163419f2018-08-17 15:01:37 +000048 case ResourceStateEvent::RS_RESERVED:
Andrea Di Biagio0875e752018-08-20 14:41:36 +000049 return Scheduler::SC_DISPATCH_GROUP_STALL;
50 case ResourceStateEvent::RS_BUFFER_AVAILABLE:
Andrea Di Biagio163419f2018-08-17 15:01:37 +000051 break;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000052 }
Andrea Di Biagiob24953b2018-04-11 18:05:23 +000053
Andrea Di Biagio0875e752018-08-20 14:41:36 +000054 // Give lower priority to LSUnit stall events.
55 switch (LSU->isAvailable(IR)) {
56 case LSUnit::LSU_LQUEUE_FULL:
57 return Scheduler::SC_LOAD_QUEUE_FULL;
58 case LSUnit::LSU_SQUEUE_FULL:
59 return Scheduler::SC_STORE_QUEUE_FULL;
60 case LSUnit::LSU_AVAILABLE:
61 return Scheduler::SC_AVAILABLE;
62 }
63
64 llvm_unreachable("Don't know how to process this LSU state result!");
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000065}
66
Andrea Di Biagio27c4b092018-04-24 14:53:16 +000067void Scheduler::issueInstructionImpl(
Matt Davis21a8d322018-05-07 18:29:15 +000068 InstRef &IR,
Andrea Di Biagio27c4b092018-04-24 14:53:16 +000069 SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources) {
Matt Davis21a8d322018-05-07 18:29:15 +000070 Instruction *IS = IR.getInstruction();
71 const InstrDesc &D = IS->getDesc();
Andrea Di Biagioa3f2e482018-03-20 18:20:39 +000072
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000073 // Issue the instruction and collect all the consumed resources
74 // into a vector. That vector is then used to notify the listener.
Matt Davisad78e662018-04-26 22:30:40 +000075 Resources->issueInstruction(D, UsedResources);
Andrea Di Biagio27c4b092018-04-24 14:53:16 +000076
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000077 // Notify the instruction that it started executing.
78 // This updates the internal state of each write.
Matt Davis21a8d322018-05-07 18:29:15 +000079 IS->execute();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000080
Matt Davis21a8d322018-05-07 18:29:15 +000081 if (IS->isExecuting())
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +000082 IssuedSet.emplace_back(IR);
Andrea Di Biagio0875e752018-08-20 14:41:36 +000083 else if (IS->isExecuted())
84 LSU->onInstructionExecuted(IR);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000085}
86
Matt Davis488ac4c2018-06-14 01:20:18 +000087// Release the buffered resources and issue the instruction.
88void Scheduler::issueInstruction(
Andrea Di Biagio4660fd22018-08-22 10:23:28 +000089 InstRef &IR, SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources,
Andrea Di Biagio51849952018-08-21 12:40:15 +000090 SmallVectorImpl<InstRef> &ReadyInstructions) {
91 const Instruction &Inst = *IR.getInstruction();
92 bool HasDependentUsers = Inst.hasDependentUsers();
93
94 Resources->releaseBuffers(Inst.getDesc().Buffers);
Matt Davis488ac4c2018-06-14 01:20:18 +000095 issueInstructionImpl(IR, UsedResources);
Andrea Di Biagio51849952018-08-21 12:40:15 +000096 // Instructions that have been issued during this cycle might have unblocked
97 // other dependent instructions. Dependent instructions may be issued during
98 // this same cycle if operands have ReadAdvance entries. Promote those
99 // instructions to the ReadySet and notify the caller that those are ready.
100 if (HasDependentUsers)
101 promoteToReadySet(ReadyInstructions);
Andrea Di Biagio27c4b092018-04-24 14:53:16 +0000102}
103
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000104void Scheduler::promoteToReadySet(SmallVectorImpl<InstRef> &Ready) {
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000105 // Scan the set of waiting instructions and promote them to the
106 // ready queue if operands are all ready.
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000107 unsigned RemovedElements = 0;
Matt Davis06ac6af2018-08-17 18:06:01 +0000108 for (auto I = WaitSet.begin(), E = WaitSet.end(); I != E;) {
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000109 InstRef &IR = *I;
110 if (!IR.isValid())
111 break;
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000112
113 // Check if this instruction is now ready. In case, force
114 // a transition in state using method 'update()'.
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000115 Instruction &IS = *IR.getInstruction();
116 if (!IS.isReady())
117 IS.update();
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000118
Andrea Di Biagiof3374f02018-08-21 18:20:16 +0000119 // Check if there are still unsolved data dependencies.
Andrea Di Biagio0875e752018-08-20 14:41:36 +0000120 if (!isReady(IR)) {
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000121 ++I;
Andrea Di Biagioc7526162018-04-13 15:19:07 +0000122 continue;
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000123 }
Andrea Di Biagioc7526162018-04-13 15:19:07 +0000124
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000125 Ready.emplace_back(IR);
126 ReadySet.emplace_back(IR);
127
128 IR.invalidate();
129 ++RemovedElements;
130 std::iter_swap(I, E - RemovedElements);
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000131 }
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000132
133 WaitSet.resize(WaitSet.size() - RemovedElements);
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000134}
135
Matt Davis21a8d322018-05-07 18:29:15 +0000136InstRef Scheduler::select() {
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000137 unsigned QueueIndex = ReadySet.size();
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000138 for (unsigned I = 0, E = ReadySet.size(); I != E; ++I) {
139 const InstRef &IR = ReadySet[I];
Andrea Di Biagiof3374f02018-08-21 18:20:16 +0000140 if (QueueIndex == ReadySet.size() ||
141 Strategy->compare(IR, ReadySet[QueueIndex])) {
142 const InstrDesc &D = IR.getInstruction()->getDesc();
143 if (Resources->canBeIssued(D))
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000144 QueueIndex = I;
Andrea Di Biagio61c52af2018-07-06 08:08:30 +0000145 }
146 }
147
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000148 if (QueueIndex == ReadySet.size())
149 return InstRef();
150
Andrea Di Biagio27c4b092018-04-24 14:53:16 +0000151 // We found an instruction to issue.
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000152 InstRef IR = ReadySet[QueueIndex];
153 std::swap(ReadySet[QueueIndex], ReadySet[ReadySet.size() - 1]);
154 ReadySet.pop_back();
Matt Davis21a8d322018-05-07 18:29:15 +0000155 return IR;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000156}
157
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000158void Scheduler::updateIssuedSet(SmallVectorImpl<InstRef> &Executed) {
159 unsigned RemovedElements = 0;
Matt Davis06ac6af2018-08-17 18:06:01 +0000160 for (auto I = IssuedSet.begin(), E = IssuedSet.end(); I != E;) {
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000161 InstRef &IR = *I;
162 if (!IR.isValid())
163 break;
164 Instruction &IS = *IR.getInstruction();
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000165 if (!IS.isExecuted()) {
166 LLVM_DEBUG(dbgs() << "[SCHEDULER]: Instruction #" << IR
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000167 << " is still executing.\n");
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000168 ++I;
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000169 continue;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000170 }
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000171
Andrea Di Biagio0875e752018-08-20 14:41:36 +0000172 // Instruction IR has completed execution.
173 LSU->onInstructionExecuted(IR);
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000174 Executed.emplace_back(IR);
175 ++RemovedElements;
176 IR.invalidate();
177 std::iter_swap(I, E - RemovedElements);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000178 }
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000179
180 IssuedSet.resize(IssuedSet.size() - RemovedElements);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000181}
182
Andrea Di Biagio51849952018-08-21 12:40:15 +0000183void Scheduler::cycleEvent(SmallVectorImpl<ResourceRef> &Freed,
184 SmallVectorImpl<InstRef> &Executed,
185 SmallVectorImpl<InstRef> &Ready) {
186 // Release consumed resources.
Matt Davis488ac4c2018-06-14 01:20:18 +0000187 Resources->cycleEvent(Freed);
Andrea Di Biagio51849952018-08-21 12:40:15 +0000188
189 // Propagate the cycle event to the 'Issued' and 'Wait' sets.
190 for (InstRef &IR : IssuedSet)
191 IR.getInstruction()->cycleEvent();
192
193 updateIssuedSet(Executed);
194
195 for (InstRef &IR : WaitSet)
196 IR.getInstruction()->cycleEvent();
Andrea Di Biagiof3374f02018-08-21 18:20:16 +0000197
Andrea Di Biagio51849952018-08-21 12:40:15 +0000198 promoteToReadySet(Ready);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000199}
200
Andrea Di Biagio0875e752018-08-20 14:41:36 +0000201bool Scheduler::mustIssueImmediately(const InstRef &IR) const {
202 // Instructions that use an in-order dispatch/issue processor resource must be
203 // issued immediately to the pipeline(s). Any other in-order buffered
204 // resources (i.e. BufferSize=1) is consumed.
205 const InstrDesc &Desc = IR.getInstruction()->getDesc();
206 return Desc.isZeroLatency() || Resources->mustIssueImmediately(Desc);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000207}
Andrea Di Biagioa3f2e482018-03-20 18:20:39 +0000208
Andrea Di Biagio0875e752018-08-20 14:41:36 +0000209void Scheduler::dispatch(const InstRef &IR) {
Matt Davis488ac4c2018-06-14 01:20:18 +0000210 const InstrDesc &Desc = IR.getInstruction()->getDesc();
Andrea Di Biagio0875e752018-08-20 14:41:36 +0000211 Resources->reserveBuffers(Desc.Buffers);
212
213 // If necessary, reserve queue entries in the load-store unit (LSU).
214 bool IsMemOp = Desc.MayLoad || Desc.MayStore;
215 if (IsMemOp)
216 LSU->dispatch(IR);
217
218 if (!isReady(IR)) {
219 LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR << " to the WaitSet\n");
220 WaitSet.push_back(IR);
221 return;
222 }
223
224 // Don't add a zero-latency instruction to the Ready queue.
225 // A zero-latency instruction doesn't consume any scheduler resources. That is
226 // because it doesn't need to be executed, and it is often removed at register
227 // renaming stage. For example, register-register moves are often optimized at
228 // register renaming stage by simply updating register aliases. On some
229 // targets, zero-idiom instructions (for example: a xor that clears the value
230 // of a register) are treated specially, and are often eliminated at register
231 // renaming stage.
232 if (!mustIssueImmediately(IR)) {
Andrea Di Biagio1c3bcc62018-08-03 12:55:28 +0000233 LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR << " to the ReadySet\n");
234 ReadySet.push_back(IR);
Matt Davis488ac4c2018-06-14 01:20:18 +0000235 }
Andrea Di Biagio0875e752018-08-20 14:41:36 +0000236}
237
238bool Scheduler::isReady(const InstRef &IR) const {
239 const InstrDesc &Desc = IR.getInstruction()->getDesc();
240 bool IsMemOp = Desc.MayLoad || Desc.MayStore;
241 return IR.getInstruction()->isReady() && (!IsMemOp || LSU->isReady(IR));
Andrea Di Biagioa3f2e482018-03-20 18:20:39 +0000242}
243
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000244} // namespace mca