Index: tools/llvm-mca/Backend.h =================================================================== --- tools/llvm-mca/Backend.h +++ tools/llvm-mca/Backend.h @@ -80,13 +80,9 @@ runCycle(Cycles++); } - const Instruction &getInstruction(unsigned Index) const { - const auto It = Instructions.find(Index); - assert(It != Instructions.end() && "no running instructions with index"); - assert(It->second); - return *It->second; + void eraseInstruction(const Instruction &IS) { + Instructions.erase(IS.getSourceIndex()); } - void eraseInstruction(unsigned Index) { Instructions.erase(Index); } void addEventListener(HWEventListener *Listener); void notifyCycleBegin(unsigned Cycle); Index: tools/llvm-mca/Backend.cpp =================================================================== --- tools/llvm-mca/Backend.cpp +++ tools/llvm-mca/Backend.cpp @@ -36,13 +36,12 @@ std::unique_ptr NewIS = IB.createInstruction(IR.first, *IR.second); const InstrDesc &Desc = NewIS->getDesc(); - if (!DU->isAvailable(Desc.NumMicroOps) || - !DU->canDispatch(IR.first, *NewIS)) + if (!DU->isAvailable(Desc.NumMicroOps) || !DU->canDispatch(*NewIS)) break; Instruction *IS = NewIS.get(); - Instructions[IR.first] = std::move(NewIS); - DU->dispatch(IR.first, IS, STI); + Instructions[IS->getSourceIndex()] = std::move(NewIS); + DU->dispatch(IS, STI); SM.updateNext(); } Index: tools/llvm-mca/Dispatch.h =================================================================== --- tools/llvm-mca/Dispatch.h +++ tools/llvm-mca/Dispatch.h @@ -189,12 +189,12 @@ std::unique_ptr RCU; Backend *Owner; - bool checkRAT(unsigned Index, const Instruction &Inst); - bool checkRCU(unsigned Index, const InstrDesc &Desc); - bool checkScheduler(unsigned Index, const InstrDesc &Desc); + bool checkRAT(const Instruction &IS); + bool checkRCU(const Instruction &IS); + bool checkScheduler(const Instruction &IS); void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI); - void notifyInstructionDispatched(unsigned IID, + void notifyInstructionDispatched(const Instruction &IS, llvm::ArrayRef UsedPhysRegs); public: @@ -214,14 +214,13 @@ bool isRCUEmpty() const { return RCU->isEmpty(); } - bool canDispatch(unsigned Index, const Instruction &Inst) { - const InstrDesc &Desc = Inst.getDesc(); + bool canDispatch(const Instruction &IS) { + const InstrDesc &Desc = IS.getDesc(); assert(isAvailable(Desc.NumMicroOps)); - return checkRCU(Index, Desc) && checkRAT(Index, Inst) && - checkScheduler(Index, Desc); + return checkRCU(IS) && checkRAT(IS) && checkScheduler(IS); } - void dispatch(unsigned IID, Instruction *I, const llvm::MCSubtargetInfo &STI); + void dispatch(Instruction *IS, const llvm::MCSubtargetInfo &STI); void collectWrites(llvm::SmallVectorImpl &Vec, unsigned RegID) const { @@ -235,9 +234,9 @@ CarryOver = CarryOver >= DispatchWidth ? CarryOver - DispatchWidth : 0U; } - void notifyInstructionRetired(unsigned Index); + void notifyInstructionRetired(const Instruction &IS); - void notifyDispatchStall(unsigned Index, unsigned EventType); + void notifyDispatchStall(const Instruction &IS, unsigned EventType); void onInstructionExecuted(unsigned TokenID) { RCU->onInstructionExecuted(TokenID); Index: tools/llvm-mca/Dispatch.cpp =================================================================== --- tools/llvm-mca/Dispatch.cpp +++ tools/llvm-mca/Dispatch.cpp @@ -252,50 +252,48 @@ } #endif -void DispatchUnit::notifyInstructionDispatched(unsigned Index, +void DispatchUnit::notifyInstructionDispatched(const Instruction &IS, ArrayRef UsedRegs) { - DEBUG(dbgs() << "[E] Instruction Dispatched: " << Index << '\n'); - Owner->notifyInstructionEvent(HWInstructionDispatchedEvent(Index, UsedRegs)); + DEBUG(dbgs() << "[E] Instruction Dispatched: " << IS.getSourceIndex() + << '\n'); + Owner->notifyInstructionEvent(HWInstructionDispatchedEvent(IS, UsedRegs)); } -void DispatchUnit::notifyInstructionRetired(unsigned Index) { - DEBUG(dbgs() << "[E] Instruction Retired: " << Index << '\n'); - const Instruction &IS = Owner->getInstruction(Index); +void DispatchUnit::notifyInstructionRetired(const Instruction &IS) { + DEBUG(dbgs() << "[E] Instruction Retired: " << IS.getSourceIndex() << '\n'); SmallVector FreedRegs(RAT->getNumRegisterFiles()); for (const std::unique_ptr &WS : IS.getDefs()) RAT->invalidateRegisterMapping(*WS.get(), FreedRegs); - - Owner->notifyInstructionEvent(HWInstructionRetiredEvent(Index, FreedRegs)); - Owner->eraseInstruction(Index); + Owner->notifyInstructionEvent(HWInstructionRetiredEvent(IS, FreedRegs)); + Owner->eraseInstruction(IS); } -bool DispatchUnit::checkRAT(unsigned Index, const Instruction &Instr) { +bool DispatchUnit::checkRAT(const Instruction &IS) { SmallVector RegDefs; - for (const std::unique_ptr &RegDef : Instr.getDefs()) + for (const std::unique_ptr &RegDef : IS.getDefs()) RegDefs.emplace_back(RegDef->getRegisterID()); unsigned RegisterMask = RAT->isAvailable(RegDefs); // A mask with all zeroes means: register files are available. if (RegisterMask) { - Owner->notifyStallEvent( - HWStallEvent(HWStallEvent::RegisterFileStall, Index)); + Owner->notifyStallEvent(HWStallEvent(HWStallEvent::RegisterFileStall, IS)); return false; } return true; } -bool DispatchUnit::checkRCU(unsigned Index, const InstrDesc &Desc) { - unsigned NumMicroOps = Desc.NumMicroOps; +bool DispatchUnit::checkRCU(const Instruction &IS) { + unsigned NumMicroOps = IS.getDesc().NumMicroOps; if (RCU->isAvailable(NumMicroOps)) return true; Owner->notifyStallEvent( - HWStallEvent(HWStallEvent::RetireControlUnitStall, Index)); + HWStallEvent(HWStallEvent::RetireControlUnitStall, IS)); return false; } -bool DispatchUnit::checkScheduler(unsigned Index, const InstrDesc &Desc) { - return SC->canBeDispatched(Index, Desc); +bool DispatchUnit::checkScheduler(const Instruction &IS) { + return SC->canBeDispatched(IS); } void DispatchUnit::updateRAWDependencies(ReadState &RS, @@ -326,8 +324,7 @@ DependentWrites.clear(); } -void DispatchUnit::dispatch(unsigned IID, Instruction *NewInst, - const MCSubtargetInfo &STI) { +void DispatchUnit::dispatch(Instruction *NewInst, const MCSubtargetInfo &STI) { assert(!CarryOver && "Cannot dispatch another instruction!"); unsigned NumMicroOps = NewInst->getDesc().NumMicroOps; if (NumMicroOps > DispatchWidth) { @@ -355,15 +352,15 @@ // Reserve slots in the RCU, and notify the instruction that it has been // dispatched to the schedulers for execution. - NewInst->dispatch(RCU->reserveSlot(IID, NumMicroOps)); + NewInst->dispatch(RCU->reserveSlot(*NewInst, NumMicroOps)); // Notify listeners of the "instruction dispatched" event. - notifyInstructionDispatched(IID, RegisterFiles); + notifyInstructionDispatched(*NewInst, RegisterFiles); // Now move the instruction into the scheduler's queue. // The scheduler is responsible for checking if this is a zero-latency // instruction that doesn't consume pipeline/scheduler resources. - SC->scheduleInstruction(IID, *NewInst); + SC->scheduleInstruction(*NewInst); } #ifndef NDEBUG Index: tools/llvm-mca/HWEventListener.h =================================================================== --- tools/llvm-mca/HWEventListener.h +++ tools/llvm-mca/HWEventListener.h @@ -1,4 +1,3 @@ - //===----------------------- HWEventListener.h ------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure @@ -16,6 +15,7 @@ #ifndef LLVM_TOOLS_LLVM_MCA_HWEVENTLISTENER_H #define LLVM_TOOLS_LLVM_MCA_HWEVENTLISTENER_H +#include "Instruction.h" #include "llvm/ADT/ArrayRef.h" #include @@ -48,30 +48,31 @@ LastGenericEventType, }; - HWInstructionEvent(unsigned type, unsigned index) - : Type(type), Index(index) {} + HWInstructionEvent(unsigned type, const Instruction &IS) + : Type(type), IS(IS) {} // The event type. The exact meaning depends on the subtarget. const unsigned Type; - // The index of the instruction in the source manager. - const unsigned Index; + + // The instruction this event was generated for. + const Instruction &IS; }; class HWInstructionIssuedEvent : public HWInstructionEvent { public: using ResourceRef = std::pair; - HWInstructionIssuedEvent(unsigned Index, + HWInstructionIssuedEvent(const Instruction &IS, llvm::ArrayRef> UR) - : HWInstructionEvent(HWInstructionEvent::Issued, Index), - UsedResources(UR) {} + : HWInstructionEvent(HWInstructionEvent::Issued, IS), UsedResources(UR) {} llvm::ArrayRef> UsedResources; }; class HWInstructionDispatchedEvent : public HWInstructionEvent { public: - HWInstructionDispatchedEvent(unsigned Index, llvm::ArrayRef Regs) - : HWInstructionEvent(HWInstructionEvent::Dispatched, Index), + HWInstructionDispatchedEvent(const Instruction &IS, + llvm::ArrayRef Regs) + : HWInstructionEvent(HWInstructionEvent::Dispatched, IS), UsedPhysRegs(Regs) {} // Number of physical register allocated for this instruction. There is one // entry per register file. @@ -80,8 +81,9 @@ class HWInstructionRetiredEvent : public HWInstructionEvent { public: - HWInstructionRetiredEvent(unsigned Index, llvm::ArrayRef Regs) - : HWInstructionEvent(HWInstructionEvent::Retired, Index), + HWInstructionRetiredEvent(const Instruction &IS, + llvm::ArrayRef Regs) + : HWInstructionEvent(HWInstructionEvent::Retired, IS), FreedPhysRegs(Regs) {} // Number of register writes that have been architecturally committed. There // is one entry per register file. @@ -105,12 +107,13 @@ LastGenericEvent }; - HWStallEvent(unsigned type, unsigned index) : Type(type), Index(index) {} + HWStallEvent(unsigned type, const Instruction &IS) : Type(type), IS(IS) {} // The exact meaning of the stall event type depends on the subtarget. const unsigned Type; - // The index of the instruction in the source manager. - const unsigned Index; + + // The instruction this event was generated for. + const Instruction &IS; }; class HWEventListener { Index: tools/llvm-mca/InstrBuilder.cpp =================================================================== --- tools/llvm-mca/InstrBuilder.cpp +++ tools/llvm-mca/InstrBuilder.cpp @@ -428,7 +428,7 @@ std::unique_ptr InstrBuilder::createInstruction(unsigned Idx, const MCInst &MCI) { const InstrDesc &D = getOrCreateInstrDesc(MCI); - std::unique_ptr NewIS = llvm::make_unique(D); + std::unique_ptr NewIS = llvm::make_unique(D, Idx); // Initialize Reads first. for (const ReadDescriptor &RD : D.Reads) { Index: tools/llvm-mca/Instruction.h =================================================================== --- tools/llvm-mca/Instruction.h +++ tools/llvm-mca/Instruction.h @@ -266,6 +266,9 @@ // Retire Unit token ID for this instruction. unsigned RCUTokenID; + // Lexical/Program-order source index into SourceMgr::Sequence. + const unsigned SourceIndex; + using UniqueDef = std::unique_ptr; using UniqueUse = std::unique_ptr; using VecDefs = std::vector; @@ -280,11 +283,12 @@ VecUses Uses; public: - Instruction(const InstrDesc &D) - : Desc(D), Stage(IS_INVALID), CyclesLeft(-1) {} + Instruction(const InstrDesc &D, unsigned Idx) + : Desc(D), Stage(IS_INVALID), CyclesLeft(-1), SourceIndex(Idx) {} Instruction(const Instruction &Other) = delete; Instruction &operator=(const Instruction &Other) = delete; + unsigned getSourceIndex() const { return SourceIndex; } VecDefs &getDefs() { return Defs; } const VecDefs &getDefs() const { return Defs; } VecUses &getUses() { return Uses; } Index: tools/llvm-mca/InstructionTables.cpp =================================================================== --- tools/llvm-mca/InstructionTables.cpp +++ tools/llvm-mca/InstructionTables.cpp @@ -70,7 +70,7 @@ } // Now send a fake instruction issued event to all the views. - HWInstructionIssuedEvent Event(IR.first, UsedResources); + HWInstructionIssuedEvent Event(*Inst, UsedResources); for (std::unique_ptr &Listener : Views) Listener->onInstructionEvent(Event); S.updateNext(); Index: tools/llvm-mca/LSUnit.h =================================================================== --- tools/llvm-mca/LSUnit.h +++ tools/llvm-mca/LSUnit.h @@ -16,6 +16,7 @@ #ifndef LLVM_TOOLS_LLVM_MCA_LSUNIT_H #define LLVM_TOOLS_LLVM_MCA_LSUNIT_H +#include "Instruction.h" #include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include @@ -132,7 +133,7 @@ bool isLQFull() const { return LQ_Size != 0 && LoadQueue.size() == LQ_Size; } // Returns true if this instruction has been successfully enqueued. - bool reserve(unsigned Index, const InstrDesc &Desc); + bool reserve(const Instruction &IS); // The rules are: // 1. A store may not pass a previous store. @@ -141,8 +142,8 @@ // 4. A store may not pass a previous load (regardless of flag 'NoAlias'). // 5. A load has to wait until an older load barrier is fully executed. // 6. A store has to wait until an older store barrier is fully executed. - bool isReady(unsigned Index) const; - void onInstructionExecuted(unsigned Index); + bool isReady(const Instruction &IS) const; + void onInstructionExecuted(const Instruction &IS); }; } // namespace mca Index: tools/llvm-mca/LSUnit.cpp =================================================================== --- tools/llvm-mca/LSUnit.cpp +++ tools/llvm-mca/LSUnit.cpp @@ -50,13 +50,15 @@ StoreQueue.insert(Index); } -bool LSUnit::reserve(unsigned Index, const InstrDesc &Desc) { +bool LSUnit::reserve(const Instruction &IS) { + const InstrDesc Desc = IS.getDesc(); unsigned MayLoad = Desc.MayLoad; unsigned MayStore = Desc.MayStore; unsigned IsMemBarrier = Desc.HasSideEffects; if (!MayLoad && !MayStore) return false; + const unsigned Index = IS.getSourceIndex(); if (MayLoad) { if (IsMemBarrier) LoadBarriers.insert(Index); @@ -70,7 +72,8 @@ return true; } -bool LSUnit::isReady(unsigned Index) const { +bool LSUnit::isReady(const Instruction &IS) const { + const unsigned Index = IS.getSourceIndex(); bool IsALoad = LoadQueue.count(Index) != 0; bool IsAStore = StoreQueue.count(Index) != 0; assert((IsALoad || IsAStore) && "Instruction is not in queue!"); @@ -116,7 +119,8 @@ return !IsAStore; } -void LSUnit::onInstructionExecuted(unsigned Index) { +void LSUnit::onInstructionExecuted(const Instruction &IS) { + const unsigned Index = IS.getSourceIndex(); std::set::iterator it = LoadQueue.find(Index); if (it != LoadQueue.end()) { DEBUG(dbgs() << "[LSUnit]: Instruction idx=" << Index Index: tools/llvm-mca/ResourcePressureView.cpp =================================================================== --- tools/llvm-mca/ResourcePressureView.cpp +++ tools/llvm-mca/ResourcePressureView.cpp @@ -44,7 +44,7 @@ if (Event.Type != HWInstructionEvent::Issued) return; const auto &IssueEvent = static_cast(Event); - unsigned SourceIdx = Event.Index % Source.size(); + const unsigned SourceIdx = Event.IS.getSourceIndex() % Source.size(); for (const std::pair &Use : IssueEvent.UsedResources) { const ResourceRef &RR = Use.first; assert(Resource2VecIndex.find(RR.first) != Resource2VecIndex.end()); Index: tools/llvm-mca/RetireControlUnit.h =================================================================== --- tools/llvm-mca/RetireControlUnit.h +++ tools/llvm-mca/RetireControlUnit.h @@ -47,7 +47,7 @@ // Note that the size of the reorder buffer is defined by the scheduling // model via field 'NumMicroOpBufferSize'. struct RUToken { - unsigned Index; // Instruction index. + Instruction *IS; unsigned NumSlots; // Slots reserved to this instruction. bool Executed; // True if the instruction is past the WB stage. }; @@ -74,7 +74,7 @@ } // Reserves a number of slots, and returns a new token. - unsigned reserveSlot(unsigned Index, unsigned NumMicroOps); + unsigned reserveSlot(Instruction &IS, unsigned NumMicroOps); /// Retires instructions in program order. void cycleEvent(); Index: tools/llvm-mca/RetireControlUnit.cpp =================================================================== --- tools/llvm-mca/RetireControlUnit.cpp +++ tools/llvm-mca/RetireControlUnit.cpp @@ -28,7 +28,7 @@ } // Reserves a number of slots, and returns a new token. -unsigned RetireControlUnit::reserveSlot(unsigned Index, unsigned NumMicroOps) { +unsigned RetireControlUnit::reserveSlot(Instruction &IS, unsigned NumMicroOps) { assert(isAvailable(NumMicroOps)); unsigned NormalizedQuantity = std::min(NumMicroOps, static_cast(Queue.size())); @@ -37,7 +37,7 @@ // resources, they still consume one slot in the retire queue. NormalizedQuantity = std::max(NormalizedQuantity, 1U); unsigned TokenID = NextAvailableSlotIdx; - Queue[NextAvailableSlotIdx] = {Index, NormalizedQuantity, false}; + Queue[NextAvailableSlotIdx] = {&IS, NormalizedQuantity, false}; NextAvailableSlotIdx += NormalizedQuantity; NextAvailableSlotIdx %= Queue.size(); AvailableSlots -= NormalizedQuantity; @@ -56,7 +56,7 @@ assert(Current.NumSlots && "Reserved zero slots?"); if (!Current.Executed) break; - Owner->notifyInstructionRetired(Current.Index); + Owner->notifyInstructionRetired(*Current.IS); CurrentInstructionSlotIdx += Current.NumSlots; CurrentInstructionSlotIdx %= Queue.size(); AvailableSlots += Current.NumSlots; @@ -66,7 +66,7 @@ void RetireControlUnit::onInstructionExecuted(unsigned TokenID) { assert(Queue.size() > TokenID); - assert(Queue[TokenID].Executed == false && Queue[TokenID].Index != ~0U); + assert(Queue[TokenID].Executed == false && Queue[TokenID].IS); Queue[TokenID].Executed = true; } Index: tools/llvm-mca/Scheduler.h =================================================================== --- tools/llvm-mca/Scheduler.h +++ tools/llvm-mca/Scheduler.h @@ -419,10 +419,10 @@ std::map IssuedQueue; void - notifyInstructionIssued(unsigned Index, + notifyInstructionIssued(const Instruction &IS, llvm::ArrayRef> Used); - void notifyInstructionExecuted(unsigned Index); - void notifyInstructionReady(unsigned Index); + void notifyInstructionExecuted(const Instruction &IS); + void notifyInstructionReady(const Instruction &IS); void notifyResourceAvailable(const ResourceRef &RR); // Notify the Backend that buffered resources were consumed. @@ -436,15 +436,15 @@ /// Move instructions from the WaitQueue to the ReadyQueue if input operands /// are all available. - void promoteToReadyQueue(llvm::SmallVectorImpl &Ready); + void promoteToReadyQueue(llvm::SmallVectorImpl &Ready); /// Issue an instruction without updating the ready queue. void issueInstructionImpl( - unsigned Index, Instruction &IS, + Instruction &IS, llvm::SmallVectorImpl> &Pipes); - void updatePendingQueue(llvm::SmallVectorImpl &Ready); - void updateIssuedQueue(llvm::SmallVectorImpl &Executed); + void updatePendingQueue(llvm::SmallVectorImpl &Ready); + void updateIssuedQueue(llvm::SmallVectorImpl &Executed); public: Scheduler(Backend *B, const llvm::MCSchedModel &Model, unsigned LoadQueueSize, @@ -456,18 +456,18 @@ void setDispatchUnit(DispatchUnit *DispUnit) { DU = DispUnit; } - /// Check if instruction at index Idx can be dispatched. + /// Check if instruction 'IS' can be dispatched. /// /// The DispatchUnit is responsible for querying the Scheduler before /// dispatching new instructions. Queries are performed through method /// `Scheduler::CanBeDispatched`. If scheduling resources are available, /// and the instruction can be dispatched, then this method returns true. /// Otherwise, a generic HWStallEvent is notified to the listeners. - bool canBeDispatched(unsigned Idx, const InstrDesc &Desc) const; - void scheduleInstruction(unsigned Idx, Instruction &MCIS); + bool canBeDispatched(const Instruction &IS) const; + void scheduleInstruction(Instruction &IS); /// Issue an instruction. - void issueInstruction(unsigned Index, Instruction &IS); + void issueInstruction(Instruction &IS); /// Reserve one entry in each buffered resource. void reserveBuffers(llvm::ArrayRef Buffers) { Index: tools/llvm-mca/Scheduler.cpp =================================================================== --- tools/llvm-mca/Scheduler.cpp +++ tools/llvm-mca/Scheduler.cpp @@ -228,7 +228,8 @@ BusyResources.erase(RF); } -void Scheduler::scheduleInstruction(unsigned Idx, Instruction &MCIS) { +void Scheduler::scheduleInstruction(Instruction &IS) { + const unsigned Idx = IS.getSourceIndex(); assert(WaitQueue.find(Idx) == WaitQueue.end()); assert(ReadyQueue.find(Idx) == ReadyQueue.end()); assert(IssuedQueue.find(Idx) == IssuedQueue.end()); @@ -237,18 +238,18 @@ // 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 = MCIS.getDesc(); + const InstrDesc &Desc = IS.getDesc(); reserveBuffers(Desc.Buffers); notifyReservedBuffers(Desc.Buffers); // If necessary, reserve queue entries in the load-store unit (LSU). - bool Reserved = LSU->reserve(Idx, Desc); - if (!MCIS.isReady() || (Reserved && !LSU->isReady(Idx))) { + bool Reserved = LSU->reserve(IS); + if (!IS.isReady() || (Reserved && !LSU->isReady(IS))) { DEBUG(dbgs() << "[SCHEDULER] Adding " << Idx << " to the Wait Queue\n"); - WaitQueue[Idx] = &MCIS; + WaitQueue[Idx] = &IS; return; } - notifyInstructionReady(Idx); + notifyInstructionReady(IS); // 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 @@ -265,14 +266,16 @@ // resources (i.e. BufferSize=1) is consumed. if (!IsZeroLatency && !Resources->mustIssueImmediately(Desc)) { - DEBUG(dbgs() << "[SCHEDULER] Adding " << Idx << " to the Ready Queue\n"); - ReadyQueue[Idx] = &MCIS; + DEBUG(dbgs() << "[SCHEDULER] Adding " << IS.getSourceIndex() + << " to the Ready Queue\n"); + ReadyQueue[IS.getSourceIndex()] = &IS; return; } - DEBUG(dbgs() << "[SCHEDULER] Instruction " << Idx << " issued immediately\n"); + DEBUG(dbgs() << "[SCHEDULER] Instruction " << IS.getSourceIndex() + << " issued immediately\n"); // Release buffered resources and issue MCIS to the underlying pipelines. - issueInstruction(Idx, MCIS); + issueInstruction(IS); } void Scheduler::cycleEvent() { @@ -282,20 +285,20 @@ for (const ResourceRef &RR : ResourcesFreed) notifyResourceAvailable(RR); - SmallVector InstructionIDs; + SmallVector InstructionIDs; updateIssuedQueue(InstructionIDs); - for (unsigned Idx : InstructionIDs) - notifyInstructionExecuted(Idx); + for (const Instruction *IS : InstructionIDs) + notifyInstructionExecuted(*IS); InstructionIDs.clear(); updatePendingQueue(InstructionIDs); - for (unsigned Idx : InstructionIDs) - notifyInstructionReady(Idx); + for (const Instruction *IS : InstructionIDs) + notifyInstructionReady(*IS); InstructionIDs.clear(); std::pair Inst = select(); while (Inst.second) { - issueInstruction(Inst.first, *Inst.second); + issueInstruction(*Inst.second); // Instructions that have been issued during this cycle might have unblocked // other dependent instructions. Dependent instructions may be issued during @@ -303,8 +306,8 @@ // instructions to the ReadyQueue and tell to the caller that we need // another round of 'issue()'. promoteToReadyQueue(InstructionIDs); - for (unsigned Idx : InstructionIDs) - notifyInstructionReady(Idx); + for (const Instruction *IS : InstructionIDs) + notifyInstructionReady(*IS); InstructionIDs.clear(); // Select the next instruction to issue. @@ -321,8 +324,9 @@ } #endif -bool Scheduler::canBeDispatched(unsigned Index, const InstrDesc &Desc) const { +bool Scheduler::canBeDispatched(const Instruction &IS) const { HWStallEvent::GenericEventType Type = HWStallEvent::Invalid; + const InstrDesc &Desc = IS.getDesc(); if (Desc.MayLoad && LSU->isLQFull()) Type = HWStallEvent::LoadQueueFull; @@ -340,12 +344,12 @@ } } - Owner->notifyStallEvent(HWStallEvent(Type, Index)); + Owner->notifyStallEvent(HWStallEvent(Type, IS)); return false; } void Scheduler::issueInstructionImpl( - unsigned InstrIndex, Instruction &IS, + Instruction &IS, SmallVectorImpl> &UsedResources) { const InstrDesc &D = IS.getDesc(); @@ -358,10 +362,10 @@ IS.execute(); if (IS.isExecuting()) - IssuedQueue[InstrIndex] = &IS; + IssuedQueue[IS.getSourceIndex()] = &IS; } -void Scheduler::issueInstruction(unsigned InstrIndex, Instruction &IS) { +void Scheduler::issueInstruction(Instruction &IS) { // Release buffered resources. const InstrDesc &Desc = IS.getDesc(); releaseBuffers(Desc.Buffers); @@ -369,33 +373,33 @@ // Issue IS to the underlying pipelines and notify listeners. SmallVector, 4> Pipes; - issueInstructionImpl(InstrIndex, IS, Pipes); - notifyInstructionIssued(InstrIndex, Pipes); + issueInstructionImpl(IS, Pipes); + notifyInstructionIssued(IS, Pipes); if (IS.isExecuted()) - notifyInstructionExecuted(InstrIndex); + notifyInstructionExecuted(IS); } -void Scheduler::promoteToReadyQueue(SmallVectorImpl &Ready) { +void Scheduler::promoteToReadyQueue(SmallVectorImpl &Ready) { // Scan the set of waiting instructions and promote them to the // ready queue if operands are all ready. for (auto I = WaitQueue.begin(), E = WaitQueue.end(); I != E;) { const QueueEntryTy &Entry = *I; - unsigned IID = Entry.first; - Instruction &Inst = *Entry.second; + const unsigned IID = Entry.first; + Instruction *IS = Entry.second; // Check if this instruction is now ready. In case, force // a transition in state using method 'update()'. - Inst.update(); + IS->update(); - const InstrDesc &Desc = Inst.getDesc(); + const InstrDesc &Desc = IS->getDesc(); bool IsMemOp = Desc.MayLoad || Desc.MayStore; - if (!Inst.isReady() || (IsMemOp && !LSU->isReady(IID))) { + if (!IS->isReady() || (IsMemOp && !LSU->isReady(*IS))) { ++I; continue; } - Ready.emplace_back(IID); - ReadyQueue[IID] = &Inst; + Ready.emplace_back(IS); + ReadyQueue[IID] = IS; auto ToRemove = I; ++I; WaitQueue.erase(ToRemove); @@ -421,7 +425,7 @@ return Entry; } -void Scheduler::updatePendingQueue(SmallVectorImpl &Ready) { +void Scheduler::updatePendingQueue(SmallVectorImpl &Ready) { // Notify to instructions in the pending queue that a new cycle just // started. for (QueueEntryTy Entry : WaitQueue) @@ -429,12 +433,14 @@ promoteToReadyQueue(Ready); } -void Scheduler::updateIssuedQueue(SmallVectorImpl &Executed) { +void Scheduler::updateIssuedQueue(SmallVectorImpl &Executed) { for (auto I = IssuedQueue.begin(), E = IssuedQueue.end(); I != E;) { const QueueEntryTy Entry = *I; - Entry.second->cycleEvent(); - if (Entry.second->isExecuted()) { - Executed.push_back(Entry.first); + Instruction *IS = Entry.second; + assert(IS->getSourceIndex() == Entry.first && "Corrupted IssuedQueue."); + IS->cycleEvent(); + if (IS->isExecuted()) { + Executed.push_back(IS); auto ToRemove = I; ++I; IssuedQueue.erase(ToRemove); @@ -447,32 +453,30 @@ } void Scheduler::notifyInstructionIssued( - unsigned Index, ArrayRef> Used) { + const Instruction &IS, ArrayRef> Used) { DEBUG({ - dbgs() << "[E] Instruction Issued: " << Index << '\n'; + dbgs() << "[E] Instruction Issued: " << IS.getSourceIndex() << '\n'; for (const std::pair &Resource : Used) { dbgs() << "[E] Resource Used: [" << Resource.first.first << '.' << Resource.first.second << "]\n"; dbgs() << " cycles: " << Resource.second << '\n'; } }); - Owner->notifyInstructionEvent(HWInstructionIssuedEvent(Index, Used)); + Owner->notifyInstructionEvent(HWInstructionIssuedEvent(IS, Used)); } -void Scheduler::notifyInstructionExecuted(unsigned Index) { - LSU->onInstructionExecuted(Index); - DEBUG(dbgs() << "[E] Instruction Executed: " << Index << '\n'); +void Scheduler::notifyInstructionExecuted(const Instruction &IS) { + LSU->onInstructionExecuted(IS); + DEBUG(dbgs() << "[E] Instruction Executed: " << IS.getSourceIndex() << '\n'); Owner->notifyInstructionEvent( - HWInstructionEvent(HWInstructionEvent::Executed, Index)); - - const Instruction &IS = Owner->getInstruction(Index); + HWInstructionEvent(HWInstructionEvent::Executed, IS)); DU->onInstructionExecuted(IS.getRCUTokenID()); } -void Scheduler::notifyInstructionReady(unsigned Index) { - DEBUG(dbgs() << "[E] Instruction Ready: " << Index << '\n'); +void Scheduler::notifyInstructionReady(const Instruction &IS) { + DEBUG(dbgs() << "[E] Instruction Ready: " << IS.getSourceIndex() << '\n'); Owner->notifyInstructionEvent( - HWInstructionEvent(HWInstructionEvent::Ready, Index)); + HWInstructionEvent(HWInstructionEvent::Ready, IS)); } void Scheduler::notifyResourceAvailable(const ResourceRef &RR) { Index: tools/llvm-mca/TimelineView.cpp =================================================================== --- tools/llvm-mca/TimelineView.cpp +++ tools/llvm-mca/TimelineView.cpp @@ -35,15 +35,16 @@ } void TimelineView::onInstructionEvent(const HWInstructionEvent &Event) { - if (CurrentCycle >= MaxCycle || Event.Index >= Timeline.size()) + const unsigned Index = Event.IS.getSourceIndex(); + if (CurrentCycle >= MaxCycle || Index >= Timeline.size()) return; switch (Event.Type) { case HWInstructionEvent::Retired: { - TimelineViewEntry &TVEntry = Timeline[Event.Index]; + TimelineViewEntry &TVEntry = Timeline[Index]; TVEntry.CycleRetired = CurrentCycle; // Update the WaitTime entry which corresponds to this Index. - WaitTimeEntry &WTEntry = WaitTime[Event.Index % AsmSequence.size()]; + WaitTimeEntry &WTEntry = WaitTime[Index % AsmSequence.size()]; WTEntry.Executions++; WTEntry.CyclesSpentInSchedulerQueue += TVEntry.CycleIssued - TVEntry.CycleDispatched; @@ -55,16 +56,16 @@ break; } case HWInstructionEvent::Ready: - Timeline[Event.Index].CycleReady = CurrentCycle; + Timeline[Index].CycleReady = CurrentCycle; break; case HWInstructionEvent::Issued: - Timeline[Event.Index].CycleIssued = CurrentCycle; + Timeline[Index].CycleIssued = CurrentCycle; break; case HWInstructionEvent::Executed: - Timeline[Event.Index].CycleExecuted = CurrentCycle; + Timeline[Index].CycleExecuted = CurrentCycle; break; case HWInstructionEvent::Dispatched: - Timeline[Event.Index].CycleDispatched = CurrentCycle; + Timeline[Index].CycleDispatched = CurrentCycle; break; default: return;