[llvm] [RISC-V] Make Short Forward Branches capable of matching Zibi instructions (PR #208637)

Jesse Huang via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 13 00:03:26 PDT 2026


https://github.com/jaidTw updated https://github.com/llvm/llvm-project/pull/208637

>From 4657c75c208135717d0ce012e2e5dedb4df5368d Mon Sep 17 00:00:00 2001
From: Jesse Huang <jesse.huang at sifive.com>
Date: Fri, 10 Jul 2026 00:09:53 -0700
Subject: [PATCH 1/2] [RISC-V][CodeGen] Make SFB capable of matching Zibi
 instructions

---
 llvm/lib/Target/RISCV/RISCVInstrInfoSFB.td    |  22 +
 .../RISCV/short-forward-branch-opt-zibi.ll    | 415 ++++++++++++++++++
 2 files changed, 437 insertions(+)
 create mode 100644 llvm/test/CodeGen/RISCV/short-forward-branch-opt-zibi.ll

diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoSFB.td b/llvm/lib/Target/RISCV/RISCVInstrInfoSFB.td
index 3838c1c4b1095..409aeb4c86546 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfoSFB.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfoSFB.td
@@ -69,6 +69,15 @@ def CCtoQC_BccI : SDNodeXForm<cond, [{
   return CurDAG->getTargetConstant(BccOpcode, SDLoc(N), MVT::i32);
 }]>;
 
+// cond -> bcc_opcode (BEQI/BNEI)
+def CCtoZibiBCC : SDNodeXForm<cond, [{
+  ISD::CondCode CC = N->get();
+  RISCVCC::CondCode RvCC = getRISCVCCForIntCC(CC);
+  RvCC = RISCVCC::getInverseBranchCondition(RvCC);
+  unsigned BccOpcode = RISCVCC::getBrCond(RvCC, RISCV::Select_GPR_Using_CC_Imm5_Zibi);
+  return CurDAG->getTargetConstant(BccOpcode, SDLoc(N), MVT::i32);
+}]>;
+
 // For each of the short forward branch pseudos, corresponding code for
 // getting correct size of the pseduo is needed in getInstSizeInBytes.
 let Predicates = [HasShortForwardBranchIALU], isSelect = 1,
@@ -251,3 +260,16 @@ def PseudoCCLBU : SFBLoad;
 def PseudoCCLWU : SFBLoad;
 def PseudoCCLD : SFBLoad;
 }
