//===- XtensaInstrInfo.cpp - Xtensa Instruction Information ---------------===//
//
//                     The LLVM Compiler Infrastructure
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file contains the Xtensa implementation of the TargetInstrInfo class.
//
//===----------------------------------------------------------------------===//

#include "XtensaInstrInfo.h"
#include "XtensaConstantPoolValue.h"
#include "XtensaMachineFunctionInfo.h"
#include "XtensaTargetMachine.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/CodeGen/RegisterScavenging.h"

#define GET_INSTRINFO_CTOR_DTOR
#include "XtensaGenInstrInfo.inc"

using namespace llvm;

static const MachineInstrBuilder &
addFrameReference(const MachineInstrBuilder &MIB, int FI) {
  MachineInstr *MI = MIB;
  MachineFunction &MF = *MI->getParent()->getParent();
  MachineFrameInfo &MFFrame = MF.getFrameInfo();
  const MCInstrDesc &MCID = MI->getDesc();
  MachineMemOperand::Flags Flags = MachineMemOperand::MONone;
  if (MCID.mayLoad())
    Flags |= MachineMemOperand::MOLoad;
  if (MCID.mayStore())
    Flags |= MachineMemOperand::MOStore;
  int64_t Offset = 0;
  Align Alignment = MFFrame.getObjectAlign(FI);

  MachineMemOperand *MMO =
      MF.getMachineMemOperand(MachinePointerInfo::getFixedStack(MF, FI, Offset),
                              Flags, MFFrame.getObjectSize(FI), Alignment);
  return MIB.addFrameIndex(FI).addImm(Offset).addMemOperand(MMO);
}

XtensaInstrInfo::XtensaInstrInfo(const XtensaSubtarget &STI)
    : XtensaGenInstrInfo(Xtensa::ADJCALLSTACKDOWN, Xtensa::ADJCALLSTACKUP),
      RI(STI), STI(STI) {}

Register XtensaInstrInfo::isLoadFromStackSlot(const MachineInstr &MI,
                                              int &FrameIndex) const {
  if (MI.getOpcode() == Xtensa::L32I) {
    if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() &&
        MI.getOperand(2).getImm() == 0) {
      FrameIndex = MI.getOperand(1).getIndex();
      return MI.getOperand(0).getReg();
    }
  }
  return Register();
}

Register XtensaInstrInfo::isStoreToStackSlot(const MachineInstr &MI,
                                             int &FrameIndex) const {
  if (MI.getOpcode() == Xtensa::S32I) {
    if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() &&
        MI.getOperand(2).getImm() == 0) {
      FrameIndex = MI.getOperand(1).getIndex();
      return MI.getOperand(0).getReg();
    }
  }
  return Register();
}

/// Adjust SP by Amount bytes.
void XtensaInstrInfo::adjustStackPtr(MCRegister SP, int64_t Amount,
                                     MachineBasicBlock &MBB,
                                     MachineBasicBlock::iterator I) const {
  DebugLoc DL = I != MBB.end() ? I->getDebugLoc() : DebugLoc();

  if (Amount == 0)
    return;

  MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo();
  const TargetRegisterClass *RC = &Xtensa::ARRegClass;

  // create virtual reg to store immediate
  MCRegister Reg = RegInfo.createVirtualRegister(RC);

  if (isInt<8>(Amount)) { // addi sp, sp, amount
    BuildMI(MBB, I, DL, get(Xtensa::ADDI), Reg).addReg(SP).addImm(Amount);
  } else { // Expand immediate that doesn't fit in 8-bit.
    MCRegister Reg1;
    loadImmediate(MBB, I, &Reg1, Amount);
    BuildMI(MBB, I, DL, get(Xtensa::ADD), Reg)
        .addReg(SP)
        .addReg(Reg1, RegState::Kill);
  }

  if (STI.isWindowedABI()) {
    BuildMI(MBB, I, DL, get(Xtensa::MOVSP), SP).addReg(Reg, RegState::Kill);
  } else {
    BuildMI(MBB, I, DL, get(Xtensa::OR), SP)
        .addReg(Reg, RegState::Kill)
        .addReg(Reg, RegState::Kill);
  }
}

void XtensaInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
                                  MachineBasicBlock::iterator MBBI,
                                  const DebugLoc &DL, Register DestReg,
                                  Register SrcReg, bool KillSrc,
                                  bool RenamableDest, bool RenamableSrc) const {
  // The MOV instruction is not present in core ISA,
  // so use OR instruction.
  if (Xtensa::ARRegClass.contains(DestReg, SrcReg))
    BuildMI(MBB, MBBI, DL, get(Xtensa::OR), DestReg)
        .addReg(SrcReg, getKillRegState(KillSrc))
        .addReg(SrcReg, getKillRegState(KillSrc));
  else
    report_fatal_error("Impossible reg-to-reg copy");
}

void XtensaInstrInfo::storeRegToStackSlot(
    MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register SrcReg,
    bool isKill, int FrameIdx, const TargetRegisterClass *RC,
    const TargetRegisterInfo *TRI, Register VReg,
    MachineInstr::MIFlag Flags) const {
  DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
  unsigned LoadOpcode, StoreOpcode;
  getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode, FrameIdx);
  MachineInstrBuilder MIB = BuildMI(MBB, MBBI, DL, get(StoreOpcode))
                                .addReg(SrcReg, getKillRegState(isKill));
  addFrameReference(MIB, FrameIdx);
}

void XtensaInstrInfo::loadRegFromStackSlot(
    MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI, Register DestReg,
    int FrameIdx, const TargetRegisterClass *RC, const TargetRegisterInfo *TRI,
    Register VReg, MachineInstr::MIFlag Flags) const {
  DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
  unsigned LoadOpcode, StoreOpcode;
  getLoadStoreOpcodes(RC, LoadOpcode, StoreOpcode, FrameIdx);
  addFrameReference(BuildMI(MBB, MBBI, DL, get(LoadOpcode), DestReg), FrameIdx);
}

void XtensaInstrInfo::getLoadStoreOpcodes(const TargetRegisterClass *RC,
                                          unsigned &LoadOpcode,
                                          unsigned &StoreOpcode,
                                          int64_t offset) const {
  if (RC == &Xtensa::ARRegClass) {
    LoadOpcode = Xtensa::L32I;
    StoreOpcode = Xtensa::S32I;
  } else if (RC == &Xtensa::FPRRegClass) {
    LoadOpcode = Xtensa::LSI;
    StoreOpcode = Xtensa::SSI;
  } else {
    llvm_unreachable("Unsupported regclass to load or store");
  }
}

void XtensaInstrInfo::loadImmediate(MachineBasicBlock &MBB,
                                    MachineBasicBlock::iterator MBBI,
                                    MCRegister *Reg, int64_t Value) const {
  DebugLoc DL = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
  MachineRegisterInfo &RegInfo = MBB.getParent()->getRegInfo();
  const TargetRegisterClass *RC = &Xtensa::ARRegClass;

  // create virtual reg to store immediate
  *Reg = RegInfo.createVirtualRegister(RC);
  if (Value >= -2048 && Value <= 2047) {
    BuildMI(MBB, MBBI, DL, get(Xtensa::MOVI), *Reg).addImm(Value);
  } else if (Value >= -32768 && Value <= 32767) {
    int Low = Value & 0xFF;
    int High = Value & ~0xFF;

    BuildMI(MBB, MBBI, DL, get(Xtensa::MOVI), *Reg).addImm(Low);
    BuildMI(MBB, MBBI, DL, get(Xtensa::ADDMI), *Reg).addReg(*Reg).addImm(High);
  } else if (Value >= -4294967296LL && Value <= 4294967295LL) {
    // 32 bit arbitrary constant
    MachineConstantPool *MCP = MBB.getParent()->getConstantPool();
    uint64_t UVal = ((uint64_t)Value) & 0xFFFFFFFFLL;
    const Constant *CVal = ConstantInt::get(
        Type::getInt32Ty(MBB.getParent()->getFunction().getContext()), UVal,
        false);
    unsigned Idx = MCP->getConstantPoolIndex(CVal, Align(2U));
    //	MCSymbol MSym
    BuildMI(MBB, MBBI, DL, get(Xtensa::L32R), *Reg).addConstantPoolIndex(Idx);
  } else {
    // use L32R to let assembler load immediate best
    // TODO replace to L32R
    report_fatal_error("Unsupported load immediate value");
  }
}

