[llvm] [RISCV] Don't transfer (select c, t, f) to Zicond when optimizing for size (PR #163501)

Jim Lin via llvm-commits llvm-commits at lists.llvm.org
Mon Jul 20 01:18:33 PDT 2026


https://github.com/tclin914 updated https://github.com/llvm/llvm-project/pull/163501

>From 972d0365b9ca53373f807c2c164b51deeaacc976 Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Wed, 15 Oct 2025 09:38:28 +0800
Subject: [PATCH 1/6] [RISCV] Pre-commit

---
 llvm/test/CodeGen/RISCV/zicond-opts.ll | 63 ++++++++++++++++++++++++++
 1 file changed, 63 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/zicond-opts.ll b/llvm/test/CodeGen/RISCV/zicond-opts.ll
index 0568b0e1fae05..962376bbcf263 100644
--- a/llvm/test/CodeGen/RISCV/zicond-opts.ll
+++ b/llvm/test/CodeGen/RISCV/zicond-opts.ll
@@ -401,3 +401,66 @@ entry:
   %clzg = select i1 %iszero, i32 -9, i32 %cast
   ret i32 %clzg
 }
+
+define i64 @select_wo_optsize_minsize(i64 %true, i64 %false, i1 zeroext %c) {
+; RV32ZICOND-LABEL: select_wo_optsize_minsize:
+; RV32ZICOND:       # %bb.0:
+; RV32ZICOND-NEXT:    czero.nez a2, a2, a4
+; RV32ZICOND-NEXT:    czero.eqz a0, a0, a4
+; RV32ZICOND-NEXT:    czero.nez a3, a3, a4
+; RV32ZICOND-NEXT:    czero.eqz a1, a1, a4
+; RV32ZICOND-NEXT:    or a0, a0, a2
+; RV32ZICOND-NEXT:    or a1, a1, a3
+; RV32ZICOND-NEXT:    ret
+;
+; RV64ZICOND-LABEL: select_wo_optsize_minsize:
+; RV64ZICOND:       # %bb.0:
+; RV64ZICOND-NEXT:    czero.nez a1, a1, a2
+; RV64ZICOND-NEXT:    czero.eqz a0, a0, a2
+; RV64ZICOND-NEXT:    or a0, a0, a1
+; RV64ZICOND-NEXT:    ret
+  %r = select i1 %c, i64 %true, i64 %false
+  ret i64 %r
+}
+
+define i64 @select_w_optsize(i64 %true, i64 %false, i1 zeroext %c) optsize {
+; RV32ZICOND-LABEL: select_w_optsize:
+; RV32ZICOND:       # %bb.0:
+; RV32ZICOND-NEXT:    czero.nez a2, a2, a4
+; RV32ZICOND-NEXT:    czero.eqz a0, a0, a4
+; RV32ZICOND-NEXT:    czero.nez a3, a3, a4
+; RV32ZICOND-NEXT:    czero.eqz a1, a1, a4
+; RV32ZICOND-NEXT:    or a0, a0, a2
+; RV32ZICOND-NEXT:    or a1, a1, a3
+; RV32ZICOND-NEXT:    ret
+;
+; RV64ZICOND-LABEL: select_w_optsize:
+; RV64ZICOND:       # %bb.0:
+; RV64ZICOND-NEXT:    czero.nez a1, a1, a2
+; RV64ZICOND-NEXT:    czero.eqz a0, a0, a2
+; RV64ZICOND-NEXT:    or a0, a0, a1
+; RV64ZICOND-NEXT:    ret
+  %r = select i1 %c, i64 %true, i64 %false
+  ret i64 %r
+}
+
+define i64 @select_w_minsize(i64 %true, i64 %false, i1 zeroext %c) minsize {
+; RV32ZICOND-LABEL: select_w_minsize:
+; RV32ZICOND:       # %bb.0:
+; RV32ZICOND-NEXT:    czero.nez a2, a2, a4
+; RV32ZICOND-NEXT:    czero.eqz a0, a0, a4
+; RV32ZICOND-NEXT:    czero.nez a3, a3, a4
+; RV32ZICOND-NEXT:    czero.eqz a1, a1, a4
+; RV32ZICOND-NEXT:    or a0, a0, a2
+; RV32ZICOND-NEXT:    or a1, a1, a3
+; RV32ZICOND-NEXT:    ret
+;
+; RV64ZICOND-LABEL: select_w_minsize:
+; RV64ZICOND:       # %bb.0:
+; RV64ZICOND-NEXT:    czero.nez a1, a1, a2
+; RV64ZICOND-NEXT:    czero.eqz a0, a0, a2
+; RV64ZICOND-NEXT:    or a0, a0, a1
+; RV64ZICOND-NEXT:    ret
+  %r = select i1 %c, i64 %true, i64 %false
+  ret i64 %r
+}

