blob: 51fe0d8791b532850fe0a2f2c2a129668a108059 [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 Biagio94fafdf2018-03-24 16:05:36 +0000226void DispatchUnit::notifyInstructionDispatched(unsigned Index,
227 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) {
Andrea Di Biagio9ecb4012018-03-27 15:23:41 +0000277 SmallVector<unsigned, 4> RegDefs;
278 for (const std::unique_ptr<WriteState> &RegDef : Instr.getDefs())
279 RegDefs.emplace_back(RegDef->getRegisterID());
280
281 unsigned RegisterMask = RAT->isAvailable(RegDefs);
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000282 // A mask with all zeroes means: register files are available.
283 if (RegisterMask) {
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000284 Owner->notifyStallEvent(
285 HWStallEvent(HWStallEvent::RegisterFileStall, Index));
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000286 return false;
287 }
288
289 return true;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000290}
291
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000292bool DispatchUnit::checkRCU(unsigned Index, const InstrDesc &Desc) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000293 unsigned NumMicroOps = Desc.NumMicroOps;
294 if (RCU->isAvailable(NumMicroOps))
295 return true;
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000296 Owner->notifyStallEvent(
297 HWStallEvent(HWStallEvent::RetireControlUnitStall, Index));
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000298 return false;
299}
300
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000301bool DispatchUnit::checkScheduler(unsigned Index, const InstrDesc &Desc) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000302 // If this is a zero-latency instruction, then it bypasses
303 // the scheduler.
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000304 HWStallEvent::GenericEventType Type = HWStallEvent::Invalid;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000305 switch (SC->canBeDispatched(Desc)) {
306 case Scheduler::HWS_AVAILABLE:
307 return true;
308 case Scheduler::HWS_QUEUE_UNAVAILABLE:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000309 Type = HWStallEvent::SchedulerQueueFull;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000310 break;
311 case Scheduler::HWS_LD_QUEUE_UNAVAILABLE:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000312 Type = HWStallEvent::LoadQueueFull;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000313 break;
314 case Scheduler::HWS_ST_QUEUE_UNAVAILABLE:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000315 Type = HWStallEvent::StoreQueueFull;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000316 break;
317 case Scheduler::HWS_DISPATCH_GROUP_RESTRICTION:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000318 Type = HWStallEvent::DispatchGroupStall;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000319 }
320
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000321 Owner->notifyStallEvent(HWStallEvent(Type, Index));
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000322 return false;
323}
324
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000325void DispatchUnit::updateRAWDependencies(ReadState &RS,
326 const MCSubtargetInfo &STI) {
327 SmallVector<WriteState *, 4> DependentWrites;
328
329 collectWrites(DependentWrites, RS.getRegisterID());
330 RS.setDependentWrites(DependentWrites.size());
331 DEBUG(dbgs() << "Found " << DependentWrites.size() << " dependent writes\n");
332 // We know that this read depends on all the writes in DependentWrites.
333 // For each write, check if we have ReadAdvance information, and use it
334 // to figure out in how many cycles this read becomes available.
335 const ReadDescriptor &RD = RS.getDescriptor();
336 if (!RD.HasReadAdvanceEntries) {
337 for (WriteState *WS : DependentWrites)
338 WS->addUser(&RS, /* ReadAdvance */ 0);
339 return;
340 }
341
342 const MCSchedModel &SM = STI.getSchedModel();
343 const MCSchedClassDesc *SC = SM.getSchedClassDesc(RD.SchedClassID);
344 for (WriteState *WS : DependentWrites) {
345 unsigned WriteResID = WS->getWriteResourceID();
346 int ReadAdvance = STI.getReadAdvanceCycles(SC, RD.OpIndex, WriteResID);
347 WS->addUser(&RS, ReadAdvance);
348 }
349 // Prepare the set for another round.
350 DependentWrites.clear();
351}
352
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000353void DispatchUnit::dispatch(unsigned IID, Instruction *NewInst,
354 const MCSubtargetInfo &STI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000355 assert(!CarryOver && "Cannot dispatch another instruction!");
356 unsigned NumMicroOps = NewInst->getDesc().NumMicroOps;
357 if (NumMicroOps > DispatchWidth) {
358 assert(AvailableEntries == DispatchWidth);
359 AvailableEntries = 0;
360 CarryOver = NumMicroOps - DispatchWidth;
361 } else {
362 assert(AvailableEntries >= NumMicroOps);
363 AvailableEntries -= NumMicroOps;
364 }
365
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000366 // Update RAW dependencies.
367 for (std::unique_ptr<ReadState> &RS : NewInst->getUses())
368 updateRAWDependencies(*RS, STI);
369
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000370 // Allocate new mappings.
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000371 SmallVector<unsigned, 4> RegisterFiles(RAT->getNumRegisterFiles());
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000372 for (std::unique_ptr<WriteState> &WS : NewInst->getDefs())
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000373 RAT->addRegisterMapping(*WS, RegisterFiles);
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000374
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000375 // Reserve slots in the RCU, and notify the instruction that it has been
376 // dispatched to the schedulers for execution.
377 NewInst->dispatch(RCU->reserveSlot(IID, NumMicroOps));
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000378
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000379 // Notify listeners of the "instruction dispatched" event.
Andrea Di Biagio12ef5262018-03-21 18:11:05 +0000380 notifyInstructionDispatched(IID, RegisterFiles);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000381
Andrea Di Biagio09ea09e2018-03-22 11:39:34 +0000382 // Now move the instruction into the scheduler's queue.
383 // The scheduler is responsible for checking if this is a zero-latency
384 // instruction that doesn't consume pipeline/scheduler resources.
Andrea Di Biagio44bfcd22018-03-19 19:09:38 +0000385 SC->scheduleInstruction(IID, *NewInst);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000386}
387
388#ifndef NDEBUG
389void DispatchUnit::dump() const {
390 RAT->dump();
391 RCU->dump();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000392}
393#endif
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000394} // namespace mca