[llvm] [RISCV][CodeGen] Add CodeGen support of Zibi experimental extension (PR #146858)
Boyao Wang via llvm-commits
llvm-commits at lists.llvm.org
Fri Sep 12 02:03:33 PDT 2025
https://github.com/BoyaoWang430 updated https://github.com/llvm/llvm-project/pull/146858
>From 979ede4bc98ac1c0145bceb481833dddf60b2b2d Mon Sep 17 00:00:00 2001
From: wangboyao <wangboyao at bytedance.com>
Date: Fri, 12 Sep 2025 17:00:28 +0800
Subject: [PATCH] [RISCV][CodeGen] Add CodeGen support of Zibi experimental
extension
---
.../RISCV/GISel/RISCVInstructionSelector.cpp | 5 +-
.../Target/RISCV/RISCVExpandPseudoInsts.cpp | 2 +-
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 11 +-
llvm/lib/Target/RISCV/RISCVInstrInfo.cpp | 22 +-
llvm/lib/Target/RISCV/RISCVInstrInfo.h | 3 +-
llvm/lib/Target/RISCV/RISCVInstrInfoZibi.td | 9 +
llvm/test/CodeGen/RISCV/zibi.ll | 198 ++++++++++++++++++
7 files changed, 238 insertions(+), 12 deletions(-)
create mode 100644 llvm/test/CodeGen/RISCV/zibi.ll
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
index 7df1b7e580002..148d6bc3ddde5 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVInstructionSelector.cpp
@@ -802,8 +802,9 @@ bool RISCVInstructionSelector::select(MachineInstr &MI) {
RISCVCC::CondCode CC;
getOperandsForBranch(MI.getOperand(0).getReg(), CC, LHS, RHS, *MRI);
- auto Bcc = MIB.buildInstr(RISCVCC::getBrCond(CC), {}, {LHS, RHS})
- .addMBB(MI.getOperand(1).getMBB());
+ auto Bcc =
+ MIB.buildInstr(RISCVCC::getBrCond(*Subtarget, CC), {}, {LHS, RHS})
+ .addMBB(MI.getOperand(1).getMBB());
MI.eraseFromParent();
return constrainSelectedInstRegOperands(*Bcc, TII, TRI, RBI);
}
diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
index cb57c4377779f..685215b64ba92 100644
--- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
@@ -196,7 +196,7 @@ bool RISCVExpandPseudo::expandCCOp(MachineBasicBlock &MBB,
CC = RISCVCC::getOppositeBranchCondition(CC);
// Insert branch instruction.
- BuildMI(MBB, MBBI, DL, TII->get(RISCVCC::getBrCond(CC)))
+ BuildMI(MBB, MBBI, DL, TII->get(RISCVCC::getBrCond(*STI, CC)))
.addReg(MI.getOperand(1).getReg())
.addReg(MI.getOperand(2).getReg())
.addMBB(MergeBB);
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 4f137756d2f48..f1b420feb349e 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -22093,7 +22093,8 @@ EmitLoweredCascadedSelect(MachineInstr &First, MachineInstr &Second,
Register FLHS = First.getOperand(1).getReg();
Register FRHS = First.getOperand(2).getReg();
// Insert appropriate branch.
- BuildMI(FirstMBB, DL, TII.get(RISCVCC::getBrCond(FirstCC, First.getOpcode())))
+ BuildMI(FirstMBB, DL,
+ TII.get(RISCVCC::getBrCond(Subtarget, FirstCC, First.getOpcode())))
.addReg(FLHS)
.addReg(FRHS)
.addMBB(SinkMBB);
@@ -22106,7 +22107,7 @@ EmitLoweredCascadedSelect(MachineInstr &First, MachineInstr &Second,
auto SecondCC = static_cast<RISCVCC::CondCode>(Second.getOperand(3).getImm());
// Insert appropriate branch.
BuildMI(ThisMBB, DL,
- TII.get(RISCVCC::getBrCond(SecondCC, Second.getOpcode())))
+ TII.get(RISCVCC::getBrCond(Subtarget, SecondCC, Second.getOpcode())))
.addReg(SLHS)
.addReg(SRHS)
.addMBB(SinkMBB);
@@ -22241,12 +22242,14 @@ static MachineBasicBlock *emitSelectPseudo(MachineInstr &MI,
// Insert appropriate branch.
if (MI.getOperand(2).isImm())
- BuildMI(HeadMBB, DL, TII.get(RISCVCC::getBrCond(CC, MI.getOpcode())))
+ BuildMI(HeadMBB, DL,
+ TII.get(RISCVCC::getBrCond(Subtarget, CC, MI.getOpcode(), true)))
.addReg(LHS)
.addImm(MI.getOperand(2).getImm())
.addMBB(TailMBB);
else
- BuildMI(HeadMBB, DL, TII.get(RISCVCC::getBrCond(CC, MI.getOpcode())))
+ BuildMI(HeadMBB, DL,
+ TII.get(RISCVCC::getBrCond(Subtarget, CC, MI.getOpcode())))
.addReg(LHS)
.addReg(RHS)
.addMBB(TailMBB);
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index d0bb57a3eaa13..22ef2ff1a812d 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -955,6 +955,7 @@ RISCVCC::CondCode RISCVInstrInfo::getCondFromBranchOpc(unsigned Opc) {
default:
return RISCVCC::COND_INVALID;
case RISCV::BEQ:
+ case RISCV::BEQI:
case RISCV::CV_BEQIMM:
case RISCV::QC_BEQI:
case RISCV::QC_E_BEQI:
@@ -962,6 +963,7 @@ RISCVCC::CondCode RISCVInstrInfo::getCondFromBranchOpc(unsigned Opc) {
case RISCV::NDS_BEQC:
return RISCVCC::COND_EQ;
case RISCV::BNE:
+ case RISCV::BNEI:
case RISCV::QC_BNEI:
case RISCV::QC_E_BNEI:
case RISCV::CV_BNEIMM:
@@ -1021,16 +1023,17 @@ static void parseCondBranch(MachineInstr &LastInst, MachineBasicBlock *&Target,
Cond.push_back(LastInst.getOperand(1));
}
-unsigned RISCVCC::getBrCond(RISCVCC::CondCode CC, unsigned SelectOpc) {
+unsigned RISCVCC::getBrCond(const RISCVSubtarget &STI, CondCode CC,
+ unsigned SelectOpc, bool Imm) {
switch (SelectOpc) {
default:
switch (CC) {
default:
llvm_unreachable("Unexpected condition code!");
case RISCVCC::COND_EQ:
- return RISCV::BEQ;
+ return (Imm && STI.hasStdExtZibi()) ? RISCV::BEQI : RISCV::BEQ;
case RISCVCC::COND_NE:
- return RISCV::BNE;
+ return (Imm && STI.hasStdExtZibi()) ? RISCV::BNEI : RISCV::BNE;
case RISCVCC::COND_LT:
return RISCV::BLT;
case RISCVCC::COND_GE:
@@ -1359,9 +1362,15 @@ bool RISCVInstrInfo::reverseBranchCondition(
case RISCV::BEQ:
Cond[0].setImm(RISCV::BNE);
break;
+ case RISCV::BEQI:
+ Cond[0].setImm(RISCV::BNEI);
+ break;
case RISCV::BNE:
Cond[0].setImm(RISCV::BEQ);
break;
+ case RISCV::BNEI:
+ Cond[0].setImm(RISCV::BEQI);
+ break;
case RISCV::BLT:
Cond[0].setImm(RISCV::BGE);
break;
@@ -1536,7 +1545,7 @@ bool RISCVInstrInfo::optimizeCondBranch(MachineInstr &MI) const {
return Register();
};
- unsigned NewOpc = RISCVCC::getBrCond(getOppositeBranchCondition(CC));
+ unsigned NewOpc = RISCVCC::getBrCond(STI, getOppositeBranchCondition(CC));
// Might be case 1.
// Don't change 0 to 1 since we can use x0.
@@ -1611,6 +1620,8 @@ bool RISCVInstrInfo::isBranchOffsetInRange(unsigned BranchOp,
case RISCV::BGE:
case RISCV::BLTU:
case RISCV::BGEU:
+ case RISCV::BEQI:
+ case RISCV::BNEI:
case RISCV::CV_BEQIMM:
case RISCV::CV_BNEIMM:
case RISCV::QC_BEQI:
@@ -2859,6 +2870,9 @@ bool RISCVInstrInfo::verifyInstruction(const MachineInstr &MI,
case RISCVOp::OPERAND_FOUR:
Ok = Imm == 4;
break;
+ case RISCVOp::OPERAND_IMM5_ZIBI:
+ Ok = (isUInt<5>(Imm) && Imm != 0) || Imm == -1;
+ break;
// clang-format off
CASE_OPERAND_SIMM(5)
CASE_OPERAND_SIMM(6)
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.h b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
index 57ec431749ebe..1cc0395b32006 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.h
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.h
@@ -45,7 +45,8 @@ enum CondCode {
};
CondCode getOppositeBranchCondition(CondCode);
-unsigned getBrCond(CondCode CC, unsigned SelectOpc = 0);
+unsigned getBrCond(const RISCVSubtarget &STI, CondCode CC,
+ unsigned SelectOpc = 0, bool Imm = false);
} // end of namespace RISCVCC
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoZibi.td b/llvm/lib/Target/RISCV/RISCVInstrInfoZibi.td
index 1570355e3da54..9c9d18201cdb2 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoZibi.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoZibi.td
@@ -42,3 +42,12 @@ let Predicates = [HasStdExtZibi] in {
def BEQI : Branch_imm<0b010, "beqi">;
def BNEI : Branch_imm<0b011, "bnei">;
} // Predicates = [HasStdExtZibi]
+
+let Predicates = [HasStdExtZibi] in {
+ multiclass BccImmPat<CondCode Cond, Branch_imm Inst> {
+ def : Pat<(riscv_brcc(XLenVT GPR:$rs1), imm5_zibi:$cimm, Cond, bb:$imm12),
+ (Inst GPR:$rs1, imm5_zibi:$cimm, bare_simm13_lsb0_bb:$imm12)>;
+ }
+ defm : BccImmPat<SETEQ, BEQI>;
+ defm : BccImmPat<SETNE, BNEI>;
+} // Predicates = [HasStdExtZibi]
diff --git a/llvm/test/CodeGen/RISCV/zibi.ll b/llvm/test/CodeGen/RISCV/zibi.ll
new file mode 100644
index 0000000000000..4266b2b23d605
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/zibi.ll
@@ -0,0 +1,198 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-zibi -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=ZIBI %s
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-zibi -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=ZIBI %s
+
+define void @test_bne_neg(ptr %b) nounwind {
+; ZIBI-LABEL: test_bne_neg:
+; ZIBI: # %bb.0:
+; ZIBI-NEXT: lw a1, 0(a0)
+; ZIBI-NEXT: bnei a1, -1, .LBB0_2
+; ZIBI-NEXT: # %bb.1: # %test2
+; ZIBI-NEXT: lw zero, 0(a0)
+; ZIBI-NEXT: .LBB0_2: # %end
+; ZIBI-NEXT: ret
+ %val1 = load volatile i32, ptr %b
+ %tst1 = icmp ne i32 %val1, -1
+ br i1 %tst1, label %end, label %test2, !prof !0
+test2:
+ %val2 = load volatile i32, ptr %b
+ br label %end
+end:
+ ret void
+}
+
+define void @test_beq_neg(ptr %b) nounwind {
+; ZIBI-LABEL: test_beq_neg:
+; ZIBI: # %bb.0:
+; ZIBI-NEXT: lw a1, 0(a0)
+; ZIBI-NEXT: beqi a1, -1, .LBB1_2
+; ZIBI-NEXT: # %bb.1: # %test2
+; ZIBI-NEXT: lw zero, 0(a0)
+; ZIBI-NEXT: .LBB1_2: # %end
+; ZIBI-NEXT: ret
+ %val1 = load volatile i32, ptr %b
+ %tst1 = icmp eq i32 %val1, -1
+ br i1 %tst1, label %end, label %test2, !prof !0
+test2:
+ %val2 = load volatile i32, ptr %b
+ br label %end
+end:
+ ret void
+}
+
+define void @test_bne_zero(ptr %b) nounwind {
+; ZIBI-LABEL: test_bne_zero:
+; ZIBI: # %bb.0:
+; ZIBI-NEXT: lw a1, 0(a0)
+; ZIBI-NEXT: bnez a1, .LBB2_2
+; ZIBI-NEXT: # %bb.1: # %test2
+; ZIBI-NEXT: lw zero, 0(a0)
+; ZIBI-NEXT: .LBB2_2: # %end
+; ZIBI-NEXT: ret
+ %val1 = load volatile i32, ptr %b
+ %tst1 = icmp ne i32 %val1, 0
+ br i1 %tst1, label %end, label %test2, !prof !0
+test2:
+ %val2 = load volatile i32, ptr %b
+ br label %end
+end:
+ ret void
+}
+
+define void @test_beq_zero(ptr %b) nounwind {
+; ZIBI-LABEL: test_beq_zero:
+; ZIBI: # %bb.0:
+; ZIBI-NEXT: lw a1, 0(a0)
+; ZIBI-NEXT: beqz a1, .LBB3_2
+; ZIBI-NEXT: # %bb.1: # %test2
+; ZIBI-NEXT: lw zero, 0(a0)
+; ZIBI-NEXT: .LBB3_2: # %end
+; ZIBI-NEXT: ret
+ %val1 = load volatile i32, ptr %b
+ %tst1 = icmp eq i32 %val1, 0
+ br i1 %tst1, label %end, label %test2, !prof !0
+test2:
+ %val2 = load volatile i32, ptr %b
+ br label %end
+end:
+ ret void
+}
+
+define void @test_bne_1(ptr %b) nounwind {
+; ZIBI-LABEL: test_bne_1:
+; ZIBI: # %bb.0:
+; ZIBI-NEXT: lw a1, 0(a0)
+; ZIBI-NEXT: bnei a1, 1, .LBB4_2
+; ZIBI-NEXT: # %bb.1: # %test2
+; ZIBI-NEXT: lw zero, 0(a0)
+; ZIBI-NEXT: .LBB4_2: # %end
+; ZIBI-NEXT: ret
+ %val1 = load volatile i32, ptr %b
+ %tst1 = icmp ne i32 %val1, 1
+ br i1 %tst1, label %end, label %test2, !prof !0
+test2:
+ %val2 = load volatile i32, ptr %b
+ br label %end
+end:
+ ret void
+}
+
+define void @test_beq_1(ptr %b) nounwind {
+; ZIBI-LABEL: test_beq_1:
+; ZIBI: # %bb.0:
+; ZIBI-NEXT: lw a1, 0(a0)
+; ZIBI-NEXT: beqi a1, 1, .LBB5_2
+; ZIBI-NEXT: # %bb.1: # %test2
+; ZIBI-NEXT: lw zero, 0(a0)
+; ZIBI-NEXT: .LBB5_2: # %end
+; ZIBI-NEXT: ret
+ %val1 = load volatile i32, ptr %b
+ %tst1 = icmp eq i32 %val1, 1
+ br i1 %tst1, label %end, label %test2, !prof !0
+test2:
+ %val2 = load volatile i32, ptr %b
+ br label %end
+end:
+ ret void
+}
+
+define void @test_bne_31(ptr %b) nounwind {
+; ZIBI-LABEL: test_bne_31:
+; ZIBI: # %bb.0:
+; ZIBI-NEXT: lw a1, 0(a0)
+; ZIBI-NEXT: bnei a1, 31, .LBB6_2
+; ZIBI-NEXT: # %bb.1: # %test2
+; ZIBI-NEXT: lw zero, 0(a0)
+; ZIBI-NEXT: .LBB6_2: # %end
+; ZIBI-NEXT: ret
+ %val1 = load volatile i32, ptr %b
+ %tst1 = icmp ne i32 %val1, 31
+ br i1 %tst1, label %end, label %test2, !prof !0
+test2:
+ %val2 = load volatile i32, ptr %b
+ br label %end
+end:
+ ret void
+}
+
+define void @test_beq_31(ptr %b) nounwind {
+; ZIBI-LABEL: test_beq_31:
+; ZIBI: # %bb.0:
+; ZIBI-NEXT: lw a1, 0(a0)
+; ZIBI-NEXT: beqi a1, 1, .LBB7_2
+; ZIBI-NEXT: # %bb.1: # %test2
+; ZIBI-NEXT: lw zero, 0(a0)
+; ZIBI-NEXT: .LBB7_2: # %end
+; ZIBI-NEXT: ret
+ %val1 = load volatile i32, ptr %b
+ %tst1 = icmp eq i32 %val1, 1
+ br i1 %tst1, label %end, label %test2, !prof !0
+test2:
+ %val2 = load volatile i32, ptr %b
+ br label %end
+end:
+ ret void
+}
+
+define void @test_bne_32(ptr %b) nounwind {
+; ZIBI-LABEL: test_bne_32:
+; ZIBI: # %bb.0:
+; ZIBI-NEXT: lw a1, 0(a0)
+; ZIBI-NEXT: li a2, 32
+; ZIBI-NEXT: bne a1, a2, .LBB8_2
+; ZIBI-NEXT: # %bb.1: # %test2
+; ZIBI-NEXT: lw zero, 0(a0)
+; ZIBI-NEXT: .LBB8_2: # %end
+; ZIBI-NEXT: ret
+ %val1 = load volatile i32, ptr %b
+ %tst1 = icmp ne i32 %val1, 32
+ br i1 %tst1, label %end, label %test2, !prof !0
+test2:
+ %val2 = load volatile i32, ptr %b
+ br label %end
+end:
+ ret void
+}
+
+define void @test_beq_32(ptr %b) nounwind {
+; ZIBI-LABEL: test_beq_32:
+; ZIBI: # %bb.0:
+; ZIBI-NEXT: lw a1, 0(a0)
+; ZIBI-NEXT: li a2, 32
+; ZIBI-NEXT: beq a1, a2, .LBB9_2
+; ZIBI-NEXT: # %bb.1: # %test2
+; ZIBI-NEXT: lw zero, 0(a0)
+; ZIBI-NEXT: .LBB9_2: # %end
+; ZIBI-NEXT: ret
+ %val1 = load volatile i32, ptr %b
+ %tst1 = icmp eq i32 %val1, 32
+ br i1 %tst1, label %end, label %test2, !prof !0
+test2:
+ %val2 = load volatile i32, ptr %b
+ br label %end
+end:
+ ret void
+}
+!0 = !{!"branch_weights", i32 1, i32 99}
More information about the llvm-commits
mailing list