[llvm] [Xtensa] Implement branch analysis. (PR #110959)

Andrei Safronov via llvm-commits llvm-commits at lists.llvm.org
Thu Oct 10 16:54:16 PDT 2024


================
@@ -185,3 +187,479 @@ void XtensaInstrInfo::loadImmediate(MachineBasicBlock &MBB,
     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;
+
+  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();
+
+  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);
+  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();
+
+  if (!isInt<32>(BrOffset))
+    report_fatal_error(
+        "Branch offsets outside of the signed 32-bit range not supported");
+  XtensaConstantPoolValue *C =
+      XtensaConstantPoolMBB::Create(MF->getFunction().getContext(), &DestBB, 0);
+  unsigned Idx = ConstantPool->getConstantPoolIndex(C, Align(4));
+
+  // FIXME: A virtual register must be used initially, as the register
+  // scavenger won't work with empty blocks (SIInstrInfo::insertIndirectBranch
+  // uses the same workaround).
+  Register ScratchReg = MRI.createVirtualRegister(&Xtensa::ARRegClass);
----------------
andreisfr wrote:

Currently this code is removed as redundant.

https://github.com/llvm/llvm-project/pull/110959


More information about the llvm-commits mailing list