+
+// Zibi: select with immediate comparison folded into SFB.
+// imm5_zibi is defined in RISCVInstrInfoZibi.td (included before this file).
+class SelectZibiSFB<CondCode Cond>
+    : Pat<(riscv_selectcc (XLenVT GPR:$lhs), imm5_zibi:$cimm, Cond:$cc,
+                          (XLenVT GPR:$truev), GPR:$falsev),
+          (PseudoCCMOVGPR GPR:$falsev, GPR:$truev, (CCtoZibiBCC $cc), GPR:$lhs,
+                          imm5_zibi:$cimm)>;
+
+let Predicates = [HasStdExtZibi, HasShortForwardBranchImm] in {
+  def : SelectZibiSFB<SETEQ>;
+  def : SelectZibiSFB<SETNE>;
+} // Predicates = [HasStdExtZibi, HasShortForwardBranchImm]
diff --git a/llvm/test/CodeGen/RISCV/short-forward-branch-opt-zibi.ll b/llvm/test/CodeGen/RISCV/short-forward-branch-opt-zibi.ll
new file mode 100644
index 0000000000000..d2e1d119616f2
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/short-forward-branch-opt-zibi.ll
@@ -0,0 +1,415 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-zibi -verify-machineinstrs < %s \
+; RUN:     | FileCheck %s --check-prefixes=RV32
+; RUN: llc -mtriple=riscv32 -mattr=+experimental-zibi,+short-forward-branch-ialu,+short-forward-branch-imm -verify-machineinstrs < %s \
+; RUN:     | FileCheck %s --check-prefixes=RV32-SFB
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-zibi -verify-machineinstrs < %s \
+; RUN:     | FileCheck %s --check-prefixes=RV64
+; RUN: llc -mtriple=riscv64 -mattr=+experimental-zibi,+short-forward-branch-ialu,+short-forward-branch-imm -verify-machineinstrs < %s \
+; RUN:     | FileCheck %s --check-prefixes=RV64-SFB
+
+; Basic select eq with Zibi immediate: should use bnei+mv SFB pattern when SFB enabled.
+define i32 @select_eq(i32 %a, i32 %b, i32 %c) {
+; RV32-LABEL: select_eq:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mv a3, a0
+; RV32-NEXT:    mv a0, a1
+; RV32-NEXT:    beqi a3, 5, .LBB0_2
+; RV32-NEXT:  # %bb.1:
+; RV32-NEXT:    mv a0, a2
+; RV32-NEXT:  .LBB0_2:
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_eq:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    beqi a0, 5, .LBB0_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    mv a1, a2
+; RV32-SFB-NEXT:  .LBB0_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_eq:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sext.w a3, a0
+; RV64-NEXT:    mv a0, a1
+; RV64-NEXT:    beqi a3, 5, .LBB0_2
+; RV64-NEXT:  # %bb.1:
+; RV64-NEXT:    mv a0, a2
+; RV64-NEXT:  .LBB0_2:
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_eq:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    beqi a0, 5, .LBB0_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    mv a1, a2
+; RV64-SFB-NEXT:  .LBB0_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp eq i32 %a, 5
+  %ret = select i1 %tst, i32 %b, i32 %c
+  ret i32 %ret
+}
+
+; Basic select ne with Zibi immediate.
+define i32 @select_ne(i32 %a, i32 %b, i32 %c) {
+; RV32-LABEL: select_ne:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mv a3, a0
+; RV32-NEXT:    mv a0, a1
+; RV32-NEXT:    bnei a3, 5, .LBB1_2
+; RV32-NEXT:  # %bb.1:
+; RV32-NEXT:    mv a0, a2
+; RV32-NEXT:  .LBB1_2:
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_ne:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    bnei a0, 5, .LBB1_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    mv a1, a2
+; RV32-SFB-NEXT:  .LBB1_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_ne:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sext.w a3, a0
+; RV64-NEXT:    mv a0, a1
+; RV64-NEXT:    bnei a3, 5, .LBB1_2
+; RV64-NEXT:  # %bb.1:
+; RV64-NEXT:    mv a0, a2
+; RV64-NEXT:  .LBB1_2:
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_ne:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    bnei a0, 5, .LBB1_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    mv a1, a2
+; RV64-SFB-NEXT:  .LBB1_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp ne i32 %a, 5
+  %ret = select i1 %tst, i32 %b, i32 %c
+  ret i32 %ret
+}
+
+; optimizeSelect folding: the XOR is folded into PseudoCCXOR with beqi/bnei branch.
+define i32 @select_eq_xor(i32 %a, i32 %b, i32 %c) {
+; RV32-LABEL: select_eq_xor:
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi a0, a0, -5
+; RV32-NEXT:    snez a0, a0
+; RV32-NEXT:    addi a0, a0, -1
+; RV32-NEXT:    and a0, a0, a2
+; RV32-NEXT:    xor a0, a1, a0
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_eq_xor:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    bnei a0, 5, .LBB2_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    xor a1, a1, a2
+; RV32-SFB-NEXT:  .LBB2_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_eq_xor:
+; RV64:       # %bb.0:
+; RV64-NEXT:    addiw a0, a0, -5
+; RV64-NEXT:    snez a0, a0
+; RV64-NEXT:    addi a0, a0, -1
+; RV64-NEXT:    and a0, a0, a2
+; RV64-NEXT:    xor a0, a1, a0
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_eq_xor:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    bnei a0, 5, .LBB2_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    xor a1, a1, a2
+; RV64-SFB-NEXT:  .LBB2_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp eq i32 %a, 5
+  %xor = xor i32 %b, %c
+  %ret = select i1 %tst, i32 %xor, i32 %b
+  ret i32 %ret
+}
+
+define i32 @select_ne_add(i32 %a, i32 %b, i32 %c) {
+; RV32-LABEL: select_ne_add:
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi a0, a0, -5
+; RV32-NEXT:    seqz a0, a0
+; RV32-NEXT:    addi a0, a0, -1
+; RV32-NEXT:    and a0, a0, a2
+; RV32-NEXT:    add a0, a1, a0
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_ne_add:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    beqi a0, 5, .LBB3_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    add a1, a1, a2
+; RV32-SFB-NEXT:  .LBB3_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_ne_add:
+; RV64:       # %bb.0:
+; RV64-NEXT:    addiw a0, a0, -5
+; RV64-NEXT:    seqz a0, a0
+; RV64-NEXT:    addi a0, a0, -1
+; RV64-NEXT:    and a0, a0, a2
+; RV64-NEXT:    addw a0, a1, a0
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_ne_add:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    beqi a0, 5, .LBB3_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    addw a1, a1, a2
+; RV64-SFB-NEXT:  .LBB3_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp ne i32 %a, 5
+  %add = add i32 %b, %c
+  %ret = select i1 %tst, i32 %add, i32 %b
+  ret i32 %ret
+}
+
+; Boundary: immediate = 1 (minimum valid Zibi positive immediate).
+define i32 @select_eq_imm1(i32 %a, i32 %b, i32 %c) {
+; RV32-LABEL: select_eq_imm1:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mv a3, a0
+; RV32-NEXT:    mv a0, a1
+; RV32-NEXT:    beqi a3, 1, .LBB4_2
+; RV32-NEXT:  # %bb.1:
+; RV32-NEXT:    mv a0, a2
+; RV32-NEXT:  .LBB4_2:
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_eq_imm1:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    beqi a0, 1, .LBB4_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    mv a1, a2
+; RV32-SFB-NEXT:  .LBB4_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_eq_imm1:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sext.w a3, a0
+; RV64-NEXT:    mv a0, a1
+; RV64-NEXT:    beqi a3, 1, .LBB4_2
+; RV64-NEXT:  # %bb.1:
+; RV64-NEXT:    mv a0, a2
+; RV64-NEXT:  .LBB4_2:
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_eq_imm1:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    beqi a0, 1, .LBB4_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    mv a1, a2
+; RV64-SFB-NEXT:  .LBB4_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp eq i32 %a, 1
+  %ret = select i1 %tst, i32 %b, i32 %c
+  ret i32 %ret
+}
+
+; Boundary: immediate = 31 (maximum valid Zibi immediate).
+define i32 @select_eq_imm31(i32 %a, i32 %b, i32 %c) {
+; RV32-LABEL: select_eq_imm31:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mv a3, a0
+; RV32-NEXT:    mv a0, a1
+; RV32-NEXT:    beqi a3, 31, .LBB5_2
+; RV32-NEXT:  # %bb.1:
+; RV32-NEXT:    mv a0, a2
+; RV32-NEXT:  .LBB5_2:
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_eq_imm31:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    beqi a0, 31, .LBB5_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    mv a1, a2
+; RV32-SFB-NEXT:  .LBB5_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_eq_imm31:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sext.w a3, a0
+; RV64-NEXT:    mv a0, a1
+; RV64-NEXT:    beqi a3, 31, .LBB5_2
+; RV64-NEXT:  # %bb.1:
+; RV64-NEXT:    mv a0, a2
+; RV64-NEXT:  .LBB5_2:
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_eq_imm31:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    beqi a0, 31, .LBB5_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    mv a1, a2
+; RV64-SFB-NEXT:  .LBB5_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp eq i32 %a, 31
+  %ret = select i1 %tst, i32 %b, i32 %c
+  ret i32 %ret
+}
+
+; Boundary: immediate = -1 (valid Zibi, encoded as 0).
+define i32 @select_eq_imm_neg1(i32 %a, i32 %b, i32 %c) {
+; RV32-LABEL: select_eq_imm_neg1:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mv a3, a0
+; RV32-NEXT:    mv a0, a1
+; RV32-NEXT:    beqi a3, -1, .LBB6_2
+; RV32-NEXT:  # %bb.1:
+; RV32-NEXT:    mv a0, a2
+; RV32-NEXT:  .LBB6_2:
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_eq_imm_neg1:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    beqi a0, -1, .LBB6_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    mv a1, a2
+; RV32-SFB-NEXT:  .LBB6_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_eq_imm_neg1:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sext.w a3, a0
+; RV64-NEXT:    mv a0, a1
+; RV64-NEXT:    beqi a3, -1, .LBB6_2
+; RV64-NEXT:  # %bb.1:
+; RV64-NEXT:    mv a0, a2
+; RV64-NEXT:  .LBB6_2:
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_eq_imm_neg1:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    beqi a0, -1, .LBB6_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    mv a1, a2
+; RV64-SFB-NEXT:  .LBB6_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp eq i32 %a, -1
+  %ret = select i1 %tst, i32 %b, i32 %c
+  ret i32 %ret
+}
+
+; Out of range: immediate = 32. Must NOT use Zibi SFB (falls back to reg-reg).
+define i32 @select_eq_imm32(i32 %a, i32 %b, i32 %c) {
+; RV32-LABEL: select_eq_imm32:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mv a3, a0
+; RV32-NEXT:    li a4, 32
+; RV32-NEXT:    mv a0, a1
+; RV32-NEXT:    beq a3, a4, .LBB7_2
+; RV32-NEXT:  # %bb.1:
+; RV32-NEXT:    mv a0, a2
+; RV32-NEXT:  .LBB7_2:
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_eq_imm32:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    li a3, 32
+; RV32-SFB-NEXT:    beq a0, a3, .LBB7_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    mv a1, a2
+; RV32-SFB-NEXT:  .LBB7_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_eq_imm32:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sext.w a3, a0
+; RV64-NEXT:    li a4, 32
+; RV64-NEXT:    mv a0, a1
+; RV64-NEXT:    beq a3, a4, .LBB7_2
+; RV64-NEXT:  # %bb.1:
+; RV64-NEXT:    mv a0, a2
+; RV64-NEXT:  .LBB7_2:
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_eq_imm32:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    li a3, 32
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    beq a0, a3, .LBB7_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    mv a1, a2
+; RV64-SFB-NEXT:  .LBB7_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp eq i32 %a, 32
+  %ret = select i1 %tst, i32 %b, i32 %c
+  ret i32 %ret
+}
+
+; immediate = 0 is not valid for Zibi. Must NOT use Zibi SFB.
+define i32 @select_eq_imm0(i32 %a, i32 %b, i32 %c) {
+; RV32-LABEL: select_eq_imm0:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mv a3, a0
+; RV32-NEXT:    mv a0, a1
+; RV32-NEXT:    beqz a3, .LBB8_2
+; RV32-NEXT:  # %bb.1:
+; RV32-NEXT:    mv a0, a2
+; RV32-NEXT:  .LBB8_2:
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_eq_imm0:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    beqz a0, .LBB8_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    mv a1, a2
+; RV32-SFB-NEXT:  .LBB8_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_eq_imm0:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sext.w a3, a0
+; RV64-NEXT:    mv a0, a1
+; RV64-NEXT:    beqz a3, .LBB8_2
+; RV64-NEXT:  # %bb.1:
+; RV64-NEXT:    mv a0, a2
+; RV64-NEXT:  .LBB8_2:
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_eq_imm0:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    beqz a0, .LBB8_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    mv a1, a2
+; RV64-SFB-NEXT:  .LBB8_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp eq i32 %a, 0
+  %ret = select i1 %tst, i32 %b, i32 %c
+  ret i32 %ret
+}

