[llvm] 3c8ed91 - [RISCV] Fold vmnot.m of an integer compare into the compare (#222553)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 21 02:25:27 PDT 2026


Author: Marton Moro
Date: 2026-09-21T09:25:21Z
New Revision: 3c8ed91159b2144284672cf490cedd7befaba3fa

URL: https://github.com/llvm/llvm-project/commit/3c8ed91159b2144284672cf490cedd7befaba3fa
DIFF: https://github.com/llvm/llvm-project/commit/3c8ed91159b2144284672cf490cedd7befaba3fa.diff

LOG: [RISCV] Fold vmnot.m of an integer compare into the compare (#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 and an undef passthru is
handled. The NOT also flips the masked-off lanes, which the inverted compare
would copy unchanged from the passthru, so the passthru must be undef.
The mask can be anything. FP compares are excluded since the inverse of an
ordered compare is unordered.

Fixes #222158

Added: 
    llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll

Modified: 
    llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 2c05e3000c5eb..f17d9e90bfb73 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -19601,6 +19601,31 @@ 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 &&
+      N->getOperand(1).getOpcode() != RISCVISD::VMSET_VL)
+    return SDValue();
+
+  if (Cmp.getOpcode() == RISCVISD::VMSET_VL)
+    Cmp = N->getOperand(1);
+
+  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);
@@ -25522,6 +25547,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..20959082c9167
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/combine-vmnot-setcc.ll
@@ -0,0 +1,79 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=riscv32 -mattr=+v < %s | FileCheck %s
+; RUN: llc -mtriple=riscv64 -mattr=+v < %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:    vmseq.vi v8, v8, 0
+; 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:    vmsgt.vi v8, v8, 4
+; 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:    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)
+  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 no 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:    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)
+  ret <8 x i1> %n
+}


        


More information about the llvm-commits mailing list