unsigned XtensaInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
  switch (MI.getOpcode()) {
  case TargetOpcode::INLINEASM: { // Inline Asm: Variable size.
    const MachineFunction *MF = MI.getParent()->getParent();
    const char *AsmStr = MI.getOperand(0).getSymbolName();
    return getInlineAsmLength(AsmStr, *MF->getTarget().getMCAsmInfo());
  }
  default:
    return MI.getDesc().getSize();
  }
}

bool XtensaInstrInfo::reverseBranchCondition(
    SmallVectorImpl<MachineOperand> &Cond) const {
  assert(Cond.size() <= 4 && "Invalid branch condition!");

  switch (Cond[0].getImm()) {
  case Xtensa::BEQ:
    Cond[0].setImm(Xtensa::BNE);
    return false;
  case Xtensa::BNE:
    Cond[0].setImm(Xtensa::BEQ);
    return false;
  case Xtensa::BLT:
    Cond[0].setImm(Xtensa::BGE);
    return false;
  case Xtensa::BGE:
    Cond[0].setImm(Xtensa::BLT);
    return false;
  case Xtensa::BLTU:
    Cond[0].setImm(Xtensa::BGEU);
    return false;
  case Xtensa::BGEU:
    Cond[0].setImm(Xtensa::BLTU);
    return false;
  case Xtensa::BEQI:
    Cond[0].setImm(Xtensa::BNEI);
    return false;
  case Xtensa::BNEI:
    Cond[0].setImm(Xtensa::BEQI);
    return false;
  case Xtensa::BGEI:
    Cond[0].setImm(Xtensa::BLTI);
    return false;
  case Xtensa::BLTI:
    Cond[0].setImm(Xtensa::BGEI);
    return false;
  case Xtensa::BGEUI:
    Cond[0].setImm(Xtensa::BLTUI);
    return false;
  case Xtensa::BLTUI:
    Cond[0].setImm(Xtensa::BGEUI);
    return false;
  case Xtensa::BEQZ:
    Cond[0].setImm(Xtensa::BNEZ);
    return false;
  case Xtensa::BNEZ:
    Cond[0].setImm(Xtensa::BEQZ);
    return false;
  case Xtensa::BLTZ:
    Cond[0].setImm(Xtensa::BGEZ);
    return false;
  case Xtensa::BGEZ:
    Cond[0].setImm(Xtensa::BLTZ);
    return false;
  case Xtensa::BF:
    Cond[0].setImm(Xtensa::BT);
    return false;
  case Xtensa::BT:
    Cond[0].setImm(Xtensa::BF);
    return false;
  default:
    report_fatal_error("Invalid branch condition!");
  }
}

MachineBasicBlock *
XtensaInstrInfo::getBranchDestBlock(const MachineInstr &MI) const {
  unsigned OpCode = MI.getOpcode();
  switch (OpCode) {
  case Xtensa::BR_JT:
  case Xtensa::JX:
    return nullptr;
  case Xtensa::J:
    return MI.getOperand(0).getMBB();
  case Xtensa::BEQ:
  case Xtensa::BNE:
  case Xtensa::BLT:
  case Xtensa::BLTU:
  case Xtensa::BGE:
  case Xtensa::BGEU:
    return MI.getOperand(2).getMBB();
  case Xtensa::BEQI:
  case Xtensa::BNEI:
  case Xtensa::BLTI:
  case Xtensa::BLTUI:
  case Xtensa::BGEI:
  case Xtensa::BGEUI:
    return MI.getOperand(2).getMBB();
  case Xtensa::BEQZ:
  case Xtensa::BNEZ:
  case Xtensa::BLTZ:
  case Xtensa::BGEZ:
    return MI.getOperand(1).getMBB();
  case Xtensa::BT:
  case Xtensa::BF:
    return MI.getOperand(1).getMBB();
  default:
    llvm_unreachable("Unknown branch opcode");
  }
}

