From 09ea09e47880c0ef0a9885254d1d5276b735c8d2 Mon Sep 17 00:00:00 2001 From: Andrea Di Biagio Date: Thu, 22 Mar 2018 11:39:34 +0000 Subject: [PATCH] [llvm-mca] Simplify (and better standardize) the Instruction interface. llvm-svn: 328190 --- llvm/tools/llvm-mca/Backend.cpp | 2 +- llvm/tools/llvm-mca/Dispatch.cpp | 18 +++++++++--------- llvm/tools/llvm-mca/Dispatch.h | 7 +++---- llvm/tools/llvm-mca/Instruction.cpp | 10 +++++++++- llvm/tools/llvm-mca/Instruction.h | 16 ++++------------ llvm/tools/llvm-mca/Scheduler.cpp | 7 +++---- 6 files changed, 29 insertions(+), 31 deletions(-) diff --git a/llvm/tools/llvm-mca/Backend.cpp b/llvm/tools/llvm-mca/Backend.cpp index 7d69466..94edf87 100644 --- a/llvm/tools/llvm-mca/Backend.cpp +++ b/llvm/tools/llvm-mca/Backend.cpp @@ -42,7 +42,7 @@ void Backend::runCycle(unsigned Cycle) { Instruction *IS = NewIS.get(); Instructions[IR.first] = std::move(NewIS); - IS->setRCUTokenID(DU->dispatch(IR.first, IS, STI)); + DU->dispatch(IR.first, IS, STI); SM.updateNext(); } diff --git a/llvm/tools/llvm-mca/Dispatch.cpp b/llvm/tools/llvm-mca/Dispatch.cpp index 36f1bc3..c1e5d3e 100644 --- a/llvm/tools/llvm-mca/Dispatch.cpp +++ b/llvm/tools/llvm-mca/Dispatch.cpp @@ -348,8 +348,8 @@ void DispatchUnit::updateRAWDependencies(ReadState &RS, DependentWrites.clear(); } -unsigned DispatchUnit::dispatch(unsigned IID, Instruction *NewInst, - const MCSubtargetInfo &STI) { +void DispatchUnit::dispatch(unsigned IID, Instruction *NewInst, + const MCSubtargetInfo &STI) { assert(!CarryOver && "Cannot dispatch another instruction!"); unsigned NumMicroOps = NewInst->getDesc().NumMicroOps; if (NumMicroOps > DispatchWidth) { @@ -370,17 +370,17 @@ unsigned DispatchUnit::dispatch(unsigned IID, Instruction *NewInst, for (std::unique_ptr &WS : NewInst->getDefs()) RAT->addRegisterMapping(*WS, RegisterFiles); - // Set the cycles left before the write-back stage. - const InstrDesc &D = NewInst->getDesc(); - NewInst->setCyclesLeft(D.MaxLatency); + // 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)); - // Reserve slots in the RCU. - unsigned RCUTokenID = RCU->reserveSlot(IID, NumMicroOps); - NewInst->setRCUTokenID(RCUTokenID); + // Notify listeners of the "instruction dispatched" event. notifyInstructionDispatched(IID, 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); - return RCUTokenID; } #ifndef NDEBUG diff --git a/llvm/tools/llvm-mca/Dispatch.h b/llvm/tools/llvm-mca/Dispatch.h index c1093fa..9ac7c3c 100644 --- a/llvm/tools/llvm-mca/Dispatch.h +++ b/llvm/tools/llvm-mca/Dispatch.h @@ -250,7 +250,8 @@ class DispatchUnit { bool checkScheduler(unsigned Index, const InstrDesc &Desc); void updateRAWDependencies(ReadState &RS, const llvm::MCSubtargetInfo &STI); - void notifyInstructionDispatched(unsigned IID, llvm::ArrayRef UsedPhysRegs); + void notifyInstructionDispatched(unsigned IID, + llvm::ArrayRef UsedPhysRegs); public: DispatchUnit(Backend *B, const llvm::MCRegisterInfo &MRI, @@ -279,8 +280,7 @@ public: checkScheduler(Index, Desc); } - unsigned dispatch(unsigned IID, Instruction *NewInst, - const llvm::MCSubtargetInfo &STI); + void dispatch(unsigned IID, Instruction *I, const llvm::MCSubtargetInfo &STI); void collectWrites(llvm::SmallVectorImpl &Vec, unsigned RegID) const { @@ -306,7 +306,6 @@ public: void dump() const; #endif }; - } // namespace mca #endif diff --git a/llvm/tools/llvm-mca/Instruction.cpp b/llvm/tools/llvm-mca/Instruction.cpp index e3b26bd..edf321a 100644 --- a/llvm/tools/llvm-mca/Instruction.cpp +++ b/llvm/tools/llvm-mca/Instruction.cpp @@ -92,10 +92,12 @@ void WriteState::dump() const { } #endif -void Instruction::dispatch() { +void Instruction::dispatch(unsigned RCUToken) { assert(Stage == IS_INVALID); Stage = IS_AVAILABLE; + RCUTokenID = RCUToken; + // Check if input operands are already available. if (std::all_of(Uses.begin(), Uses.end(), [](const UniqueUse &Use) { return Use->isReady(); })) Stage = IS_READY; @@ -104,8 +106,14 @@ void Instruction::dispatch() { void Instruction::execute() { assert(Stage == IS_READY); Stage = IS_EXECUTING; + + // Set the cycles left before the write-back stage. + setCyclesLeft(Desc.MaxLatency); + for (UniqueDef &Def : Defs) Def->onInstructionIssued(); + + // Transition to the "executed" stage if this is a zero-latency instruction. if (!CyclesLeft) Stage = IS_EXECUTED; } diff --git a/llvm/tools/llvm-mca/Instruction.h b/llvm/tools/llvm-mca/Instruction.h index 7a0591b..a4a1498 100644 --- a/llvm/tools/llvm-mca/Instruction.h +++ b/llvm/tools/llvm-mca/Instruction.h @@ -110,11 +110,9 @@ public: int getCyclesLeft() const { return CyclesLeft; } unsigned getWriteResourceID() const { return WD.SClassOrWriteResourceID; } unsigned getRegisterID() const { return RegisterID; } - void setRegisterID(unsigned ID) { RegisterID = ID; } void addUser(ReadState *Use, int ReadAdvance); bool fullyUpdatesSuperRegs() const { return WD.FullyUpdatesSuperRegs; } - bool isWrittenBack() const { return CyclesLeft == 0; } // On every cycle, update CyclesLeft and notify dependent users. void cycleEvent(); @@ -291,22 +289,16 @@ public: unsigned getRCUTokenID() const { return RCUTokenID; } int getCyclesLeft() const { return CyclesLeft; } void setCyclesLeft(int Cycles) { CyclesLeft = Cycles; } - void setRCUTokenID(unsigned TokenID) { RCUTokenID = TokenID; } - // Transition to the dispatch stage. - // No definition is updated because the instruction is not "executing". - void dispatch(); + // Transition to the dispatch stage, and assign a RCUToken to this + // instruction. The RCUToken is used to track the completion of every + // register write performed by this instruction. + void dispatch(unsigned RCUTokenID); // Instruction issued. Transition to the IS_EXECUTING state, and update // all the definitions. void execute(); - void forceExecuted() { - assert((Stage == IS_INVALID && isZeroLatency()) || - (Stage == IS_READY && Desc.MaxLatency == 0)); - Stage = IS_EXECUTED; - } - bool isDispatched() const { return Stage == IS_AVAILABLE; } bool isReady() const { return Stage == IS_READY; } bool isExecuting() const { return Stage == IS_EXECUTING; } diff --git a/llvm/tools/llvm-mca/Scheduler.cpp b/llvm/tools/llvm-mca/Scheduler.cpp index e722844..70b073b 100644 --- a/llvm/tools/llvm-mca/Scheduler.cpp +++ b/llvm/tools/llvm-mca/Scheduler.cpp @@ -241,16 +241,16 @@ void Scheduler::scheduleInstruction(unsigned Idx, Instruction &MCIS) { // eliminated at register renaming stage, since we know in advance that those // clear their output register. if (MCIS.isZeroLatency()) { + assert(MCIS.isReady() && "data dependent zero-latency instruction?"); notifyInstructionReady(Idx); - MCIS.forceExecuted(); + MCIS.execute(); notifyInstructionIssued(Idx, {}); + assert(MCIS.isExecuted() && "Unexpected non-zero latency!"); notifyInstructionExecuted(Idx); return; } - // Consume entries in the reservation stations. const InstrDesc &Desc = MCIS.getDesc(); - if (!Desc.Buffers.empty()) { // Reserve a slot in each buffered resource. Also, mark units with // BufferSize=0 as reserved. Resources with a buffer size of zero will only @@ -265,7 +265,6 @@ void Scheduler::scheduleInstruction(unsigned Idx, Instruction &MCIS) { if (MayLoad || MayStore) LSU->reserve(Idx, MayLoad, MayStore, Desc.HasSideEffects); - MCIS.dispatch(); bool IsReady = MCIS.isReady(); if (IsReady && (MayLoad || MayStore)) IsReady &= LSU->isReady(Idx); -- 2.7.4