[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