bool XtensaInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
                                            int64_t BrOffset) const {
  switch (BranchOp) {
  case Xtensa::J:
    BrOffset -= 4;
    return isIntN(18, BrOffset);
  case Xtensa::JX:
    return true;
  case Xtensa::BR_JT:
    return true;
  case Xtensa::BEQ:
  case Xtensa::BNE:
  case Xtensa::BLT:
  case Xtensa::BLTU:
  case Xtensa::BGE:
  case Xtensa::BGEU:
  case Xtensa::BEQI:
  case Xtensa::BNEI:
  case Xtensa::BLTI:
  case Xtensa::BLTUI:
  case Xtensa::BGEI:
  case Xtensa::BGEUI:
    BrOffset -= 4;
    return isIntN(8, BrOffset);
  case Xtensa::BEQZ:
  case Xtensa::BNEZ:
  case Xtensa::BLTZ:
  case Xtensa::BGEZ:
    BrOffset -= 4;
    return isIntN(12, BrOffset);
  case Xtensa::BT:
  case Xtensa::BF:
    BrOffset -= 4;
    return isIntN(8, BrOffset);
  default:
    llvm_unreachable("Unknown branch opcode");
  }
}

bool XtensaInstrInfo::analyzeBranch(MachineBasicBlock &MBB,
                                    MachineBasicBlock *&TBB,
                                    MachineBasicBlock *&FBB,
                                    SmallVectorImpl<MachineOperand> &Cond,
                                    bool AllowModify = false) const {
  // Most of the code and comments here are boilerplate.

  // Start from the bottom of the block and work up, examining the
  // terminator instructions.
  MachineBasicBlock::iterator I = MBB.end();
  while (I != MBB.begin()) {
    --I;
    if (I->isDebugValue())
      continue;

    // Working from the bottom, when we see a non-terminator instruction, we're
    // done.
    if (!isUnpredicatedTerminator(*I))
      break;

    // A terminator that isn't a branch can't easily be handled by this
    // analysis.
    SmallVector<MachineOperand, 4> ThisCond;
    ThisCond.push_back(MachineOperand::CreateImm(0));
    const MachineOperand *ThisTarget;
    if (!isBranch(I, ThisCond, ThisTarget))
      return true;

    // Can't handle indirect branches.
    if (!ThisTarget->isMBB())
      return true;

    if (ThisCond[0].getImm() == Xtensa::J) {
      // Handle unconditional branches.
      if (!AllowModify) {
        TBB = ThisTarget->getMBB();
        continue;
      }

      // If the block has any instructions after a JMP, delete them.
      while (std::next(I) != MBB.end())
        std::next(I)->eraseFromParent();

      Cond.clear();
      FBB = 0;

      // TBB is used to indicate the unconditinal destination.
      TBB = ThisTarget->getMBB();
      continue;
    }

    // Working from the bottom, handle the first conditional branch.
    if (Cond.empty()) {
      // FIXME: add X86-style branch swap
      FBB = TBB;
      TBB = ThisTarget->getMBB();
      Cond.push_back(MachineOperand::CreateImm(ThisCond[0].getImm()));

      // push remaining operands
      for (unsigned int i = 0; i < (I->getNumExplicitOperands() - 1); i++)
        Cond.push_back(I->getOperand(i));

      continue;
    }

    // Handle subsequent conditional branches.
    assert(Cond.size() <= 4);
    assert(TBB);

    // Only handle the case where all conditional branches branch to the same
    // destination.
    if (TBB != ThisTarget->getMBB())
      return true;

    // If the conditions are the same, we can leave them alone.
    unsigned OldCond = Cond[0].getImm();
    if (OldCond == ThisCond[0].getImm())
      continue;
  }

  return false;
}

