[llvm] [RISCV] Fold vmnot.m of an integer compare into the compare (PR #222553)
Marton Moro via llvm-commits
llvm-commits at lists.llvm.org
Thu Sep 10 04:40:11 PDT 2026
https://github.com/martonmoro updated https://github.com/llvm/llvm-project/pull/222553
>From 96282a562717a7a6737b406f9c2c60ccfcd3ba5f Mon Sep 17 00:00:00 2001
From: Marton Moro <moro.marton at gmail.com>
Date: Thu, 10 Sep 2026 12:34:38 +0200
Subject: [PATCH 1/2] [RISCV] Add tests for mask NOT of integer vector
compares. NFC
---
.../CodeGen/RISCV/rvv/combine-vmnot-setcc.ll | 84 +++++++++++++++++++
1 file changed, 84 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll
diff --git a/llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll b/llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll
new file mode 100644
index 0000000000000..4ab973b3c7a44
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll
@@ -0,0 +1,84 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv32 -mattr=+v -verify-machineinstrs < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+v -verify-machineinstrs < %s | FileCheck %s
+
+define i1 @reduce_and_trunc_v8i8(<8 x i8> %v) {
+; CHECK-LABEL: reduce_and_trunc_v8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vand.vi v8, v8, 1
+; CHECK-NEXT: vmsne.vi v8, v8, 0
+; CHECK-NEXT: vmnot.m v8, v8
+; CHECK-NEXT: vcpop.m a0, v8
+; CHECK-NEXT: seqz a0, a0
+; CHECK-NEXT: ret
+ %t = trunc <8 x i8> %v to <8 x i1>
+ %r = call i1 @llvm.vector.reduce.and.v8i1(<8 x i1> %t)
+ ret i1 %r
+}
+
+define i1 @reduce_and_icmp_slt_v8i8(<8 x i8> %v) {
+; CHECK-LABEL: reduce_and_icmp_slt_v8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vmsle.vi v8, v8, 4
+; CHECK-NEXT: vmnot.m v8, v8
+; CHECK-NEXT: vcpop.m a0, v8
+; CHECK-NEXT: seqz a0, a0
+; CHECK-NEXT: ret
+ %c = icmp slt <8 x i8> %v, splat (i8 5)
+ %r = call i1 @llvm.vector.reduce.and.v8i1(<8 x i1> %c)
+ ret i1 %r
+}
+
+define <8 x i1> @not_trunc_v8i8(<8 x i8> %v) {
+; CHECK-LABEL: not_trunc_v8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vand.vi v8, v8, 1
+; CHECK-NEXT: vmsne.vi v8, v8, 0
+; CHECK-NEXT: vmnot.m v0, v8
+; CHECK-NEXT: ret
+ %t = trunc <8 x i8> %v to <8 x i1>
+ %n = xor <8 x i1> %t, splat (i1 true)
+ ret <8 x i1> %n
+}
+
+; Floating-point compares must not be inverted
+define i1 @reduce_and_fcmp_olt_v8f32(<8 x float> %v) {
+; CHECK-LABEL: reduce_and_fcmp_olt_v8f32:
+; CHECK: # %bb.0:
+; CHECK-NEXT: fmv.w.x fa5, zero
+; CHECK-NEXT: vsetivli zero, 8, e32, m2, ta, ma
+; CHECK-NEXT: vmflt.vf v10, v8, fa5
+; CHECK-NEXT: vmnot.m v8, v10
+; CHECK-NEXT: vcpop.m a0, v8
+; CHECK-NEXT: seqz a0, a0
+; CHECK-NEXT: ret
+ %c = fcmp olt <8 x float> %v, zeroinitializer
+ %r = call i1 @llvm.vector.reduce.and.v8i1(<8 x i1> %c)
+ ret i1 %r
+}
+
+; The compare below has a non-trivial mask and an undef passthru.
+define <8 x i1> @not_vp_reverse_v8i1(<8 x i1> %v, <8 x i1> %m, i32 zeroext %evl) {
+; CHECK-LABEL: not_vp_reverse_v8i1:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetvli zero, a0, e8, mf2, ta, ma
+; CHECK-NEXT: vmv.v.i v9, 0
+; CHECK-NEXT: vmerge.vim v9, v9, 1, v0
+; CHECK-NEXT: vmv1r.v v0, v8
+; CHECK-NEXT: vsetvli zero, zero, e16, m1, ta, ma
+; CHECK-NEXT: vid.v v10, v0.t
+; CHECK-NEXT: addi a0, a0, -1
+; CHECK-NEXT: vrsub.vx v10, v10, a0, v0.t
+; CHECK-NEXT: vsetvli zero, zero, e8, mf2, ta, ma
+; CHECK-NEXT: vrgatherei16.vv v11, v9, v10, v0.t
+; CHECK-NEXT: vmsne.vi v8, v11, 0, v0.t
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vmnot.m v0, v8
+; CHECK-NEXT: ret
+ %r = call <8 x i1> @llvm.experimental.vp.reverse.v8i1(<8 x i1> %v, <8 x i1> %m, i32 %evl)
+ %n = xor <8 x i1> %r, splat (i1 true)
+ ret <8 x i1> %n
+}
>From 268d285c0a6bd24b43e79fba632ca120cf1531b0 Mon Sep 17 00:00:00 2001
From: Marton Moro <moro.marton at gmail.com>
Date: Thu, 10 Sep 2026 13:31:44 +0200
Subject: [PATCH 2/2] [RISCV] Fold vmnot.m of an integer compare into the
compare
(vmxor_vl (setcc_vl a, b, cc), vmset_vl) -> (setcc_vl a, b, !cc)
Fixes #222158
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 25 +++++++++++++++++++
.../CodeGen/RISCV/rvv/combine-vmnot-setcc.ll | 13 +++-------
2 files changed, 29 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 5f8ad5da42da1..6accbbbcaa9a5 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -19253,6 +19253,29 @@ static SDValue performORCombine(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
return combineSelectAndUseCommutative(N, DAG, /*AllOnes*/ false, Subtarget);
}
+// Fold (vmxor_vl (setcc_vl a, b, cc), vmset_vl) -> (setcc_vl a, b, !cc) for
+// integer compares. The NOT also flips the masked-off lanes, which the inverted
+// compare copies unchanged from the passthru. So the passthru must be undef,
+// but any mask is fine.
+static SDValue combineVMNOTOfSetCC(SDNode *N, SelectionDAG &DAG) {
+ SDValue Cmp = N->getOperand(0);
+ if (Cmp.getOpcode() == RISCVISD::VMSET_VL)
+ Cmp = N->getOperand(1);
+ else if (N->getOperand(1).getOpcode() != RISCVISD::VMSET_VL)
+ return SDValue();
+
+ if (Cmp.getOpcode() != RISCVISD::SETCC_VL || !Cmp.hasOneUse() ||
+ !Cmp.getOperand(0).getValueType().isInteger() ||
+ !Cmp.getOperand(3).isUndef())
+ return SDValue();
+
+ ISD::CondCode CC = cast<CondCodeSDNode>(Cmp.getOperand(2))->get();
+ CC = ISD::getSetCCInverse(CC, Cmp.getOperand(0).getValueType());
+ return DAG.getNode(RISCVISD::SETCC_VL, SDLoc(N), Cmp.getValueType(),
+ {Cmp.getOperand(0), Cmp.getOperand(1), DAG.getCondCode(CC),
+ Cmp.getOperand(3), Cmp.getOperand(4), Cmp.getOperand(5)});
+}
+
static SDValue performXORCombine(SDNode *N, SelectionDAG &DAG,
const RISCVSubtarget &Subtarget) {
SDValue N0 = N->getOperand(0);
@@ -25260,6 +25283,8 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
return N->getOperand(0);
break;
}
+ case RISCVISD::VMXOR_VL:
+ return combineVMNOTOfSetCC(N, DAG);
case RISCVISD::VMERGE_VL: {
// vmerge_vl allones, x, y, passthru, vl -> vmv_v_v passthru, x, vl
SDValue Mask = N->getOperand(0);
diff --git a/llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll b/llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll
index 4ab973b3c7a44..7d0204a66b818 100644
--- a/llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll
@@ -7,8 +7,7 @@ define i1 @reduce_and_trunc_v8i8(<8 x i8> %v) {
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
; CHECK-NEXT: vand.vi v8, v8, 1
-; CHECK-NEXT: vmsne.vi v8, v8, 0
-; CHECK-NEXT: vmnot.m v8, v8
+; CHECK-NEXT: vmseq.vi v8, v8, 0
; CHECK-NEXT: vcpop.m a0, v8
; CHECK-NEXT: seqz a0, a0
; CHECK-NEXT: ret
@@ -21,8 +20,7 @@ define i1 @reduce_and_icmp_slt_v8i8(<8 x i8> %v) {
; CHECK-LABEL: reduce_and_icmp_slt_v8i8:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
-; CHECK-NEXT: vmsle.vi v8, v8, 4
-; CHECK-NEXT: vmnot.m v8, v8
+; CHECK-NEXT: vmsgt.vi v8, v8, 4
; CHECK-NEXT: vcpop.m a0, v8
; CHECK-NEXT: seqz a0, a0
; CHECK-NEXT: ret
@@ -36,8 +34,7 @@ define <8 x i1> @not_trunc_v8i8(<8 x i8> %v) {
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
; CHECK-NEXT: vand.vi v8, v8, 1
-; CHECK-NEXT: vmsne.vi v8, v8, 0
-; CHECK-NEXT: vmnot.m v0, v8
+; CHECK-NEXT: vmseq.vi v0, v8, 0
; CHECK-NEXT: ret
%t = trunc <8 x i8> %v to <8 x i1>
%n = xor <8 x i1> %t, splat (i1 true)
@@ -74,9 +71,7 @@ define <8 x i1> @not_vp_reverse_v8i1(<8 x i1> %v, <8 x i1> %m, i32 zeroext %evl)
; CHECK-NEXT: vrsub.vx v10, v10, a0, v0.t
; CHECK-NEXT: vsetvli zero, zero, e8, mf2, ta, ma
; CHECK-NEXT: vrgatherei16.vv v11, v9, v10, v0.t
-; CHECK-NEXT: vmsne.vi v8, v11, 0, v0.t
-; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
-; CHECK-NEXT: vmnot.m v0, v8
+; CHECK-NEXT: vmseq.vi v0, v11, 0, v0.t
; CHECK-NEXT: ret
%r = call <8 x i1> @llvm.experimental.vp.reverse.v8i1(<8 x i1> %v, <8 x i1> %m, i32 %evl)
%n = xor <8 x i1> %r, splat (i1 true)
More information about the llvm-commits
mailing list