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

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


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v

Author: Craig Topper (topperc)

<details>
<summary>Changes</summary>

Assisted-by: Claude

---
Full diff: https://github.com/llvm/llvm-project/pull/217181.diff


2 Files Affected:

- (modified) llvm/lib/Target/RISCV/RISCVISelLowering.cpp (+22-2) 
- (modified) llvm/test/CodeGen/RISCV/condops.ll (+141) 


``````````diff
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
+}
+

``````````

</details>


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


More information about the llvm-commits mailing list