[v2] RISC-V: Implement autovec abs, vneg, vnot.

Message ID c886bc2b-94dd-f9fd-56b1-e72529848d4f@gmail.com
State Unresolved
Headers
Series [v2] RISC-V: Implement autovec abs, vneg, vnot. |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Robin Dapp May 25, 2023, 10:08 a.m. UTC
  Hi,

this patch implements abs<mode>2, vneg<mode>2 and vnot<mode>2 expanders
for integer vector registers and adds tests for them.

v2 is rebased against Juzhe's latest refactoring.

Regards
 Robin

gcc/ChangeLog:

	* config/riscv/autovec.md (<optab><mode>2): Add vneg/vnot.
	(abs<mode>2): Add.
	* config/riscv/riscv-protos.h (emit_vlmax_masked_insn): Declare.
	* config/riscv/riscv-v.cc (emit_vlmax_masked_insn): New
	function.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/rvv.exp: Add unop tests.
	* gcc.target/riscv/rvv/autovec/unop/abs-run.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/abs-template.h: New test.
	* gcc.target/riscv/rvv/autovec/unop/vneg-run.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vneg-template.h: New test.
	* gcc.target/riscv/rvv/autovec/unop/vnot-run.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vnot-template.h: New test.
---
 gcc/config/riscv/autovec.md                   | 45 ++++++++++++++++++-
 gcc/config/riscv/riscv-protos.h               |  1 +
 gcc/config/riscv/riscv-v.cc                   | 16 +++++++
 .../riscv/rvv/autovec/unop/abs-run.c          | 29 ++++++++++++
 .../riscv/rvv/autovec/unop/abs-rv32gcv.c      |  7 +++
 .../riscv/rvv/autovec/unop/abs-rv64gcv.c      |  7 +++
 .../riscv/rvv/autovec/unop/abs-template.h     | 26 +++++++++++
 .../riscv/rvv/autovec/unop/vneg-run.c         | 29 ++++++++++++
 .../riscv/rvv/autovec/unop/vneg-rv32gcv.c     |  6 +++
 .../riscv/rvv/autovec/unop/vneg-rv64gcv.c     |  6 +++
 .../riscv/rvv/autovec/unop/vneg-template.h    | 18 ++++++++
 .../riscv/rvv/autovec/unop/vnot-run.c         | 43 ++++++++++++++++++
 .../riscv/rvv/autovec/unop/vnot-rv32gcv.c     |  6 +++
 .../riscv/rvv/autovec/unop/vnot-rv64gcv.c     |  6 +++
 .../riscv/rvv/autovec/unop/vnot-template.h    | 22 +++++++++
 gcc/testsuite/gcc.target/riscv/rvv/rvv.exp    |  2 +
 16 files changed, 268 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
  

Comments

juzhe.zhong@rivai.ai May 25, 2023, 10:50 a.m. UTC | #1
+(define_expand "abs<mode>2"
+  [(set (match_operand:VI 0 "register_operand")
+    (match_operand:VI 1 "register_operand"))]
+  "TARGET_VECTOR"
+{
+  rtx zero = gen_const_vec_duplicate (<MODE>mode, GEN_INT (0));
+  machine_mode mask_mode = riscv_vector::get_mask_mode (<MODE>mode).require ();
+  rtx mask = gen_reg_rtx (mask_mode);
+  riscv_vector::expand_vec_cmp (mask, LT, operands[1], zero);
+
+  /* For masking we need two more operands than a regular unop, the mask
+     itself and the maskoff operand.  */
+  rtx ops[] = {operands[0], mask, operands[1], operands[1]};
+  riscv_vector::emit_vlmax_masked_insn (code_for_pred (NEG, <MODE>mode),
+ riscv_vector::RVV_UNOP + 2, ops);
+  DONE;
+})

+/* This function emits a masked instruction.  */
+void
+emit_vlmax_masked_insn (unsigned icode, int op_num, rtx *ops)
+{
+  machine_mode dest_mode = GET_MODE (ops[0]);
+  machine_mode mask_mode = get_mask_mode (dest_mode).require ();
+  insn_expander<11> e (/*OP_NUM*/ op_num, /*HAS_DEST_P*/ true,
+        /*FULLY_UNMASKED_P*/ false,
+        /*USE_REAL_MERGE_P*/ true,
+        /*HAS_AVL_P*/ true,
+        /*VLMAX_P*/ true, dest_mode, mask_mode);
+  e.set_policy (TAIL_ANY);
+  e.set_policy (MASK_ANY);
+  e.emit_insn ((enum insn_code) icode, ops);
+}

I think it's logically incorrect.  For ABS, you want:

operands[0] = operads[1] > 0 ? operands[1] :  (-operands[1])
So you should do this following sequence:

vmslt v0,v1,0
vneg v1,v1v0.t (should use Mask undisturbed)

Here I see you set:
e.set_policy (MASK_ANY); which is incorrect.
You should use e.set_policy (MASK_UNDISTURBED); instead.

Your testcases fail to catch this issue (you should create a testcase to catch this bug with this patch implementation.)

Besides, 
riscv_vector::RVV_UNOP + 2, ops);

You should not use RVV_UNOP+2. Instead, you should add an enum call RVV_UNOP_MU and replace it.

Thanks.


juzhe.zhong@rivai.ai
 
From: Robin Dapp
Date: 2023-05-25 18:08
To: gcc-patches; Kito Cheng; palmer; juzhe.zhong@rivai.ai; jeffreyalaw
CC: rdapp.gcc
Subject: [PATCH v2] RISC-V: Implement autovec abs, vneg, vnot.
Hi,
 
this patch implements abs<mode>2, vneg<mode>2 and vnot<mode>2 expanders
for integer vector registers and adds tests for them.
 
v2 is rebased against Juzhe's latest refactoring.
 
Regards
Robin
 
gcc/ChangeLog:
 
* config/riscv/autovec.md (<optab><mode>2): Add vneg/vnot.
(abs<mode>2): Add.
* config/riscv/riscv-protos.h (emit_vlmax_masked_insn): Declare.
* config/riscv/riscv-v.cc (emit_vlmax_masked_insn): New
function.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/rvv.exp: Add unop tests.
* gcc.target/riscv/rvv/autovec/unop/abs-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-template.h: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-template.h: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-template.h: New test.
---
gcc/config/riscv/autovec.md                   | 45 ++++++++++++++++++-
gcc/config/riscv/riscv-protos.h               |  1 +
gcc/config/riscv/riscv-v.cc                   | 16 +++++++
.../riscv/rvv/autovec/unop/abs-run.c          | 29 ++++++++++++
.../riscv/rvv/autovec/unop/abs-rv32gcv.c      |  7 +++
.../riscv/rvv/autovec/unop/abs-rv64gcv.c      |  7 +++
.../riscv/rvv/autovec/unop/abs-template.h     | 26 +++++++++++
.../riscv/rvv/autovec/unop/vneg-run.c         | 29 ++++++++++++
.../riscv/rvv/autovec/unop/vneg-rv32gcv.c     |  6 +++
.../riscv/rvv/autovec/unop/vneg-rv64gcv.c     |  6 +++
.../riscv/rvv/autovec/unop/vneg-template.h    | 18 ++++++++
.../riscv/rvv/autovec/unop/vnot-run.c         | 43 ++++++++++++++++++
.../riscv/rvv/autovec/unop/vnot-rv32gcv.c     |  6 +++
.../riscv/rvv/autovec/unop/vnot-rv64gcv.c     |  6 +++
.../riscv/rvv/autovec/unop/vnot-template.h    | 22 +++++++++
gcc/testsuite/gcc.target/riscv/rvv/rvv.exp    |  2 +
16 files changed, 268 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
 
diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index 7fe4d94de39..8d26f16d5dc 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -145,7 +145,7 @@ (define_expand "<optab><mode>3"
})
;; -------------------------------------------------------------------------
-;; ---- [INT] Binary shifts by scalar.
+;; ---- [INT] Binary shifts by vector.
;; -------------------------------------------------------------------------
;; Includes:
;; - vsll.vv/vsra.vv/vsrl.vv
@@ -373,3 +373,46 @@ (define_expand "vcondu<V:mode><VI:mode>"
     DONE;
   }
)
+
+;; =========================================================================
+;; == Unary arithmetic
+;; =========================================================================
+
+;; -------------------------------------------------------------------------------
+;; ---- [INT] Unary operations
+;; -------------------------------------------------------------------------------
+;; Includes:
+;; - vneg.v/vnot.v
+;; -------------------------------------------------------------------------------
+(define_expand "<optab><mode>2"
+  [(set (match_operand:VI 0 "register_operand")
+    (any_int_unop:VI
+     (match_operand:VI 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------------
+;; - ABS expansion to vmslt and vneg
+;; -------------------------------------------------------------------------------
+
+(define_expand "abs<mode>2"
+  [(set (match_operand:VI 0 "register_operand")
+    (match_operand:VI 1 "register_operand"))]
+  "TARGET_VECTOR"
+{
+  rtx zero = gen_const_vec_duplicate (<MODE>mode, GEN_INT (0));
+  machine_mode mask_mode = riscv_vector::get_mask_mode (<MODE>mode).require ();
+  rtx mask = gen_reg_rtx (mask_mode);
+  riscv_vector::expand_vec_cmp (mask, LT, operands[1], zero);
+
+  /* For masking we need two more operands than a regular unop, the mask
+     itself and the maskoff operand.  */
+  rtx ops[] = {operands[0], mask, operands[1], operands[1]};
+  riscv_vector::emit_vlmax_masked_insn (code_for_pred (NEG, <MODE>mode),
+ riscv_vector::RVV_UNOP + 2, ops);
+  DONE;
+})
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 36419c95bbd..a24a47a42db 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -180,6 +180,7 @@ void emit_nonvlmax_insn (unsigned, int, rtx *, rtx);
void emit_vlmax_merge_insn (unsigned, int, rtx *);
void emit_vlmax_cmp_insn (unsigned, rtx *);
void emit_vlmax_cmp_mu_insn (unsigned, rtx *);
+void emit_vlmax_masked_insn (unsigned, int, rtx *);
enum vlmul_type get_vlmul (machine_mode);
unsigned int get_ratio (machine_mode);
unsigned int get_nf (machine_mode);
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index f71ad9e46a1..2fed3865ea5 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -426,6 +426,22 @@ emit_vlmax_cmp_mu_insn (unsigned icode, rtx *ops)
   e.emit_insn ((enum insn_code) icode, ops);
}
+/* This function emits a masked instruction.  */
+void
+emit_vlmax_masked_insn (unsigned icode, int op_num, rtx *ops)
+{
+  machine_mode dest_mode = GET_MODE (ops[0]);
+  machine_mode mask_mode = get_mask_mode (dest_mode).require ();
+  insn_expander<11> e (/*OP_NUM*/ op_num, /*HAS_DEST_P*/ true,
+        /*FULLY_UNMASKED_P*/ false,
+        /*USE_REAL_MERGE_P*/ true,
+        /*HAS_AVL_P*/ true,
+        /*VLMAX_P*/ true, dest_mode, mask_mode);
+  e.set_policy (TAIL_ANY);
+  e.set_policy (MASK_ANY);
+  e.emit_insn ((enum insn_code) icode, ops);
+}
+
/* Expand series const vector.  */
void
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
new file mode 100644
index 00000000000..d6aaa785055
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
@@ -0,0 +1,29 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE) \
+  TYPE a##TYPE[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    a##TYPE[i] = i - 127;             \
+  }                             \
+  vabs_##TYPE (a##TYPE, a##TYPE, SZ);         \
+  for (int i = 0; i < SZ; i++) \
+    assert (a##TYPE[i] == abs (i - 127));       \
+
+#define RUN_ALL()                         \
+ RUN(int8_t)                                 \
+ RUN(int16_t)                                 \
+ RUN(int32_t)                                 \
+ RUN(int64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
new file mode 100644
index 00000000000..cbe0ba0b0ba
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
new file mode 100644
index 00000000000..c0c52176a42
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
@@ -0,0 +1,7 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
new file mode 100644
index 00000000000..a54238c8ff2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+  __attribute__((noipa)) \
+  void vabs_##TYPE (TYPE *dst, TYPE *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] = abs (a[i]); \
+  }
+
+#define TEST_TYPE2(TYPE) \
+  __attribute__((noipa)) \
+  void vabs_##TYPE (TYPE *dst, TYPE *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] = llabs (a[i]); \
+  }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE2(int64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
new file mode 100644
index 00000000000..abeb50f21ea
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
@@ -0,0 +1,29 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE) \
+  TYPE a##TYPE[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    a##TYPE[i] = i - 127;             \
+  }                             \
+  vneg_##TYPE (a##TYPE, a##TYPE, SZ); \
+  for (int i = 0; i < SZ; i++) \
+    assert (a##TYPE[i] == -(i - 127));
+
+#define RUN_ALL()                         \
+ RUN(int8_t)                                 \
+ RUN(int16_t)                                 \
+ RUN(int32_t)                                 \
+ RUN(int64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
new file mode 100644
index 00000000000..69d9ebb0953
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
new file mode 100644
index 00000000000..d2c2e17c13e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
new file mode 100644
index 00000000000..f766a3b6461
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
@@ -0,0 +1,18 @@
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+  __attribute__((noipa)) \
+  void vneg_##TYPE (TYPE *dst, TYPE *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] =  -a[i]; \
+  }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE(int64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
new file mode 100644
index 00000000000..2870b21a218
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
@@ -0,0 +1,43 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE) \
+  TYPE a##TYPE[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    a##TYPE[i] = i - 127;             \
+  }                             \
+  vnot_##TYPE (a##TYPE, a##TYPE, SZ);         \
+  for (int i = 0; i < SZ; i++) \
+    assert (a##TYPE[i] == (TYPE)~(i - 127));
+
+#define RUN2(TYPE) \
+  TYPE a##TYPE[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    a##TYPE[i] = i;             \
+  }                             \
+  vnot_##TYPE (a##TYPE, a##TYPE, SZ);         \
+  for (int i = 0; i < SZ; i++) \
+    assert (a##TYPE[i] == (TYPE)~i);
+
+#define RUN_ALL()                         \
+ RUN(int8_t)                                 \
+ RUN(int16_t)                                 \
+ RUN(int32_t)                                 \
+ RUN(int64_t)                                 \
+ RUN(uint8_t)                                 \
+ RUN(uint16_t)                                 \
+ RUN(uint32_t)                                 \
+ RUN(uint64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
new file mode 100644
index 00000000000..ecc4316bd4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
new file mode 100644
index 00000000000..67e28af2cd8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
new file mode 100644
index 00000000000..b7a63f04485
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
@@ -0,0 +1,22 @@
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+  __attribute__((noipa)) \
+  void vnot_##TYPE (TYPE *dst, TYPE *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] =  ~a[i]; \
+  }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(uint8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(uint16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE(uint32_t) \
+ TEST_TYPE(int64_t) \
+ TEST_TYPE(uint64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index 9809a421fc8..f5c022d0a30 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -65,6 +65,8 @@ foreach op $AUTOVEC_TEST_OPTS {
     "" "$op"
   dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/cmp/*.\[cS\]]] \
     "" "$op"
+  dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/unop/*.\[cS\]]] \
+    "" "$op"
}
# VLS-VLMAX tests
-- 
2.40.1
  
Robin Dapp May 25, 2023, 12:32 p.m. UTC | #2
> I think it's logically incorrect.  For ABS, you want:
> 
> operands[0] = operads[1] > 0 ? operands[1] :  (-operands[1])
> So you should do this following sequence:
> 
> vmslt v0,v1,0
> vneg v1,v1v0.t (should use Mask undisturbed)

Yes, this is the emitted sequence, but the vsetvli mask is indeed
wrong.  Just got lucky there.  Or what else did you mean with
logically incorrect?

> Here I see you set:
> e.set_policy (MASK_ANY); which is incorrect.
> You should use e.set_policy (MASK_UNDISTURBED); instead.> 
> Your testcases fail to catch this issue (you should create a testcase
> to catch this bug with this patch implementation.)

Added a regex to look for "ta,mu".

> You should not use RVV_UNOP+2. Instead, you should add an enum call
> RVV_UNOP_MU and replace it.

I was a bit weary of adding yet another, would rather have that
unified somehow, but well ;) Another time.  Adjusted locally.
  
juzhe.zhong@rivai.ai May 25, 2023, 1:05 p.m. UTC | #3
>> Yes, this is the emitted sequence, but the vsetvli mask is indeed
>> wrong.  Just got lucky there.  Or what else did you mean with
>> logically incorrect?
Oh, sorry. I didn't mean this patch logically incorrect.
I mean the MASK_ANY is logicall incorrect.
This patch is ok to me as long as you change MASK TAIL into MASK_UNDISTURBED.

Beside, V2 patch should change this:
emit_vlmax_masked_insn (unsigned icode, int op_num, rtx *ops)

change it into emit_vlmax_masked_mu_insn .


Thanks.


juzhe.zhong@rivai.ai
 
From: Robin Dapp
Date: 2023-05-25 20:32
To: juzhe.zhong@rivai.ai; gcc-patches; kito.cheng; palmer; jeffreyalaw
CC: rdapp.gcc
Subject: Re: [PATCH v2] RISC-V: Implement autovec abs, vneg, vnot.
> I think it's logically incorrect.  For ABS, you want:
> 
> operands[0] = operads[1] > 0 ? operands[1] :  (-operands[1])
> So you should do this following sequence:
> 
> vmslt v0,v1,0
> vneg v1,v1v0.t (should use Mask undisturbed)
 
Yes, this is the emitted sequence, but the vsetvli mask is indeed
wrong.  Just got lucky there.  Or what else did you mean with
logically incorrect?
 
> Here I see you set:
> e.set_policy (MASK_ANY); which is incorrect.
> You should use e.set_policy (MASK_UNDISTURBED); instead.> 
> Your testcases fail to catch this issue (you should create a testcase
> to catch this bug with this patch implementation.)
 
Added a regex to look for "ta,mu".
 
> You should not use RVV_UNOP+2. Instead, you should add an enum call
> RVV_UNOP_MU and replace it.
 
I was a bit weary of adding yet another, would rather have that
unified somehow, but well ;) Another time.  Adjusted locally.
  
Robin Dapp May 25, 2023, 2:43 p.m. UTC | #4
> Beside, V2 patch should change this:
> emit_vlmax_masked_insn (unsigned icode, int op_num, rtx *ops)
> 
> change it into emit_vlmax_masked_mu_insn .

V3 is inline with these changes.

This patch implements abs<mode>2, vneg<mode>2 and vnot<mode>2 expanders
for integer vector registers and adds tests for them.

gcc/ChangeLog:

	* config/riscv/autovec.md (<optab><mode>2): Add vneg/vnot.
	(abs<mode>2): Add.
	* config/riscv/riscv-protos.h (emit_vlmax_masked_mu_insn):
	Declare.
	* config/riscv/riscv-v.cc (emit_vlmax_masked_mu_insn): New
	function.

gcc/testsuite/ChangeLog:

	* gcc.target/riscv/rvv/rvv.exp: Add unop tests.
	* gcc.target/riscv/rvv/autovec/unop/abs-run.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/abs-template.h: New test.
	* gcc.target/riscv/rvv/autovec/unop/vneg-run.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vneg-template.h: New test.
	* gcc.target/riscv/rvv/autovec/unop/vnot-run.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c: New test.
	* gcc.target/riscv/rvv/autovec/unop/vnot-template.h: New test.
---
 gcc/config/riscv/autovec.md                   | 43 ++++++++++++++++++-
 gcc/config/riscv/riscv-protos.h               |  2 +
 gcc/config/riscv/riscv-v.cc                   | 16 +++++++
 .../riscv/rvv/autovec/unop/abs-run.c          | 39 +++++++++++++++++
 .../riscv/rvv/autovec/unop/abs-rv32gcv.c      |  8 ++++
 .../riscv/rvv/autovec/unop/abs-rv64gcv.c      |  8 ++++
 .../riscv/rvv/autovec/unop/abs-template.h     | 26 +++++++++++
 .../riscv/rvv/autovec/unop/vneg-run.c         | 29 +++++++++++++
 .../riscv/rvv/autovec/unop/vneg-rv32gcv.c     |  6 +++
 .../riscv/rvv/autovec/unop/vneg-rv64gcv.c     |  6 +++
 .../riscv/rvv/autovec/unop/vneg-template.h    | 18 ++++++++
 .../riscv/rvv/autovec/unop/vnot-run.c         | 43 +++++++++++++++++++
 .../riscv/rvv/autovec/unop/vnot-rv32gcv.c     |  6 +++
 .../riscv/rvv/autovec/unop/vnot-rv64gcv.c     |  6 +++
 .../riscv/rvv/autovec/unop/vnot-template.h    | 22 ++++++++++
 gcc/testsuite/gcc.target/riscv/rvv/rvv.exp    |  2 +
 16 files changed, 279 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
 create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h

diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index 7fe4d94de39..38216d9812f 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -145,7 +145,7 @@ (define_expand "<optab><mode>3"
 })
 
 ;; -------------------------------------------------------------------------
-;; ---- [INT] Binary shifts by scalar.
+;; ---- [INT] Binary shifts by vector.
 ;; -------------------------------------------------------------------------
 ;; Includes:
 ;; - vsll.vv/vsra.vv/vsrl.vv
@@ -373,3 +373,44 @@ (define_expand "vcondu<V:mode><VI:mode>"
     DONE;
   }
 )
+
+;; =========================================================================
+;; == Unary arithmetic
+;; =========================================================================
+
+;; -------------------------------------------------------------------------------
+;; ---- [INT] Unary operations
+;; -------------------------------------------------------------------------------
+;; Includes:
+;; - vneg.v/vnot.v
+;; -------------------------------------------------------------------------------
+(define_expand "<optab><mode>2"
+  [(set (match_operand:VI 0 "register_operand")
+    (any_int_unop:VI
+     (match_operand:VI 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------------
+;; - ABS expansion to vmslt and vneg
+;; -------------------------------------------------------------------------------
+
+(define_expand "abs<mode>2"
+  [(set (match_operand:VI 0 "register_operand")
+    (match_operand:VI 1 "register_operand"))]
+  "TARGET_VECTOR"
+{
+  rtx zero = gen_const_vec_duplicate (<MODE>mode, GEN_INT (0));
+  machine_mode mask_mode = riscv_vector::get_mask_mode (<MODE>mode).require ();
+  rtx mask = gen_reg_rtx (mask_mode);
+  riscv_vector::expand_vec_cmp (mask, LT, operands[1], zero);
+
+  rtx ops[] = {operands[0], mask, operands[1], operands[1]};
+  riscv_vector::emit_vlmax_masked_mu_insn (code_for_pred (NEG, <MODE>mode),
+					   riscv_vector::RVV_UNOP_MU, ops);
+  DONE;
+})
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 36419c95bbd..b6a8be5d90b 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -140,6 +140,7 @@ enum insn_type
   RVV_MERGE_OP = 4,
   RVV_CMP_OP = 4,
   RVV_CMP_MU_OP = RVV_CMP_OP + 2, /* +2 means mask and maskoff operand.  */
+  RVV_UNOP_MU = RVV_UNOP + 2,	  /* Likewise.  */
 };
 enum vlmul_type
 {
@@ -180,6 +181,7 @@ void emit_nonvlmax_insn (unsigned, int, rtx *, rtx);
 void emit_vlmax_merge_insn (unsigned, int, rtx *);
 void emit_vlmax_cmp_insn (unsigned, rtx *);
 void emit_vlmax_cmp_mu_insn (unsigned, rtx *);
+void emit_vlmax_masked_mu_insn (unsigned, int, rtx *);
 enum vlmul_type get_vlmul (machine_mode);
 unsigned int get_ratio (machine_mode);
 unsigned int get_nf (machine_mode);
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index f71ad9e46a1..6a2299bad7c 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -426,6 +426,22 @@ emit_vlmax_cmp_mu_insn (unsigned icode, rtx *ops)
   e.emit_insn ((enum insn_code) icode, ops);
 }
 
+/* This function emits a masked instruction.  */
+void
+emit_vlmax_masked_mu_insn (unsigned icode, int op_num, rtx *ops)
+{
+  machine_mode dest_mode = GET_MODE (ops[0]);
+  machine_mode mask_mode = get_mask_mode (dest_mode).require ();
+  insn_expander<11> e (/*OP_NUM*/ op_num, /*HAS_DEST_P*/ true,
+		       /*FULLY_UNMASKED_P*/ false,
+		       /*USE_REAL_MERGE_P*/ true,
+		       /*HAS_AVL_P*/ true,
+		       /*VLMAX_P*/ true, dest_mode, mask_mode);
+  e.set_policy (TAIL_ANY);
+  e.set_policy (MASK_UNDISTURBED);
+  e.emit_insn ((enum insn_code) icode, ops);
+}
+
 /* Expand series const vector.  */
 
 void
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
new file mode 100644
index 00000000000..7404dbe037e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
@@ -0,0 +1,39 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+#include <assert.h>
+
+#define SZ 128
+
+#define RUN(TYPE)				\
+  TYPE a##TYPE[SZ];				\
+  for (int i = 0; i < SZ; i++)			\
+    {                             		\
+      if (i & 1)				\
+	a##TYPE[i] = i - 64;            	\
+      else					\
+	a##TYPE[i] = i;            		\
+    }                             		\
+  vabs_##TYPE (a##TYPE, a##TYPE, SZ);	        \
+  for (int i = 0; i < SZ; i++)			\
+    {						\
+      printf ("%d %d %d\n", i, a##TYPE[i], i - 64);	\
+      if (i & 1)				\
+	assert (a##TYPE[i] == abs (i - 64));    \
+      else					\
+	assert (a##TYPE[i] == i);		\
+    }
+
+
+#define RUN_ALL()	                        \
+ RUN(int8_t)	                                \
+ RUN(int16_t)	                                \
+ RUN(int32_t)	                                \
+ RUN(int64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
new file mode 100644
index 00000000000..a8b92c9450f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvseti?vli\s+[a-z0-9,]+,ta,mu} 4 } } */
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg.v\sv[0-9]+,v[0-9]+,v0\.t} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
new file mode 100644
index 00000000000..2e7f0864ee7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvseti?vli\s+[a-z0-9,]+,ta,mu} 4 } } */
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg.v\sv[0-9]+,v[0-9]+,v0\.t} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
new file mode 100644
index 00000000000..882de9f4efb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) 				\
+  __attribute__((noipa))				\
+  void vabs_##TYPE (TYPE *dst, TYPE *a, int n)		\
+  {							\
+    for (int i = 0; i < n; i++)				\
+      dst[i] = abs (a[i]);				\
+  }
+
+#define TEST_TYPE2(TYPE) 				\
+  __attribute__((noipa))				\
+  void vabs_##TYPE (TYPE *dst, TYPE *a, int n)		\
+  {							\
+    for (int i = 0; i < n; i++)				\
+      dst[i] = llabs (a[i]);				\
+  }
+
+#define TEST_ALL()	\
+ TEST_TYPE(int8_t)	\
+ TEST_TYPE(int16_t)	\
+ TEST_TYPE(int32_t)	\
+ TEST_TYPE2(int64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
new file mode 100644
index 00000000000..abeb50f21ea
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
@@ -0,0 +1,29 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE)				\
+  TYPE a##TYPE[SZ];				\
+  for (int i = 0; i < SZ; i++)			\
+  {                             		\
+    a##TYPE[i] = i - 127;             		\
+  }                             		\
+  vneg_##TYPE (a##TYPE, a##TYPE, SZ);	\
+  for (int i = 0; i < SZ; i++)			\
+    assert (a##TYPE[i] == -(i - 127));
+
+#define RUN_ALL()	                        \
+ RUN(int8_t)	                                \
+ RUN(int16_t)	                                \
+ RUN(int32_t)	                                \
+ RUN(int64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
new file mode 100644
index 00000000000..69d9ebb0953
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
new file mode 100644
index 00000000000..d2c2e17c13e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
new file mode 100644
index 00000000000..f766a3b6461
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
@@ -0,0 +1,18 @@
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) 				\
+  __attribute__((noipa))				\
+  void vneg_##TYPE (TYPE *dst, TYPE *a, int n)		\
+  {							\
+    for (int i = 0; i < n; i++)				\
+      dst[i] =  -a[i];					\
+  }
+
+#define TEST_ALL()	\
+ TEST_TYPE(int8_t)	\
+ TEST_TYPE(int16_t)	\
+ TEST_TYPE(int32_t)	\
+ TEST_TYPE(int64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
new file mode 100644
index 00000000000..2870b21a218
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
@@ -0,0 +1,43 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE)				\
+  TYPE a##TYPE[SZ];				\
+  for (int i = 0; i < SZ; i++)			\
+  {                             		\
+    a##TYPE[i] = i - 127;             		\
+  }                             		\
+  vnot_##TYPE (a##TYPE, a##TYPE, SZ);	        \
+  for (int i = 0; i < SZ; i++)			\
+    assert (a##TYPE[i] == (TYPE)~(i - 127));
+
+#define RUN2(TYPE)				\
+  TYPE a##TYPE[SZ];				\
+  for (int i = 0; i < SZ; i++)			\
+  {                             		\
+    a##TYPE[i] = i;             		\
+  }                             		\
+  vnot_##TYPE (a##TYPE, a##TYPE, SZ);	        \
+  for (int i = 0; i < SZ; i++)			\
+    assert (a##TYPE[i] == (TYPE)~i);
+
+#define RUN_ALL()	                        \
+ RUN(int8_t)	                                \
+ RUN(int16_t)	                                \
+ RUN(int32_t)	                                \
+ RUN(int64_t)	                                \
+ RUN(uint8_t)	                                \
+ RUN(uint16_t)	                                \
+ RUN(uint32_t)	                                \
+ RUN(uint64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
new file mode 100644
index 00000000000..ecc4316bd4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
new file mode 100644
index 00000000000..67e28af2cd8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
new file mode 100644
index 00000000000..b7a63f04485
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
@@ -0,0 +1,22 @@
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) 				\
+  __attribute__((noipa))				\
+  void vnot_##TYPE (TYPE *dst, TYPE *a, int n)		\
+  {							\
+    for (int i = 0; i < n; i++)				\
+      dst[i] =  ~a[i];					\
+  }
+
+#define TEST_ALL()	\
+ TEST_TYPE(int8_t)	\
+ TEST_TYPE(uint8_t)	\
+ TEST_TYPE(int16_t)	\
+ TEST_TYPE(uint16_t)	\
+ TEST_TYPE(int32_t)	\
+ TEST_TYPE(uint32_t)	\
+ TEST_TYPE(int64_t)	\
+ TEST_TYPE(uint64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index 9809a421fc8..f5c022d0a30 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -65,6 +65,8 @@ foreach op $AUTOVEC_TEST_OPTS {
     "" "$op"
   dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/cmp/*.\[cS\]]] \
     "" "$op"
+  dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/unop/*.\[cS\]]] \
+    "" "$op"
 }
 
 # VLS-VLMAX tests
  
juzhe.zhong@rivai.ai May 25, 2023, 10:49 p.m. UTC | #5
LGTM this patch. Let's wait for kito's final approval.
Thanks.


juzhe.zhong@rivai.ai
 
From: Robin Dapp
Date: 2023-05-25 22:43
To: 钟居哲; gcc-patches; kito.cheng; palmer; Jeff Law
CC: rdapp.gcc
Subject: Re: [PATCH v2] RISC-V: Implement autovec abs, vneg, vnot.
> Beside, V2 patch should change this:
> emit_vlmax_masked_insn (unsigned icode, int op_num, rtx *ops)
> 
> change it into emit_vlmax_masked_mu_insn .
 
V3 is inline with these changes.
 
This patch implements abs<mode>2, vneg<mode>2 and vnot<mode>2 expanders
for integer vector registers and adds tests for them.
 
gcc/ChangeLog:
 
* config/riscv/autovec.md (<optab><mode>2): Add vneg/vnot.
(abs<mode>2): Add.
* config/riscv/riscv-protos.h (emit_vlmax_masked_mu_insn):
Declare.
* config/riscv/riscv-v.cc (emit_vlmax_masked_mu_insn): New
function.
 
gcc/testsuite/ChangeLog:
 
* gcc.target/riscv/rvv/rvv.exp: Add unop tests.
* gcc.target/riscv/rvv/autovec/unop/abs-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/abs-template.h: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vneg-template.h: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-run.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c: New test.
* gcc.target/riscv/rvv/autovec/unop/vnot-template.h: New test.
---
gcc/config/riscv/autovec.md                   | 43 ++++++++++++++++++-
gcc/config/riscv/riscv-protos.h               |  2 +
gcc/config/riscv/riscv-v.cc                   | 16 +++++++
.../riscv/rvv/autovec/unop/abs-run.c          | 39 +++++++++++++++++
.../riscv/rvv/autovec/unop/abs-rv32gcv.c      |  8 ++++
.../riscv/rvv/autovec/unop/abs-rv64gcv.c      |  8 ++++
.../riscv/rvv/autovec/unop/abs-template.h     | 26 +++++++++++
.../riscv/rvv/autovec/unop/vneg-run.c         | 29 +++++++++++++
.../riscv/rvv/autovec/unop/vneg-rv32gcv.c     |  6 +++
.../riscv/rvv/autovec/unop/vneg-rv64gcv.c     |  6 +++
.../riscv/rvv/autovec/unop/vneg-template.h    | 18 ++++++++
.../riscv/rvv/autovec/unop/vnot-run.c         | 43 +++++++++++++++++++
.../riscv/rvv/autovec/unop/vnot-rv32gcv.c     |  6 +++
.../riscv/rvv/autovec/unop/vnot-rv64gcv.c     |  6 +++
.../riscv/rvv/autovec/unop/vnot-template.h    | 22 ++++++++++
gcc/testsuite/gcc.target/riscv/rvv/rvv.exp    |  2 +
16 files changed, 279 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
 
diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index 7fe4d94de39..38216d9812f 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -145,7 +145,7 @@ (define_expand "<optab><mode>3"
})
;; -------------------------------------------------------------------------
-;; ---- [INT] Binary shifts by scalar.
+;; ---- [INT] Binary shifts by vector.
;; -------------------------------------------------------------------------
;; Includes:
;; - vsll.vv/vsra.vv/vsrl.vv
@@ -373,3 +373,44 @@ (define_expand "vcondu<V:mode><VI:mode>"
     DONE;
   }
)
+
+;; =========================================================================
+;; == Unary arithmetic
+;; =========================================================================
+
+;; -------------------------------------------------------------------------------
+;; ---- [INT] Unary operations
+;; -------------------------------------------------------------------------------
+;; Includes:
+;; - vneg.v/vnot.v
+;; -------------------------------------------------------------------------------
+(define_expand "<optab><mode>2"
+  [(set (match_operand:VI 0 "register_operand")
+    (any_int_unop:VI
+     (match_operand:VI 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------------
+;; - ABS expansion to vmslt and vneg
+;; -------------------------------------------------------------------------------
+
+(define_expand "abs<mode>2"
+  [(set (match_operand:VI 0 "register_operand")
+    (match_operand:VI 1 "register_operand"))]
+  "TARGET_VECTOR"
+{
+  rtx zero = gen_const_vec_duplicate (<MODE>mode, GEN_INT (0));
+  machine_mode mask_mode = riscv_vector::get_mask_mode (<MODE>mode).require ();
+  rtx mask = gen_reg_rtx (mask_mode);
+  riscv_vector::expand_vec_cmp (mask, LT, operands[1], zero);
+
+  rtx ops[] = {operands[0], mask, operands[1], operands[1]};
+  riscv_vector::emit_vlmax_masked_mu_insn (code_for_pred (NEG, <MODE>mode),
+    riscv_vector::RVV_UNOP_MU, ops);
+  DONE;
+})
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 36419c95bbd..b6a8be5d90b 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -140,6 +140,7 @@ enum insn_type
   RVV_MERGE_OP = 4,
   RVV_CMP_OP = 4,
   RVV_CMP_MU_OP = RVV_CMP_OP + 2, /* +2 means mask and maskoff operand.  */
+  RVV_UNOP_MU = RVV_UNOP + 2,   /* Likewise.  */
};
enum vlmul_type
{
@@ -180,6 +181,7 @@ void emit_nonvlmax_insn (unsigned, int, rtx *, rtx);
void emit_vlmax_merge_insn (unsigned, int, rtx *);
void emit_vlmax_cmp_insn (unsigned, rtx *);
void emit_vlmax_cmp_mu_insn (unsigned, rtx *);
+void emit_vlmax_masked_mu_insn (unsigned, int, rtx *);
enum vlmul_type get_vlmul (machine_mode);
unsigned int get_ratio (machine_mode);
unsigned int get_nf (machine_mode);
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index f71ad9e46a1..6a2299bad7c 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -426,6 +426,22 @@ emit_vlmax_cmp_mu_insn (unsigned icode, rtx *ops)
   e.emit_insn ((enum insn_code) icode, ops);
}
+/* This function emits a masked instruction.  */
+void
+emit_vlmax_masked_mu_insn (unsigned icode, int op_num, rtx *ops)
+{
+  machine_mode dest_mode = GET_MODE (ops[0]);
+  machine_mode mask_mode = get_mask_mode (dest_mode).require ();
+  insn_expander<11> e (/*OP_NUM*/ op_num, /*HAS_DEST_P*/ true,
+        /*FULLY_UNMASKED_P*/ false,
+        /*USE_REAL_MERGE_P*/ true,
+        /*HAS_AVL_P*/ true,
+        /*VLMAX_P*/ true, dest_mode, mask_mode);
+  e.set_policy (TAIL_ANY);
+  e.set_policy (MASK_UNDISTURBED);
+  e.emit_insn ((enum insn_code) icode, ops);
+}
+
/* Expand series const vector.  */
void
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
new file mode 100644
index 00000000000..7404dbe037e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
@@ -0,0 +1,39 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+#include <assert.h>
+
+#define SZ 128
+
+#define RUN(TYPE) \
+  TYPE a##TYPE[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+    {                             \
+      if (i & 1) \
+ a##TYPE[i] = i - 64;            \
+      else \
+ a##TYPE[i] = i;            \
+    }                             \
+  vabs_##TYPE (a##TYPE, a##TYPE, SZ);         \
+  for (int i = 0; i < SZ; i++) \
+    { \
+      printf ("%d %d %d\n", i, a##TYPE[i], i - 64); \
+      if (i & 1) \
+ assert (a##TYPE[i] == abs (i - 64));    \
+      else \
+ assert (a##TYPE[i] == i); \
+    }
+
+
+#define RUN_ALL()                         \
+ RUN(int8_t)                                 \
+ RUN(int16_t)                                 \
+ RUN(int32_t)                                 \
+ RUN(int64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
new file mode 100644
index 00000000000..a8b92c9450f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvseti?vli\s+[a-z0-9,]+,ta,mu} 4 } } */
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg.v\sv[0-9]+,v[0-9]+,v0\.t} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
new file mode 100644
index 00000000000..2e7f0864ee7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvseti?vli\s+[a-z0-9,]+,ta,mu} 4 } } */
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg.v\sv[0-9]+,v[0-9]+,v0\.t} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
new file mode 100644
index 00000000000..882de9f4efb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
@@ -0,0 +1,26 @@
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+  __attribute__((noipa)) \
+  void vabs_##TYPE (TYPE *dst, TYPE *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] = abs (a[i]); \
+  }
+
+#define TEST_TYPE2(TYPE) \
+  __attribute__((noipa)) \
+  void vabs_##TYPE (TYPE *dst, TYPE *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] = llabs (a[i]); \
+  }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE2(int64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
new file mode 100644
index 00000000000..abeb50f21ea
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
@@ -0,0 +1,29 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE) \
+  TYPE a##TYPE[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    a##TYPE[i] = i - 127;             \
+  }                             \
+  vneg_##TYPE (a##TYPE, a##TYPE, SZ); \
+  for (int i = 0; i < SZ; i++) \
+    assert (a##TYPE[i] == -(i - 127));
+
+#define RUN_ALL()                         \
+ RUN(int8_t)                                 \
+ RUN(int16_t)                                 \
+ RUN(int32_t)                                 \
+ RUN(int64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
new file mode 100644
index 00000000000..69d9ebb0953
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
new file mode 100644
index 00000000000..d2c2e17c13e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
new file mode 100644
index 00000000000..f766a3b6461
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
@@ -0,0 +1,18 @@
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+  __attribute__((noipa)) \
+  void vneg_##TYPE (TYPE *dst, TYPE *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] =  -a[i]; \
+  }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE(int64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
new file mode 100644
index 00000000000..2870b21a218
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
@@ -0,0 +1,43 @@
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE) \
+  TYPE a##TYPE[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    a##TYPE[i] = i - 127;             \
+  }                             \
+  vnot_##TYPE (a##TYPE, a##TYPE, SZ);         \
+  for (int i = 0; i < SZ; i++) \
+    assert (a##TYPE[i] == (TYPE)~(i - 127));
+
+#define RUN2(TYPE) \
+  TYPE a##TYPE[SZ]; \
+  for (int i = 0; i < SZ; i++) \
+  {                             \
+    a##TYPE[i] = i;             \
+  }                             \
+  vnot_##TYPE (a##TYPE, a##TYPE, SZ);         \
+  for (int i = 0; i < SZ; i++) \
+    assert (a##TYPE[i] == (TYPE)~i);
+
+#define RUN_ALL()                         \
+ RUN(int8_t)                                 \
+ RUN(int16_t)                                 \
+ RUN(int32_t)                                 \
+ RUN(int64_t)                                 \
+ RUN(uint8_t)                                 \
+ RUN(uint16_t)                                 \
+ RUN(uint32_t)                                 \
+ RUN(uint64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
new file mode 100644
index 00000000000..ecc4316bd4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
new file mode 100644
index 00000000000..67e28af2cd8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
@@ -0,0 +1,6 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
new file mode 100644
index 00000000000..b7a63f04485
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
@@ -0,0 +1,22 @@
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) \
+  __attribute__((noipa)) \
+  void vnot_##TYPE (TYPE *dst, TYPE *a, int n) \
+  { \
+    for (int i = 0; i < n; i++) \
+      dst[i] =  ~a[i]; \
+  }
+
+#define TEST_ALL() \
+ TEST_TYPE(int8_t) \
+ TEST_TYPE(uint8_t) \
+ TEST_TYPE(int16_t) \
+ TEST_TYPE(uint16_t) \
+ TEST_TYPE(int32_t) \
+ TEST_TYPE(uint32_t) \
+ TEST_TYPE(int64_t) \
+ TEST_TYPE(uint64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index 9809a421fc8..f5c022d0a30 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -65,6 +65,8 @@ foreach op $AUTOVEC_TEST_OPTS {
     "" "$op"
   dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/cmp/*.\[cS\]]] \
     "" "$op"
+  dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/unop/*.\[cS\]]] \
+    "" "$op"
}
# VLS-VLMAX tests
-- 
2.40.1
  
Jeff Law May 26, 2023, 4:36 p.m. UTC | #6
On 5/25/23 08:43, Robin Dapp wrote:
>> Beside, V2 patch should change this:
>> emit_vlmax_masked_insn (unsigned icode, int op_num, rtx *ops)
>>
>> change it into emit_vlmax_masked_mu_insn .
> 
> V3 is inline with these changes.
> 
> This patch implements abs<mode>2, vneg<mode>2 and vnot<mode>2 expanders
> for integer vector registers and adds tests for them.
> 
> gcc/ChangeLog:
> 
> 	* config/riscv/autovec.md (<optab><mode>2): Add vneg/vnot.
> 	(abs<mode>2): Add.
> 	* config/riscv/riscv-protos.h (emit_vlmax_masked_mu_insn):
> 	Declare.
> 	* config/riscv/riscv-v.cc (emit_vlmax_masked_mu_insn): New
> 	function.
> 
> gcc/testsuite/ChangeLog:
> 
> 	* gcc.target/riscv/rvv/rvv.exp: Add unop tests.
> 	* gcc.target/riscv/rvv/autovec/unop/abs-run.c: New test.
> 	* gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/unop/abs-template.h: New test.
> 	* gcc.target/riscv/rvv/autovec/unop/vneg-run.c: New test.
> 	* gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/unop/vneg-template.h: New test.
> 	* gcc.target/riscv/rvv/autovec/unop/vnot-run.c: New test.
> 	* gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c: New test.
> 	* gcc.target/riscv/rvv/autovec/unop/vnot-template.h: New test.
OK for the trunk.  BUt one comment inline...



> +
> +;; -------------------------------------------------------------------------------
> +;; - ABS expansion to vmslt and vneg
> +;; -------------------------------------------------------------------------------
> +
> +(define_expand "abs<mode>2"
> +  [(set (match_operand:VI 0 "register_operand")
> +    (match_operand:VI 1 "register_operand"))]
> +  "TARGET_VECTOR"
> +{
> +  rtx zero = gen_const_vec_duplicate (<MODE>mode, GEN_INT (0));
> +  machine_mode mask_mode = riscv_vector::get_mask_mode (<MODE>mode).require ();
> +  rtx mask = gen_reg_rtx (mask_mode);
> +  riscv_vector::expand_vec_cmp (mask, LT, operands[1], zero);
> +
> +  rtx ops[] = {operands[0], mask, operands[1], operands[1]};
> +  riscv_vector::emit_vlmax_masked_mu_insn (code_for_pred (NEG, <MODE>mode),
> +					   riscv_vector::RVV_UNOP_MU, ops);
> +  DONE;
> +})
So I'm a bit surprised we needed this.  Presumably we needed to expose 
the vector abs because the vectorizer doesn't have any code to 
synthesize abs from other primitives?

WRT the actual synthesis...  It looks like you're building a mask based 
on which elements are < 0 then doing a masked negation to flip them. 
Would this synthesis be better:

   t = -x;
   res = max (x, t);

That's the preferred synthesis at the gimple->rtl border for scalars.

Anyway, if we think that's a better synthesis, we can adjust as a 
follow-up patch.

So again, OK for the trunk.

jeff
  

Patch

diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index 7fe4d94de39..8d26f16d5dc 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -145,7 +145,7 @@  (define_expand "<optab><mode>3"
 })
 
 ;; -------------------------------------------------------------------------
-;; ---- [INT] Binary shifts by scalar.
+;; ---- [INT] Binary shifts by vector.
 ;; -------------------------------------------------------------------------
 ;; Includes:
 ;; - vsll.vv/vsra.vv/vsrl.vv
@@ -373,3 +373,46 @@  (define_expand "vcondu<V:mode><VI:mode>"
     DONE;
   }
 )
+
+;; =========================================================================
+;; == Unary arithmetic
+;; =========================================================================
+
+;; -------------------------------------------------------------------------------
+;; ---- [INT] Unary operations
+;; -------------------------------------------------------------------------------
+;; Includes:
+;; - vneg.v/vnot.v
+;; -------------------------------------------------------------------------------
+(define_expand "<optab><mode>2"
+  [(set (match_operand:VI 0 "register_operand")
+    (any_int_unop:VI
+     (match_operand:VI 1 "register_operand")))]
+  "TARGET_VECTOR"
+{
+  insn_code icode = code_for_pred (<CODE>, <MODE>mode);
+  riscv_vector::emit_vlmax_insn (icode, riscv_vector::RVV_UNOP, operands);
+  DONE;
+})
+
+;; -------------------------------------------------------------------------------
+;; - ABS expansion to vmslt and vneg
+;; -------------------------------------------------------------------------------
+
+(define_expand "abs<mode>2"
+  [(set (match_operand:VI 0 "register_operand")
+    (match_operand:VI 1 "register_operand"))]
+  "TARGET_VECTOR"
+{
+  rtx zero = gen_const_vec_duplicate (<MODE>mode, GEN_INT (0));
+  machine_mode mask_mode = riscv_vector::get_mask_mode (<MODE>mode).require ();
+  rtx mask = gen_reg_rtx (mask_mode);
+  riscv_vector::expand_vec_cmp (mask, LT, operands[1], zero);
+
+  /* For masking we need two more operands than a regular unop, the mask
+     itself and the maskoff operand.  */
+  rtx ops[] = {operands[0], mask, operands[1], operands[1]};
+  riscv_vector::emit_vlmax_masked_insn (code_for_pred (NEG, <MODE>mode),
+					riscv_vector::RVV_UNOP + 2, ops);
+  DONE;
+})
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 36419c95bbd..a24a47a42db 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -180,6 +180,7 @@  void emit_nonvlmax_insn (unsigned, int, rtx *, rtx);
 void emit_vlmax_merge_insn (unsigned, int, rtx *);
 void emit_vlmax_cmp_insn (unsigned, rtx *);
 void emit_vlmax_cmp_mu_insn (unsigned, rtx *);
+void emit_vlmax_masked_insn (unsigned, int, rtx *);
 enum vlmul_type get_vlmul (machine_mode);
 unsigned int get_ratio (machine_mode);
 unsigned int get_nf (machine_mode);
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index f71ad9e46a1..2fed3865ea5 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -426,6 +426,22 @@  emit_vlmax_cmp_mu_insn (unsigned icode, rtx *ops)
   e.emit_insn ((enum insn_code) icode, ops);
 }
 
+/* This function emits a masked instruction.  */
+void
+emit_vlmax_masked_insn (unsigned icode, int op_num, rtx *ops)
+{
+  machine_mode dest_mode = GET_MODE (ops[0]);
+  machine_mode mask_mode = get_mask_mode (dest_mode).require ();
+  insn_expander<11> e (/*OP_NUM*/ op_num, /*HAS_DEST_P*/ true,
+		       /*FULLY_UNMASKED_P*/ false,
+		       /*USE_REAL_MERGE_P*/ true,
+		       /*HAS_AVL_P*/ true,
+		       /*VLMAX_P*/ true, dest_mode, mask_mode);
+  e.set_policy (TAIL_ANY);
+  e.set_policy (MASK_ANY);
+  e.emit_insn ((enum insn_code) icode, ops);
+}
+
 /* Expand series const vector.  */
 
 void
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
new file mode 100644
index 00000000000..d6aaa785055
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-run.c
@@ -0,0 +1,29 @@ 
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE)				\
+  TYPE a##TYPE[SZ];				\
+  for (int i = 0; i < SZ; i++)			\
+  {                             		\
+    a##TYPE[i] = i - 127;             		\
+  }                             		\
+  vabs_##TYPE (a##TYPE, a##TYPE, SZ);	        \
+  for (int i = 0; i < SZ; i++)			\
+    assert (a##TYPE[i] == abs (i - 127));       \
+
+#define RUN_ALL()	                        \
+ RUN(int8_t)	                                \
+ RUN(int16_t)	                                \
+ RUN(int32_t)	                                \
+ RUN(int64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
new file mode 100644
index 00000000000..cbe0ba0b0ba
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv32gcv.c
@@ -0,0 +1,7 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
new file mode 100644
index 00000000000..c0c52176a42
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-rv64gcv.c
@@ -0,0 +1,7 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "abs-template.h"
+
+/* { dg-final { scan-assembler-times {\tvmslt\.vi} 4 } } */
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
new file mode 100644
index 00000000000..a54238c8ff2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/abs-template.h
@@ -0,0 +1,26 @@ 
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) 				\
+  __attribute__((noipa))				\
+  void vabs_##TYPE (TYPE *dst, TYPE *a, int n)	\
+  {							\
+    for (int i = 0; i < n; i++)				\
+      dst[i] = abs (a[i]);				\
+  }
+
+#define TEST_TYPE2(TYPE) 				\
+  __attribute__((noipa))				\
+  void vabs_##TYPE (TYPE *dst, TYPE *a, int n)	\
+  {							\
+    for (int i = 0; i < n; i++)				\
+      dst[i] = llabs (a[i]);				\
+  }
+
+#define TEST_ALL()	\
+ TEST_TYPE(int8_t)	\
+ TEST_TYPE(int16_t)	\
+ TEST_TYPE(int32_t)	\
+ TEST_TYPE2(int64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
new file mode 100644
index 00000000000..abeb50f21ea
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-run.c
@@ -0,0 +1,29 @@ 
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE)				\
+  TYPE a##TYPE[SZ];				\
+  for (int i = 0; i < SZ; i++)			\
+  {                             		\
+    a##TYPE[i] = i - 127;             		\
+  }                             		\
+  vneg_##TYPE (a##TYPE, a##TYPE, SZ);	\
+  for (int i = 0; i < SZ; i++)			\
+    assert (a##TYPE[i] == -(i - 127));
+
+#define RUN_ALL()	                        \
+ RUN(int8_t)	                                \
+ RUN(int16_t)	                                \
+ RUN(int32_t)	                                \
+ RUN(int64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
new file mode 100644
index 00000000000..69d9ebb0953
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv32gcv.c
@@ -0,0 +1,6 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
new file mode 100644
index 00000000000..d2c2e17c13e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-rv64gcv.c
@@ -0,0 +1,6 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vneg-template.h"
+
+/* { dg-final { scan-assembler-times {\tvneg\.v} 4 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
new file mode 100644
index 00000000000..f766a3b6461
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
@@ -0,0 +1,18 @@ 
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) 				\
+  __attribute__((noipa))				\
+  void vneg_##TYPE (TYPE *dst, TYPE *a, int n)		\
+  {							\
+    for (int i = 0; i < n; i++)				\
+      dst[i] =  -a[i];					\
+  }
+
+#define TEST_ALL()	\
+ TEST_TYPE(int8_t)	\
+ TEST_TYPE(int16_t)	\
+ TEST_TYPE(int32_t)	\
+ TEST_TYPE(int64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
new file mode 100644
index 00000000000..2870b21a218
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
@@ -0,0 +1,43 @@ 
+/* { dg-do run { target { riscv_vector } } } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+#include <assert.h>
+
+#define SZ 255
+
+#define RUN(TYPE)				\
+  TYPE a##TYPE[SZ];				\
+  for (int i = 0; i < SZ; i++)			\
+  {                             		\
+    a##TYPE[i] = i - 127;             		\
+  }                             		\
+  vnot_##TYPE (a##TYPE, a##TYPE, SZ);	        \
+  for (int i = 0; i < SZ; i++)			\
+    assert (a##TYPE[i] == (TYPE)~(i - 127));
+
+#define RUN2(TYPE)				\
+  TYPE a##TYPE[SZ];				\
+  for (int i = 0; i < SZ; i++)			\
+  {                             		\
+    a##TYPE[i] = i;             		\
+  }                             		\
+  vnot_##TYPE (a##TYPE, a##TYPE, SZ);	        \
+  for (int i = 0; i < SZ; i++)			\
+    assert (a##TYPE[i] == (TYPE)~i);
+
+#define RUN_ALL()	                        \
+ RUN(int8_t)	                                \
+ RUN(int16_t)	                                \
+ RUN(int32_t)	                                \
+ RUN(int64_t)	                                \
+ RUN(uint8_t)	                                \
+ RUN(uint16_t)	                                \
+ RUN(uint32_t)	                                \
+ RUN(uint64_t)
+
+int main ()
+{
+  RUN_ALL()
+}
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
new file mode 100644
index 00000000000..ecc4316bd4f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv32gcv.c
@@ -0,0 +1,6 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv32gcv -mabi=ilp32d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
new file mode 100644
index 00000000000..67e28af2cd8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-rv64gcv.c
@@ -0,0 +1,6 @@ 
+/* { dg-do compile } */
+/* { dg-additional-options "-std=c99 -fno-vect-cost-model -march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax" } */
+
+#include "vnot-template.h"
+
+/* { dg-final { scan-assembler-times {\tvnot\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
new file mode 100644
index 00000000000..b7a63f04485
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
@@ -0,0 +1,22 @@ 
+#include <stdlib.h>
+#include <stdint-gcc.h>
+
+#define TEST_TYPE(TYPE) 				\
+  __attribute__((noipa))				\
+  void vnot_##TYPE (TYPE *dst, TYPE *a, int n)		\
+  {							\
+    for (int i = 0; i < n; i++)				\
+      dst[i] =  ~a[i];					\
+  }
+
+#define TEST_ALL()	\
+ TEST_TYPE(int8_t)	\
+ TEST_TYPE(uint8_t)	\
+ TEST_TYPE(int16_t)	\
+ TEST_TYPE(uint16_t)	\
+ TEST_TYPE(int32_t)	\
+ TEST_TYPE(uint32_t)	\
+ TEST_TYPE(int64_t)	\
+ TEST_TYPE(uint64_t)
+
+TEST_ALL()
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index 9809a421fc8..f5c022d0a30 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -65,6 +65,8 @@  foreach op $AUTOVEC_TEST_OPTS {
     "" "$op"
   dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/cmp/*.\[cS\]]] \
     "" "$op"
+  dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/unop/*.\[cS\]]] \
+    "" "$op"
 }
 
 # VLS-VLMAX tests