Path: blob/main/contrib/llvm-project/llvm/lib/MCA/Instruction.cpp
35259 views
//===--------------------- Instruction.cpp ----------------------*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file defines abstractions used by the Pipeline to model register reads,9// register writes and instructions.10//11//===----------------------------------------------------------------------===//1213#include "llvm/MCA/Instruction.h"14#include "llvm/Support/Debug.h"15#include "llvm/Support/raw_ostream.h"1617namespace llvm {18namespace mca {1920void WriteState::writeStartEvent(unsigned IID, MCPhysReg RegID,21unsigned Cycles) {22CRD.IID = IID;23CRD.RegID = RegID;24CRD.Cycles = Cycles;25DependentWriteCyclesLeft = Cycles;26DependentWrite = nullptr;27}2829void ReadState::writeStartEvent(unsigned IID, MCPhysReg RegID,30unsigned Cycles) {31assert(DependentWrites);32assert(CyclesLeft == UNKNOWN_CYCLES);3334// This read may be dependent on more than one write. This typically occurs35// when a definition is the result of multiple writes where at least one36// write does a partial register update.37// The HW is forced to do some extra bookkeeping to track of all the38// dependent writes, and implement a merging scheme for the partial writes.39--DependentWrites;40if (TotalCycles < Cycles) {41CRD.IID = IID;42CRD.RegID = RegID;43CRD.Cycles = Cycles;44TotalCycles = Cycles;45}4647if (!DependentWrites) {48CyclesLeft = TotalCycles;49IsReady = !CyclesLeft;50}51}5253void WriteState::onInstructionIssued(unsigned IID) {54assert(CyclesLeft == UNKNOWN_CYCLES);55// Update the number of cycles left based on the WriteDescriptor info.56CyclesLeft = getLatency();5758// Now that the time left before write-back is known, notify59// all the users.60for (const std::pair<ReadState *, int> &User : Users) {61ReadState *RS = User.first;62unsigned ReadCycles = std::max(0, CyclesLeft - User.second);63RS->writeStartEvent(IID, RegisterID, ReadCycles);64}6566// Notify any writes that are in a false dependency with this write.67if (PartialWrite)68PartialWrite->writeStartEvent(IID, RegisterID, CyclesLeft);69}7071void WriteState::addUser(unsigned IID, ReadState *User, int ReadAdvance) {72// If CyclesLeft is different than -1, then we don't need to73// update the list of users. We can just notify the user with74// the actual number of cycles left (which may be zero).75if (CyclesLeft != UNKNOWN_CYCLES) {76unsigned ReadCycles = std::max(0, CyclesLeft - ReadAdvance);77User->writeStartEvent(IID, RegisterID, ReadCycles);78return;79}8081Users.emplace_back(User, ReadAdvance);82}8384void WriteState::addUser(unsigned IID, WriteState *User) {85if (CyclesLeft != UNKNOWN_CYCLES) {86User->writeStartEvent(IID, RegisterID, std::max(0, CyclesLeft));87return;88}8990assert(!PartialWrite && "PartialWrite already set!");91PartialWrite = User;92User->setDependentWrite(this);93}9495void WriteState::cycleEvent() {96// Note: CyclesLeft can be a negative number. It is an error to97// make it an unsigned quantity because users of this write may98// specify a negative ReadAdvance.99if (CyclesLeft != UNKNOWN_CYCLES)100CyclesLeft--;101102if (DependentWriteCyclesLeft)103DependentWriteCyclesLeft--;104}105106void ReadState::cycleEvent() {107// Update the total number of cycles.108if (DependentWrites && TotalCycles) {109--TotalCycles;110return;111}112113// Bail out immediately if we don't know how many cycles are left.114if (CyclesLeft == UNKNOWN_CYCLES)115return;116117if (CyclesLeft) {118--CyclesLeft;119IsReady = !CyclesLeft;120}121}122123#ifndef NDEBUG124void WriteState::dump() const {125dbgs() << "{ OpIdx=" << WD->OpIndex << ", Lat=" << getLatency() << ", RegID "126<< getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }";127}128#endif129130const CriticalDependency &Instruction::computeCriticalRegDep() {131if (CriticalRegDep.Cycles)132return CriticalRegDep;133134unsigned MaxLatency = 0;135for (const WriteState &WS : getDefs()) {136const CriticalDependency &WriteCRD = WS.getCriticalRegDep();137if (WriteCRD.Cycles > MaxLatency)138CriticalRegDep = WriteCRD;139}140141for (const ReadState &RS : getUses()) {142const CriticalDependency &ReadCRD = RS.getCriticalRegDep();143if (ReadCRD.Cycles > MaxLatency)144CriticalRegDep = ReadCRD;145}146147return CriticalRegDep;148}149150void Instruction::reset() {151// Note that this won't clear read/write descriptors152// or other non-trivial fields153Stage = IS_INVALID;154CyclesLeft = UNKNOWN_CYCLES;155clearOptimizableMove();156RCUTokenID = 0;157LSUTokenID = 0;158CriticalResourceMask = 0;159IsEliminated = false;160}161162void Instruction::dispatch(unsigned RCUToken) {163assert(Stage == IS_INVALID);164Stage = IS_DISPATCHED;165RCUTokenID = RCUToken;166167// Check if input operands are already available.168if (updateDispatched())169updatePending();170}171172void Instruction::execute(unsigned IID) {173assert(Stage == IS_READY);174Stage = IS_EXECUTING;175176// Set the cycles left before the write-back stage.177CyclesLeft = getLatency();178179for (WriteState &WS : getDefs())180WS.onInstructionIssued(IID);181182// Transition to the "executed" stage if this is a zero-latency instruction.183if (!CyclesLeft)184Stage = IS_EXECUTED;185}186187void Instruction::forceExecuted() {188assert(Stage == IS_READY && "Invalid internal state!");189CyclesLeft = 0;190Stage = IS_EXECUTED;191}192193bool Instruction::updatePending() {194assert(isPending() && "Unexpected instruction stage found!");195196if (!all_of(getUses(), [](const ReadState &Use) { return Use.isReady(); }))197return false;198199// A partial register write cannot complete before a dependent write.200if (!all_of(getDefs(), [](const WriteState &Def) { return Def.isReady(); }))201return false;202203Stage = IS_READY;204return true;205}206207bool Instruction::updateDispatched() {208assert(isDispatched() && "Unexpected instruction stage found!");209210if (!all_of(getUses(), [](const ReadState &Use) {211return Use.isPending() || Use.isReady();212}))213return false;214215// A partial register write cannot complete before a dependent write.216if (!all_of(getDefs(),217[](const WriteState &Def) { return !Def.getDependentWrite(); }))218return false;219220Stage = IS_PENDING;221return true;222}223224void Instruction::update() {225if (isDispatched())226updateDispatched();227if (isPending())228updatePending();229}230231void Instruction::cycleEvent() {232if (isReady())233return;234235if (isDispatched() || isPending()) {236for (ReadState &Use : getUses())237Use.cycleEvent();238239for (WriteState &Def : getDefs())240Def.cycleEvent();241242update();243return;244}245246assert(isExecuting() && "Instruction not in-flight?");247assert(CyclesLeft && "Instruction already executed?");248for (WriteState &Def : getDefs())249Def.cycleEvent();250CyclesLeft--;251if (!CyclesLeft)252Stage = IS_EXECUTED;253}254255} // namespace mca256} // namespace llvm257258259