[llvm] [RISCV] Lower (select c, x, -x) -> (sub (czero_eqz x, c), (czero_nez x, c)) with Zicond. (PR #217181)

Craig Topper via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 18 17:57:07 PDT 2026


https://github.com/topperc created https://github.com/llvm/llvm-project/pull/217181

None

>From 60fc603f43fc5eadfdc8396b79225dfbda332b9d Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Tue, 18 Aug 2026 17:31:06 -0700
Subject: [PATCH 1/2] Pre-commit tests

---
 llvm/test/CodeGen/RISCV/condops.ll | 149 +++++++++++++++++++++++++++++
 1 file changed, 149 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/condops.ll b/llvm/test/CodeGen/RISCV/condops.ll
index 71af806811a4b..18d95b2612070 100644
--- a/llvm/test/CodeGen/RISCV/condops.ll
+++ b/llvm/test/CodeGen/RISCV/condops.ll
@@ -4554,3 +4554,152 @@ entry:
   %cond = select i1 %tobool.not, i64 0, i64 %x
   ret i64 %cond
 }
+
+define i64 @neg1(i64 %rs1, i1 zeroext %rc) {
+; RV32I-LABEL: neg1:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    bnez a2, .LBB66_2
+; RV32I-NEXT:  # %bb.1:
+; RV32I-NEXT:    snez a2, a0
+; RV32I-NEXT:    neg a1, a1
+; RV32I-NEXT:    sub a1, a1, a2
+; RV32I-NEXT:    neg a0, a0
+; RV32I-NEXT:  .LBB66_2:
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: neg1:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    bnez a1, .LBB66_2
+; RV64I-NEXT:  # %bb.1:
+; RV64I-NEXT:    neg a0, a0
+; RV64I-NEXT:  .LBB66_2:
+; RV64I-NEXT:    ret
+;
+; RV32XVENTANACONDOPS-LABEL: neg1:
+; RV32XVENTANACONDOPS:       # %bb.0:
+; RV32XVENTANACONDOPS-NEXT:    neg a3, a1
+; RV32XVENTANACONDOPS-NEXT:    snez a4, a0
+; RV32XVENTANACONDOPS-NEXT:    sub a3, a3, a4
+; RV32XVENTANACONDOPS-NEXT:    neg a4, a0
+; RV32XVENTANACONDOPS-NEXT:    vt.maskc a0, a0, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a4, a4, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskc a1, a1, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a2, a3, a2
+; RV32XVENTANACONDOPS-NEXT:    or a0, a0, a4
+; RV32XVENTANACONDOPS-NEXT:    or a1, a1, a2
+; RV32XVENTANACONDOPS-NEXT:    ret
+;
+; RV64XVENTANACONDOPS-LABEL: neg1:
+; RV64XVENTANACONDOPS:       # %bb.0:
+; RV64XVENTANACONDOPS-NEXT:    neg a2, a0
+; RV64XVENTANACONDOPS-NEXT:    vt.maskc a0, a0, a1
+; RV64XVENTANACONDOPS-NEXT:    vt.maskcn a1, a2, a1
+; RV64XVENTANACONDOPS-NEXT:    or a0, a0, a1
+; RV64XVENTANACONDOPS-NEXT:    ret
+;
+; RV64XTHEADCONDMOV-LABEL: neg1:
+; RV64XTHEADCONDMOV:       # %bb.0:
+; RV64XTHEADCONDMOV-NEXT:    neg a2, a0
+; RV64XTHEADCONDMOV-NEXT:    th.mveqz a0, a2, a1
+; RV64XTHEADCONDMOV-NEXT:    ret
+;
+; RV32ZICOND-LABEL: neg1:
+; RV32ZICOND:       # %bb.0:
+; RV32ZICOND-NEXT:    neg a3, a1
+; RV32ZICOND-NEXT:    snez a4, a0
+; RV32ZICOND-NEXT:    sub a3, a3, a4
+; RV32ZICOND-NEXT:    neg a4, a0
+; RV32ZICOND-NEXT:    czero.eqz a0, a0, a2
+; RV32ZICOND-NEXT:    czero.nez a4, a4, a2
+; RV32ZICOND-NEXT:    czero.eqz a1, a1, a2
+; RV32ZICOND-NEXT:    czero.nez a2, a3, a2
+; RV32ZICOND-NEXT:    or a0, a0, a4
+; RV32ZICOND-NEXT:    or a1, a1, a2
+; RV32ZICOND-NEXT:    ret
+;
+; RV64ZICOND-LABEL: neg1:
+; RV64ZICOND:       # %bb.0:
+; RV64ZICOND-NEXT:    neg a2, a0
+; RV64ZICOND-NEXT:    czero.eqz a0, a0, a1
+; RV64ZICOND-NEXT:    czero.nez a1, a2, a1
+; RV64ZICOND-NEXT:    or a0, a0, a1
+; RV64ZICOND-NEXT:    ret
+  %neg = sub i64 0, %rs1
+  %sel = select i1 %rc, i64 %rs1, i64 %neg
+  ret i64 %sel
+}
+
+define i64 @neg2(i64 %rs1, i1 zeroext %rc) {
+; RV32I-LABEL: neg2:
+; RV32I:       # %bb.0:
+; RV32I-NEXT:    beqz a2, .LBB67_2
+; RV32I-NEXT:  # %bb.1:
+; RV32I-NEXT:    snez a2, a0
+; RV32I-NEXT:    neg a1, a1
+; RV32I-NEXT:    sub a1, a1, a2
+; RV32I-NEXT:    neg a0, a0
+; RV32I-NEXT:  .LBB67_2:
+; RV32I-NEXT:    ret
+;
+; RV64I-LABEL: neg2:
+; RV64I:       # %bb.0:
+; RV64I-NEXT:    beqz a1, .LBB67_2
+; RV64I-NEXT:  # %bb.1:
+; RV64I-NEXT:    neg a0, a0
+; RV64I-NEXT:  .LBB67_2:
+; RV64I-NEXT:    ret
+;
+; RV32XVENTANACONDOPS-LABEL: neg2:
+; RV32XVENTANACONDOPS:       # %bb.0:
+; RV32XVENTANACONDOPS-NEXT:    neg a3, a1
+; RV32XVENTANACONDOPS-NEXT:    snez a4, a0
+; RV32XVENTANACONDOPS-NEXT:    sub a3, a3, a4
+; RV32XVENTANACONDOPS-NEXT:    neg a4, a0
+; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a0, a0, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskc a4, a4, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a1, a1, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskc a2, a3, a2
+; RV32XVENTANACONDOPS-NEXT:    or a0, a4, a0
+; RV32XVENTANACONDOPS-NEXT:    or a1, a2, a1
+; RV32XVENTANACONDOPS-NEXT:    ret
+;
+; RV64XVENTANACONDOPS-LABEL: neg2:
+; RV64XVENTANACONDOPS:       # %bb.0:
+; RV64XVENTANACONDOPS-NEXT:    neg a2, a0
+; RV64XVENTANACONDOPS-NEXT:    vt.maskcn a0, a0, a1
+; RV64XVENTANACONDOPS-NEXT:    vt.maskc a1, a2, a1
+; RV64XVENTANACONDOPS-NEXT:    or a0, a1, a0
+; RV64XVENTANACONDOPS-NEXT:    ret
+;
+; RV64XTHEADCONDMOV-LABEL: neg2:
+; RV64XTHEADCONDMOV:       # %bb.0:
+; RV64XTHEADCONDMOV-NEXT:    neg a2, a0
+; RV64XTHEADCONDMOV-NEXT:    th.mvnez a0, a2, a1
+; RV64XTHEADCONDMOV-NEXT:    ret
+;
+; RV32ZICOND-LABEL: neg2:
+; RV32ZICOND:       # %bb.0:
+; RV32ZICOND-NEXT:    neg a3, a1
+; RV32ZICOND-NEXT:    snez a4, a0
+; RV32ZICOND-NEXT:    sub a3, a3, a4
+; RV32ZICOND-NEXT:    neg a4, a0
+; RV32ZICOND-NEXT:    czero.nez a0, a0, a2
+; RV32ZICOND-NEXT:    czero.eqz a4, a4, a2
+; RV32ZICOND-NEXT:    czero.nez a1, a1, a2
+; RV32ZICOND-NEXT:    czero.eqz a2, a3, a2
+; RV32ZICOND-NEXT:    or a0, a4, a0
+; RV32ZICOND-NEXT:    or a1, a2, a1
+; RV32ZICOND-NEXT:    ret
+;
+; RV64ZICOND-LABEL: neg2:
+; RV64ZICOND:       # %bb.0:
+; RV64ZICOND-NEXT:    neg a2, a0
+; RV64ZICOND-NEXT:    czero.nez a0, a0, a1
+; RV64ZICOND-NEXT:    czero.eqz a1, a2, a1
+; RV64ZICOND-NEXT:    or a0, a1, a0
+; RV64ZICOND-NEXT:    ret
+  %neg = sub i64 0, %rs1
+  %sel = select i1 %rc, i64 %neg, i64 %rs1
+  ret i64 %sel
+}
+

