diff options
Diffstat (limited to 'llvm/tools/llvm-mca/Scheduler.cpp')
-rw-r--r-- | llvm/tools/llvm-mca/Scheduler.cpp | 93 |
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 |