blob: c1e5d3e707ce8cd470e031ad3a616936b195f5a3 [file] [log] [blame]
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +00001//===--------------------- Dispatch.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 implements methods declared by class RegisterFile, DispatchUnit
12/// and RetireControlUnit.
13///
14//===----------------------------------------------------------------------===//
15
16#include "Dispatch.h"
17#include "Backend.h"
Clement Courbet844f22d2018-03-13 13:11:01 +000018#include "HWEventListener.h"
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000019#include "Scheduler.h"
20#include "llvm/Support/Debug.h"
21
22using namespace llvm;
23
24#define DEBUG_TYPE "llvm-mca"
25
26namespace mca {
27
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000028void RegisterFile::addRegisterFile(ArrayRef<unsigned> RegisterClasses,
29 unsigned NumTemps) {
30 unsigned RegisterFileIndex = RegisterFiles.size();
31 assert(RegisterFileIndex < 32 && "Too many register files!");
32 RegisterFiles.emplace_back(NumTemps);
33
34 // Special case where there are no register classes specified.
35 // An empty register class set means *all* registers.
36 if (RegisterClasses.empty()) {
37 for (std::pair<WriteState *, unsigned> &Mapping : RegisterMappings)
38 Mapping.second |= 1U << RegisterFileIndex;
39 } else {
40 for (const unsigned RegClassIndex : RegisterClasses) {
41 const MCRegisterClass &RC = MRI.getRegClass(RegClassIndex);
42 for (const MCPhysReg Reg : RC)
43 RegisterMappings[Reg].second |= 1U << RegisterFileIndex;
44 }
45 }
46}
47
Andrea Di Biagio12ef5262018-03-21 18:11:05 +000048void RegisterFile::createNewMappings(unsigned RegisterFileMask,
49 MutableArrayRef<unsigned> UsedPhysRegs) {
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000050 assert(RegisterFileMask && "RegisterFileMask cannot be zero!");
51 // Notify each register file that contains RegID.
52 do {
53 unsigned NextRegisterFile = llvm::PowerOf2Floor(RegisterFileMask);
54 unsigned RegisterFileIndex = llvm::countTrailingZeros(NextRegisterFile);
55 RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex];
56 RMT.NumUsedMappings++;
Andrea Di Biagio12ef5262018-03-21 18:11:05 +000057 UsedPhysRegs[RegisterFileIndex]++;
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000058 RegisterFileMask ^= NextRegisterFile;
59 } while (RegisterFileMask);
60}
61
Andrea Di Biagio12ef5262018-03-21 18:11:05 +000062void RegisterFile::removeMappings(unsigned RegisterFileMask,
63 MutableArrayRef<unsigned> FreedPhysRegs) {
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000064 assert(RegisterFileMask && "RegisterFileMask cannot be zero!");
65 // Notify each register file that contains RegID.
66 do {
67 unsigned NextRegisterFile = llvm::PowerOf2Floor(RegisterFileMask);
68 unsigned RegisterFileIndex = llvm::countTrailingZeros(NextRegisterFile);
69 RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex];
70 assert(RMT.NumUsedMappings);
71 RMT.NumUsedMappings--;
Andrea Di Biagio12ef5262018-03-21 18:11:05 +000072 FreedPhysRegs[RegisterFileIndex]++;
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000073 RegisterFileMask ^= NextRegisterFile;
74 } while (RegisterFileMask);
75}
76
Andrea Di Biagio12ef5262018-03-21 18:11:05 +000077void RegisterFile::addRegisterMapping(WriteState &WS,
78 MutableArrayRef<unsigned> UsedPhysRegs) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000079 unsigned RegID = WS.getRegisterID();
80 assert(RegID && "Adding an invalid register definition?");
81
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000082 RegisterMapping &Mapping = RegisterMappings[RegID];
83 Mapping.first = &WS;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000084 for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I)
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000085 RegisterMappings[*I].first = &WS;
86
Andrea Di Biagio12ef5262018-03-21 18:11:05 +000087 createNewMappings(Mapping.second, UsedPhysRegs);
88
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000089 // If this is a partial update, then we are done.
90 if (!WS.fullyUpdatesSuperRegs())
91 return;
92
93 for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I)
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000094 RegisterMappings[*I].first = &WS;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000095}
96
Andrea Di Biagio12ef5262018-03-21 18:11:05 +000097void RegisterFile::invalidateRegisterMapping(
98 const WriteState &WS, MutableArrayRef<unsigned> FreedPhysRegs) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000099 unsigned RegID = WS.getRegisterID();
100 bool ShouldInvalidateSuperRegs = WS.fullyUpdatesSuperRegs();
101
102 assert(RegID != 0 && "Invalidating an already invalid register?");
103 assert(WS.getCyclesLeft() != -512 &&
104 "Invalidating a write of unknown cycles!");
105 assert(WS.getCyclesLeft() <= 0 && "Invalid cycles left for this write!");
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000106 RegisterMapping &Mapping = RegisterMappings[RegID];
107 if (!Mapping.first)
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000108 return;
109
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000110 removeMappings(Mapping.second, FreedPhysRegs);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000111
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000112 if (Mapping.first == &WS)
113 Mapping.first = nullptr;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000114
115 for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I)
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000116 if (RegisterMappings[*I].first == &WS)
117 RegisterMappings[*I].first = nullptr;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000118
119 if (!ShouldInvalidateSuperRegs)
120 return;
121
122 for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I)
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000123 if (RegisterMappings[*I].first == &WS)
124 RegisterMappings[*I].first = nullptr;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000125}
126
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000127void RegisterFile::collectWrites(SmallVectorImpl<WriteState *> &Writes,
128 unsigned RegID) const {
129 assert(RegID && RegID < RegisterMappings.size());
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000130 WriteState *WS = RegisterMappings[RegID].first;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000131 if (WS) {
132 DEBUG(dbgs() << "Found a dependent use of RegID=" << RegID << '\n');
133 Writes.push_back(WS);
134 }
135
136 // Handle potential partial register updates.
137 for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) {
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000138 WS = RegisterMappings[*I].first;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000139 if (WS && std::find(Writes.begin(), Writes.end(), WS) == Writes.end()) {
140 DEBUG(dbgs() << "Found a dependent use of subReg " << *I << " (part of "
141 << RegID << ")\n");
142 Writes.push_back(WS);
143 }
144 }
145}
146
Andrea Di Biagio847accd2018-03-20 19:06:34 +0000147unsigned RegisterFile::isAvailable(ArrayRef<unsigned> Regs) const {
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000148 SmallVector<unsigned, 4> NumTemporaries(getNumRegisterFiles());
149
150 // Find how many new mappings must be created for each register file.
151 for (const unsigned RegID : Regs) {
152 unsigned RegisterFileMask = RegisterMappings[RegID].second;
153 do {
154 unsigned NextRegisterFileID = llvm::PowerOf2Floor(RegisterFileMask);
155 NumTemporaries[llvm::countTrailingZeros(NextRegisterFileID)]++;
156 RegisterFileMask ^= NextRegisterFileID;
157 } while (RegisterFileMask);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000158 }
159
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000160 unsigned Response = 0;
161 for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) {
162 unsigned Temporaries = NumTemporaries[I];
163 if (!Temporaries)
164 continue;
165
166 const RegisterMappingTracker &RMT = RegisterFiles[I];
167 if (!RMT.TotalMappings) {
168 // The register file has an unbound number of microarchitectural
169 // registers.
170 continue;
171 }
172
173 if (RMT.TotalMappings < Temporaries) {
174 // The current register file is too small. This may occur if the number of
175 // microarchitectural registers in register file #0 was changed by the
176 // users via flag -reg-file-size. Alternatively, the scheduling model
177 // specified a too small number of registers for this register file.
178 report_fatal_error(
179 "Not enough microarchitectural registers in the register file");
180 }
181
182 if (RMT.TotalMappings < RMT.NumUsedMappings + Temporaries)
183 Response |= (1U << I);
184 }
185
186 return Response;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000187}
188
189#ifndef NDEBUG
190void RegisterFile::dump() const {
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000191 for (unsigned I = 0, E = MRI.getNumRegs(); I < E; ++I) {
192 const RegisterMapping &RM = RegisterMappings[I];
193 dbgs() << MRI.getName(I) << ", " << I << ", Map=" << RM.second << ", ";
194 if (RM.first)
195 RM.first->dump();
196 else
197 dbgs() << "(null)\n";
198 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000199
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000200 for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) {
201 dbgs() << "Register File #" << I;
202 const RegisterMappingTracker &RMT = RegisterFiles[I];
203 dbgs() << "\n TotalMappings: " << RMT.TotalMappings
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000204 << "\n NumUsedMappings: " << RMT.NumUsedMappings << '\n';
205 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000206}
207#endif
208
209// Reserves a number of slots, and returns a new token.
210unsigned RetireControlUnit::reserveSlot(unsigned Index, unsigned NumMicroOps) {
211 assert(isAvailable(NumMicroOps));
212 unsigned NormalizedQuantity =
213 std::min(NumMicroOps, static_cast<unsigned>(Queue.size()));
214 // Zero latency instructions may have zero mOps. Artificially bump this
215 // value to 1. Although zero latency instructions don't consume scheduler
216 // resources, they still consume one slot in the retire queue.
217 NormalizedQuantity = std::max(NormalizedQuantity, 1U);
218 unsigned TokenID = NextAvailableSlotIdx;
219 Queue[NextAvailableSlotIdx] = {Index, NormalizedQuantity, false};
220 NextAvailableSlotIdx += NormalizedQuantity;
221 NextAvailableSlotIdx %= Queue.size();
222 AvailableSlots -= NormalizedQuantity;
223 return TokenID;
224}
225
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000226void DispatchUnit::notifyInstructionDispatched(
227 unsigned Index, ArrayRef<unsigned> UsedRegs) {
Clement Courbet844f22d2018-03-13 13:11:01 +0000228 DEBUG(dbgs() << "[E] Instruction Dispatched: " << Index << '\n');
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000229 Owner->notifyInstructionEvent(HWInstructionDispatchedEvent(Index, UsedRegs));
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000230}
231
232void DispatchUnit::notifyInstructionRetired(unsigned Index) {
Clement Courbet844f22d2018-03-13 13:11:01 +0000233 DEBUG(dbgs() << "[E] Instruction Retired: " << Index << '\n');
Clement Courbet844f22d2018-03-13 13:11:01 +0000234 const Instruction &IS = Owner->getInstruction(Index);
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000235 SmallVector<unsigned, 4> FreedRegs(RAT->getNumRegisterFiles());
Andrea Di Biagio43e8f7d2018-03-21 12:49:07 +0000236 for (const std::unique_ptr<WriteState> &WS : IS.getDefs())
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000237 RAT->invalidateRegisterMapping(*WS.get(), FreedRegs);
Andrea Di Biagio43e8f7d2018-03-21 12:49:07 +0000238
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000239 Owner->notifyInstructionEvent(HWInstructionRetiredEvent(Index, FreedRegs));
Clement Courbet844f22d2018-03-13 13:11:01 +0000240 Owner->eraseInstruction(Index);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000241}
242
243void RetireControlUnit::cycleEvent() {
244 if (isEmpty())
245 return;
246
247 unsigned NumRetired = 0;
248 while (!isEmpty()) {
249 if (MaxRetirePerCycle != 0 && NumRetired == MaxRetirePerCycle)
250 break;
251 RUToken &Current = Queue[CurrentInstructionSlotIdx];
252 assert(Current.NumSlots && "Reserved zero slots?");
253 if (!Current.Executed)
254 break;
255 Owner->notifyInstructionRetired(Current.Index);
256 CurrentInstructionSlotIdx += Current.NumSlots;
257 CurrentInstructionSlotIdx %= Queue.size();
258 AvailableSlots += Current.NumSlots;
259 NumRetired++;
260 }
261}
262
263void RetireControlUnit::onInstructionExecuted(unsigned TokenID) {
264 assert(Queue.size() > TokenID);
265 assert(Queue[TokenID].Executed == false && Queue[TokenID].Index != ~0U);
266 Queue[TokenID].Executed = true;
267}
268
269#ifndef NDEBUG
270void RetireControlUnit::dump() const {
271 dbgs() << "Retire Unit: { Total Slots=" << Queue.size()
272 << ", Available Slots=" << AvailableSlots << " }\n";
273}
274#endif
275
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000276bool DispatchUnit::checkRAT(unsigned Index, const Instruction &Instr) {
277 const InstrDesc &Desc = Instr.getDesc();
278 unsigned NumWrites = Desc.Writes.size();
279 unsigned RegisterMask = RAT->isAvailable(NumWrites);
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000280 // A mask with all zeroes means: register files are available.
281 if (RegisterMask) {
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000282 Owner->notifyStallEvent(
283 HWStallEvent(HWStallEvent::RegisterFileStall, Index));
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000284 return false;
285 }
286
287 return true;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000288}
289
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000290bool DispatchUnit::checkRCU(unsigned Index, const InstrDesc &Desc) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000291 unsigned NumMicroOps = Desc.NumMicroOps;
292 if (RCU->isAvailable(NumMicroOps))
293 return true;
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000294 Owner->notifyStallEvent(
295 HWStallEvent(HWStallEvent::RetireControlUnitStall, Index));
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000296 return false;
297}
298
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000299bool DispatchUnit::checkScheduler(unsigned Index, const InstrDesc &Desc) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000300 // If this is a zero-latency instruction, then it bypasses
301 // the scheduler.
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000302 HWStallEvent::GenericEventType Type = HWStallEvent::Invalid;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000303 switch (SC->canBeDispatched(Desc)) {
304 case Scheduler::HWS_AVAILABLE:
305 return true;
306 case Scheduler::HWS_QUEUE_UNAVAILABLE:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000307 Type = HWStallEvent::SchedulerQueueFull;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000308 break;
309 case Scheduler::HWS_LD_QUEUE_UNAVAILABLE:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000310 Type = HWStallEvent::LoadQueueFull;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000311 break;
312 case Scheduler::HWS_ST_QUEUE_UNAVAILABLE:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000313 Type = HWStallEvent::StoreQueueFull;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000314 break;
315 case Scheduler::HWS_DISPATCH_GROUP_RESTRICTION:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000316 Type = HWStallEvent::DispatchGroupStall;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000317 }
318
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000319 Owner->notifyStallEvent(HWStallEvent(Type, Index));
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000320 return false;
321}
322
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000323void DispatchUnit::updateRAWDependencies(ReadState &RS,
324 const MCSubtargetInfo &STI) {
325 SmallVector<WriteState *, 4> DependentWrites;
326
327 collectWrites(DependentWrites, RS.getRegisterID());
328 RS.setDependentWrites(DependentWrites.size());
329 DEBUG(dbgs() << "Found " << DependentWrites.size() << " dependent writes\n");
330 // We know that this read depends on all the writes in DependentWrites.
331 // For each write, check if we have ReadAdvance information, and use it
332 // to figure out in how many cycles this read becomes available.
333 const ReadDescriptor &RD = RS.getDescriptor();
334 if (!RD.HasReadAdvanceEntries) {
335 for (WriteState *WS : DependentWrites)
336 WS->addUser(&RS, /* ReadAdvance */ 0);
337 return;
338 }
339
340 const MCSchedModel &SM = STI.getSchedModel();
341 const MCSchedClassDesc *SC = SM.getSchedClassDesc(RD.SchedClassID);
342 for (WriteState *WS : DependentWrites) {
343 unsigned WriteResID = WS->getWriteResourceID();
344 int ReadAdvance = STI.getReadAdvanceCycles(SC, RD.OpIndex, WriteResID);
345 WS->addUser(&RS, ReadAdvance);
346 }
347 // Prepare the set for another round.
348 DependentWrites.clear();
349}
350
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000351void DispatchUnit::dispatch(unsigned IID, Instruction *NewInst,
352 const MCSubtargetInfo &STI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000353 assert(!CarryOver && "Cannot dispatch another instruction!");
354 unsigned NumMicroOps = NewInst->getDesc().NumMicroOps;
355 if (NumMicroOps > DispatchWidth) {
356 assert(AvailableEntries == DispatchWidth);
357 AvailableEntries = 0;
358 CarryOver = NumMicroOps - DispatchWidth;
359 } else {
360 assert(AvailableEntries >= NumMicroOps);
361 AvailableEntries -= NumMicroOps;
362 }
363
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000364 // Update RAW dependencies.
365 for (std::unique_ptr<ReadState> &RS : NewInst->getUses())
366 updateRAWDependencies(*RS, STI);
367
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000368 // Allocate new mappings.
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000369 SmallVector<unsigned, 4> RegisterFiles(RAT->getNumRegisterFiles());
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000370 for (std::unique_ptr<WriteState> &WS : NewInst->getDefs())
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000371 RAT->addRegisterMapping(*WS, RegisterFiles);
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000372
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000373 // Reserve slots in the RCU, and notify the instruction that it has been
374 // dispatched to the schedulers for execution.
375 NewInst->dispatch(RCU->reserveSlot(IID, NumMicroOps));
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000376
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000377 // Notify listeners of the "instruction dispatched" event.
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000378 notifyInstructionDispatched(IID, RegisterFiles);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000379
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000380 // Now move the instruction into the scheduler's queue.
381 // The scheduler is responsible for checking if this is a zero-latency
382 // instruction that doesn't consume pipeline/scheduler resources.
Andrea Di Biagio44bfcd22018-03-19 19:09:38 +0000383 SC->scheduleInstruction(IID, *NewInst);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000384}
385
386#ifndef NDEBUG
387void DispatchUnit::dump() const {
388 RAT->dump();
389 RCU->dump();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000390}
391#endif
392
393} // namespace mca