>From 0c1ff91fe5249853ec055a58642e653494924b20 Mon Sep 17 00:00:00 2001
From: Craig Topper <craig.topper at sifive.com>
Date: Tue, 18 Aug 2026 17:38:46 -0700
Subject: [PATCH 2/2] [RISCV] Lower (select c, x, -x) -> (sub (czero_eqz x, c),
 (czero_nez x, c)) with Zicond.

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 24 +++++++++++--
 llvm/test/CodeGen/RISCV/condops.ll          | 40 +++++++++------------
 2 files changed, 38 insertions(+), 26 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 2dbc048d8dc6b..b10f5a40ef4bd 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -10622,15 +10622,35 @@ 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 we are
     // optimizing for size.
-    if (!Subtarget.hasConditionalMoveFusion() && !DAG.shouldOptForSize())
+    if (!Subtarget.hasConditionalMoveFusion() && !DAG.shouldOptForSize()) {
+      using namespace llvm::SDPatternMatch;
+
+      // (select c, x, -x) -> (sub (czero_eqz x, c), (czero_nez x, c))
+      if (sd_match(FalseV, m_Neg(m_Specific(TrueV)))) {
+        TrueV = DAG.getFreeze(TrueV);
+        return DAG.getNode(
+            ISD::SUB, DL, VT,
+            DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, TrueV, CondV),
+            DAG.getNode(RISCVISD::CZERO_NEZ, DL, VT, TrueV, CondV));
+      }
+      // (select c, -x, x) -> (sub (czero_nez x, c), (czero_eqz x, c))
+      if (sd_match(TrueV, m_Neg(m_Specific(FalseV)))) {
+        FalseV = DAG.getFreeze(FalseV);
+        return DAG.getNode(
+            ISD::SUB, DL, VT,
+            DAG.getNode(RISCVISD::CZERO_NEZ, DL, VT, FalseV, CondV),
+            DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, FalseV, CondV));
+      }
+
+      // (select c, t, f) -> (or (czero_eqz t, c), (czero_nez f, c))
       return DAG.getNode(
           ISD::OR, DL, VT,
           DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, TrueV, CondV),
           DAG.getNode(RISCVISD::CZERO_NEZ, DL, VT, FalseV, CondV),
           SDNodeFlags::Disjoint);