unsigned XtensaInstrInfo::removeBranch(MachineBasicBlock &MBB,
                                       int *BytesRemoved) const {
  // Most of the code and comments here are boilerplate.
  MachineBasicBlock::iterator I = MBB.end();
  unsigned Count = 0;
  if (BytesRemoved)
    *BytesRemoved = 0;

  while (I != MBB.begin()) {
    --I;
    SmallVector<MachineOperand, 4> Cond;
    Cond.push_back(MachineOperand::CreateImm(0));
    const MachineOperand *Target;
    if (!isBranch(I, Cond, Target))
      break;
    if (!Target->isMBB())
      break;
    // Remove the branch.
    if (BytesRemoved)
      *BytesRemoved += getInstSizeInBytes(*I);
    I->eraseFromParent();
    I = MBB.end();
    ++Count;
  }
  return Count;
}

unsigned XtensaInstrInfo::insertBranch(
    MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB,
    ArrayRef<MachineOperand> Cond, const DebugLoc &DL, int *BytesAdded) const {
  unsigned Count = 0;
  if (BytesAdded)
    *BytesAdded = 0;
  if (FBB) {
    // Need to build two branches then
    // one to branch to TBB on Cond
    // and a second one immediately after to unconditionally jump to FBB
    Count = insertBranchAtInst(MBB, MBB.end(), TBB, Cond, DL, BytesAdded);
    auto &MI = *BuildMI(&MBB, DL, get(Xtensa::J)).addMBB(FBB);
    Count++;
    if (BytesAdded)
      *BytesAdded += getInstSizeInBytes(MI);
    return Count;
  }
  // This function inserts the branch at the end of the MBB
  Count += insertBranchAtInst(MBB, MBB.end(), TBB, Cond, DL, BytesAdded);
  return Count;
}

void XtensaInstrInfo::insertIndirectBranch(MachineBasicBlock &MBB,
                                           MachineBasicBlock &DestBB,
                                           MachineBasicBlock &RestoreBB,
                                           const DebugLoc &DL, int64_t BrOffset,
                                           RegScavenger *RS) const {
  assert(RS && "RegScavenger required for long branching");
  assert(MBB.empty() &&
         "new block should be inserted for expanding unconditional branch");
  assert(MBB.pred_size() == 1);

  MachineFunction *MF = MBB.getParent();
  MachineRegisterInfo &MRI = MF->getRegInfo();
  MachineConstantPool *ConstantPool = MF->getConstantPool();
  auto *XtensaFI = MF->getInfo<XtensaMachineFunctionInfo>();
  MachineBasicBlock *JumpToMBB = &DestBB;

  if (!isInt<32>(BrOffset))
    report_fatal_error(
        "Branch offsets outside of the signed 32-bit range not supported");

  Register ScratchReg = MRI.createVirtualRegister(&Xtensa::ARRegClass);
  auto II = MBB.end();

  // Create l32r without last operand. We will add this operand later when
  // JumpToMMB will be calculated and placed to the ConstantPool.
  MachineInstr &L32R = *BuildMI(MBB, II, DL, get(Xtensa::L32R), ScratchReg);
  BuildMI(MBB, II, DL, get(Xtensa::JX)).addReg(ScratchReg, RegState::Kill);

  RS->enterBasicBlockEnd(MBB);
  Register ScavRegister =
      RS->scavengeRegisterBackwards(Xtensa::ARRegClass, L32R.getIterator(),
                                    /*RestoreAfter=*/false, /*SpAdj=*/0,
                                    /*AllowSpill=*/false);
  if (ScavRegister != Xtensa::NoRegister)
    RS->setRegUsed(ScavRegister);
  else {
    // The case when there is no scavenged register needs special handling.
    // Pick A8 because it doesn't make a difference
    ScavRegister = Xtensa::A12;

    int FrameIndex = XtensaFI->getBranchRelaxationScratchFrameIndex();
    if (FrameIndex == -1)
      report_fatal_error(
          "Unable to properly handle scavenged register for indirect jump, "
          "function code size is significantly larger than estimated");

    storeRegToStackSlot(MBB, L32R, ScavRegister, /*IsKill=*/true, FrameIndex,
                        &Xtensa::ARRegClass, &RI, Register());
    RI.eliminateFrameIndex(std::prev(L32R.getIterator()),
                           /*SpAdj=*/0, /*FIOperandNum=*/1);

    loadRegFromStackSlot(RestoreBB, RestoreBB.end(), ScavRegister, FrameIndex,
                         &Xtensa::ARRegClass, &RI, Register());
    RI.eliminateFrameIndex(RestoreBB.back(),
                           /*SpAdj=*/0, /*FIOperandNum=*/1);
    JumpToMBB = &RestoreBB;
  }

  unsigned LabelId = XtensaFI->createCPLabelId();

  XtensaConstantPoolValue *C = XtensaConstantPoolMBB::Create(
      MF->getFunction().getContext(), JumpToMBB, LabelId);
  unsigned Idx = ConstantPool->getConstantPoolIndex(C, Align(4));
  L32R.addOperand(MachineOperand::CreateCPI(Idx, 0));

  MRI.replaceRegWith(ScratchReg, ScavRegister);
  MRI.clearVirtRegs();
}

