[llvm] [RISCV] DAGCombine canonicalizes the true operand of vselect to have one use (PR #206449)

Liao Chunyu via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 29 20:51:40 PDT 2026


https://github.com/ChunyuLiao updated https://github.com/llvm/llvm-project/pull/206449

>From 4adde7ff3bd64bfd81478f01ed0bc5855c217fbe Mon Sep 17 00:00:00 2001
From: Liao Chunyu <chunyu at iscas.ac.cn>
Date: Mon, 29 Jun 2026 06:02:24 +0000
Subject: [PATCH 1/3] init

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 52 +++++++++++++++++++--
 1 file changed, 47 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index e5ce36afb7b2f..fbb2da73a0f6d 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -20355,6 +20355,40 @@ static SDValue useInversedSetcc(SDNode *N, SelectionDAG &DAG,
   return SDValue();
 }
 
+static SDValue
+canonicalizeVSelectTrueToOneUse(SDNode *N, SelectionDAG &DAG,
+                                const RISCVSubtarget &Subtarget) {
+  SDValue CC = N->getOperand(0);
+  SDValue TrueVal = N->getOperand(1);
+  SDValue FalseVal = N->getOperand(2);
+
+  if (CC.getOpcode() != ISD::SETCC || !CC.hasOneUse() || TrueVal.hasOneUse() ||
+      !FalseVal.hasOneUse())
+    return SDValue();
+
+  ISD::CondCode CCVal = cast<CondCodeSDNode>(CC.getOperand(2))->get();
+  if (CCVal != ISD::SETEQ && CCVal != ISD::SETNE)
+    return SDValue();
+
+  EVT VT = TrueVal.getValueType();
+  if (!VT.isSimple())
+    return SDValue();
+
+  if (VT.getVectorElementType().getSizeInBits() > Subtarget.getXLen())
+    return SDValue();
+
+  if (DAG.isSplatValue(TrueVal) || DAG.isSplatValue(FalseVal))
+    return SDValue();
+
+  SDLoc DL(N);
+  // Only handles ISD::SETEQ and ISD::SETNE; no extra RVV introduced.
+  ISD::CondCode InvCC = CCVal == ISD::SETEQ ? ISD::SETNE : ISD::SETEQ;
+  SDValue InvertedCC = DAG.getSetCC(DL, CC.getValueType(), CC.getOperand(0),
+                                    CC.getOperand(1), InvCC);
+  return DAG.getNode(ISD::VSELECT, DL, N->getValueType(0), InvertedCC, FalseVal,
+                     TrueVal);
+}
+
 static bool matchSelectAddSub(SDValue TrueVal, SDValue FalseVal, bool &SwapCC) {
   if (!TrueVal.hasOneUse() || !FalseVal.hasOneUse())
     return false;
@@ -20375,16 +20409,24 @@ static bool matchSelectAddSub(SDValue TrueVal, SDValue FalseVal, bool &SwapCC) {
           (TrueVal.getOperand(1) == A && TrueVal.getOperand(0) == B));
 }
 
-/// Convert vselect CC, (add a, b), (sub a, b) to add a, (vselect CC, -b, b).
-/// This allows us match a vadd.vv fed by a masked vrsub, which reduces
-/// register pressure over the add followed by masked vsub sequence.
-static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG) {
+static SDValue performVSELECTCombine(SDNode *N, SelectionDAG &DAG,
+                                     const RISCVSubtarget &Subtarget) {
   SDLoc DL(N);
   EVT VT = N->getValueType(0);
   SDValue CC = N->getOperand(0);
   SDValue TrueVal = N->getOperand(1);
   SDValue FalseVal = N->getOperand(2);
 
+  // Convert (vselect CC, true, false) to (vselect InvertCC, false, true when)
+  // false has one use and true has multiple use.
+  // It relies on RISCVVectorPeephole.cpp foldVMergeToMask to eliminate
+  // vmerge.vv
+  if (SDValue V = canonicalizeVSelectTrueToOneUse(N, DAG, Subtarget))
+    return V;
+
+  // Convert vselect CC, (add a, b), (sub a, b) to add a, (vselect CC, -b, b).
+  // This allows us match a vadd.vv fed by a masked vrsub, which reduces
+  // register pressure over the add followed by masked vsub sequence.
   bool SwapCC;
   if (!matchSelectAddSub(TrueVal, FalseVal, SwapCC))
     return SDValue();
@@ -22143,7 +22185,7 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
   case ISD::SELECT:
     return performSELECTCombine(N, DAG, Subtarget);
   case ISD::VSELECT:
-    return performVSELECTCombine(N, DAG);
+    return performVSELECTCombine(N, DAG, Subtarget);
   case RISCVISD::CZERO_EQZ:
   case RISCVISD::CZERO_NEZ: {
     SDValue Val = N->getOperand(0);

>From 7217235da34d404064f3db575aadba7e80a52c52 Mon Sep 17 00:00:00 2001
From: Liao Chunyu <chunyu at iscas.ac.cn>
Date: Mon, 29 Jun 2026 10:07:20 +0000
Subject: [PATCH 2/3] testcase

---
 llvm/test/CodeGen/RISCV/rvv/vselect-fp.ll | 30 +++++++++++++++++++++++
 1 file changed, 30 insertions(+)

diff --git a/llvm/test/CodeGen/RISCV/rvv/vselect-fp.ll b/llvm/test/CodeGen/RISCV/rvv/vselect-fp.ll
index 1d8daf2667ffa..93a9a033d782f 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vselect-fp.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vselect-fp.ll
@@ -537,3 +537,33 @@ define void @vselect_legalize_regression(<vscale x 16 x double> %a, <vscale x 16
   store <vscale x 16 x double> %sel, ptr %out
   ret void
 }
+
+
+define <vscale x 2 x double> @vselect_true_hasmultipleuse(<vscale x 2 x i32> %vc, <vscale x 2 x double> %va) {
+; RV32-LABEL: vselect_true_hasmultipleuse:
+; RV32:       # %bb.0:
+; RV32-NEXT:    lui a0, %hi(.LCPI40_0)
+; RV32-NEXT:    fld fa5, %lo(.LCPI40_0)(a0)
+; RV32-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; RV32-NEXT:    vmseq.vi v0, v8, 1
+; RV32-NEXT:    vsetvli zero, zero, e64, m2, ta, ma
+; RV32-NEXT:    vfmin.vf v8, v10, fa5
+; RV32-NEXT:    vmerge.vvm v8, v8, v10, v0
+; RV32-NEXT:    ret
+;
+; RV64-LABEL: vselect_true_hasmultipleuse:
+; RV64:       # %bb.0:
+; RV64-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; RV64-NEXT:    vmsne.vi v0, v8, 1
+; RV64-NEXT:    li a0, 1
+; RV64-NEXT:    slli a0, a0, 62
+; RV64-NEXT:    fmv.d.x fa5, a0
+; RV64-NEXT:    vsetvli zero, zero, e64, m2, ta, mu
+; RV64-NEXT:    vfmin.vf v10, v10, fa5, v0.t
+; RV64-NEXT:    vmv.v.v v8, v10
+; RV64-NEXT:    ret
+  %cmp = icmp eq <vscale x 2 x i32> %vc, splat (i32 1)
+  %min = tail call fast <vscale x 2 x double> @llvm.minnum.nxv2f64(<vscale x 2 x double> %va, <vscale x 2 x double> splat (double 2.000000e+00))
+  %sel = select fast <vscale x 2 x i1> %cmp, <vscale x 2 x double> %va, <vscale x 2 x double> %min
+  ret <vscale x 2 x double> %sel
+}

>From 1ad6af9f09de1ea53cb90d11daa977a4b9d621a7 Mon Sep 17 00:00:00 2001
From: Liao Chunyu <chunyu at iscas.ac.cn>
Date: Tue, 30 Jun 2026 03:25:04 +0000
Subject: [PATCH 3/3] address comment and check opcode

---
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 23 +++++++++------------
 llvm/test/CodeGen/RISCV/rvv/vselect-fp.ll   | 10 ++++-----
 2 files changed, 15 insertions(+), 18 deletions(-)

diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index fbb2da73a0f6d..27ff0d476df8b 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -20366,25 +20366,22 @@ canonicalizeVSelectTrueToOneUse(SDNode *N, SelectionDAG &DAG,
       !FalseVal.hasOneUse())
     return SDValue();
 
+  // Only handles ISD::SETEQ and ISD::SETNE; no extra RVV introduced.
   ISD::CondCode CCVal = cast<CondCodeSDNode>(CC.getOperand(2))->get();
-  if (CCVal != ISD::SETEQ && CCVal != ISD::SETNE)
-    return SDValue();
-
-  EVT VT = TrueVal.getValueType();
-  if (!VT.isSimple())
+  if (!isIntEqualitySetCC(CCVal))
     return SDValue();
 
-  if (VT.getVectorElementType().getSizeInBits() > Subtarget.getXLen())
-    return SDValue();
-
-  if (DAG.isSplatValue(TrueVal) || DAG.isSplatValue(FalseVal))
+  if (DAG.isSplatValue(TrueVal) || DAG.isSplatValue(FalseVal) ||
+      TrueVal.getOpcode() == ISD::SPLAT_VECTOR_PARTS ||
+      FalseVal.getOpcode() == ISD::SPLAT_VECTOR_PARTS ||
+      TrueVal.getOpcode() == RISCVISD::VMV_V_X_VL ||
+      FalseVal.getOpcode() == RISCVISD::VMV_V_X_VL)
     return SDValue();
 
   SDLoc DL(N);
-  // Only handles ISD::SETEQ and ISD::SETNE; no extra RVV introduced.
-  ISD::CondCode InvCC = CCVal == ISD::SETEQ ? ISD::SETNE : ISD::SETEQ;
-  SDValue InvertedCC = DAG.getSetCC(DL, CC.getValueType(), CC.getOperand(0),
-                                    CC.getOperand(1), InvCC);
+  EVT CVT = CC.getValueType();
+  SDValue InvertedCC = DAG.getSetCC(DL, CVT, CC.getOperand(0), CC.getOperand(1),
+                                    ISD::getSetCCInverse(CCVal, CVT));
   return DAG.getNode(ISD::VSELECT, DL, N->getValueType(0), InvertedCC, FalseVal,
                      TrueVal);
 }
diff --git a/llvm/test/CodeGen/RISCV/rvv/vselect-fp.ll b/llvm/test/CodeGen/RISCV/rvv/vselect-fp.ll
index 93a9a033d782f..e267c98c59efd 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vselect-fp.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vselect-fp.ll
@@ -542,13 +542,13 @@ define void @vselect_legalize_regression(<vscale x 16 x double> %a, <vscale x 16
 define <vscale x 2 x double> @vselect_true_hasmultipleuse(<vscale x 2 x i32> %vc, <vscale x 2 x double> %va) {
 ; RV32-LABEL: vselect_true_hasmultipleuse:
 ; RV32:       # %bb.0:
+; RV32-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
+; RV32-NEXT:    vmsne.vi v0, v8, 1
 ; RV32-NEXT:    lui a0, %hi(.LCPI40_0)
 ; RV32-NEXT:    fld fa5, %lo(.LCPI40_0)(a0)
-; RV32-NEXT:    vsetvli a0, zero, e32, m1, ta, ma
-; RV32-NEXT:    vmseq.vi v0, v8, 1
-; RV32-NEXT:    vsetvli zero, zero, e64, m2, ta, ma
-; RV32-NEXT:    vfmin.vf v8, v10, fa5
-; RV32-NEXT:    vmerge.vvm v8, v8, v10, v0
+; RV32-NEXT:    vsetvli zero, zero, e64, m2, ta, mu
+; RV32-NEXT:    vfmin.vf v10, v10, fa5, v0.t
+; RV32-NEXT:    vmv.v.v v8, v10
 ; RV32-NEXT:    ret
 ;
 ; RV64-LABEL: vselect_true_hasmultipleuse:



More information about the llvm-commits mailing list