#include "llvm/MCA/Instruction.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/raw_ostream.h"
namespace llvm {
namespace mca {
void WriteState::writeStartEvent(unsigned IID, MCPhysReg RegID,
                                 unsigned Cycles) {
  CRD.IID = IID;
  CRD.RegID = RegID;
  CRD.Cycles = Cycles;
  DependentWriteCyclesLeft = Cycles;
  DependentWrite = nullptr;
}
void ReadState::writeStartEvent(unsigned IID, MCPhysReg RegID,
                                unsigned Cycles) {
  assert(DependentWrites);
  assert(CyclesLeft == UNKNOWN_CYCLES);
            --DependentWrites;
  if (TotalCycles < Cycles) {
    CRD.IID = IID;
    CRD.RegID = RegID;
    CRD.Cycles = Cycles;
    TotalCycles = Cycles;
  }
  if (!DependentWrites) {
    CyclesLeft = TotalCycles;
    IsReady = !CyclesLeft;
  }
}
void WriteState::onInstructionIssued(unsigned IID) {
  assert(CyclesLeft == UNKNOWN_CYCLES);
    CyclesLeft = getLatency();
      for (const std::pair<ReadState *, int> &User : Users) {
    ReadState *RS = User.first;
    unsigned ReadCycles = std::max(0, CyclesLeft - User.second);
    RS->writeStartEvent(IID, RegisterID, ReadCycles);
  }
    if (PartialWrite)
    PartialWrite->writeStartEvent(IID, RegisterID, CyclesLeft);
}
void WriteState::addUser(unsigned IID, ReadState *User, int ReadAdvance) {
        if (CyclesLeft != UNKNOWN_CYCLES) {
    unsigned ReadCycles = std::max(0, CyclesLeft - ReadAdvance);
    User->writeStartEvent(IID, RegisterID, ReadCycles);
    return;
  }
  Users.emplace_back(User, ReadAdvance);
}
void WriteState::addUser(unsigned IID, WriteState *User) {
  if (CyclesLeft != UNKNOWN_CYCLES) {
    User->writeStartEvent(IID, RegisterID, std::max(0, CyclesLeft));
    return;
  }
  assert(!PartialWrite && "PartialWrite already set!");
  PartialWrite = User;
  User->setDependentWrite(this);
}
void WriteState::cycleEvent() {
        if (CyclesLeft != UNKNOWN_CYCLES)
    CyclesLeft--;
  if (DependentWriteCyclesLeft)
    DependentWriteCyclesLeft--;
}
void ReadState::cycleEvent() {
    if (DependentWrites && TotalCycles) {
    --TotalCycles;
    return;
  }
    if (CyclesLeft == UNKNOWN_CYCLES)
    return;
  if (CyclesLeft) {
    --CyclesLeft;
    IsReady = !CyclesLeft;
  }
}
#ifndef NDEBUG
void WriteState::dump() const {
  dbgs() << "{ OpIdx=" << WD->OpIndex << ", Lat=" << getLatency() << ", RegID "
         << getRegisterID() << ", Cycles Left=" << getCyclesLeft() << " }";
}
#endif
const CriticalDependency &Instruction::computeCriticalRegDep() {
  if (CriticalRegDep.Cycles)
    return CriticalRegDep;
  unsigned MaxLatency = 0;
  for (const WriteState &WS : getDefs()) {
    const CriticalDependency &WriteCRD = WS.getCriticalRegDep();
    if (WriteCRD.Cycles > MaxLatency)
      CriticalRegDep = WriteCRD;
  }
  for (const ReadState &RS : getUses()) {
    const CriticalDependency &ReadCRD = RS.getCriticalRegDep();
    if (ReadCRD.Cycles > MaxLatency)
      CriticalRegDep = ReadCRD;
  }
  return CriticalRegDep;
}
void Instruction::reset() {
      Stage = IS_INVALID;
  CyclesLeft = UNKNOWN_CYCLES;
  clearOptimizableMove();
  RCUTokenID = 0;
  LSUTokenID = 0;
  CriticalResourceMask = 0;
  IsEliminated = false;
}
void Instruction::dispatch(unsigned RCUToken) {
  assert(Stage == IS_INVALID);
  Stage = IS_DISPATCHED;
  RCUTokenID = RCUToken;
    if (updateDispatched())
    updatePending();
}
void Instruction::execute(unsigned IID) {
  assert(Stage == IS_READY);
  Stage = IS_EXECUTING;
    CyclesLeft = getLatency();
  for (WriteState &WS : getDefs())
    WS.onInstructionIssued(IID);
    if (!CyclesLeft)
    Stage = IS_EXECUTED;
}
void Instruction::forceExecuted() {
  assert(Stage == IS_READY && "Invalid internal state!");
  CyclesLeft = 0;
  Stage = IS_EXECUTED;
}
bool Instruction::updatePending() {
  assert(isPending() && "Unexpected instruction stage found!");
  if (!all_of(getUses(), [](const ReadState &Use) { return Use.isReady(); }))
    return false;
    if (!all_of(getDefs(), [](const WriteState &Def) { return Def.isReady(); }))
    return false;
  Stage = IS_READY;
  return true;
}
bool Instruction::updateDispatched() {
  assert(isDispatched() && "Unexpected instruction stage found!");
  if (!all_of(getUses(), [](const ReadState &Use) {
        return Use.isPending() || Use.isReady();
      }))
    return false;
    if (!all_of(getDefs(),
              [](const WriteState &Def) { return !Def.getDependentWrite(); }))
    return false;
  Stage = IS_PENDING;
  return true;
}
void Instruction::update() {
  if (isDispatched())
    updateDispatched();
  if (isPending())
    updatePending();
}
void Instruction::cycleEvent() {
  if (isReady())
    return;
  if (isDispatched() || isPending()) {
    for (ReadState &Use : getUses())
      Use.cycleEvent();
    for (WriteState &Def : getDefs())
      Def.cycleEvent();
    update();
    return;
  }
  assert(isExecuting() && "Instruction not in-flight?");
  assert(CyclesLeft && "Instruction already executed?");
  for (WriteState &Def : getDefs())
    Def.cycleEvent();
  CyclesLeft--;
  if (!CyclesLeft)
    Stage = IS_EXECUTED;
}
} }