[llvm-mca] Introduce the ExecuteStage (was originally the Scheduler class).
Summary: This patch transforms the Scheduler class into the ExecuteStage. Most of the logic remains.
Reviewers: andreadb, RKSimon, courbet
Reviewed By: andreadb
Subscribers: mgorny, javed.absar, tschuett, gbedwell, llvm-commits
Differential Revision: https://reviews.llvm.org/D47246
llvm-svn: 334679
diff --git a/llvm/tools/llvm-mca/Scheduler.cpp b/llvm/tools/llvm-mca/Scheduler.cpp
index 2782bac..ebf67bc 100644
--- a/llvm/tools/llvm-mca/Scheduler.cpp
+++ b/llvm/tools/llvm-mca/Scheduler.cpp
@@ -15,11 +15,8 @@
#include "Backend.h"
#include "HWEventListener.h"
#include "Support.h"
-#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
-#define DEBUG_TYPE "llvm-mca"
-
namespace mca {
using namespace llvm;
@@ -226,93 +223,6 @@
BusyResources.erase(RF);
}
-void Scheduler::scheduleInstruction(InstRef &IR) {
- const unsigned Idx = IR.getSourceIndex();
- assert(WaitQueue.find(Idx) == WaitQueue.end());
- assert(ReadyQueue.find(Idx) == ReadyQueue.end());
- assert(IssuedQueue.find(Idx) == IssuedQueue.end());
-
- // Reserve a slot in each buffered resource. Also, mark units with
- // BufferSize=0 as reserved. Resources with a buffer size of zero will only
- // be released after MCIS is issued, and all the ResourceCycles for those
- // units have been consumed.
- const InstrDesc &Desc = IR.getInstruction()->getDesc();
- reserveBuffers(Desc.Buffers);
- notifyReservedBuffers(Desc.Buffers);
-
- // If necessary, reserve queue entries in the load-store unit (LSU).
- bool Reserved = LSU->reserve(IR);
- if (!IR.getInstruction()->isReady() || (Reserved && !LSU->isReady(IR))) {
- LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding " << Idx
- << " to the Wait Queue\n");
- WaitQueue[Idx] = IR.getInstruction();
- return;
- }
- notifyInstructionReady(IR);
-
- // Don't add a zero-latency instruction to the Wait or Ready queue.
- // A zero-latency instruction doesn't consume any scheduler resources. That is
- // because it doesn't need to be executed, and it is often removed at register
- // renaming stage. For example, register-register moves are often optimized at
- // register renaming stage by simply updating register aliases. On some
- // targets, zero-idiom instructions (for example: a xor that clears the value
- // of a register) are treated speacially, and are often eliminated at register
- // renaming stage.
-
- // Instructions that use an in-order dispatch/issue processor resource must be
- // issued immediately to the pipeline(s). Any other in-order buffered
- // resources (i.e. BufferSize=1) is consumed.
-
- if (!Desc.isZeroLatency() && !Resources->mustIssueImmediately(Desc)) {
- LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding " << IR
- << " to the Ready Queue\n");
- ReadyQueue[IR.getSourceIndex()] = IR.getInstruction();
- return;
- }
-
- LLVM_DEBUG(dbgs() << "[SCHEDULER] Instruction " << IR
- << " issued immediately\n");
- // Release buffered resources and issue MCIS to the underlying pipelines.
- issueInstruction(IR);
-}
-
-void Scheduler::cycleEvent() {
- SmallVector<ResourceRef, 8> ResourcesFreed;
- Resources->cycleEvent(ResourcesFreed);
-
- for (const ResourceRef &RR : ResourcesFreed)
- notifyResourceAvailable(RR);
-
- SmallVector<InstRef, 4> InstructionIDs;
- updateIssuedQueue(InstructionIDs);
- for (const InstRef &IR : InstructionIDs)
- notifyInstructionExecuted(IR);
- InstructionIDs.clear();
-
- updatePendingQueue(InstructionIDs);
- for (const InstRef &IR : InstructionIDs)
- notifyInstructionReady(IR);
- InstructionIDs.clear();
-
- InstRef IR = select();
- while (IR.isValid()) {
- issueInstruction(IR);
-
- // Instructions that have been issued during this cycle might have unblocked
- // other dependent instructions. Dependent instructions may be issued during
- // this same cycle if operands have ReadAdvance entries. Promote those
- // instructions to the ReadyQueue and tell to the caller that we need
- // another round of 'issue()'.
- promoteToReadyQueue(InstructionIDs);
- for (const InstRef &I : InstructionIDs)
- notifyInstructionReady(I);
- InstructionIDs.clear();
-
- // Select the next instruction to issue.
- IR = select();
- }
-}
-
#ifndef NDEBUG
void Scheduler::dump() const {
dbgs() << "[SCHEDULER]: WaitQueue size is: " << WaitQueue.size() << '\n';
@@ -322,27 +232,27 @@
}
#endif
-bool Scheduler::canBeDispatched(const InstRef &IR) const {
- HWStallEvent::GenericEventType Type = HWStallEvent::Invalid;
+bool Scheduler::canBeDispatched(const InstRef &IR,
+ HWStallEvent::GenericEventType &Event) const {
+ Event = HWStallEvent::Invalid;
const InstrDesc &Desc = IR.getInstruction()->getDesc();
if (Desc.MayLoad && LSU->isLQFull())
- Type = HWStallEvent::LoadQueueFull;
+ Event = HWStallEvent::LoadQueueFull;
else if (Desc.MayStore && LSU->isSQFull())
- Type = HWStallEvent::StoreQueueFull;
+ Event = HWStallEvent::StoreQueueFull;
else {
switch (Resources->canBeDispatched(Desc.Buffers)) {
default:
return true;
case ResourceStateEvent::RS_BUFFER_UNAVAILABLE:
- Type = HWStallEvent::SchedulerQueueFull;
+ Event = HWStallEvent::SchedulerQueueFull;
break;
case ResourceStateEvent::RS_RESERVED:
- Type = HWStallEvent::DispatchGroupStall;
+ Event = HWStallEvent::DispatchGroupStall;
}
}
- Owner->notifyStallEvent(HWStallEvent(Type, IR));
return false;
}
@@ -364,18 +274,13 @@
IssuedQueue[IR.getSourceIndex()] = IS;
}
-void Scheduler::issueInstruction(InstRef &IR) {
- // Release buffered resources.
+// Release the buffered resources and issue the instruction.
+void Scheduler::issueInstruction(
+ InstRef &IR,
+ SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources) {
const InstrDesc &Desc = IR.getInstruction()->getDesc();
releaseBuffers(Desc.Buffers);
- notifyReleasedBuffers(Desc.Buffers);
-
- // Issue IS to the underlying pipelines and notify listeners.
- SmallVector<std::pair<ResourceRef, double>, 4> Pipes;
- issueInstructionImpl(IR, Pipes);
- notifyInstructionIssued(IR, Pipes);
- if (IR.getInstruction()->isExecuted())
- notifyInstructionExecuted(IR);
+ issueInstructionImpl(IR, UsedResources);
}
void Scheduler::promoteToReadyQueue(SmallVectorImpl<InstRef> &Ready) {
@@ -448,56 +353,34 @@
}
}
-void Scheduler::notifyInstructionIssued(
- const InstRef &IR, ArrayRef<std::pair<ResourceRef, double>> Used) {
- LLVM_DEBUG({
- dbgs() << "[E] Instruction Issued: " << IR << '\n';
- for (const std::pair<ResourceRef, unsigned> &Resource : Used) {
- dbgs() << "[E] Resource Used: [" << Resource.first.first << '.'
- << Resource.first.second << "]\n";
- dbgs() << " cycles: " << Resource.second << '\n';
- }
- });
- Owner->notifyInstructionEvent(HWInstructionIssuedEvent(IR, Used));
-}
-
-void Scheduler::notifyInstructionExecuted(const InstRef &IR) {
+void Scheduler::onInstructionExecuted(const InstRef &IR) {
LSU->onInstructionExecuted(IR);
- LLVM_DEBUG(dbgs() << "[E] Instruction Executed: " << IR << '\n');
- Owner->notifyInstructionEvent(
- HWInstructionEvent(HWInstructionEvent::Executed, IR));
- RCU.onInstructionExecuted(IR.getInstruction()->getRCUTokenID());
}
-void Scheduler::notifyInstructionReady(const InstRef &IR) {
- LLVM_DEBUG(dbgs() << "[E] Instruction Ready: " << IR << '\n');
- Owner->notifyInstructionEvent(
- HWInstructionEvent(HWInstructionEvent::Ready, IR));
+void Scheduler::reclaimSimulatedResources(SmallVectorImpl<ResourceRef> &Freed) {
+ Resources->cycleEvent(Freed);
}
-void Scheduler::notifyResourceAvailable(const ResourceRef &RR) {
- Owner->notifyResourceAvailable(RR);
+bool Scheduler::reserveResources(InstRef &IR) {
+ // If necessary, reserve queue entries in the load-store unit (LSU).
+ const bool Reserved = LSU->reserve(IR);
+ if (!IR.getInstruction()->isReady() || (Reserved && !LSU->isReady(IR))) {
+ LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding " << IR << " to the Wait Queue\n");
+ WaitQueue[IR.getSourceIndex()] = IR.getInstruction();
+ return false;
+ }
+ return true;
}
-void Scheduler::notifyReservedBuffers(ArrayRef<uint64_t> Buffers) {
- if (Buffers.empty())
- return;
-
- SmallVector<unsigned, 4> BufferIDs(Buffers.begin(), Buffers.end());
- std::transform(
- Buffers.begin(), Buffers.end(), BufferIDs.begin(),
- [&](uint64_t Op) { return Resources->resolveResourceMask(Op); });
- Owner->notifyReservedBuffers(BufferIDs);
+bool Scheduler::issueImmediately(InstRef &IR) {
+ const InstrDesc &Desc = IR.getInstruction()->getDesc();
+ if (!Desc.isZeroLatency() && !Resources->mustIssueImmediately(Desc)) {
+ LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding " << IR
+ << " to the Ready Queue\n");
+ ReadyQueue[IR.getSourceIndex()] = IR.getInstruction();
+ return false;
+ }
+ return true;
}
-void Scheduler::notifyReleasedBuffers(ArrayRef<uint64_t> Buffers) {
- if (Buffers.empty())
- return;
-
- SmallVector<unsigned, 4> BufferIDs(Buffers.begin(), Buffers.end());
- std::transform(
- Buffers.begin(), Buffers.end(), BufferIDs.begin(),
- [&](uint64_t Op) { return Resources->resolveResourceMask(Op); });
- Owner->notifyReleasedBuffers(BufferIDs);
-}
} // namespace mca