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

via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 18 21:20:46 PDT 2026


Author: Craig Topper
Date: 2026-08-18T21:20:40-07:00
New Revision: b29eb4b10264aeb3d2339db52bcb982bdf6d7e07

URL: https://github.com/llvm/llvm-project/commit/b29eb4b10264aeb3d2339db52bcb982bdf6d7e07
DIFF: https://github.com/llvm/llvm-project/commit/b29eb4b10264aeb3d2339db52bcb982bdf6d7e07.diff

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

Assisted-by: Claude

Added: 
    

Modified: 
    llvm/lib/Target/RISCV/RISCVISelLowering.cpp
    llvm/test/CodeGen/RISCV/condops.ll

Removed: 
    


################################################################################
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 71af806811a4b..3c62b322efece 100644
--- a/llvm/test/CodeGen/RISCV/condops.ll
+++ b/llvm/test/CodeGen/RISCV/condops.ll
@@ -4554,3 +4554,144 @@ 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:    vt.maskcn a4, a0, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskc a0, a0, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskc a1, a1, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a2, a3, a2
+; RV32XVENTANACONDOPS-NEXT:    sub a0, a0, a4
+; RV32XVENTANACONDOPS-NEXT:    or a1, a1, a2
+; RV32XVENTANACONDOPS-NEXT:    ret
+;
+; RV64XVENTANACONDOPS-LABEL: neg1:
+; RV64XVENTANACONDOPS:       # %bb.0:
+; RV64XVENTANACONDOPS-NEXT:    vt.maskcn a2, a0, a1
+; RV64XVENTANACONDOPS-NEXT:    vt.maskc a0, a0, a1
+; RV64XVENTANACONDOPS-NEXT:    sub a0, a0, a2
+; 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:    czero.nez a4, a0, a2
+; RV32ZICOND-NEXT:    czero.eqz a0, a0, a2
+; RV32ZICOND-NEXT:    czero.eqz a1, a1, a2
+; RV32ZICOND-NEXT:    czero.nez a2, a3, a2
+; RV32ZICOND-NEXT:    sub a0, a0, a4
+; RV32ZICOND-NEXT:    or a1, a1, a2
+; RV32ZICOND-NEXT:    ret
+;
+; RV64ZICOND-LABEL: neg1:
+; RV64ZICOND:       # %bb.0:
+; RV64ZICOND-NEXT:    czero.nez a2, a0, a1
+; RV64ZICOND-NEXT:    czero.eqz 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
+  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:    vt.maskc a4, a0, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a0, a0, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskcn a1, a1, a2
+; RV32XVENTANACONDOPS-NEXT:    vt.maskc a2, a3, a2
+; RV32XVENTANACONDOPS-NEXT:    sub a0, a0, a4
+; RV32XVENTANACONDOPS-NEXT:    or a1, a2, a1
+; RV32XVENTANACONDOPS-NEXT:    ret
+;
+; RV64XVENTANACONDOPS-LABEL: neg2:
+; RV64XVENTANACONDOPS:       # %bb.0:
+; RV64XVENTANACONDOPS-NEXT:    vt.maskc a2, a0, a1
+; RV64XVENTANACONDOPS-NEXT:    vt.maskcn a0, a0, a1
+; RV64XVENTANACONDOPS-NEXT:    sub a0, a0, a2
+; 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:    czero.eqz a4, a0, a2
+; RV32ZICOND-NEXT:    czero.nez a0, a0, a2
+; RV32ZICOND-NEXT:    czero.nez a1, a1, a2
+; RV32ZICOND-NEXT:    czero.eqz a2, a3, a2
+; RV32ZICOND-NEXT:    sub a0, a0, a4
+; RV32ZICOND-NEXT:    or a1, a2, a1
+; RV32ZICOND-NEXT:    ret
+;
+; RV64ZICOND-LABEL: neg2:
+; RV64ZICOND:       # %bb.0:
+; RV64ZICOND-NEXT:    czero.eqz a2, a0, a1
+; RV64ZICOND-NEXT:    czero.nez a0, a0, a1
+; RV64ZICOND-NEXT:    sub a0, a0, a2
+; RV64ZICOND-NEXT:    ret
+  %neg = sub i64 0, %rs1
+  %sel = select i1 %rc, i64 %neg, i64 %rs1
+  ret i64 %sel
+}
+


        


More information about the llvm-commits mailing list