blob: 52968ea1174fef5f6090259831e1bd22b00243e7 [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
48void RegisterFile::createNewMappings(unsigned RegisterFileMask) {
49 assert(RegisterFileMask && "RegisterFileMask cannot be zero!");
50 // Notify each register file that contains RegID.
51 do {
52 unsigned NextRegisterFile = llvm::PowerOf2Floor(RegisterFileMask);
53 unsigned RegisterFileIndex = llvm::countTrailingZeros(NextRegisterFile);
54 RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex];
55 RMT.NumUsedMappings++;
56 RMT.MaxUsedMappings = std::max(RMT.MaxUsedMappings, RMT.NumUsedMappings);
57 RMT.TotalMappingsCreated++;
58 RegisterFileMask ^= NextRegisterFile;
59 } while (RegisterFileMask);
60}
61
62void RegisterFile::removeMappings(unsigned RegisterFileMask) {
63 assert(RegisterFileMask && "RegisterFileMask cannot be zero!");
64 // Notify each register file that contains RegID.
65 do {
66 unsigned NextRegisterFile = llvm::PowerOf2Floor(RegisterFileMask);
67 unsigned RegisterFileIndex = llvm::countTrailingZeros(NextRegisterFile);
68 RegisterMappingTracker &RMT = RegisterFiles[RegisterFileIndex];
69 assert(RMT.NumUsedMappings);
70 RMT.NumUsedMappings--;
71 RegisterFileMask ^= NextRegisterFile;
72 } while (RegisterFileMask);
73}
74
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000075void RegisterFile::addRegisterMapping(WriteState &WS) {
76 unsigned RegID = WS.getRegisterID();
77 assert(RegID && "Adding an invalid register definition?");
78
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000079 RegisterMapping &Mapping = RegisterMappings[RegID];
80 Mapping.first = &WS;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000081 for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I)
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000082 RegisterMappings[*I].first = &WS;
83
84 createNewMappings(Mapping.second);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000085 // If this is a partial update, then we are done.
86 if (!WS.fullyUpdatesSuperRegs())
87 return;
88
89 for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I)
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +000090 RegisterMappings[*I].first = &WS;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +000091}
92
93void RegisterFile::invalidateRegisterMapping(const WriteState &WS) {
94 unsigned RegID = WS.getRegisterID();
95 bool ShouldInvalidateSuperRegs = WS.fullyUpdatesSuperRegs();
96
97 assert(RegID != 0 && "Invalidating an already invalid register?");
98 assert(WS.getCyclesLeft() != -512 &&
99 "Invalidating a write of unknown cycles!");
100 assert(WS.getCyclesLeft() <= 0 && "Invalid cycles left for this write!");
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000101 RegisterMapping &Mapping = RegisterMappings[RegID];
102 if (!Mapping.first)
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000103 return;
104
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000105 removeMappings(Mapping.second);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000106
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000107 if (Mapping.first == &WS)
108 Mapping.first = nullptr;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000109
110 for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I)
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000111 if (RegisterMappings[*I].first == &WS)
112 RegisterMappings[*I].first = nullptr;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000113
114 if (!ShouldInvalidateSuperRegs)
115 return;
116
117 for (MCSuperRegIterator I(RegID, &MRI); I.isValid(); ++I)
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000118 if (RegisterMappings[*I].first == &WS)
119 RegisterMappings[*I].first = nullptr;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000120}
121
122// Update the number of used mappings in the event of instruction retired.
123// This mehod delegates to the register file the task of invalidating
124// register mappings that were created for instruction IS.
125void DispatchUnit::invalidateRegisterMappings(const Instruction &IS) {
126 for (const std::unique_ptr<WriteState> &WS : IS.getDefs()) {
127 DEBUG(dbgs() << "[RAT] Invalidating mapping for: ");
128 DEBUG(WS->dump());
129 RAT->invalidateRegisterMapping(*WS.get());
130 }
131}
132
133void RegisterFile::collectWrites(SmallVectorImpl<WriteState *> &Writes,
134 unsigned RegID) const {
135 assert(RegID && RegID < RegisterMappings.size());
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000136 WriteState *WS = RegisterMappings[RegID].first;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000137 if (WS) {
138 DEBUG(dbgs() << "Found a dependent use of RegID=" << RegID << '\n');
139 Writes.push_back(WS);
140 }
141
142 // Handle potential partial register updates.
143 for (MCSubRegIterator I(RegID, &MRI); I.isValid(); ++I) {
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000144 WS = RegisterMappings[*I].first;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000145 if (WS && std::find(Writes.begin(), Writes.end(), WS) == Writes.end()) {
146 DEBUG(dbgs() << "Found a dependent use of subReg " << *I << " (part of "
147 << RegID << ")\n");
148 Writes.push_back(WS);
149 }
150 }
151}
152
Andrea Di Biagio847accd2018-03-20 19:06:34 +0000153unsigned RegisterFile::isAvailable(ArrayRef<unsigned> Regs) const {
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000154 SmallVector<unsigned, 4> NumTemporaries(getNumRegisterFiles());
155
156 // Find how many new mappings must be created for each register file.
157 for (const unsigned RegID : Regs) {
158 unsigned RegisterFileMask = RegisterMappings[RegID].second;
159 do {
160 unsigned NextRegisterFileID = llvm::PowerOf2Floor(RegisterFileMask);
161 NumTemporaries[llvm::countTrailingZeros(NextRegisterFileID)]++;
162 RegisterFileMask ^= NextRegisterFileID;
163 } while (RegisterFileMask);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000164 }
165
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000166 unsigned Response = 0;
167 for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) {
168 unsigned Temporaries = NumTemporaries[I];
169 if (!Temporaries)
170 continue;
171
172 const RegisterMappingTracker &RMT = RegisterFiles[I];
173 if (!RMT.TotalMappings) {
174 // The register file has an unbound number of microarchitectural
175 // registers.
176 continue;
177 }
178
179 if (RMT.TotalMappings < Temporaries) {
180 // The current register file is too small. This may occur if the number of
181 // microarchitectural registers in register file #0 was changed by the
182 // users via flag -reg-file-size. Alternatively, the scheduling model
183 // specified a too small number of registers for this register file.
184 report_fatal_error(
185 "Not enough microarchitectural registers in the register file");
186 }
187
188 if (RMT.TotalMappings < RMT.NumUsedMappings + Temporaries)
189 Response |= (1U << I);
190 }
191
192 return Response;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000193}
194
195#ifndef NDEBUG
196void RegisterFile::dump() const {
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000197 for (unsigned I = 0, E = MRI.getNumRegs(); I < E; ++I) {
198 const RegisterMapping &RM = RegisterMappings[I];
199 dbgs() << MRI.getName(I) << ", " << I << ", Map=" << RM.second << ", ";
200 if (RM.first)
201 RM.first->dump();
202 else
203 dbgs() << "(null)\n";
204 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000205
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000206 for (unsigned I = 0, E = getNumRegisterFiles(); I < E; ++I) {
207 dbgs() << "Register File #" << I;
208 const RegisterMappingTracker &RMT = RegisterFiles[I];
209 dbgs() << "\n TotalMappings: " << RMT.TotalMappings
210 << "\n TotalMappingsCreated: " << RMT.TotalMappingsCreated
211 << "\n MaxUsedMappings: " << RMT.MaxUsedMappings
212 << "\n NumUsedMappings: " << RMT.NumUsedMappings << '\n';
213 }
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000214}
215#endif
216
217// Reserves a number of slots, and returns a new token.
218unsigned RetireControlUnit::reserveSlot(unsigned Index, unsigned NumMicroOps) {
219 assert(isAvailable(NumMicroOps));
220 unsigned NormalizedQuantity =
221 std::min(NumMicroOps, static_cast<unsigned>(Queue.size()));
222 // Zero latency instructions may have zero mOps. Artificially bump this
223 // value to 1. Although zero latency instructions don't consume scheduler
224 // resources, they still consume one slot in the retire queue.
225 NormalizedQuantity = std::max(NormalizedQuantity, 1U);
226 unsigned TokenID = NextAvailableSlotIdx;
227 Queue[NextAvailableSlotIdx] = {Index, NormalizedQuantity, false};
228 NextAvailableSlotIdx += NormalizedQuantity;
229 NextAvailableSlotIdx %= Queue.size();
230 AvailableSlots -= NormalizedQuantity;
231 return TokenID;
232}
233
234void DispatchUnit::notifyInstructionDispatched(unsigned Index) {
Clement Courbet844f22d2018-03-13 13:11:01 +0000235 DEBUG(dbgs() << "[E] Instruction Dispatched: " << Index << '\n');
236 Owner->notifyInstructionEvent(
237 HWInstructionEvent(HWInstructionEvent::Dispatched, Index));
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000238}
239
240void DispatchUnit::notifyInstructionRetired(unsigned Index) {
Clement Courbet844f22d2018-03-13 13:11:01 +0000241 DEBUG(dbgs() << "[E] Instruction Retired: " << Index << '\n');
242 Owner->notifyInstructionEvent(
243 HWInstructionEvent(HWInstructionEvent::Retired, Index));
244
245 const Instruction &IS = Owner->getInstruction(Index);
246 invalidateRegisterMappings(IS);
247 Owner->eraseInstruction(Index);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000248}
249
250void RetireControlUnit::cycleEvent() {
251 if (isEmpty())
252 return;
253
254 unsigned NumRetired = 0;
255 while (!isEmpty()) {
256 if (MaxRetirePerCycle != 0 && NumRetired == MaxRetirePerCycle)
257 break;
258 RUToken &Current = Queue[CurrentInstructionSlotIdx];
259 assert(Current.NumSlots && "Reserved zero slots?");
260 if (!Current.Executed)
261 break;
262 Owner->notifyInstructionRetired(Current.Index);
263 CurrentInstructionSlotIdx += Current.NumSlots;
264 CurrentInstructionSlotIdx %= Queue.size();
265 AvailableSlots += Current.NumSlots;
266 NumRetired++;
267 }
268}
269
270void RetireControlUnit::onInstructionExecuted(unsigned TokenID) {
271 assert(Queue.size() > TokenID);
272 assert(Queue[TokenID].Executed == false && Queue[TokenID].Index != ~0U);
273 Queue[TokenID].Executed = true;
274}
275
276#ifndef NDEBUG
277void RetireControlUnit::dump() const {
278 dbgs() << "Retire Unit: { Total Slots=" << Queue.size()
279 << ", Available Slots=" << AvailableSlots << " }\n";
280}
281#endif
282
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000283bool DispatchUnit::checkRAT(unsigned Index, const Instruction &Instr) {
284 const InstrDesc &Desc = Instr.getDesc();
285 unsigned NumWrites = Desc.Writes.size();
286 unsigned RegisterMask = RAT->isAvailable(NumWrites);
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000287 // A mask with all zeroes means: register files are available.
288 if (RegisterMask) {
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000289 Owner->notifyStallEvent(
290 HWStallEvent(HWStallEvent::RegisterFileStall, Index));
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000291 return false;
292 }
293
294 return true;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000295}
296
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000297bool DispatchUnit::checkRCU(unsigned Index, const InstrDesc &Desc) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000298 unsigned NumMicroOps = Desc.NumMicroOps;
299 if (RCU->isAvailable(NumMicroOps))
300 return true;
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000301 Owner->notifyStallEvent(
302 HWStallEvent(HWStallEvent::RetireControlUnitStall, Index));
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000303 return false;
304}
305
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000306bool DispatchUnit::checkScheduler(unsigned Index, const InstrDesc &Desc) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000307 // If this is a zero-latency instruction, then it bypasses
308 // the scheduler.
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000309 HWStallEvent::GenericEventType Type = HWStallEvent::Invalid;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000310 switch (SC->canBeDispatched(Desc)) {
311 case Scheduler::HWS_AVAILABLE:
312 return true;
313 case Scheduler::HWS_QUEUE_UNAVAILABLE:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000314 Type = HWStallEvent::SchedulerQueueFull;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000315 break;
316 case Scheduler::HWS_LD_QUEUE_UNAVAILABLE:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000317 Type = HWStallEvent::LoadQueueFull;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000318 break;
319 case Scheduler::HWS_ST_QUEUE_UNAVAILABLE:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000320 Type = HWStallEvent::StoreQueueFull;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000321 break;
322 case Scheduler::HWS_DISPATCH_GROUP_RESTRICTION:
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000323 Type = HWStallEvent::DispatchGroupStall;
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000324 }
325
Andrea Di Biagio91ab2ee2018-03-19 13:23:07 +0000326 Owner->notifyStallEvent(HWStallEvent(Type, Index));
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000327 return false;
328}
329
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000330void DispatchUnit::updateRAWDependencies(ReadState &RS,
331 const MCSubtargetInfo &STI) {
332 SmallVector<WriteState *, 4> DependentWrites;
333
334 collectWrites(DependentWrites, RS.getRegisterID());
335 RS.setDependentWrites(DependentWrites.size());
336 DEBUG(dbgs() << "Found " << DependentWrites.size() << " dependent writes\n");
337 // We know that this read depends on all the writes in DependentWrites.
338 // For each write, check if we have ReadAdvance information, and use it
339 // to figure out in how many cycles this read becomes available.
340 const ReadDescriptor &RD = RS.getDescriptor();
341 if (!RD.HasReadAdvanceEntries) {
342 for (WriteState *WS : DependentWrites)
343 WS->addUser(&RS, /* ReadAdvance */ 0);
344 return;
345 }
346
347 const MCSchedModel &SM = STI.getSchedModel();
348 const MCSchedClassDesc *SC = SM.getSchedClassDesc(RD.SchedClassID);
349 for (WriteState *WS : DependentWrites) {
350 unsigned WriteResID = WS->getWriteResourceID();
351 int ReadAdvance = STI.getReadAdvanceCycles(SC, RD.OpIndex, WriteResID);
352 WS->addUser(&RS, ReadAdvance);
353 }
354 // Prepare the set for another round.
355 DependentWrites.clear();
356}
357
358unsigned DispatchUnit::dispatch(unsigned IID, Instruction *NewInst,
359 const MCSubtargetInfo &STI) {
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000360 assert(!CarryOver && "Cannot dispatch another instruction!");
361 unsigned NumMicroOps = NewInst->getDesc().NumMicroOps;
362 if (NumMicroOps > DispatchWidth) {
363 assert(AvailableEntries == DispatchWidth);
364 AvailableEntries = 0;
365 CarryOver = NumMicroOps - DispatchWidth;
366 } else {
367 assert(AvailableEntries >= NumMicroOps);
368 AvailableEntries -= NumMicroOps;
369 }
370
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000371 // Update RAW dependencies.
372 for (std::unique_ptr<ReadState> &RS : NewInst->getUses())
373 updateRAWDependencies(*RS, STI);
374
Andrea Di Biagioe64f3b12018-03-18 15:33:27 +0000375 // Allocate new mappings.
Andrea Di Biagio4732d43ca2018-03-14 14:57:23 +0000376 for (std::unique_ptr<WriteState> &WS : NewInst->getDefs())
377 addNewRegisterMapping(*WS);
378
379 // Set the cycles left before the write-back stage.
380 const InstrDesc &D = NewInst->getDesc();
381 NewInst->setCyclesLeft(D.MaxLatency);
382
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000383 // Reserve slots in the RCU.
384 unsigned RCUTokenID = RCU->reserveSlot(IID, NumMicroOps);
Andrea Di Biagio373c38a2018-03-08 20:21:55 +0000385 NewInst->setRCUTokenID(RCUTokenID);
Clement Courbet844f22d2018-03-13 13:11:01 +0000386 notifyInstructionDispatched(IID);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000387
Andrea Di Biagio44bfcd22018-03-19 19:09:38 +0000388 SC->scheduleInstruction(IID, *NewInst);
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000389 return RCUTokenID;
390}
391
392#ifndef NDEBUG
393void DispatchUnit::dump() const {
394 RAT->dump();
395 RCU->dump();
Andrea Di Biagio3a6b0922018-03-08 13:05:02 +0000396}
397#endif
398
399} // namespace mca