LLVM  9.0.0svn
ExecuteStage.cpp
Go to the documentation of this file.
1 //===---------------------- ExecuteStage.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 /// This file defines the execution stage of an instruction pipeline.
11 ///
12 /// The ExecuteStage is responsible for managing the hardware scheduler
13 /// and issuing notifications that an instruction has been executed.
14 ///
15 //===----------------------------------------------------------------------===//
16 
18 #include "llvm/ADT/SmallVector.h"
19 #include "llvm/Support/Debug.h"
20 
21 #define DEBUG_TYPE "llvm-mca"
22 
23 namespace llvm {
24 namespace mca {
25 
27  switch (Status) {
37  return HWStallEvent::Invalid;
38  }
39 
40  llvm_unreachable("Don't know how to process this StallKind!");
41 }
42 
43 bool ExecuteStage::isAvailable(const InstRef &IR) const {
44  if (Scheduler::Status S = HWS.isAvailable(IR)) {
46  notifyEvent<HWStallEvent>(HWStallEvent(ET, IR));
47  return false;
48  }
49 
50  return true;
51 }
52 
53 Error ExecuteStage::issueInstruction(InstRef &IR) {
56  HWS.issueInstruction(IR, Used, Ready);
57  NumIssuedOpcodes += IR.getInstruction()->getDesc().NumMicroOps;
58 
59  notifyReservedOrReleasedBuffers(IR, /* Reserved */ false);
60 
61  notifyInstructionIssued(IR, Used);
62  if (IR.getInstruction()->isExecuted()) {
64  // FIXME: add a buffer of executed instructions.
65  if (Error S = moveToTheNextStage(IR))
66  return S;
67  }
68 
69  for (const InstRef &I : Ready)
71  return ErrorSuccess();
72 }
73 
74 Error ExecuteStage::issueReadyInstructions() {
75  InstRef IR = HWS.select();
76  while (IR) {
77  if (Error Err = issueInstruction(IR))
78  return Err;
79 
80  // Select the next instruction to issue.
81  IR = HWS.select();
82  }
83 
84  return ErrorSuccess();
85 }
86 
89  SmallVector<InstRef, 4> Executed;
91 
92  HWS.cycleEvent(Freed, Executed, Ready);
93  NumDispatchedOpcodes = 0;
94  NumIssuedOpcodes = 0;
95 
96  for (const ResourceRef &RR : Freed)
98 
99  for (InstRef &IR : Executed) {
101  // FIXME: add a buffer of executed instructions.
102  if (Error S = moveToTheNextStage(IR))
103  return S;
104  }
105 
106  for (const InstRef &IR : Ready)
108 
109  return issueReadyInstructions();
110 }
111 
113  if (!EnablePressureEvents)
114  return ErrorSuccess();
115 
116  // Always conservatively report any backpressure events if the dispatch logic
117  // was stalled due to unavailable scheduler resources.
118  if (!HWS.hadTokenStall() && NumDispatchedOpcodes <= NumIssuedOpcodes)
119  return ErrorSuccess();
120 
122  uint64_t Mask = HWS.analyzeResourcePressure(Insts);
123  if (Mask) {
124  LLVM_DEBUG(dbgs() << "[E] Backpressure increased because of unavailable "
125  "pipeline resources: "
126  << format_hex(Mask, 16) << '\n');
128  notifyEvent(Ev);
129  return ErrorSuccess();
130  }
131 
132  SmallVector<InstRef, 8> RegDeps;
133  SmallVector<InstRef, 8> MemDeps;
134  HWS.analyzeDataDependencies(RegDeps, MemDeps);
135  if (RegDeps.size()) {
136  LLVM_DEBUG(
137  dbgs() << "[E] Backpressure increased by register dependencies\n");
139  notifyEvent(Ev);
140  }
141 
142  if (MemDeps.size()) {
143  LLVM_DEBUG(dbgs() << "[E] Backpressure increased by memory dependencies\n");
145  notifyEvent(Ev);
146  }
147 
148  return ErrorSuccess();
149 }
150 
151 #ifndef NDEBUG
152 static void verifyInstructionEliminated(const InstRef &IR) {
153  const Instruction &Inst = *IR.getInstruction();
154  assert(Inst.isEliminated() && "Instruction was not eliminated!");
155  assert(Inst.isReady() && "Instruction in an inconsistent state!");
156 
157  // Ensure that instructions eliminated at register renaming stage are in a
158  // consistent state.
159  const InstrDesc &Desc = Inst.getDesc();
160  assert(!Desc.MayLoad && !Desc.MayStore && "Cannot eliminate a memory op!");
161 }
162 #endif
163 
164 Error ExecuteStage::handleInstructionEliminated(InstRef &IR) {
165 #ifndef NDEBUG
167 #endif
169  notifyInstructionIssued(IR, {});
172  return moveToTheNextStage(IR);
173 }
174 
175 // Schedule the instruction for execution on the hardware.
177  assert(isAvailable(IR) && "Scheduler is not available!");
178 
179 #ifndef NDEBUG
180  // Ensure that the HWS has not stored this instruction in its queues.
181  HWS.sanityCheck(IR);
182 #endif
183 
184  if (IR.getInstruction()->isEliminated())
185  return handleInstructionEliminated(IR);
186 
187  // Reserve a slot in each buffered resource. Also, mark units with
188  // BufferSize=0 as reserved. Resources with a buffer size of zero will only
189  // be released after MCIS is issued, and all the ResourceCycles for those
190  // units have been consumed.
191  bool IsReadyInstruction = HWS.dispatch(IR);
192  NumDispatchedOpcodes += IR.getInstruction()->getDesc().NumMicroOps;
193  notifyReservedOrReleasedBuffers(IR, /* Reserved */ true);
194  if (!IsReadyInstruction)
195  return ErrorSuccess();
196 
197  // If we did not return early, then the scheduler is ready for execution.
199 
200  // If we cannot issue immediately, the HWS will add IR to its ready queue for
201  // execution later, so we must return early here.
202  if (!HWS.mustIssueImmediately(IR))
203  return ErrorSuccess();
204 
205  // Issue IR to the underlying pipelines.
206  return issueInstruction(IR);
207 }
208 
210  LLVM_DEBUG(dbgs() << "[E] Instruction Executed: #" << IR << '\n');
211  notifyEvent<HWInstructionEvent>(
213 }
214 
216  LLVM_DEBUG(dbgs() << "[E] Instruction Ready: #" << IR << '\n');
217  notifyEvent<HWInstructionEvent>(
219 }
220 
222  LLVM_DEBUG(dbgs() << "[E] Resource Available: [" << RR.first << '.'
223  << RR.second << "]\n");
224  for (HWEventListener *Listener : getListeners())
225  Listener->onResourceAvailable(RR);
226 }
227 
229  const InstRef &IR,
230  MutableArrayRef<std::pair<ResourceRef, ResourceCycles>> Used) const {
231  LLVM_DEBUG({
232  dbgs() << "[E] Instruction Issued: #" << IR << '\n';
233  for (const std::pair<ResourceRef, ResourceCycles> &Resource : Used) {
234  assert(Resource.second.getDenominator() == 1 && "Invalid cycles!");
235  dbgs() << "[E] Resource Used: [" << Resource.first.first << '.'
236  << Resource.first.second << "], ";
237  dbgs() << "cycles: " << Resource.second.getNumerator() << '\n';
238  }
239  });
240 
241  // Replace resource masks with valid resource processor IDs.
242  for (std::pair<ResourceRef, ResourceCycles> &Use : Used)
243  Use.first.first = HWS.getResourceID(Use.first.first);
244 
245  notifyEvent<HWInstructionEvent>(HWInstructionIssuedEvent(IR, Used));
246 }
247 
249  bool Reserved) const {
250  const InstrDesc &Desc = IR.getInstruction()->getDesc();
251  if (Desc.Buffers.empty())
252  return;
253 
254  SmallVector<unsigned, 4> BufferIDs(Desc.Buffers.begin(), Desc.Buffers.end());
255  std::transform(Desc.Buffers.begin(), Desc.Buffers.end(), BufferIDs.begin(),
256  [&](uint64_t Op) { return HWS.getResourceID(Op); });
257  if (Reserved) {
258  for (HWEventListener *Listener : getListeners())
259  Listener->onReservedBuffers(IR, BufferIDs);
260  return;
261  }
262 
263  for (HWEventListener *Listener : getListeners())
264  Listener->onReleasedBuffers(IR, BufferIDs);
265 }
266 
267 } // namespace mca
268 } // namespace llvm
Instruction * getInstruction()
Definition: Instruction.h:531
void notifyEvent(const EventT &Event) const
Notify listeners of a particular hardware event.
Definition: Stage.h:79
An instruction propagated through the simulated instruction pipeline.
Definition: Instruction.h:430
void cycleEvent(SmallVectorImpl< ResourceRef > &Freed, SmallVectorImpl< InstRef > &Ready, SmallVectorImpl< InstRef > &Executed)
This routine notifies the Scheduler that a new cycle just started.
Definition: Scheduler.cpp:252
This class represents lattice values for constants.
Definition: AllocatorList.h:23
void sanityCheck(const InstRef &IR) const
Definition: Scheduler.h:254
Status isAvailable(const InstRef &IR)
Check if the instruction in &#39;IR&#39; can be dispatched during this cycle.
Definition: Scheduler.cpp:40
FormattedNumber format_hex(uint64_t N, unsigned Width, bool Upper=false)
format_hex - Output N as a fixed width hexadecimal.
Definition: Format.h:185
SmallVector< uint64_t, 4 > Buffers
Definition: Instruction.h:346
const std::set< HWEventListener * > & getListeners() const
Definition: Stage.h:35
Subclass of Error for the sole purpose of identifying the success path in the type system...
Definition: Error.h:324
void notifyInstructionReady(const InstRef &IR) const
InstRef select()
Select the next instruction to issue from the ReadySet.
Definition: Scheduler.cpp:180
bool isAvailable(const InstRef &IR) const override
Returns true if it can execute IR during this cycle.
An InstRef contains both a SourceMgr index and Instruction pair.
Definition: Instruction.h:521
Error cycleStart() override
Called once at the start of each cycle.
HWStallEvent::GenericEventType toHWStallEventType(Scheduler::Status Status)
void notifyResourceAvailable(const ResourceRef &RR) const
This file defines the execution stage of a default instruction pipeline.
unsigned getResourceID(uint64_t Mask) const
Convert a resource mask into a valid llvm processor resource identifier.
Definition: Scheduler.h:219
A Use represents the edge between a Value definition and its users.
Definition: Use.h:55
static void verifyInstructionEliminated(const InstRef &IR)
bool isEliminated() const
Definition: Instruction.h:494
void notifyInstructionIssued(const InstRef &IR, MutableArrayRef< std::pair< ResourceRef, ResourceCycles >> Used) const
uint64_t analyzeResourcePressure(SmallVectorImpl< InstRef > &Insts)
Returns a mask of busy resources, and populates vector Insts with instructions that could not be issu...
Definition: Scheduler.cpp:230
const InstrDesc & getDesc() const
Definition: Instruction.h:404
Error cycleEnd() override
Called once at the end of each cycle.
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition: ArrayRef.h:290
void notifyReservedOrReleasedBuffers(const InstRef &IR, bool Reserved) const
bool dispatch(const InstRef &IR)
Reserves buffer and LSUnit queue resources that are necessary to issue this instruction.
Definition: Scheduler.cpp:285
std::pair< uint64_t, uint64_t > ResourceRef
A resource unit identifier.
void issueInstruction(InstRef &IR, SmallVectorImpl< std::pair< ResourceRef, ResourceCycles >> &Used, SmallVectorImpl< InstRef > &Ready)
Issue an instruction and populates a vector of used pipeline resources, and a vector of instructions ...
Definition: Scheduler.cpp:92
size_t size() const
Definition: SmallVector.h:52
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
void notifyInstructionExecuted(const InstRef &IR) const
This is a &#39;vector&#39; (really, a variable-sized array), optimized for the case when the array is small...
Definition: SmallVector.h:841
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition: Debug.cpp:132
bool isReady() const
Definition: Instruction.h:489
bool hadTokenStall() const
Definition: Scheduler.h:246
Error moveToTheNextStage(InstRef &IR)
Called when an instruction is ready to move the next pipeline stage.
Definition: Stage.h:70
An instruction descriptor.
Definition: Instruction.h:337
bool mustIssueImmediately(const InstRef &IR) const
Returns true if IR has to be issued immediately, or if IR is a zero latency instruction.
Definition: Scheduler.cpp:275
void analyzeDataDependencies(SmallVectorImpl< InstRef > &RegDeps, SmallVectorImpl< InstRef > &MemDeps)
This method is called by the ExecuteStage at the end of each cycle to identify bottlenecks caused by ...
Definition: Scheduler.cpp:235
LLVM_NODISCARD bool empty() const
Definition: SmallVector.h:55
#define I(x, y, z)
Definition: MD5.cpp:58
OutputIt transform(R &&Range, OutputIt d_first, UnaryPredicate P)
Wrapper function around std::transform to apply a function to a range and store the result elsewhere...
Definition: STLExtras.h:1267
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
Lightweight error class with error context and mandatory checking.
Definition: Error.h:157
std::underlying_type< E >::type Mask()
Get a bitmask with 1s in all places up to the high-order bit of E&#39;s largest value.
Definition: BitmaskEnum.h:80
bool isExecuted() const
Definition: Instruction.h:491
Error execute(InstRef &IR) override
The primary action that this stage performs on instruction IR.
#define LLVM_DEBUG(X)
Definition: Debug.h:122
Statically lint checks LLVM IR
Definition: Lint.cpp:192