[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