unsigned XtensaInstrInfo::insertConstBranchAtInst(
    MachineBasicBlock &MBB, MachineInstr *I, int64_t offset,
    ArrayRef<MachineOperand> Cond, DebugLoc DL, int *BytesAdded) const {
  assert(Cond.size() <= 4 &&
         "Xtensa branch conditions have less than four components!");

  if (Cond.empty() || (Cond[0].getImm() == Xtensa::J)) {
    // Unconditional branch
    MachineInstr *MI = BuildMI(MBB, I, DL, get(Xtensa::J)).addImm(offset);
    if (BytesAdded && MI)
      *BytesAdded += getInstSizeInBytes(*MI);
    return 1;
  }

  unsigned Count = 0;
  unsigned BR_C = Cond[0].getImm();
  MachineInstr *MI = nullptr;
  switch (BR_C) {
  case Xtensa::BEQ:
  case Xtensa::BNE:
  case Xtensa::BLT:
  case Xtensa::BLTU:
  case Xtensa::BGE:
  case Xtensa::BGEU:
    MI = BuildMI(MBB, I, DL, get(BR_C))
             .addImm(offset)
             .addReg(Cond[1].getReg())
             .addReg(Cond[2].getReg());
    break;
  case Xtensa::BEQI:
  case Xtensa::BNEI:
  case Xtensa::BLTI:
  case Xtensa::BLTUI:
  case Xtensa::BGEI:
  case Xtensa::BGEUI:
    MI = BuildMI(MBB, I, DL, get(BR_C))
             .addImm(offset)
             .addReg(Cond[1].getReg())
             .addImm(Cond[2].getImm());
    break;
  case Xtensa::BEQZ:
  case Xtensa::BNEZ:
  case Xtensa::BLTZ:
  case Xtensa::BGEZ:
    MI = BuildMI(MBB, I, DL, get(BR_C)).addImm(offset).addReg(Cond[1].getReg());
    break;
  case Xtensa::BT:
  case Xtensa::BF:
    MI = BuildMI(MBB, I, DL, get(BR_C)).addImm(offset).addReg(Cond[1].getReg());
    break;
  default:
    llvm_unreachable("Invalid branch type!");
  }
  if (BytesAdded && MI)
    *BytesAdded += getInstSizeInBytes(*MI);
  ++Count;
  return Count;
}

