summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-mca/Scheduler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-mca/Scheduler.cpp')
-rw-r--r--llvm/tools/llvm-mca/Scheduler.cpp93
1 files changed, 57 insertions, 36 deletions
diff --git a/llvm/tools/llvm-mca/Scheduler.cpp b/llvm/tools/llvm-mca/Scheduler.cpp
index ae8395be3ea..3684ad59bc3 100644
--- a/llvm/tools/llvm-mca/Scheduler.cpp
+++ b/llvm/tools/llvm-mca/Scheduler.cpp
@@ -171,7 +171,7 @@ bool ResourceManager::canBeIssued(const InstrDesc &Desc) const {
// Returns true if all resources are in-order, and there is at least one
// resource which is a dispatch hazard (BufferSize = 0).
-bool ResourceManager::mustIssueImmediately(const InstrDesc &Desc) {
+bool ResourceManager::mustIssueImmediately(const InstrDesc &Desc) const {
if (!canBeIssued(Desc))
return false;
bool AllInOrderResources = all_of(Desc.Buffers, [&](uint64_t BufferMask) {
@@ -257,29 +257,29 @@ void Scheduler::dump() const {
}
#endif
-bool Scheduler::canBeDispatched(const InstRef &IR,
- Scheduler::StallKind &Event) const {
- Event = StallKind::NoStall;
+Scheduler::Status Scheduler::isAvailable(const InstRef &IR) const {
const InstrDesc &Desc = IR.getInstruction()->getDesc();
-
- // Give lower priority to these stall events.
- if (Desc.MayStore && LSU->isSQFull())
- Event = StallKind::StoreQueueFull;
- if (Desc.MayLoad && LSU->isLQFull())
- Event = StallKind::LoadQueueFull;
-
+
switch (Resources->canBeDispatched(Desc.Buffers)) {
case ResourceStateEvent::RS_BUFFER_UNAVAILABLE:
- Event = StallKind::SchedulerQueueFull;
- break;
+ return Scheduler::SC_BUFFERS_FULL;
case ResourceStateEvent::RS_RESERVED:
- Event = StallKind::DispatchGroupStall;
- break;
- default:
+ return Scheduler::SC_DISPATCH_GROUP_STALL;
+ case ResourceStateEvent::RS_BUFFER_AVAILABLE:
break;
}
- return Event == StallKind::NoStall;
+ // Give lower priority to LSUnit stall events.
+ switch (LSU->isAvailable(IR)) {
+ case LSUnit::LSU_LQUEUE_FULL:
+ return Scheduler::SC_LOAD_QUEUE_FULL;
+ case LSUnit::LSU_SQUEUE_FULL:
+ return Scheduler::SC_STORE_QUEUE_FULL;
+ case LSUnit::LSU_AVAILABLE:
+ return Scheduler::SC_AVAILABLE;
+ }
+
+ llvm_unreachable("Don't know how to process this LSU state result!");
}
void Scheduler::issueInstructionImpl(
@@ -298,6 +298,8 @@ void Scheduler::issueInstructionImpl(
if (IS->isExecuting())
IssuedSet.emplace_back(IR);
+ else if (IS->isExecuted())
+ LSU->onInstructionExecuted(IR);
}
// Release the buffered resources and issue the instruction.
@@ -305,7 +307,7 @@ void Scheduler::issueInstruction(
InstRef &IR,
SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources) {
const InstrDesc &Desc = IR.getInstruction()->getDesc();
- releaseBuffers(Desc.Buffers);
+ Resources->releaseBuffers(Desc.Buffers);
issueInstructionImpl(IR, UsedResources);
}
@@ -324,9 +326,8 @@ void Scheduler::promoteToReadySet(SmallVectorImpl<InstRef> &Ready) {
if (!IS.isReady())
IS.update();
- const InstrDesc &Desc = IS.getDesc();
- bool IsMemOp = Desc.MayLoad || Desc.MayStore;
- if (!IS.isReady() || (IsMemOp && !LSU->isReady(IR))) {
+ // Check f there are still unsolved data dependencies.
+ if (!isReady(IR)) {
++I;
continue;
}
@@ -405,6 +406,8 @@ void Scheduler::updateIssuedSet(SmallVectorImpl<InstRef> &Executed) {
continue;
}
+ // Instruction IR has completed execution.
+ LSU->onInstructionExecuted(IR);
Executed.emplace_back(IR);
++RemovedElements;
IR.invalidate();
@@ -414,33 +417,51 @@ void Scheduler::updateIssuedSet(SmallVectorImpl<InstRef> &Executed) {
IssuedSet.resize(IssuedSet.size() - RemovedElements);
}
-void Scheduler::onInstructionExecuted(const InstRef &IR) {
- LSU->onInstructionExecuted(IR);
-}
-
void Scheduler::reclaimSimulatedResources(SmallVectorImpl<ResourceRef> &Freed) {
Resources->cycleEvent(Freed);
}
-bool Scheduler::reserveResources(InstRef &IR) {
+bool Scheduler::mustIssueImmediately(const InstRef &IR) const {
+ // 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.
+ const InstrDesc &Desc = IR.getInstruction()->getDesc();
+ return Desc.isZeroLatency() || Resources->mustIssueImmediately(Desc);
+}
+
+void Scheduler::dispatch(const InstRef &IR) {
+ const InstrDesc &Desc = IR.getInstruction()->getDesc();
+ Resources->reserveBuffers(Desc.Buffers);
+
// 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))) {
+ bool IsMemOp = Desc.MayLoad || Desc.MayStore;
+ if (IsMemOp)
+ LSU->dispatch(IR);
+
+ if (!isReady(IR)) {
LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR << " to the WaitSet\n");
WaitSet.push_back(IR);
- return false;
+ return;
}
- return true;
-}
-bool Scheduler::issueImmediately(InstRef &IR) {
- const InstrDesc &Desc = IR.getInstruction()->getDesc();
- if (!Desc.isZeroLatency() && !Resources->mustIssueImmediately(Desc)) {
+ // Don't add a zero-latency instruction to the 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 specially, and are often eliminated at register
+ // renaming stage.
+ if (!mustIssueImmediately(IR)) {
LLVM_DEBUG(dbgs() << "[SCHEDULER] Adding #" << IR << " to the ReadySet\n");
ReadySet.push_back(IR);
- return false;
}
- return true;
+}
+
+bool Scheduler::isReady(const InstRef &IR) const {
+ const InstrDesc &Desc = IR.getInstruction()->getDesc();
+ bool IsMemOp = Desc.MayLoad || Desc.MayStore;
+ return IR.getInstruction()->isReady() && (!IsMemOp || LSU->isReady(IR));
}
} // namespace mca
OpenPOWER on IntegriCloud