>From 69e5d5e72a7c1fe7131ac2d13182c159e87e963a Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Wed, 15 Oct 2025 09:47:43 +0800
Subject: [PATCH 2/6] [RISCV] Don't transfer (select c, t, f) to Zicond when
 optimizing for size

In general, there is no code size issue when the branch version
(branch+mv+mv) is replaced with the Zicond version
(czero.nez+czero.eqz+or), as both contain 3 instructions. However, if the
cond of select is shared by multiple select instructions, fewer
instructions are required (they can share the same comparision
instruction) when using branch rather than Zicond. We add the checking
whether CondV has one use when optimizing for size.

Fixes https://github.com/llvm/llvm-project/issues/158633.
---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  7 +++++--
 llvm/test/CodeGen/RISCV/zicond-opts.ll      | 22 ++++++++++-----------
 2 files changed, 15 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 8b3b555cb2656..b8c3148aca816 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -10471,8 +10471,11 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
     }
 
     // (select c, t, f) -> (or (czero_eqz t, c), (czero_nez f, c))
-    // Unless we have the short forward branch optimization.
-    if (!Subtarget.hasConditionalMoveFusion())
+    // Unless we have the short forward branch optimization or CondV has one use
+    // when optimizaing for size.
+    if (!Subtarget.hasConditionalMoveFusion() &&
+        (!DAG.shouldOptForSize() ||
+         (DAG.shouldOptForSize() && CondV.hasOneUse())))
       return DAG.getNode(
           ISD::OR, DL, VT,
           DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, TrueV, CondV),
