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(); } }
// Schedule the instruction for execution on the hardware. Error ExecuteStage::execute(InstRef &IR) { assert(isAvailable(IR) && "Scheduler is not available!"); #ifndef NDEBUG // Ensure that the HWS has not stored this instruction in its queues. HWS.sanityCheck(IR); #endif if (IR.getInstruction()->isEliminated()) return handleInstructionEliminated(IR); // 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. bool IsReadyInstruction = HWS.dispatch(IR); const Instruction &Inst = *IR.getInstruction(); NumDispatchedOpcodes += Inst.getDesc().NumMicroOps; notifyReservedOrReleasedBuffers(IR, /* Reserved */ true); if (!IsReadyInstruction) { if (Inst.isPending()) notifyInstructionPending(IR); return ErrorSuccess(); } notifyInstructionPending(IR); // If we did not return early, then the scheduler is ready for execution. notifyInstructionReady(IR); // If we cannot issue immediately, the HWS will add IR to its ready queue for // execution later, so we must return early here. if (!HWS.mustIssueImmediately(IR)) return ErrorSuccess(); // Issue IR to the underlying pipelines. return issueInstruction(IR); }