unsigned XtensaInstrInfo::insertBranchAtInst(MachineBasicBlock &MBB,
                                             MachineBasicBlock::iterator I,
                                             MachineBasicBlock *TBB,
                                             ArrayRef<MachineOperand> Cond,
                                             const DebugLoc &DL,
                                             int *BytesAdded) const {
  // Shouldn't be a fall through.
  assert(TBB && "InsertBranch must not be told to insert a fallthrough");
  assert(Cond.size() <= 4 &&
         "Xtensa branch conditions have less than four components!");

  if (Cond.empty() || (Cond[0].getImm() == Xtensa::J)) {
    // Unconditional branch
    MachineInstr *MI = BuildMI(MBB, I, DL, get(Xtensa::J)).addMBB(TBB);
    if (BytesAdded && MI)
      *BytesAdded += getInstSizeInBytes(*MI);
    return 1;
  }

  unsigned Count = 0;
  unsigned BR_C = Cond[0].getImm();
  MachineInstr *MI = nullptr;
  switch (BR_C) {
  case Xtensa::BEQ:
  case Xtensa::BNE:
  case Xtensa::BLT:
  case Xtensa::BLTU:
  case Xtensa::BGE:
  case Xtensa::BGEU:
    MI = BuildMI(MBB, I, DL, get(BR_C))
             .addReg(Cond[1].getReg())
             .addReg(Cond[2].getReg())
             .addMBB(TBB);
    break;
  case Xtensa::BEQI:
  case Xtensa::BNEI:
  case Xtensa::BLTI:
  case Xtensa::BLTUI:
  case Xtensa::BGEI:
  case Xtensa::BGEUI:
    MI = BuildMI(MBB, I, DL, get(BR_C))
             .addReg(Cond[1].getReg())
             .addImm(Cond[2].getImm())
             .addMBB(TBB);
    break;
  case Xtensa::BEQZ:
  case Xtensa::BNEZ:
  case Xtensa::BLTZ:
  case Xtensa::BGEZ:
    MI = BuildMI(MBB, I, DL, get(BR_C)).addReg(Cond[1].getReg()).addMBB(TBB);
    break;
  case Xtensa::BT:
  case Xtensa::BF:
    MI = BuildMI(MBB, I, DL, get(BR_C)).addReg(Cond[1].getReg()).addMBB(TBB);
    break;
  default:
    report_fatal_error("Invalid branch type!");
  }
  if (BytesAdded && MI)
    *BytesAdded += getInstSizeInBytes(*MI);
  ++Count;
  return Count;
}

bool XtensaInstrInfo::isBranch(const MachineBasicBlock::iterator &MI,
                               SmallVectorImpl<MachineOperand> &Cond,
                               const MachineOperand *&Target) const {
  unsigned OpCode = MI->getOpcode();
  switch (OpCode) {
  case Xtensa::J:
  case Xtensa::JX:
  case Xtensa::BR_JT:
    Cond[0].setImm(OpCode);
    Target = &MI->getOperand(0);
    return true;
  case Xtensa::BEQ:
  case Xtensa::BNE:
  case Xtensa::BLT:
  case Xtensa::BLTU:
  case Xtensa::BGE:
  case Xtensa::BGEU:
    Cond[0].setImm(OpCode);
    Target = &MI->getOperand(2);
    return true;

  case Xtensa::BEQI:
  case Xtensa::BNEI:
  case Xtensa::BLTI:
  case Xtensa::BLTUI:
  case Xtensa::BGEI:
  case Xtensa::BGEUI:
    Cond[0].setImm(OpCode);
    Target = &MI->getOperand(2);
    return true;

  case Xtensa::BEQZ:
  case Xtensa::BNEZ:
  case Xtensa::BLTZ:
  case Xtensa::BGEZ:
    Cond[0].setImm(OpCode);
    Target = &MI->getOperand(1);
    return true;

  case Xtensa::BT:
  case Xtensa::BF:
    Cond[0].setImm(OpCode);
    Target = &MI->getOperand(1);
    return true;

  default:
    assert(!MI->getDesc().isBranch() && "Unknown branch opcode");
    return false;
  }
}