+    }
   }
 
   if (Op.hasOneUse()) {
diff --git a/llvm/test/CodeGen/RISCV/condops.ll b/llvm/test/CodeGen/RISCV/condops.ll
index 18d95b2612070..3c62b322efece 100644
--- a/llvm/test/CodeGen/RISCV/condops.ll
+++ b/llvm/test/CodeGen/RISCV/condops.ll
@@ -4580,21 +4580,19 @@ define i64 @neg1(i64 %rs1, i1 zeroext %rc) {
 ; RV32XVENTANACONDOPS-NEXT:    neg a3, a1
 ; RV32XVENTANACONDOPS-NEXT:    snez a4, a0
 ; RV32XVENTANACONDOPS-NEXT:    sub a3, a3, a4
-; RV32XVENTANACONDOPS-NEXT:    neg a4, a0
+; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a4, a0, a2
 ; RV32XVENTANACONDOPS-NEXT:    vt.maskc a0, a0, a2
-; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a4, a4, a2
 ; RV32XVENTANACONDOPS-NEXT:    vt.maskc a1, a1, a2
 ; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a2, a3, a2
-; RV32XVENTANACONDOPS-NEXT:    or a0, a0, a4
+; RV32XVENTANACONDOPS-NEXT:    sub a0, a0, a4
 ; RV32XVENTANACONDOPS-NEXT:    or a1, a1, a2
 ; RV32XVENTANACONDOPS-NEXT:    ret
 ;
 ; RV64XVENTANACONDOPS-LABEL: neg1:
 ; RV64XVENTANACONDOPS:       # %bb.0:
-; RV64XVENTANACONDOPS-NEXT:    neg a2, a0
+; RV64XVENTANACONDOPS-NEXT:    vt.maskcn a2, a0, a1
 ; RV64XVENTANACONDOPS-NEXT:    vt.maskc a0, a0, a1
-; RV64XVENTANACONDOPS-NEXT:    vt.maskcn a1, a2, a1
-; RV64XVENTANACONDOPS-NEXT:    or a0, a0, a1
+; RV64XVENTANACONDOPS-NEXT:    sub a0, a0, a2
 ; RV64XVENTANACONDOPS-NEXT:    ret
 ;
 ; RV64XTHEADCONDMOV-LABEL: neg1:
@@ -4608,21 +4606,19 @@ define i64 @neg1(i64 %rs1, i1 zeroext %rc) {
 ; RV32ZICOND-NEXT:    neg a3, a1
 ; RV32ZICOND-NEXT:    snez a4, a0
 ; RV32ZICOND-NEXT:    sub a3, a3, a4
-; RV32ZICOND-NEXT:    neg a4, a0
+; RV32ZICOND-NEXT:    czero.nez a4, a0, a2
 ; RV32ZICOND-NEXT:    czero.eqz a0, a0, a2
-; RV32ZICOND-NEXT:    czero.nez a4, a4, a2
 ; RV32ZICOND-NEXT:    czero.eqz a1, a1, a2
 ; RV32ZICOND-NEXT:    czero.nez a2, a3, a2
-; RV32ZICOND-NEXT:    or a0, a0, a4
+; RV32ZICOND-NEXT:    sub a0, a0, a4
 ; RV32ZICOND-NEXT:    or a1, a1, a2
 ; RV32ZICOND-NEXT:    ret
 ;
 ; RV64ZICOND-LABEL: neg1:
 ; RV64ZICOND:       # %bb.0:
-; RV64ZICOND-NEXT:    neg a2, a0
+; RV64ZICOND-NEXT:    czero.nez a2, a0, a1
 ; RV64ZICOND-NEXT:    czero.eqz a0, a0, a1
-; RV64ZICOND-NEXT:    czero.nez a1, a2, a1
-; RV64ZICOND-NEXT:    or a0, a0, a1
+; RV64ZICOND-NEXT:    sub a0, a0, a2
 ; RV64ZICOND-NEXT:    ret
   %neg = sub i64 0, %rs1
   %sel = select i1 %rc, i64 %rs1, i64 %neg
@@ -4654,21 +4650,19 @@ define i64 @neg2(i64 %rs1, i1 zeroext %rc) {
 ; RV32XVENTANACONDOPS-NEXT:    neg a3, a1
 ; RV32XVENTANACONDOPS-NEXT:    snez a4, a0
 ; RV32XVENTANACONDOPS-NEXT:    sub a3, a3, a4
-; RV32XVENTANACONDOPS-NEXT:    neg a4, a0
+; RV32XVENTANACONDOPS-NEXT:    vt.maskc a4, a0, a2
 ; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a0, a0, a2
-; RV32XVENTANACONDOPS-NEXT:    vt.maskc a4, a4, a2
 ; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a1, a1, a2
 ; RV32XVENTANACONDOPS-NEXT:    vt.maskc a2, a3, a2
-; RV32XVENTANACONDOPS-NEXT:    or a0, a4, a0
+; RV32XVENTANACONDOPS-NEXT:    sub a0, a0, a4
 ; RV32XVENTANACONDOPS-NEXT:    or a1, a2, a1
 ; RV32XVENTANACONDOPS-NEXT:    ret
 ;
 ; RV64XVENTANACONDOPS-LABEL: neg2:
 ; RV64XVENTANACONDOPS:       # %bb.0:
-; RV64XVENTANACONDOPS-NEXT:    neg a2, a0
+; RV64XVENTANACONDOPS-NEXT:    vt.maskc a2, a0, a1
 ; RV64XVENTANACONDOPS-NEXT:    vt.maskcn a0, a0, a1
-; RV64XVENTANACONDOPS-NEXT:    vt.maskc a1, a2, a1
-; RV64XVENTANACONDOPS-NEXT:    or a0, a1, a0
+; RV64XVENTANACONDOPS-NEXT:    sub a0, a0, a2
 ; RV64XVENTANACONDOPS-NEXT:    ret
 ;
 ; RV64XTHEADCONDMOV-LABEL: neg2:
@@ -4682,21 +4676,19 @@ define i64 @neg2(i64 %rs1, i1 zeroext %rc) {
 ; RV32ZICOND-NEXT:    neg a3, a1
 ; RV32ZICOND-NEXT:    snez a4, a0
 ; RV32ZICOND-NEXT:    sub a3, a3, a4
-; RV32ZICOND-NEXT:    neg a4, a0
+; RV32ZICOND-NEXT:    czero.eqz a4, a0, a2
 ; RV32ZICOND-NEXT:    czero.nez a0, a0, a2
-; RV32ZICOND-NEXT:    czero.eqz a4, a4, a2
 ; RV32ZICOND-NEXT:    czero.nez a1, a1, a2
 ; RV32ZICOND-NEXT:    czero.eqz a2, a3, a2
-; RV32ZICOND-NEXT:    or a0, a4, a0
+; RV32ZICOND-NEXT:    sub a0, a0, a4
 ; RV32ZICOND-NEXT:    or a1, a2, a1
 ; RV32ZICOND-NEXT:    ret
 ;
 ; RV64ZICOND-LABEL: neg2:
 ; RV64ZICOND:       # %bb.0:
-; RV64ZICOND-NEXT:    neg a2, a0
+; RV64ZICOND-NEXT:    czero.eqz a2, a0, a1
 ; RV64ZICOND-NEXT:    czero.nez a0, a0, a1
-; RV64ZICOND-NEXT:    czero.eqz a1, a2, a1
-; RV64ZICOND-NEXT:    or a0, a1, a0
+; RV64ZICOND-NEXT:    sub a0, a0, a2
 ; RV64ZICOND-NEXT:    ret
   %neg = sub i64 0, %rs1
   %sel = select i1 %rc, i64 %neg, i64 %rs1



More information about the llvm-commits mailing list