diff --git a/llvm/test/CodeGen/RISCV/zicond-opts.ll b/llvm/test/CodeGen/RISCV/zicond-opts.ll
index 962376bbcf263..59f1521dc10ea 100644
--- a/llvm/test/CodeGen/RISCV/zicond-opts.ll
+++ b/llvm/test/CodeGen/RISCV/zicond-opts.ll
@@ -426,12 +426,11 @@ define i64 @select_wo_optsize_minsize(i64 %true, i64 %false, i1 zeroext %c) {
 define i64 @select_w_optsize(i64 %true, i64 %false, i1 zeroext %c) optsize {
 ; RV32ZICOND-LABEL: select_w_optsize:
 ; RV32ZICOND:       # %bb.0:
-; RV32ZICOND-NEXT:    czero.nez a2, a2, a4
-; RV32ZICOND-NEXT:    czero.eqz a0, a0, a4
-; RV32ZICOND-NEXT:    czero.nez a3, a3, a4
-; RV32ZICOND-NEXT:    czero.eqz a1, a1, a4
-; RV32ZICOND-NEXT:    or a0, a0, a2
-; RV32ZICOND-NEXT:    or a1, a1, a3
+; RV32ZICOND-NEXT:    bnez a4, .LBB16_2
+; RV32ZICOND-NEXT:  # %bb.1:
+; RV32ZICOND-NEXT:    mv a0, a2
+; RV32ZICOND-NEXT:    mv a1, a3
+; RV32ZICOND-NEXT:  .LBB16_2:
 ; RV32ZICOND-NEXT:    ret
 ;
 ; RV64ZICOND-LABEL: select_w_optsize:
@@ -447,12 +446,11 @@ define i64 @select_w_optsize(i64 %true, i64 %false, i1 zeroext %c) optsize {
 define i64 @select_w_minsize(i64 %true, i64 %false, i1 zeroext %c) minsize {
 ; RV32ZICOND-LABEL: select_w_minsize:
 ; RV32ZICOND:       # %bb.0:
-; RV32ZICOND-NEXT:    czero.nez a2, a2, a4
-; RV32ZICOND-NEXT:    czero.eqz a0, a0, a4
-; RV32ZICOND-NEXT:    czero.nez a3, a3, a4
-; RV32ZICOND-NEXT:    czero.eqz a1, a1, a4
-; RV32ZICOND-NEXT:    or a0, a0, a2
-; RV32ZICOND-NEXT:    or a1, a1, a3
+; RV32ZICOND-NEXT:    bnez a4, .LBB17_2
+; RV32ZICOND-NEXT:  # %bb.1:
+; RV32ZICOND-NEXT:    mv a0, a2
+; RV32ZICOND-NEXT:    mv a1, a3
+; RV32ZICOND-NEXT:  .LBB17_2:
 ; RV32ZICOND-NEXT:    ret
 ;
 ; RV64ZICOND-LABEL: select_w_minsize:

>From bbb36e217fec59f97eaf5ddcdf5cd36331616131 Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Thu, 16 Oct 2025 08:46:46 +0800
Subject: [PATCH 3/6] address comment

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index b8c3148aca816..21b18fea95a98 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -10474,8 +10474,7 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
     // Unless we have the short forward branch optimization or CondV has one use
     // when optimizaing for size.
     if (!Subtarget.hasConditionalMoveFusion() &&
-        (!DAG.shouldOptForSize() ||
-         (DAG.shouldOptForSize() && CondV.hasOneUse())))
+        (!DAG.shouldOptForSize() || CondV.hasOneUse()))
       return DAG.getNode(
           ISD::OR, DL, VT,
           DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, TrueV, CondV),

>From 3b504cb3eda807ef5f4e3c7366a92eb217b124d6 Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Mon, 20 Jul 2026 15:56:32 +0800
Subject: [PATCH 4/6] Remove the check CondV.hasOneUse()

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp |  2 +-
 llvm/test/CodeGen/RISCV/zicond-opts.ll      | 14 ++++++++------
 2 files changed, 9 insertions(+), 7 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 21b18fea95a98..895ab1061d745 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -10474,7 +10474,7 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
     // Unless we have the short forward branch optimization or CondV has one use
     // when optimizaing for size.
     if (!Subtarget.hasConditionalMoveFusion() &&
-        (!DAG.shouldOptForSize() || CondV.hasOneUse()))
+        !DAG.shouldOptForSize())
       return DAG.getNode(
           ISD::OR, DL, VT,
           DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, TrueV, CondV),
diff --git a/llvm/test/CodeGen/RISCV/zicond-opts.ll b/llvm/test/CodeGen/RISCV/zicond-opts.ll
index 59f1521dc10ea..e6b36537b2b90 100644
--- a/llvm/test/CodeGen/RISCV/zicond-opts.ll
+++ b/llvm/test/CodeGen/RISCV/zicond-opts.ll
@@ -435,9 +435,10 @@ define i64 @select_w_optsize(i64 %true, i64 %false, i1 zeroext %c) optsize {
 ;
 ; RV64ZICOND-LABEL: select_w_optsize:
 ; RV64ZICOND:       # %bb.0:
-; RV64ZICOND-NEXT:    czero.nez a1, a1, a2
-; RV64ZICOND-NEXT:    czero.eqz a0, a0, a2
-; RV64ZICOND-NEXT:    or a0, a0, a1
+; RV64ZICOND-NEXT:    bnez a2, .LBB16_2
+; RV64ZICOND-NEXT:  # %bb.1:
+; RV64ZICOND-NEXT:    mv a0, a1
+; RV64ZICOND-NEXT:  .LBB16_2:
 ; RV64ZICOND-NEXT:    ret
   %r = select i1 %c, i64 %true, i64 %false
   ret i64 %r
@@ -455,9 +456,10 @@ define i64 @select_w_minsize(i64 %true, i64 %false, i1 zeroext %c) minsize {
 ;
 ; RV64ZICOND-LABEL: select_w_minsize:
 ; RV64ZICOND:       # %bb.0:
-; RV64ZICOND-NEXT:    czero.nez a1, a1, a2
-; RV64ZICOND-NEXT:    czero.eqz a0, a0, a2
-; RV64ZICOND-NEXT:    or a0, a0, a1
+; RV64ZICOND-NEXT:    bnez a2, .LBB17_2
+; RV64ZICOND-NEXT:  # %bb.1:
+; RV64ZICOND-NEXT:    mv a0, a1
+; RV64ZICOND-NEXT:  .LBB17_2:
 ; RV64ZICOND-NEXT:    ret
   %r = select i1 %c, i64 %true, i64 %false
   ret i64 %r

>From 1e0727524066c33a6f97547a0416886bcf2df989 Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Mon, 20 Jul 2026 16:05:09 +0800
Subject: [PATCH 5/6] Fix formatting

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 895ab1061d745..671bdbc9095af 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -10473,8 +10473,7 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
     // (select c, t, f) -> (or (czero_eqz t, c), (czero_nez f, c))
     // Unless we have the short forward branch optimization or CondV has one use
     // when optimizaing for size.
-    if (!Subtarget.hasConditionalMoveFusion() &&
-        !DAG.shouldOptForSize())
+    if (!Subtarget.hasConditionalMoveFusion() && !DAG.shouldOptForSize())
       return DAG.getNode(
           ISD::OR, DL, VT,
           DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, TrueV, CondV),

>From f40bec1faf57b43114ddc3de6aa450855969bcc2 Mon Sep 17 00:00:00 2001
From: Jim Lin <jim at andestech.com>
Date: Mon, 20 Jul 2026 16:18:14 +0800
Subject: [PATCH 6/6] Update comments

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 671bdbc9095af..7b1dd613f59ff 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -10471,8 +10471,8 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
     }
 
     // (select c, t, f) -> (or (czero_eqz t, c), (czero_nez f, c))
-    // Unless we have the short forward branch optimization or CondV has one use
-    // when optimizaing for size.
+    // Unless we have the short forward branch optimization, or we are
+    // optimizing for size.
     if (!Subtarget.hasConditionalMoveFusion() && !DAG.shouldOptForSize())
       return DAG.getNode(
           ISD::OR, DL, VT,



More information about the llvm-commits mailing list