blob: a2561fc3582d56368150fa1afe6e106001ff2bd4 [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 Biagio4704f032018-03-20 12:25:54 +000015#include "Support.h"
Andrea Di Biagioeec6b812018-06-26 10:44:12 +000016#include "llvm/Support/Debug.h"
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000017#include "llvm/Support/raw_ostream.h"
18
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000019namespace mca {
20
21using namespace llvm;
22
Andrea Di Biagioeec6b812018-06-26 10:44:12 +000023#define DEBUG_TYPE "llvm-mca"
24
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000025uint64_t ResourceState::selectNextInSequence() {
26 assert(isReady());
27 uint64_t Next = getNextInSequence();
28 while (!isSubResourceReady(Next)) {
29 updateNextInSequence();
30 Next = getNextInSequence();
31 }
32 return Next;
33}
34
35#ifndef NDEBUG
36void ResourceState::dump() const {
37 dbgs() << "MASK: " << ResourceMask << ", SIZE_MASK: " << ResourceSizeMask
38 << ", NEXT: " << NextInSequenceMask << ", RDYMASK: " << ReadyMask
39 << ", BufferSize=" << BufferSize
40 << ", AvailableSlots=" << AvailableSlots
41 << ", Reserved=" << Unavailable << '\n';
42}
43#endif
44
Andrea Di Biagio4704f032018-03-20 12:25:54 +000045void ResourceManager::initialize(const llvm::MCSchedModel &SM) {
46 computeProcResourceMasks(SM, ProcResID2Mask);
47 for (unsigned I = 0, E = SM.getNumProcResourceKinds(); I < E; ++I)
48 addResource(*SM.getProcResource(I), I, ProcResID2Mask[I]);
49}
50
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000051// Adds a new resource state in Resources, as well as a new descriptor in
52// ResourceDescriptor. Map 'Resources' allows to quickly obtain ResourceState
53// objects from resource mask identifiers.
54void ResourceManager::addResource(const MCProcResourceDesc &Desc,
Andrea Di Biagioe1a1da12018-03-13 13:58:02 +000055 unsigned Index, uint64_t Mask) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000056 assert(Resources.find(Mask) == Resources.end() && "Resource already added!");
Andrea Di Biagio0c541292018-03-10 16:55:07 +000057 Resources[Mask] = llvm::make_unique<ResourceState>(Desc, Index, Mask);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000058}
59
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000060// Returns the actual resource consumed by this Use.
61// First, is the primary resource ID.
62// Second, is the specific sub-resource ID.
63std::pair<uint64_t, uint64_t> ResourceManager::selectPipe(uint64_t ResourceID) {
64 ResourceState &RS = *Resources[ResourceID];
65 uint64_t SubResourceID = RS.selectNextInSequence();
66 if (RS.isAResourceGroup())
67 return selectPipe(SubResourceID);
68 return std::pair<uint64_t, uint64_t>(ResourceID, SubResourceID);
69}
70
71void ResourceState::removeFromNextInSequence(uint64_t ID) {
72 assert(NextInSequenceMask);
73 assert(countPopulation(ID) == 1);
74 if (ID > getNextInSequence())
75 RemovedFromNextInSequence |= ID;
76 NextInSequenceMask = NextInSequenceMask & (~ID);
77 if (!NextInSequenceMask) {
78 NextInSequenceMask = ResourceSizeMask;
79 assert(NextInSequenceMask != RemovedFromNextInSequence);
80 NextInSequenceMask ^= RemovedFromNextInSequence;
81 RemovedFromNextInSequence = 0;
82 }
83}
84
85void ResourceManager::use(ResourceRef RR) {
86 // Mark the sub-resource referenced by RR as used.
87 ResourceState &RS = *Resources[RR.first];
88 RS.markSubResourceAsUsed(RR.second);
89 // If there are still available units in RR.first,
90 // then we are done.
91 if (RS.isReady())
92 return;
93
94 // Notify to other resources that RR.first is no longer available.
95 for (const std::pair<uint64_t, UniqueResourceState> &Res : Resources) {
96 ResourceState &Current = *Res.second.get();
97 if (!Current.isAResourceGroup() || Current.getResourceMask() == RR.first)
98 continue;
99
100 if (Current.containsResource(RR.first)) {
101 Current.markSubResourceAsUsed(RR.first);
102 Current.removeFromNextInSequence(RR.first);
103 }
104 }
105}
106
107void ResourceManager::release(ResourceRef RR) {
108 ResourceState &RS = *Resources[RR.first];
109 bool WasFullyUsed = !RS.isReady();
110 RS.releaseSubResource(RR.second);
111 if (!WasFullyUsed)
112 return;
113
114 for (const std::pair<uint64_t, UniqueResourceState> &Res : Resources) {
115 ResourceState &Current = *Res.second.get();
116 if (!Current.isAResourceGroup() || Current.getResourceMask() == RR.first)
117 continue;
118
119 if (Current.containsResource(RR.first))
120 Current.releaseSubResource(RR.first);
121 }
122}
123
Andrea Di Biagio44bfcd22018-03-19 19:09:38 +0000124ResourceStateEvent
Andrea Di Biagio847accd2018-03-20 19:06:34 +0000125ResourceManager::canBeDispatched(ArrayRef<uint64_t> Buffers) const {
Andrea Di Biagio44bfcd22018-03-19 19:09:38 +0000126 ResourceStateEvent Result = ResourceStateEvent::RS_BUFFER_AVAILABLE;
127 for (uint64_t Buffer : Buffers) {
128 Result = isBufferAvailable(Buffer);
129 if (Result != ResourceStateEvent::RS_BUFFER_AVAILABLE)
130 break;
131 }
132 return Result;
133}
134
Andrea Di Biagio847accd2018-03-20 19:06:34 +0000135void ResourceManager::reserveBuffers(ArrayRef<uint64_t> Buffers) {
Andrea Di Biagioe1a1da12018-03-13 13:58:02 +0000136 for (const uint64_t R : Buffers) {
Andrea Di Biagio44bfcd22018-03-19 19:09:38 +0000137 reserveBuffer(R);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000138 ResourceState &Resource = *Resources[R];
139 if (Resource.isADispatchHazard()) {
140 assert(!Resource.isReserved());
141 Resource.setReserved();
142 }
143 }
144}
145
Andrea Di Biagio847accd2018-03-20 19:06:34 +0000146void ResourceManager::releaseBuffers(ArrayRef<uint64_t> Buffers) {
Andrea Di Biagio44bfcd22018-03-19 19:09:38 +0000147 for (const uint64_t R : Buffers)
148 releaseBuffer(R);
149}
150
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000151bool ResourceManager::canBeIssued(const InstrDesc &Desc) const {
152 return std::all_of(Desc.Resources.begin(), Desc.Resources.end(),
153 [&](const std::pair<uint64_t, const ResourceUsage> &E) {
154 unsigned NumUnits =
155 E.second.isReserved() ? 0U : E.second.NumUnits;
156 return isReady(E.first, NumUnits);
157 });
158}
159
160// Returns true if all resources are in-order, and there is at least one
161// resource which is a dispatch hazard (BufferSize = 0).
162bool ResourceManager::mustIssueImmediately(const InstrDesc &Desc) {
163 if (!canBeIssued(Desc))
164 return false;
Andrea Di Biagio40370112018-05-31 20:27:46 +0000165 bool AllInOrderResources = all_of(Desc.Buffers, [&](uint64_t BufferMask) {
166 const ResourceState &Resource = *Resources[BufferMask];
167 return Resource.isInOrder() || Resource.isADispatchHazard();
168 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000169 if (!AllInOrderResources)
170 return false;
171
Andrea Di Biagio40370112018-05-31 20:27:46 +0000172 return any_of(Desc.Buffers, [&](uint64_t BufferMask) {
173 return Resources[BufferMask]->isADispatchHazard();
174 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000175}
176
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000177void ResourceManager::issueInstruction(
Matt Davisad78e662018-04-26 22:30:40 +0000178 const InstrDesc &Desc,
Andrea Di Biagio51dba7d2018-03-23 17:36:07 +0000179 SmallVectorImpl<std::pair<ResourceRef, double>> &Pipes) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000180 for (const std::pair<uint64_t, ResourceUsage> &R : Desc.Resources) {
181 const CycleSegment &CS = R.second.CS;
182 if (!CS.size()) {
183 releaseResource(R.first);
184 continue;
185 }
186
187 assert(CS.begin() == 0 && "Invalid {Start, End} cycles!");
188 if (!R.second.isReserved()) {
189 ResourceRef Pipe = selectPipe(R.first);
190 use(Pipe);
191 BusyResources[Pipe] += CS.size();
Andrea Di Biagio0c541292018-03-10 16:55:07 +0000192 // Replace the resource mask with a valid processor resource index.
193 const ResourceState &RS = *Resources[Pipe.first];
194 Pipe.first = RS.getProcResourceID();
Andrea Di Biagio51dba7d2018-03-23 17:36:07 +0000195 Pipes.emplace_back(
196 std::pair<ResourceRef, double>(Pipe, static_cast<double>(CS.size())));
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000197 } else {
198 assert((countPopulation(R.first) > 1) && "Expected a group!");
199 // Mark this group as reserved.
200 assert(R.second.isReserved());
201 reserveResource(R.first);
202 BusyResources[ResourceRef(R.first, R.first)] += CS.size();
203 }
204 }
205}
206
207void ResourceManager::cycleEvent(SmallVectorImpl<ResourceRef> &ResourcesFreed) {
208 for (std::pair<ResourceRef, unsigned> &BR : BusyResources) {
209 if (BR.second)
210 BR.second--;
211 if (!BR.second) {
212 // Release this resource.
213 const ResourceRef &RR = BR.first;
214
215 if (countPopulation(RR.first) == 1)
216 release(RR);
217
218 releaseResource(RR.first);
219 ResourcesFreed.push_back(RR);
220 }
221 }
222
223 for (const ResourceRef &RF : ResourcesFreed)
224 BusyResources.erase(RF);
225}
226
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000227#ifndef NDEBUG
228void Scheduler::dump() const {
229 dbgs() << "[SCHEDULER]: WaitQueue size is: " << WaitQueue.size() << '\n';
230 dbgs() << "[SCHEDULER]: ReadyQueue size is: " << ReadyQueue.size() << '\n';
231 dbgs() << "[SCHEDULER]: IssuedQueue size is: " << IssuedQueue.size() << '\n';
232 Resources->dump();
233}
234#endif
235
Matt Davis488ac4c2018-06-14 01:20:18 +0000236bool Scheduler::canBeDispatched(const InstRef &IR,
237 HWStallEvent::GenericEventType &Event) const {
238 Event = HWStallEvent::Invalid;
Matt Davis21a8d322018-05-07 18:29:15 +0000239 const InstrDesc &Desc = IR.getInstruction()->getDesc();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000240
Andrea Di Biagiob24953b2018-04-11 18:05:23 +0000241 if (Desc.MayLoad && LSU->isLQFull())
Matt Davis488ac4c2018-06-14 01:20:18 +0000242 Event = HWStallEvent::LoadQueueFull;
Andrea Di Biagiob24953b2018-04-11 18:05:23 +0000243 else if (Desc.MayStore && LSU->isSQFull())
Matt Davis488ac4c2018-06-14 01:20:18 +0000244 Event = HWStallEvent::StoreQueueFull;
Andrea Di Biagiob24953b2018-04-11 18:05:23 +0000245 else {
246 switch (Resources->canBeDispatched(Desc.Buffers)) {
Andrea Di Biagioc7526162018-04-13 15:19:07 +0000247 default:
248 return true;
Andrea Di Biagiob24953b2018-04-11 18:05:23 +0000249 case ResourceStateEvent::RS_BUFFER_UNAVAILABLE:
Matt Davis488ac4c2018-06-14 01:20:18 +0000250 Event = HWStallEvent::SchedulerQueueFull;
Andrea Di Biagiob24953b2018-04-11 18:05:23 +0000251 break;
252 case ResourceStateEvent::RS_RESERVED:
Matt Davis488ac4c2018-06-14 01:20:18 +0000253 Event = HWStallEvent::DispatchGroupStall;
Andrea Di Biagiob24953b2018-04-11 18:05:23 +0000254 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000255 }
Andrea Di Biagiob24953b2018-04-11 18:05:23 +0000256
Andrea Di Biagiob24953b2018-04-11 18:05:23 +0000257 return false;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000258}
259
Andrea Di Biagio27c4b092018-04-24 14:53:16 +0000260void Scheduler::issueInstructionImpl(
Matt Davis21a8d322018-05-07 18:29:15 +0000261 InstRef &IR,
Andrea Di Biagio27c4b092018-04-24 14:53:16 +0000262 SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources) {
Matt Davis21a8d322018-05-07 18:29:15 +0000263 Instruction *IS = IR.getInstruction();
264 const InstrDesc &D = IS->getDesc();
Andrea Di Biagioa3f2e482018-03-20 18:20:39 +0000265
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000266 // Issue the instruction and collect all the consumed resources
267 // into a vector. That vector is then used to notify the listener.
Matt Davisad78e662018-04-26 22:30:40 +0000268 Resources->issueInstruction(D, UsedResources);
Andrea Di Biagio27c4b092018-04-24 14:53:16 +0000269
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000270 // Notify the instruction that it started executing.
271 // This updates the internal state of each write.
Matt Davis21a8d322018-05-07 18:29:15 +0000272 IS->execute();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000273
Matt Davis21a8d322018-05-07 18:29:15 +0000274 if (IS->isExecuting())
275 IssuedQueue[IR.getSourceIndex()] = IS;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000276}
277
Matt Davis488ac4c2018-06-14 01:20:18 +0000278// Release the buffered resources and issue the instruction.
279void Scheduler::issueInstruction(
280 InstRef &IR,
281 SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources) {
Matt Davis21a8d322018-05-07 18:29:15 +0000282 const InstrDesc &Desc = IR.getInstruction()->getDesc();
Andrea Di Biagio27c4b092018-04-24 14:53:16 +0000283 releaseBuffers(Desc.Buffers);
Matt Davis488ac4c2018-06-14 01:20:18 +0000284 issueInstructionImpl(IR, UsedResources);
Andrea Di Biagio27c4b092018-04-24 14:53:16 +0000285}
286
Matt Davis21a8d322018-05-07 18:29:15 +0000287void Scheduler::promoteToReadyQueue(SmallVectorImpl<InstRef> &Ready) {
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000288 // Scan the set of waiting instructions and promote them to the
289 // ready queue if operands are all ready.
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000290 for (auto I = WaitQueue.begin(), E = WaitQueue.end(); I != E;) {
Matt Davis21a8d322018-05-07 18:29:15 +0000291 const unsigned IID = I->first;
292 Instruction *IS = I->second;
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000293
294 // Check if this instruction is now ready. In case, force
295 // a transition in state using method 'update()'.
Andrea Di Biagioeb1bef62018-06-27 11:17:07 +0000296 if (!IS->isReady())
297 IS->update();
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000298
Matt Davis21a8d322018-05-07 18:29:15 +0000299 const InstrDesc &Desc = IS->getDesc();
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000300 bool IsMemOp = Desc.MayLoad || Desc.MayStore;
Matt Davis21a8d322018-05-07 18:29:15 +0000301 if (!IS->isReady() || (IsMemOp && !LSU->isReady({IID, IS}))) {
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000302 ++I;
Andrea Di Biagioc7526162018-04-13 15:19:07 +0000303 continue;
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000304 }
Andrea Di Biagioc7526162018-04-13 15:19:07 +0000305
Matt Davis21a8d322018-05-07 18:29:15 +0000306 Ready.emplace_back(IID, IS);
307 ReadyQueue[IID] = IS;
Andrea Di Biagioc7526162018-04-13 15:19:07 +0000308 auto ToRemove = I;
309 ++I;
310 WaitQueue.erase(ToRemove);
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000311 }
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000312}
313
Matt Davis21a8d322018-05-07 18:29:15 +0000314InstRef Scheduler::select() {
Andrea Di Biagio61c52af2018-07-06 08:08:30 +0000315 // Find the oldest ready-to-issue instruction in the ReadyQueue.
316 auto It = std::find_if(ReadyQueue.begin(), ReadyQueue.end(),
317 [&](const QueueEntryTy &Entry) {
318 const InstrDesc &D = Entry.second->getDesc();
319 return Resources->canBeIssued(D);
320 });
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000321
Andrea Di Biagioc7526162018-04-13 15:19:07 +0000322 if (It == ReadyQueue.end())
Andrea Di Biagio27c4b092018-04-24 14:53:16 +0000323 return {0, nullptr};
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000324
Andrea Di Biagio61c52af2018-07-06 08:08:30 +0000325 // We want to prioritize older instructions over younger instructions to
326 // minimize the pressure on the reorder buffer. We also want to
327 // rank higher the instructions with more users to better expose ILP.
328
329 // Compute a rank value based on the age of an instruction (i.e. its source
330 // index) and its number of users. The lower the rank value, the better.
331 int Rank = It->first - It->second->getNumUsers();
332 for (auto I = It, E = ReadyQueue.end(); I != E; ++I) {
333 int CurrentRank = I->first - I->second->getNumUsers();
334 if (CurrentRank < Rank) {
335 const InstrDesc &D = I->second->getDesc();
336 if (Resources->canBeIssued(D))
337 It = I;
338 }
339 }
340
Andrea Di Biagio27c4b092018-04-24 14:53:16 +0000341 // We found an instruction to issue.
Matt Davis21a8d322018-05-07 18:29:15 +0000342 InstRef IR(It->first, It->second);
Andrea Di Biagio27c4b092018-04-24 14:53:16 +0000343 ReadyQueue.erase(It);
Matt Davis21a8d322018-05-07 18:29:15 +0000344 return IR;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000345}
346
Matt Davis21a8d322018-05-07 18:29:15 +0000347void Scheduler::updatePendingQueue(SmallVectorImpl<InstRef> &Ready) {
Andrea Di Biagio0a837ef2018-03-29 14:26:56 +0000348 // Notify to instructions in the pending queue that a new cycle just
349 // started.
350 for (QueueEntryTy Entry : WaitQueue)
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000351 Entry.second->cycleEvent();
Andrea Di Biagio27c4b092018-04-24 14:53:16 +0000352 promoteToReadyQueue(Ready);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000353}
354
Matt Davis21a8d322018-05-07 18:29:15 +0000355void Scheduler::updateIssuedQueue(SmallVectorImpl<InstRef> &Executed) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000356 for (auto I = IssuedQueue.begin(), E = IssuedQueue.end(); I != E;) {
357 const QueueEntryTy Entry = *I;
Matt Davis21a8d322018-05-07 18:29:15 +0000358 Instruction *IS = Entry.second;
359 IS->cycleEvent();
360 if (IS->isExecuted()) {
361 Executed.push_back({Entry.first, Entry.second});
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000362 auto ToRemove = I;
363 ++I;
364 IssuedQueue.erase(ToRemove);
365 } else {
Nicola Zaghend34e60c2018-05-14 12:53:11 +0000366 LLVM_DEBUG(dbgs() << "[SCHEDULER]: Instruction " << Entry.first
367 << " is still executing.\n");
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000368 ++I;
369 }
370 }
371}
372
Matt Davis488ac4c2018-06-14 01:20:18 +0000373void Scheduler::onInstructionExecuted(const InstRef &IR) {
Matt Davis21a8d322018-05-07 18:29:15 +0000374 LSU->onInstructionExecuted(IR);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000375}
376
Matt Davis488ac4c2018-06-14 01:20:18 +0000377void Scheduler::reclaimSimulatedResources(SmallVectorImpl<ResourceRef> &Freed) {
378 Resources->cycleEvent(Freed);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000379}
380
Matt Davis488ac4c2018-06-14 01:20:18 +0000381bool Scheduler::reserveResources(InstRef &IR) {
382 // If necessary, reserve queue entries in the load-store unit (LSU).
383 const bool Reserved = LSU->reserve(IR);
384 if (!IR.getInstruction()->isReady() || (Reserved && !LSU->isReady(IR))) {
385 LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding " << IR << " to the Wait Queue\n");
386 WaitQueue[IR.getSourceIndex()] = IR.getInstruction();
387 return false;
388 }
389 return true;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000390}
Andrea Di Biagioa3f2e482018-03-20 18:20:39 +0000391
Matt Davis488ac4c2018-06-14 01:20:18 +0000392bool Scheduler::issueImmediately(InstRef &IR) {
393 const InstrDesc &Desc = IR.getInstruction()->getDesc();
394 if (!Desc.isZeroLatency() && !Resources->mustIssueImmediately(Desc)) {
395 LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding " << IR
396 << " to the Ready Queue\n");
397 ReadyQueue[IR.getSourceIndex()] = IR.getInstruction();
398 return false;
399 }
400 return true;
Andrea Di Biagioa3f2e482018-03-20 18:20:39 +0000401}
402
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000403} // namespace mca