[llvm] [RISCV] Avoid VMNOT by swapping VMERGE operands for mask extensions (PR #126751)
Piotr Fusik via llvm-commits
llvm-commits at lists.llvm.org
Wed Feb 19 23:19:50 PST 2025
https://github.com/pfusik updated https://github.com/llvm/llvm-project/pull/126751
>From 6ce68443da480ede43aa5134c6a5b1f302aa5580 Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Mon, 17 Feb 2025 12:08:24 +0100
Subject: [PATCH 1/2] [RISCV][test] Add tests for extending negated mask
---
llvm/test/CodeGen/RISCV/rvv/mask-exts-not.ll | 111 +++++++++++++++++++
1 file changed, 111 insertions(+)
create mode 100644 llvm/test/CodeGen/RISCV/rvv/mask-exts-not.ll
diff --git a/llvm/test/CodeGen/RISCV/rvv/mask-exts-not.ll b/llvm/test/CodeGen/RISCV/rvv/mask-exts-not.ll
new file mode 100644
index 0000000000000..1a00c84a022f3
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/rvv/mask-exts-not.ll
@@ -0,0 +1,111 @@
+; 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 <vscale x 8 x i8> @mask_sext_not_nxv8i8(<vscale x 8 x i1> %m) {
+; CHECK-LABEL: mask_sext_not_nxv8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetvli a0, zero, e8, m1, ta, ma
+; CHECK-NEXT: vmnot.m v0, v0
+; CHECK-NEXT: vmv.v.i v8, 0
+; CHECK-NEXT: vmerge.vim v8, v8, -1, v0
+; CHECK-NEXT: ret
+ %not = xor <vscale x 8 x i1> %m, splat (i1 true)
+ %ext = sext <vscale x 8 x i1> %not to <vscale x 8 x i8>
+ ret <vscale x 8 x i8> %ext
+}
+
+define <vscale x 8 x i8> @mask_zext_not_nxv8i8(<vscale x 8 x i1> %m) {
+; CHECK-LABEL: mask_zext_not_nxv8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetvli a0, zero, e8, m1, ta, ma
+; CHECK-NEXT: vmnot.m v0, v0
+; CHECK-NEXT: vmv.v.i v8, 0
+; CHECK-NEXT: vmerge.vim v8, v8, 1, v0
+; CHECK-NEXT: ret
+ %not = xor <vscale x 8 x i1> %m, splat (i1 true)
+ %ext = zext <vscale x 8 x i1> %not to <vscale x 8 x i8>
+ ret <vscale x 8 x i8> %ext
+}
+
+define <8 x i8> @mask_sext_not_v8i8(<8 x i1> %m) {
+; CHECK-LABEL: mask_sext_not_v8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vmnot.m v0, v0
+; CHECK-NEXT: vmv.v.i v8, 0
+; CHECK-NEXT: vmerge.vim v8, v8, -1, v0
+; CHECK-NEXT: ret
+ %not = xor <8 x i1> %m, splat (i1 true)
+ %ext = sext <8 x i1> %not to <8 x i8>
+ ret <8 x i8> %ext
+}
+
+define <8 x i8> @mask_zext_not_v8i8(<8 x i1> %m) {
+; CHECK-LABEL: mask_zext_not_v8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vmnot.m v0, v0
+; CHECK-NEXT: vmv.v.i v8, 0
+; CHECK-NEXT: vmerge.vim v8, v8, 1, v0
+; CHECK-NEXT: ret
+ %not = xor <8 x i1> %m, splat (i1 true)
+ %ext = zext <8 x i1> %not to <8 x i8>
+ ret <8 x i8> %ext
+}
+
+define <vscale x 8 x i8> @mask_sext_xor_nxv8i8(<vscale x 8 x i1> %m, <vscale x 8 x i1> %x) {
+; CHECK-LABEL: mask_sext_xor_nxv8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetvli a0, zero, e8, m1, ta, ma
+; CHECK-NEXT: vmxor.mm v0, v0, v8
+; CHECK-NEXT: vmv.v.i v8, 0
+; CHECK-NEXT: vmerge.vim v8, v8, -1, v0
+; CHECK-NEXT: ret
+ %xor = xor <vscale x 8 x i1> %m, %x
+ %ext = sext <vscale x 8 x i1> %xor to <vscale x 8 x i8>
+ ret <vscale x 8 x i8> %ext
+}
+
+define <vscale x 8 x i8> @mask_zext_xor_nxv8i8(<vscale x 8 x i1> %m, <vscale x 8 x i1> %x) {
+; CHECK-LABEL: mask_zext_xor_nxv8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetvli a0, zero, e8, m1, ta, ma
+; CHECK-NEXT: vmxor.mm v0, v0, v8
+; CHECK-NEXT: vmv.v.i v8, 0
+; CHECK-NEXT: vmerge.vim v8, v8, 1, v0
+; CHECK-NEXT: ret
+ %xor = xor <vscale x 8 x i1> %m, %x
+ %ext = zext <vscale x 8 x i1> %xor to <vscale x 8 x i8>
+ ret <vscale x 8 x i8> %ext
+}
+
+define <8 x i8> @mask_sext_xor_v8i8(<8 x i1> %m) {
+; CHECK-LABEL: mask_sext_xor_v8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: li a0, 85
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vmv.s.x v8, a0
+; CHECK-NEXT: vmxor.mm v0, v0, v8
+; CHECK-NEXT: vmv.v.i v8, 0
+; CHECK-NEXT: vmerge.vim v8, v8, -1, v0
+; CHECK-NEXT: ret
+ %xor = xor <8 x i1> %m, <i1 1, i1 0, i1 1, i1 0, i1 1, i1 0, i1 1, i1 0>
+ %ext = sext <8 x i1> %xor to <8 x i8>
+ ret <8 x i8> %ext
+}
+
+define <8 x i8> @mask_zext_xor_v8i8(<8 x i1> %m) {
+; CHECK-LABEL: mask_zext_xor_v8i8:
+; CHECK: # %bb.0:
+; CHECK-NEXT: li a0, 85
+; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
+; CHECK-NEXT: vmv.s.x v8, a0
+; CHECK-NEXT: vmxor.mm v0, v0, v8
+; CHECK-NEXT: vmv.v.i v8, 0
+; CHECK-NEXT: vmerge.vim v8, v8, 1, v0
+; CHECK-NEXT: ret
+ %xor = xor <8 x i1> %m, <i1 1, i1 0, i1 1, i1 0, i1 1, i1 0, i1 1, i1 0>
+ %ext = zext <8 x i1> %xor to <8 x i8>
+ ret <8 x i8> %ext
+}
>From e8f700e88f209601f8150b822e48fd5cca52d828 Mon Sep 17 00:00:00 2001
From: Piotr Fusik <p.fusik at samsung.com>
Date: Mon, 17 Feb 2025 12:31:02 +0100
Subject: [PATCH 2/2] [RISCV] Avoid VMNOT by swapping VMERGE operands for mask
extensions
Fold:
(select (not m), 1, 0) -> (select m, 0, 1)
(select (not m), -1, 0) -> (select m, 0, -1)
---
llvm/lib/Target/RISCV/RISCVISelLowering.cpp | 18 ++++++++++++++++++
llvm/test/CodeGen/RISCV/rvv/mask-exts-not.ll | 20 ++++++++------------
2 files changed, 26 insertions(+), 12 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 0f5e7bd254f68..cc2478b581741 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -8961,6 +8961,10 @@ SDValue RISCVTargetLowering::lowerVectorMaskExt(SDValue Op, SelectionDAG &DAG,
if (VecVT.isScalableVector()) {
SDValue SplatZero = DAG.getConstant(0, DL, VecVT);
SDValue SplatTrueVal = DAG.getSignedConstant(ExtTrueVal, DL, VecVT);
+ if (Src.getOpcode() == ISD::XOR &&
+ ISD::isConstantSplatVectorAllOnes(Src.getOperand(1).getNode()))
+ return DAG.getNode(ISD::VSELECT, DL, VecVT, Src.getOperand(0), SplatZero,
+ SplatTrueVal);
return DAG.getNode(ISD::VSELECT, DL, VecVT, Src, SplatTrueVal, SplatZero);
}
@@ -8976,6 +8980,20 @@ SDValue RISCVTargetLowering::lowerVectorMaskExt(SDValue Op, SelectionDAG &DAG,
SDValue SplatZero = DAG.getConstant(0, DL, XLenVT);
SDValue SplatTrueVal = DAG.getSignedConstant(ExtTrueVal, DL, XLenVT);
+ if (Src.getOpcode() == ISD::EXTRACT_SUBVECTOR) {
+ SDValue Xor = Src.getOperand(0);
+ if (Xor.getOpcode() == RISCVISD::VMXOR_VL) {
+ SDValue ScalableOnes = Xor.getOperand(1);
+ if (ScalableOnes.getOpcode() == ISD::INSERT_SUBVECTOR &&
+ ScalableOnes.getOperand(0).isUndef() &&
+ ISD::isConstantSplatVectorAllOnes(
+ ScalableOnes.getOperand(1).getNode())) {
+ CC = Xor.getOperand(0);
+ std::swap(SplatZero, SplatTrueVal);
+ }
+ }
+ }
+
SplatZero = DAG.getNode(RISCVISD::VMV_V_X_VL, DL, ContainerVT,
DAG.getUNDEF(ContainerVT), SplatZero, VL);
SplatTrueVal = DAG.getNode(RISCVISD::VMV_V_X_VL, DL, ContainerVT,
diff --git a/llvm/test/CodeGen/RISCV/rvv/mask-exts-not.ll b/llvm/test/CodeGen/RISCV/rvv/mask-exts-not.ll
index 1a00c84a022f3..ce33a3b5e197e 100644
--- a/llvm/test/CodeGen/RISCV/rvv/mask-exts-not.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/mask-exts-not.ll
@@ -6,9 +6,8 @@ define <vscale x 8 x i8> @mask_sext_not_nxv8i8(<vscale x 8 x i1> %m) {
; CHECK-LABEL: mask_sext_not_nxv8i8:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetvli a0, zero, e8, m1, ta, ma
-; CHECK-NEXT: vmnot.m v0, v0
-; CHECK-NEXT: vmv.v.i v8, 0
-; CHECK-NEXT: vmerge.vim v8, v8, -1, v0
+; CHECK-NEXT: vmv.v.i v8, -1
+; CHECK-NEXT: vmerge.vim v8, v8, 0, v0
; CHECK-NEXT: ret
%not = xor <vscale x 8 x i1> %m, splat (i1 true)
%ext = sext <vscale x 8 x i1> %not to <vscale x 8 x i8>
@@ -19,9 +18,8 @@ define <vscale x 8 x i8> @mask_zext_not_nxv8i8(<vscale x 8 x i1> %m) {
; CHECK-LABEL: mask_zext_not_nxv8i8:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetvli a0, zero, e8, m1, ta, ma
-; CHECK-NEXT: vmnot.m v0, v0
-; CHECK-NEXT: vmv.v.i v8, 0
-; CHECK-NEXT: vmerge.vim v8, v8, 1, v0
+; CHECK-NEXT: vmv.v.i v8, 1
+; CHECK-NEXT: vmerge.vim v8, v8, 0, v0
; CHECK-NEXT: ret
%not = xor <vscale x 8 x i1> %m, splat (i1 true)
%ext = zext <vscale x 8 x i1> %not to <vscale x 8 x i8>
@@ -32,9 +30,8 @@ define <8 x i8> @mask_sext_not_v8i8(<8 x i1> %m) {
; CHECK-LABEL: mask_sext_not_v8i8:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
-; CHECK-NEXT: vmnot.m v0, v0
-; CHECK-NEXT: vmv.v.i v8, 0
-; CHECK-NEXT: vmerge.vim v8, v8, -1, v0
+; CHECK-NEXT: vmv.v.i v8, -1
+; CHECK-NEXT: vmerge.vim v8, v8, 0, v0
; CHECK-NEXT: ret
%not = xor <8 x i1> %m, splat (i1 true)
%ext = sext <8 x i1> %not to <8 x i8>
@@ -45,9 +42,8 @@ define <8 x i8> @mask_zext_not_v8i8(<8 x i1> %m) {
; CHECK-LABEL: mask_zext_not_v8i8:
; CHECK: # %bb.0:
; CHECK-NEXT: vsetivli zero, 8, e8, mf2, ta, ma
-; CHECK-NEXT: vmnot.m v0, v0
-; CHECK-NEXT: vmv.v.i v8, 0
-; CHECK-NEXT: vmerge.vim v8, v8, 1, v0
+; CHECK-NEXT: vmv.v.i v8, 1
+; CHECK-NEXT: vmerge.vim v8, v8, 0, v0
; CHECK-NEXT: ret
%not = xor <8 x i1> %m, splat (i1 true)
%ext = zext <8 x i1> %not to <8 x i8>
More information about the llvm-commits
mailing list