diff options
Diffstat (limited to 'llvm/tools/llvm-mca/Instruction.cpp')
| -rw-r--r-- | llvm/tools/llvm-mca/Instruction.cpp | 134 |
1 files changed, 134 insertions, 0 deletions
diff --git a/llvm/tools/llvm-mca/Instruction.cpp b/llvm/tools/llvm-mca/Instruction.cpp new file mode 100644 index 00000000000..e7f9916cae2 --- /dev/null +++ b/llvm/tools/llvm-mca/Instruction.cpp @@ -0,0 +1,134 @@ +//===--------------------- Instruction.cpp ----------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file defines abstractions used by the Backend to model register reads, +// register writes and instructions. +// +//===----------------------------------------------------------------------===// + +#include "Instruction.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +namespace mca { + +using namespace llvm; + +void ReadState::writeStartEvent(unsigned Cycles) { + assert(DependentWrites); + assert(CyclesLeft == UNKNOWN_CYCLES); + + // This read may be dependent on more than one write. This typically occurs + // when a definition is the result of multiple writes where at least one + // write does a partial register update. + // The HW is forced to do some extra bookkeeping to track of all the + // dependent writes, and implement a merging scheme for the partial writes. + --DependentWrites; + TotalCycles = std::max(TotalCycles, Cycles); + + if (!DependentWrites) + CyclesLeft = TotalCycles; +} + +void WriteState::onInstructionIssued() { + assert(CyclesLeft == UNKNOWN_CYCLES); + // Update the number of cycles left based on the WriteDescriptor info. + CyclesLeft = WD.Latency; + + // Now that the time left before write-back is know, notify + // all the users. + for (const std::pair<ReadState *, int> &User : Users) { + ReadState *RS = User.first; + unsigned ReadCycles = std::max(0, CyclesLeft - User.second); + RS->writeStartEvent(ReadCycles); + } +} + +void WriteState::addUser(ReadState *User, int ReadAdvance) { + // If CyclesLeft is different than -1, then we don't need to + // update the list of users. We can just notify the user with + // the actual number of cycles left (which may be zero). + if (CyclesLeft != UNKNOWN_CYCLES) { + unsigned ReadCycles = std::max(0, CyclesLeft - ReadAdvance); + User->writeStartEvent(ReadCycles); + return; + } + + std::pair<ReadState *, int> NewPair(User, ReadAdvance); + Users.insert(NewPair); +} + +void WriteState::cycleEvent() { + // Note: CyclesLeft can be a negative number. It is an error to + // make it an unsigned quantity because users of this write may + // specify a negative ReadAdvance. + if (CyclesLeft != UNKNOWN_CYCLES) + CyclesLeft--; +} + +void ReadState::cycleEvent() { + // If CyclesLeft is unknown, then bail out immediately. + if (CyclesLeft == UNKNOWN_CYCLES) + return; + + // If there are still dependent writes, or we reached cycle zero, + // then just exit. + if (DependentWrites || CyclesLeft == 0) + return; + + CyclesLeft--; +} + +#ifndef NDEBUG +void WriteState::dump() const { + dbgs() << "{ OpIdx=" << WD.OpIndex << ", Lat=" << WD.Latency << ", RegID " + << getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }\n"; +} +#endif + +bool Instruction::isReady() { + if (Stage == IS_READY) + return true; + + assert(Stage == IS_AVAILABLE); + for (const UniqueUse &Use : Uses) + if (!Use.get()->isReady()) + return false; + + setReady(); + return true; +} + +void Instruction::execute() { + assert(Stage == IS_READY); + Stage = IS_EXECUTING; + for (UniqueDef &Def : Defs) + Def->onInstructionIssued(); +} + +bool Instruction::isZeroLatency() const { + return Desc.MaxLatency == 0 && Defs.size() == 0 && Uses.size() == 0; +} + +void Instruction::cycleEvent() { + if (isDispatched()) { + for (UniqueUse &Use : Uses) + Use->cycleEvent(); + return; + } + if (isExecuting()) { + for (UniqueDef &Def : Defs) + Def->cycleEvent(); + CyclesLeft--; + } + if (!CyclesLeft) + Stage = IS_EXECUTED; +} + +} // namespace mca |

