[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 01:29:10 PDT 2026
https://github.com/martonmoro created https://github.com/llvm/llvm-project/pull/222553
Fold a mask NOT of an integer vector compare into the compare by inverting
the condition code, so `vmsne.vi` + `vmnot.m` becomes `vmseq.vi`:
(vmxor_vl (setcc_vl a, b, cc), vmset_vl) -> (setcc_vl a, b, !cc)
Only `SETCC_VL` with integer operands, one use, undef passthru and an
all-ones mask is handled. FP compares are excluded since the inverse of an
ordered compare is unordered.
Fixes #222158
>From 5fab21f6d66eeee83376e8b7cd087814658e7842 Mon Sep 17 00:00:00 2001
From: Marton Moro <moro.marton at gmail.com>
Date: Thu, 10 Sep 2026 10:26:41 +0200
Subject: [PATCH] [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 | 24 +++++++
.../CodeGen/RISCV/rvv/combine-vmnot-setcc.ll | 66 +++++++++++++++++++
2 files changed, 90 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 5f8ad5da42da1..cb7a9b917d4e5 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -19253,6 +19253,28 @@ 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.
+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() ||
+ Cmp.getOperand(4).getOpcode() != RISCVISD::VMSET_VL)
+ 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 +25282,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
new file mode 100644
index 0000000000000..6bef503bf6f1c
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll
@@ -0,0 +1,66 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; 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(ptr %p) {
+; CHECK-LABEL: reduce_and_trunc_v8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vle8.v v8, (a0)
+; CHECK-NEXT: vand.vi v8, v8, 1
+; CHECK-NEXT: vmseq.vi v8, v8, 0
+; CHECK-NEXT: vcpop.m a0, v8
+; CHECK-NEXT: seqz a0, a0
+; CHECK-NEXT: ret
+ %v = load <8 x i8>, ptr %p
+ %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(ptr %p) {
+; CHECK-LABEL: reduce_and_icmp_slt_v8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vle8.v v8, (a0)
+; CHECK-NEXT: vmsgt.vi v8, v8, 4
+; CHECK-NEXT: vcpop.m a0, v8
+; CHECK-NEXT: seqz a0, a0
+; CHECK-NEXT: ret
+ %v = load <8 x i8>, ptr %p
+ %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(ptr %p) {
+; CHECK-LABEL: not_trunc_v8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vle8.v v8, (a0)
+; CHECK-NEXT: vand.vi v8, v8, 1
+; CHECK-NEXT: vmseq.vi v0, v8, 0
+; CHECK-NEXT: ret
+ %v = load <8 x i8>, ptr %p
+ %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(ptr %p) {
+; 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: vle32.v v8, (a0)
+; 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
+ %v = load <8 x float>, ptr %p
+ %c = fcmp olt <8 x float> %v, zeroinitializer
+ %r = call i1 @llvm.vector.reduce.and.v8i1(<8 x i1> %c)
+ ret i1 %r
+}
More information about the llvm-commits
mailing list