LLVM 24.0.0git
InOrderIssueStage.cpp
Go to the documentation of this file.
1//===---------------------- InOrderIssueStage.cpp ---------------*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8/// \file
9///
10/// InOrderIssueStage implements an in-order execution pipeline.
11///
12//===----------------------------------------------------------------------===//
13
19
20#define DEBUG_TYPE "llvm-mca"
21namespace llvm {
22namespace mca {
23
25 IR.invalidate();
26 CyclesLeft = 0;
28}
29
30void StallInfo::update(const InstRef &Inst, unsigned Cycles, StallKind SK) {
31 IR = Inst;
32 CyclesLeft = Cycles;
33 Kind = SK;
34}
35
37 if (!isValid())
38 return;
39
40 if (!CyclesLeft)
41 return;
42
43 --CyclesLeft;
44}
45
46InOrderIssueStage::InOrderIssueStage(const MCSubtargetInfo &STI,
48 LSUnitBase &LSU,
49 float ReservationStationScaleFactor)
50 : STI(STI), PRF(PRF),
51 RM(STI.getSchedModel(), ReservationStationScaleFactor), CB(CB), LSU(LSU),
52 NumIssued(), CarryOver(), Bandwidth(), LastWriteBackCycle() {}
53
55 return STI.getSchedModel().IssueWidth;
56}
57
59 return !IssuedInst.empty() || SI.isValid() || CarriedOver;
60}
61
63 if (SI.isValid() || CarriedOver)
64 return false;
65
66 const Instruction &Inst = *IR.getInstruction();
67 unsigned NumMicroOps = Inst.getNumMicroOps();
68
69 bool ShouldCarryOver = NumMicroOps > getIssueWidth();
70 if (Bandwidth < NumMicroOps && !ShouldCarryOver)
71 return false;
72
73 // Instruction with BeginGroup must be the first instruction to be issued in a
74 // cycle.
75 if (Inst.getBeginGroup() && NumIssued != 0)
76 return false;
77
78 return true;
79}
80
81static bool hasResourceHazard(const ResourceManager &RM, const InstRef &IR) {
82 if (RM.checkAvailability(IR.getInstruction()->getDesc())) {
83 LLVM_DEBUG(dbgs() << "[E] Stall #" << IR << '\n');
84 return true;
85 }
86
87 return false;
88}
89
90static unsigned findFirstWriteBackCycle(const InstRef &IR) {
91 unsigned FirstWBCycle = IR.getInstruction()->getLatency();
92 for (const WriteState &WS : IR.getInstruction()->getDefs()) {
93 int CyclesLeft = WS.getCyclesLeft();
94 if (CyclesLeft == UNKNOWN_CYCLES)
95 CyclesLeft = WS.getLatency();
96 if (CyclesLeft < 0)
97 CyclesLeft = 0;
98 FirstWBCycle = std::min(FirstWBCycle, (unsigned)CyclesLeft);
99 }
100 return FirstWBCycle;
101}
102
103/// Return a number of cycles left until register requirements of the
104/// instructions are met.
105static unsigned checkRegisterHazard(const RegisterFile &PRF,
106 const MCSubtargetInfo &STI,
107 const InstRef &IR) {
108 for (const ReadState &RS : IR.getInstruction()->getUses()) {
109 RegisterFile::RAWHazard Hazard = PRF.checkRAWHazards(STI, RS);
110 if (Hazard.isValid())
111 return Hazard.hasUnknownCycles() ? 1U : Hazard.CyclesLeft;
112 }
113
114 return 0;
115}
116
117bool InOrderIssueStage::canExecute(const InstRef &IR) {
118 assert(!SI.getCyclesLeft() && "Should not have reached this code!");
119 assert(!SI.isValid() && "Should not have reached this code!");
120
121 if (unsigned Cycles = checkRegisterHazard(PRF, STI, IR)) {
123 return false;
124 }
125
126 if (hasResourceHazard(RM, IR)) {
127 SI.update(IR, /* delay */ 1, StallInfo::StallKind::DISPATCH);
128 return false;
129 }
130
131 if (IR.getInstruction()->isMemOp() && !LSU.isReady(IR)) {
132 // This load (store) aliases with a preceding store (load). Delay
133 // it until the depenency is cleared.
134 SI.update(IR, /* delay */ 1, StallInfo::StallKind::LOAD_STORE);
135 return false;
136 }
137
138 if (unsigned CustomStallCycles = CB.checkCustomHazard(IssuedInst, IR)) {
139 SI.update(IR, CustomStallCycles, StallInfo::StallKind::CUSTOM_STALL);
140 return false;
141 }
142
143 if (LastWriteBackCycle) {
144 if (!IR.getInstruction()->getRetireOOO()) {
145 unsigned NextWriteBackCycle = findFirstWriteBackCycle(IR);
146 // Delay the instruction to ensure that writes happen in program order.
147 if (NextWriteBackCycle < LastWriteBackCycle) {
148 SI.update(IR, LastWriteBackCycle - NextWriteBackCycle,
150 return false;
151 }
152 }
153 }
154
155 return true;
156}
157
159 unsigned SourceIndex,
160 const MCSubtargetInfo &STI,
161 SmallVectorImpl<unsigned> &UsedRegs) {
162 assert(!IS.isEliminated());
163
164 for (ReadState &RS : IS.getUses())
165 PRF.addRegisterRead(RS, STI);
166
167 for (WriteState &WS : IS.getDefs())
168 PRF.addRegisterWrite(WriteRef(SourceIndex, &WS), UsedRegs);
169}
170
171void InOrderIssueStage::notifyInstructionIssued(const InstRef &IR,
172 ArrayRef<ResourceUse> UsedRes) {
174 HWInstructionEvent(HWInstructionEvent::Ready, IR));
175 notifyEvent<HWInstructionEvent>(HWInstructionIssuedEvent(IR, UsedRes));
176
177 LLVM_DEBUG(dbgs() << "[E] Issued #" << IR << "\n");
178}
179
180void InOrderIssueStage::notifyInstructionDispatched(
181 const InstRef &IR, unsigned Ops, ArrayRef<unsigned> UsedRegs) {
183 HWInstructionDispatchedEvent(IR, UsedRegs, Ops));
184
185 LLVM_DEBUG(dbgs() << "[E] Dispatched #" << IR << "\n");
186}
187
188void InOrderIssueStage::notifyInstructionExecuted(const InstRef &IR) {
190 HWInstructionEvent(HWInstructionEvent::Executed, IR));
191 LLVM_DEBUG(dbgs() << "[E] Instruction #" << IR << " is executed\n");
192}
193
194void InOrderIssueStage::notifyInstructionRetired(const InstRef &IR,
195 ArrayRef<unsigned> FreedRegs) {
196 notifyEvent<HWInstructionEvent>(HWInstructionRetiredEvent(IR, FreedRegs));
197 LLVM_DEBUG(dbgs() << "[E] Retired #" << IR << " \n");
198}
199
201 Instruction &IS = *IR.getInstruction();
202 if (IS.isMemOp())
203 IS.setLSUTokenID(LSU.dispatch(IR));
204
205 if (llvm::Error E = tryIssue(IR))
206 return E;
207
208 if (SI.isValid())
209 notifyStallEvent();
210
211 return llvm::ErrorSuccess();
212}
213
214llvm::Error InOrderIssueStage::tryIssue(InstRef &IR) {
215 Instruction &IS = *IR.getInstruction();
216 unsigned SourceIndex = IR.getSourceIndex();
217 const InstrDesc &Desc = IS.getDesc();
218
219 if (!canExecute(IR)) {
220 LLVM_DEBUG(dbgs() << "[N] Stalled #" << SI.getInstruction() << " for "
221 << SI.getCyclesLeft() << " cycles\n");
222 Bandwidth = 0;
223 return llvm::ErrorSuccess();
224 }
225
226 unsigned RCUTokenID = RetireControlUnit::UnhandledTokenID;
227 IS.dispatch(RCUTokenID);
228
230 addRegisterReadWrite(PRF, IS, SourceIndex, STI, UsedRegs);
231
232 unsigned NumMicroOps = IS.getNumMicroOps();
233 notifyInstructionDispatched(IR, NumMicroOps, UsedRegs);
234
235 SmallVector<ResourceUse, 4> UsedResources;
236 RM.issueInstruction(Desc, UsedResources);
237 IS.execute(SourceIndex);
238
239 if (IS.isMemOp())
241
242 // Replace resource masks with valid resource processor IDs.
243 for (ResourceUse &Use : UsedResources) {
244 uint64_t Mask = Use.first.first;
245 Use.first.first = RM.resolveResourceMask(Mask);
246 }
247 notifyInstructionIssued(IR, UsedResources);
248
249 bool ShouldCarryOver = NumMicroOps > Bandwidth;
250 if (ShouldCarryOver) {
251 CarryOver = NumMicroOps - Bandwidth;
252 CarriedOver = IR;
253 Bandwidth = 0;
254 NumIssued += Bandwidth;
255 LLVM_DEBUG(dbgs() << "[N] Carry over #" << IR << " \n");
256 } else {
257 NumIssued += NumMicroOps;
258 Bandwidth = IS.getEndGroup() ? 0 : Bandwidth - NumMicroOps;
259 }
260
261 // If the instruction has a latency of 0, we need to handle
262 // the execution and retirement now. If the instruction is issued in multiple
263 // cycles, we cannot handle the instruction being executed here so we make
264 // updateCarriedOver responsible.
265 if (IS.isExecuted() && !ShouldCarryOver) {
266 PRF.onInstructionExecuted(&IS);
267 LSU.onInstructionExecuted(IR);
268 notifyInstructionExecuted(IR);
269
270 retireInstruction(IR);
271 return llvm::ErrorSuccess();
272 }
273
274 IssuedInst.push_back(IR);
275
276 if (!IR.getInstruction()->getRetireOOO())
277 LastWriteBackCycle = IS.getCyclesLeft();
278
279 return llvm::ErrorSuccess();
280}
281
282void InOrderIssueStage::updateIssuedInst() {
283 // Update other instructions. Executed instructions will be retired during the
284 // next cycle.
285 unsigned NumExecuted = 0;
286 for (auto I = IssuedInst.begin(), E = IssuedInst.end();
287 I != (E - NumExecuted);) {
288 InstRef &IR = *I;
289 Instruction &IS = *IR.getInstruction();
290
291 IS.cycleEvent();
292 if (!IS.isExecuted()) {
293 LLVM_DEBUG(dbgs() << "[N] Instruction #" << IR
294 << " is still executing\n");
295 ++I;
296 continue;
297 }
298
299 // If an instruction takes multiple cycles to issue, defer these calls
300 // to updateCarriedOver. We still remove from IssuedInst even if there is
301 // carry over to avoid an extra call to cycleEvent in the next cycle.
302 if (CarriedOver.getInstruction() != IR.getInstruction()) {
303 PRF.onInstructionExecuted(&IS);
304 LSU.onInstructionExecuted(IR);
305 notifyInstructionExecuted(IR);
306
307 retireInstruction(*I);
308 }
309
310 ++NumExecuted;
311
312 std::iter_swap(I, E - NumExecuted);
313 }
314
315 if (NumExecuted)
316 IssuedInst.resize(IssuedInst.size() - NumExecuted);
317}
318
319void InOrderIssueStage::updateCarriedOver() {
320 if (!CarriedOver)
321 return;
322
323 assert(!SI.isValid() && "A stalled instruction cannot be carried over.");
324
325 if (CarryOver > Bandwidth) {
326 CarryOver -= Bandwidth;
327 Bandwidth = 0;
328 LLVM_DEBUG(dbgs() << "[N] Carry over (" << CarryOver << "uops left) #"
329 << CarriedOver << " \n");
330 return;
331 }
332
333 LLVM_DEBUG(dbgs() << "[N] Carry over (complete) #" << CarriedOver << " \n");
334
335 if (CarriedOver.getInstruction()->getEndGroup())
336 Bandwidth = 0;
337 else
338 Bandwidth -= CarryOver;
339
340 // updateIssuedInst defered these calls to updateCarriedOver when there was
341 // a carry over.
342 if (CarriedOver.getInstruction()->isExecuted()) {
343 PRF.onInstructionExecuted(CarriedOver.getInstruction());
344 LSU.onInstructionExecuted(CarriedOver);
345 notifyInstructionExecuted(CarriedOver);
346
347 retireInstruction(CarriedOver);
348 }
349
350 CarriedOver = InstRef();
351 CarryOver = 0;
352}
353
354void InOrderIssueStage::retireInstruction(InstRef &IR) {
355 Instruction &IS = *IR.getInstruction();
356 IS.retire();
357
358 llvm::SmallVector<unsigned, 4> FreedRegs(PRF.getNumRegisterFiles());
359 for (const WriteState &WS : IS.getDefs())
360 PRF.removeRegisterWrite(WS, FreedRegs);
361
362 if (IS.isMemOp())
363 LSU.onInstructionRetired(IR);
364
365 notifyInstructionRetired(IR, FreedRegs);
366}
367
368void InOrderIssueStage::notifyStallEvent() {
369 assert(SI.getCyclesLeft() && "A zero cycles stall?");
370 assert(SI.isValid() && "Invalid stall information found!");
371
372 const InstRef &IR = SI.getInstruction();
373
374 switch (SI.getStallKind()) {
375 default:
376 break;
379 HWStallEvent(HWStallEvent::RegisterFileStall, IR));
381 HWPressureEvent(HWPressureEvent::REGISTER_DEPS, IR));
382 break;
383 }
386 HWStallEvent(HWStallEvent::DispatchGroupStall, IR));
388 HWPressureEvent(HWPressureEvent::RESOURCES, IR));
389 break;
390 }
394 break;
395 }
396 }
397}
398
400 NumIssued = 0;
401 Bandwidth = getIssueWidth();
402
403 PRF.cycleStart();
404 LSU.cycleEvent();
405
406 // Release consumed resources.
408 RM.cycleEvent(Freed);
409
410 updateIssuedInst();
411
412 // Continue to issue the instruction carried over from the previous cycle
413 updateCarriedOver();
414
415 // Issue instructions scheduled for this cycle
416 if (SI.isValid()) {
417 if (!SI.getCyclesLeft()) {
418 // Make a copy of the reference, and try issue it again.
419 // Do not take the instruction reference because SI.clear() will
420 // invalidate it.
421 InstRef IR = SI.getInstruction();
422 SI.clear();
423
424 if (llvm::Error E = tryIssue(IR))
425 return E;
426 }
427
428 if (SI.getCyclesLeft()) {
429 // The instruction is still stalled, cannot issue any new instructions in
430 // this cycle.
431 notifyStallEvent();
432 Bandwidth = 0;
433 return llvm::ErrorSuccess();
434 }
435 }
436
437 assert((NumIssued <= getIssueWidth()) && "Overflow.");
438 return llvm::ErrorSuccess();
439}
440
442 PRF.cycleEnd();
443 SI.cycleEnd();
444
445 if (LastWriteBackCycle > 0)
446 --LastWriteBackCycle;
447
448 return llvm::ErrorSuccess();
449}
450
451} // namespace mca
452} // namespace llvm
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
uint64_t uint64_t
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
InOrderIssueStage implements an in-order execution pipeline.
const AbstractManglingParser< Derived, Alloc >::OperatorInfo AbstractManglingParser< Derived, Alloc >::Ops[]
A Load/Store unit class that models load/store queues and that implements a simple weak memory consis...
Legalize the Machine IR a function s Machine IR
Definition Legalizer.cpp:85
This file defines abstractions used by the Pipeline to model register reads, register writes and inst...
#define I(x, y, z)
Definition MD5.cpp:57
StandardInstrumentations SI(Mod->getContext(), Debug, VerifyEach)
This file defines a register mapping file class.
This file simulates the hardware responsible for retiring instructions.
#define LLVM_DEBUG(...)
Definition Debug.h:119
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
Subclass of Error for the sole purpose of identifying the success path in the type system.
Definition Error.h:334
Lightweight error class with error context and mandatory checking.
Definition Error.h:159
Generic base class for all target subtargets.
This class consists of common code factored out of the SmallVector class to reduce code duplication b...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
Class which can be overriden by targets to enforce instruction dependencies and behaviours that aren'...
bool hasWorkToComplete() const override
Returns true if some instructions are still executing this stage.
Error cycleEnd() override
Called once at the end of each cycle.
Error execute(InstRef &IR) override
The primary action that this stage performs on instruction IR.
bool isAvailable(const InstRef &) const override
Returns true if it can execute IR during this cycle.
Error cycleStart() override
Called once at the start of each cycle.
An InstRef contains both a SourceMgr index and Instruction pair.
unsigned getNumMicroOps() const
An instruction propagated through the simulated instruction pipeline.
Abstract base interface for LS (load/store) units in llvm-mca.
Definition LSUnit.h:29
virtual void onInstructionIssued(const InstRef &IR)=0
Tracks register operand latency in cycles.
Manages hardware register files, and tracks register definitions for register renaming purposes.
LLVM_ABI void addRegisterWrite(WriteRef Write, MutableArrayRef< unsigned > UsedPhysRegs)
unsigned getNumRegisterFiles() const
LLVM_ABI RAWHazard checkRAWHazards(const MCSubtargetInfo &STI, const ReadState &RS) const
LLVM_ABI void addRegisterRead(ReadState &RS, const MCSubtargetInfo &STI) const
void notifyEvent(const EventT &Event) const
Notify listeners of a particular hardware event.
Definition Stage.h:83
A reference to a register write.
Tracks uses of a register definition (e.g.
static void addRegisterReadWrite(RegisterFile &PRF, Instruction &IS, unsigned SourceIndex, const MCSubtargetInfo &STI, SmallVectorImpl< unsigned > &UsedRegs)
static bool hasResourceHazard(const ResourceManager &RM, const InstRef &IR)
static unsigned findFirstWriteBackCycle(const InstRef &IR)
std::pair< ResourceRef, ReleaseAtCycles > ResourceUse
static unsigned checkRegisterHazard(const RegisterFile &PRF, const MCSubtargetInfo &STI, const InstRef &IR)
Return a number of cycles left until register requirements of the instructions are met.
constexpr int UNKNOWN_CYCLES
Definition Instruction.h:33
friend class Instruction
Iterator for Instructions in a `BasicBlock.
Definition BasicBlock.h:73
This is an optimization pass for GlobalISel generic memory operations.
Op::Description Desc
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
An instruction descriptor.
static const unsigned UnhandledTokenID
LLVM_ABI void update(const InstRef &Inst, unsigned Cycles, StallKind SK)