>From 05192c4ade3367e8f18671bb55bd66ff4481ca56 Mon Sep 17 00:00:00 2001
From: Jesse Huang <jesse.huang at sifive.com>
Date: Mon, 13 Jul 2026 00:03:07 -0700
Subject: [PATCH 2/2] Add minsize tests

---
 .../RISCV/short-forward-branch-opt-zibi.ll    | 135 ++++++++++++++++++
 1 file changed, 135 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/short-forward-branch-opt-zibi.ll b/llvm/test/CodeGen/RISCV/short-forward-branch-opt-zibi.ll
index d2e1d119616f2..1e5c313da73cc 100644
--- a/llvm/test/CodeGen/RISCV/short-forward-branch-opt-zibi.ll
+++ b/llvm/test/CodeGen/RISCV/short-forward-branch-opt-zibi.ll
@@ -413,3 +413,138 @@ define i32 @select_eq_imm0(i32 %a, i32 %b, i32 %c) {
   %ret = select i1 %tst, i32 %b, i32 %c
   ret i32 %ret
 }
+
+; minsize: confirm SelectZibiSFB takes priority over Select_GPR_Using_CC_Imm5_Zibi
+define i32 @select_eq_minsize(i32 %a, i32 %b, i32 %c) minsize {
+; RV32-LABEL: select_eq_minsize:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mv a3, a0
+; RV32-NEXT:    mv a0, a1
+; RV32-NEXT:    beqi a3, 5, .LBB9_2
+; RV32-NEXT:  # %bb.1:
+; RV32-NEXT:    mv a0, a2
+; RV32-NEXT:  .LBB9_2:
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_eq_minsize:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    beqi a0, 5, .LBB9_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    mv a1, a2
+; RV32-SFB-NEXT:  .LBB9_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_eq_minsize:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sext.w a3, a0
+; RV64-NEXT:    mv a0, a1
+; RV64-NEXT:    beqi a3, 5, .LBB9_2
+; RV64-NEXT:  # %bb.1:
+; RV64-NEXT:    mv a0, a2
+; RV64-NEXT:  .LBB9_2:
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_eq_minsize:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    beqi a0, 5, .LBB9_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    mv a1, a2
+; RV64-SFB-NEXT:  .LBB9_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp eq i32 %a, 5
+  %ret = select i1 %tst, i32 %b, i32 %c
+  ret i32 %ret
+}
+
+define i32 @select_ne_minsize(i32 %a, i32 %b, i32 %c) minsize {
+; RV32-LABEL: select_ne_minsize:
+; RV32:       # %bb.0:
+; RV32-NEXT:    mv a3, a0
+; RV32-NEXT:    mv a0, a1
+; RV32-NEXT:    bnei a3, 5, .LBB10_2
+; RV32-NEXT:  # %bb.1:
+; RV32-NEXT:    mv a0, a2
+; RV32-NEXT:  .LBB10_2:
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_ne_minsize:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    bnei a0, 5, .LBB10_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    mv a1, a2
+; RV32-SFB-NEXT:  .LBB10_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_ne_minsize:
+; RV64:       # %bb.0:
+; RV64-NEXT:    sext.w a3, a0
+; RV64-NEXT:    mv a0, a1
+; RV64-NEXT:    bnei a3, 5, .LBB10_2
+; RV64-NEXT:  # %bb.1:
+; RV64-NEXT:    mv a0, a2
+; RV64-NEXT:  .LBB10_2:
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_ne_minsize:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    bnei a0, 5, .LBB10_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    mv a1, a2
+; RV64-SFB-NEXT:  .LBB10_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp ne i32 %a, 5
+  %ret = select i1 %tst, i32 %b, i32 %c
+  ret i32 %ret
+}
+
+; confirming SelectZibiSFB still takes priority over
+; Select_GPR_Using_CC_Imm5_Zibi for ALU ops.
+; Without SFB, falls back to branchless sequence.
+define i32 @select_eq_xor_minsize(i32 %a, i32 %b, i32 %c) minsize {
+; RV32-LABEL: select_eq_xor_minsize:
+; RV32:       # %bb.0:
+; RV32-NEXT:    addi a0, a0, -5
+; RV32-NEXT:    snez a0, a0
+; RV32-NEXT:    addi a0, a0, -1
+; RV32-NEXT:    and a0, a0, a2
+; RV32-NEXT:    xor a0, a1, a0
+; RV32-NEXT:    ret
+;
+; RV32-SFB-LABEL: select_eq_xor_minsize:
+; RV32-SFB:       # %bb.0:
+; RV32-SFB-NEXT:    bnei a0, 5, .LBB11_2
+; RV32-SFB-NEXT:  # %bb.1:
+; RV32-SFB-NEXT:    xor a1, a1, a2
+; RV32-SFB-NEXT:  .LBB11_2:
+; RV32-SFB-NEXT:    mv a0, a1
+; RV32-SFB-NEXT:    ret
+;
+; RV64-LABEL: select_eq_xor_minsize:
+; RV64:       # %bb.0:
+; RV64-NEXT:    addiw a0, a0, -5
+; RV64-NEXT:    snez a0, a0
+; RV64-NEXT:    addi a0, a0, -1
+; RV64-NEXT:    and a0, a0, a2
+; RV64-NEXT:    xor a0, a1, a0
+; RV64-NEXT:    ret
+;
+; RV64-SFB-LABEL: select_eq_xor_minsize:
+; RV64-SFB:       # %bb.0:
+; RV64-SFB-NEXT:    sext.w a0, a0
+; RV64-SFB-NEXT:    bnei a0, 5, .LBB11_2
+; RV64-SFB-NEXT:  # %bb.1:
+; RV64-SFB-NEXT:    xor a1, a1, a2
+; RV64-SFB-NEXT:  .LBB11_2:
+; RV64-SFB-NEXT:    mv a0, a1
+; RV64-SFB-NEXT:    ret
+  %tst = icmp eq i32 %a, 5
+  %xor = xor i32 %b, %c
+  %ret = select i1 %tst, i32 %xor, i32 %b
+  ret i32 %ret
+}



More information about the llvm-commits mailing list