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::issueInstructionImpl( InstRef &IR, SmallVectorImpl<std::pair<ResourceRef, double>> &UsedResources) { Instruction *IS = IR.getInstruction(); const InstrDesc &D = IS->getDesc(); // Issue the instruction and collect all the consumed resources // into a vector. That vector is then used to notify the listener. Resources->issueInstruction(D, UsedResources); // Notify the instruction that it started executing. // This updates the internal state of each write. IS->execute(); if (IS->isExecuting()) IssuedQueue[IR.getSourceIndex()] = IS; }