diff --git a/gcc/config/riscv/autovec.md b/gcc/config/riscv/autovec.md
index ce0b46537ad..8060a5cdf90 100644
--- a/gcc/config/riscv/autovec.md
+++ b/gcc/config/riscv/autovec.md
@@ -161,7 +161,7 @@ (define_expand "<optab><mode>3"
 })
 
 ;; -------------------------------------------------------------------------
-;; ---- [INT] Binary shifts by scalar.
+;; ---- [INT] Binary shifts by vector.
 ;; -------------------------------------------------------------------------
 ;; Includes:
 ;; - vsll.vv/vsra.vv/vsrl.vv
@@ -180,3 +180,52 @@ (define_expand "v<optab><mode>3"
 				NULL_RTX, <VM>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"
+{
+  riscv_vector::emit_len_op (code_for_pred (<CODE>, <MODE>mode),
+			     operands[0], operands[1], NULL_RTX, <VM>mode);
+  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"
+{
+  // Create a zero constant.
+  rtx zero = gen_const_vec_duplicate (<MODE>mode, GEN_INT (0));
+
+  // Compare the source vector against it.
+  rtx ltcmp = gen_rtx_LT (<VM>mode, operands[1], zero);
+
+  // Mask out all non-negative elements.
+  rtx mask = gen_reg_rtx (<VM>mode);
+  riscv_vector::emit_len_cmp (code_for_pred_ltge (<MODE>mode),
+			      mask, ltcmp, operands[1], zero,
+			      NULL_RTX, <VM>mode);
+
+  // Emit a masked vneg, negating only the negative elements.
+  riscv_vector::emit_masked_len_op (code_for_pred (NEG, <MODE>mode),
+				    mask, operands[0], operands[1],
+				    NULL_RTX, <VM>mode);
+  DONE;
+})
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 12634d0ac1a..7c588086fa0 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -171,6 +171,8 @@ void emit_vlmax_reg_op (unsigned, rtx, rtx, rtx, machine_mode);
 void emit_len_op (unsigned, rtx, rtx, rtx, machine_mode);
 void emit_len_binop (unsigned, rtx, rtx, rtx, rtx, machine_mode,
 		     machine_mode = VOIDmode);
+void emit_masked_len_op (unsigned, rtx, rtx, rtx, rtx, machine_mode);
+void emit_len_cmp (unsigned, rtx, rtx, rtx, rtx, rtx, machine_mode);
 enum vlmul_type get_vlmul (machine_mode);
 unsigned int get_ratio (machine_mode);
 unsigned int get_nf (machine_mode);
@@ -181,6 +183,7 @@ int get_avl_type (rtx);
 unsigned int calculate_ratio (unsigned int, enum vlmul_type);
 enum tail_policy
 {
+  TAIL_UNDEFINED = -1,
   TAIL_UNDISTURBED = 0,
   TAIL_AGNOSTIC = 1,
   TAIL_ANY = 2,
@@ -188,12 +191,13 @@ enum tail_policy
 
 enum mask_policy
 {
+  MASK_UNDEFINED = -1,
   MASK_UNDISTURBED = 0,
   MASK_AGNOSTIC = 1,
   MASK_ANY = 2,
 };
-enum tail_policy get_prefer_tail_policy ();
-enum mask_policy get_prefer_mask_policy ();
+enum tail_policy get_preferred_tail_policy ();
+enum mask_policy get_preferred_mask_policy ();
 rtx get_avl_type_rtx (enum avl_type);
 opt_machine_mode get_vector_mode (scalar_mode, poly_uint64);
 opt_machine_mode get_tuple_mode (machine_mode, unsigned int);
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index d65e7300303..64ad3970267 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -54,11 +54,11 @@ namespace riscv_vector {
 static bool
 const_vlmax_p (machine_mode mode)
 {
-  poly_uint64 nuints = GET_MODE_NUNITS (mode);
+  poly_uint64 nunits = GET_MODE_NUNITS (mode);
 
-  return nuints.is_constant ()
+  return nunits.is_constant ()
     /* The vsetivli can only hold register 0~31.  */
-    ? (IN_RANGE (nuints.to_constant (), 0, 31))
+    ? (IN_RANGE (nunits.to_constant (), 0, 31))
     /* Only allowed in VLS-VLMAX mode.  */
     : false;
 }
@@ -66,38 +66,68 @@ const_vlmax_p (machine_mode mode)
 template <int MAX_OPERANDS> class insn_expander
 {
 public:
-  insn_expander () : m_opno (0), has_dest(false) {}
+  insn_expander () : m_opno (0), has_dest (false) {}
+
   void add_output_operand (rtx x, machine_mode mode)
   {
     create_output_operand (&m_ops[m_opno++], x, mode);
     gcc_assert (m_opno <= MAX_OPERANDS);
   }
+
+  void add_source_operand (rtx x, machine_mode mode)
+    {
+      add_src (x);
+      add_input_operand (x, mode);
+    }
+
   void add_input_operand (rtx x, machine_mode mode)
   {
     create_input_operand (&m_ops[m_opno++], x, mode);
     gcc_assert (m_opno <= MAX_OPERANDS);
   }
+
   void add_all_one_mask_operand (machine_mode mode)
   {
     add_input_operand (CONSTM1_RTX (mode), mode);
   }
+
   void add_vundef_operand (machine_mode mode)
   {
     add_input_operand (RVV_VUNDEF (mode), mode);
   }
-  void add_policy_operand (enum tail_policy vta, enum mask_policy vma)
+
+  void add_policy_operands (enum tail_policy vta = TAIL_UNDEFINED,
+			    enum mask_policy vma = MASK_UNDEFINED)
   {
-    rtx tail_policy_rtx = gen_int_mode (vta, Pmode);
-    rtx mask_policy_rtx = gen_int_mode (vma, Pmode);
-    add_input_operand (tail_policy_rtx, Pmode);
-    add_input_operand (mask_policy_rtx, Pmode);
+    /* If no policies were specified, use the default ones.  */
+    if (vta == TAIL_UNDEFINED)
+      vta = get_preferred_tail_policy ();
+    if (vma == MASK_UNDEFINED)
+      vma = get_preferred_mask_policy ();
+
+    /* RVV Spec 3.4.3.
+       Mask destination tail elements are always treated as tail-agnostic,
+       regardless of the setting of vta.  */
+    if (!is_mask_destination_instruction ())
+      {
+	rtx tail_policy_rtx = gen_int_mode (vta, Pmode);
+	add_input_operand (tail_policy_rtx, Pmode);
+      }
+
+    /* RVV Spec 15.1.
+       Vector mask logical instructions are always unmasked.  */
+    if (!is_mask_logical_instruction ())
+      {
+	rtx mask_policy_rtx = gen_int_mode (vma, Pmode);
+	add_input_operand (mask_policy_rtx, Pmode);
+      }
   }
   void add_avl_type_operand (avl_type type)
   {
     add_input_operand (gen_int_mode (type, Pmode), Pmode);
   }
 
-  void set_dest_and_mask (rtx mask, rtx dest, machine_mode mask_mode)
+  void set_dest_and_mask (rtx dest, rtx mask, machine_mode mask_mode)
   {
     dest_mode = GET_MODE (dest);
     has_dest = true;
@@ -133,8 +163,7 @@ public:
 
       add_input_operand (len, Pmode);
 
-      if (GET_MODE_CLASS (dest_mode) != MODE_VECTOR_BOOL)
-	add_policy_operand (get_prefer_tail_policy (), get_prefer_mask_policy ());
+      add_policy_operands ();
 
       add_avl_type_operand (vlmax_p ? avl_type::VLMAX : avl_type::NONVLMAX);
     }
@@ -150,9 +179,36 @@ public:
       expand_insn (icode, m_opno, m_ops);
   }
 
+  bool is_mask_destination_instruction ()
+    {
+      gcc_assert (has_dest);
+      return (GET_MODE_CLASS (dest_mode) == MODE_VECTOR_BOOL);
+    }
+
+  bool is_mask_logical_instruction ()
+    {
+      if (!is_mask_destination_instruction ())
+	return false;
+
+      if (!srcs.length ())
+	return false;
+
+      for (rtx src : srcs)
+	if (GET_MODE_CLASS (GET_MODE (src)) != MODE_VECTOR_BOOL)
+	  return false;
+
+      return true;
+    }
+
+  void add_src (rtx src)
+    {
+      srcs.quick_push (src);
+    }
+
 private:
   int m_opno;
   bool has_dest;
+  auto_vec<rtx, 3> srcs;
   machine_mode dest_mode;
   expand_operand m_ops[MAX_OPERANDS];
 };
@@ -252,9 +308,9 @@ emit_pred_op (unsigned icode, rtx mask, rtx dest, rtx src, rtx len,
 	      machine_mode mask_mode, bool force_vlmax = false)
 {
   insn_expander<8> e;
-  e.set_dest_and_mask (mask, dest, mask_mode);
+  e.set_dest_and_mask (dest, mask, mask_mode);
 
-  e.add_input_operand (src, GET_MODE (src));
+  e.add_source_operand (src, GET_MODE (src));
 
   e.set_len_and_policy (len, force_vlmax);
 
@@ -269,20 +325,40 @@ emit_pred_binop (unsigned icode, rtx mask, rtx dest, rtx src1, rtx src2,
 		 machine_mode scalar_mode = VOIDmode)
 {
   insn_expander<9> e;
-  e.set_dest_and_mask (mask, dest, mask_mode);
+  e.set_dest_and_mask (dest, mask, mask_mode);
 
   gcc_assert (VECTOR_MODE_P (GET_MODE (src1))
 	      || VECTOR_MODE_P (GET_MODE (src2)));
 
   if (VECTOR_MODE_P (GET_MODE (src1)))
-    e.add_input_operand (src1, GET_MODE (src1));
+    e.add_source_operand (src1, GET_MODE (src1));
   else
-    e.add_input_operand (src1, scalar_mode);
+    e.add_source_operand (src1, scalar_mode);
 
   if (VECTOR_MODE_P (GET_MODE (src2)))
-    e.add_input_operand (src2, GET_MODE (src2));
+    e.add_source_operand (src2, GET_MODE (src2));
   else
-    e.add_input_operand (src2, scalar_mode);
+    e.add_source_operand (src2, scalar_mode);
+
+  e.set_len_and_policy (len);
+
+  e.expand ((enum insn_code) icode, MEM_P (dest) || MEM_P (src1) || MEM_P (src2));
+}
+
+/* Emit an RVV comparison.  */
+static void
+emit_pred_cmp (unsigned icode, rtx mask, rtx dest, rtx cmp,
+	       rtx src1, rtx src2,
+	       rtx len, machine_mode mask_mode)
+{
+  insn_expander<9> e;
+
+  e.set_dest_and_mask (dest, mask, mask_mode);
+
+  e.add_input_operand (cmp, GET_MODE (cmp));
+
+  e.add_source_operand (src1, GET_MODE (src1));
+  e.add_source_operand (src2, GET_MODE (src2));
 
   e.set_len_and_policy (len);
 
@@ -332,6 +408,8 @@ emit_vlmax_reg_op (unsigned icode, rtx dest, rtx src, rtx len,
 		/* Force VLMAX */ true);
 }
 
+/* Emit a binary operation with sources SRC1 and SRC2 and a given length
+   LEN.  */
 void
 emit_len_binop (unsigned icode, rtx dest, rtx src1, rtx src2, rtx len,
 		machine_mode mask_mode, machine_mode scalar_mode)
@@ -340,13 +418,29 @@ emit_len_binop (unsigned icode, rtx dest, rtx src1, rtx src2, rtx len,
 		   mask_mode, scalar_mode);
 }
 
+/* Emit a masked operation with a given length LEN.  */
+void
+emit_masked_len_op (unsigned icode, rtx mask, rtx dest, rtx src, rtx len,
+		    machine_mode mask_mode)
+{
+  emit_pred_op (icode, mask, dest, src, len, mask_mode);
+}
+
+/* Emit an unmasked comparison whose result is stored in the mask DEST.  */
+void
+emit_len_cmp (unsigned icode, rtx dest, rtx op, rtx src1, rtx src2,
+	      rtx len, machine_mode mask_mode)
+{
+  emit_pred_cmp (icode, NULL_RTX, dest, op, src1, src2, len, mask_mode);
+}
+
 /* Emit vid.v instruction.  */
 
 static void
 emit_index_op (rtx dest, machine_mode mask_mode)
 {
   insn_expander<7> e;
-  e.set_dest_and_mask (NULL, dest, mask_mode);
+  e.set_dest_and_mask (dest, NULL, mask_mode);
 
   e.set_len_and_policy (NULL, true);
 
@@ -621,9 +715,9 @@ get_ma (rtx ma)
   return INTVAL (ma);
 }
 
-/* Get prefer tail policy.  */
+/* Get preferred tail policy.  */
 enum tail_policy
-get_prefer_tail_policy ()
+get_preferred_tail_policy ()
 {
   /* TODO: By default, we choose to use TAIL_ANY which allows
      compiler pick up either agnostic or undisturbed. Maybe we
@@ -632,9 +726,9 @@ get_prefer_tail_policy ()
   return TAIL_ANY;
 }
 
-/* Get prefer mask policy.  */
+/* Get preferred mask policy.  */
 enum mask_policy
-get_prefer_mask_policy ()
+get_preferred_mask_policy ()
 {
   /* TODO: By default, we choose to use MASK_ANY which allows
      compiler pick up either agnostic or undisturbed. Maybe we
@@ -935,8 +1029,8 @@ slide1_sew64_helper (int unspec, machine_mode mode, machine_mode demote_mode,
     }
 
   rtx temp = gen_reg_rtx (demote_mode);
-  rtx ta = gen_int_mode (get_prefer_tail_policy (), Pmode);
-  rtx ma = gen_int_mode (get_prefer_mask_policy (), Pmode);
+  rtx ta = gen_int_mode (get_preferred_tail_policy (), Pmode);
+  rtx ma = gen_int_mode (get_preferred_mask_policy (), Pmode);
   rtx merge = RVV_VUNDEF (demote_mode);
   /* Handle vslide1<ud>_tu.  */
   if (register_operand (ops[2], mode)
diff --git a/gcc/config/riscv/riscv-vector-builtins.cc b/gcc/config/riscv/riscv-vector-builtins.cc
index dd714bfcee2..0487827e65e 100644
--- a/gcc/config/riscv/riscv-vector-builtins.cc
+++ b/gcc/config/riscv/riscv-vector-builtins.cc
@@ -2743,7 +2743,7 @@ get_tail_policy_for_pred (enum predication_type_index pred)
 {
   if (pred == PRED_TYPE_tu || pred == PRED_TYPE_tum || pred == PRED_TYPE_tumu)
     return gen_int_mode (TAIL_UNDISTURBED, Pmode);
-  return gen_int_mode (get_prefer_tail_policy (), Pmode);
+  return gen_int_mode (get_preferred_tail_policy (), Pmode);
 }
 
 /* Get MASK policy for predication. If predication indicates MU, return the MU.
@@ -2753,7 +2753,7 @@ get_mask_policy_for_pred (enum predication_type_index pred)
 {
   if (pred == PRED_TYPE_tumu || pred == PRED_TYPE_mu)
     return gen_int_mode (MASK_UNDISTURBED, Pmode);
-  return gen_int_mode (get_prefer_mask_policy (), Pmode);
+  return gen_int_mode (get_preferred_mask_policy (), Pmode);
 }
 
 tree
diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc
index 9847d649d1d..0ecd0bfa2ea 100644
--- a/gcc/config/riscv/riscv-vsetvl.cc
+++ b/gcc/config/riscv/riscv-vsetvl.cc
@@ -566,8 +566,8 @@ get_default_ta ()
 {
   /* For the instruction that doesn't require TA, we still need a default value
      to emit vsetvl. We pick up the default value according to prefer policy. */
-  return (bool) (get_prefer_tail_policy () & 0x1
-		 || (get_prefer_tail_policy () >> 1 & 0x1));
+  return (bool) (get_preferred_tail_policy () & 0x1
+		 || (get_preferred_tail_policy () >> 1 & 0x1));
 }
 
 /* Get default mask policy.  */
@@ -576,8 +576,8 @@ get_default_ma ()
 {
   /* For the instruction that doesn't require MA, we still need a default value
      to emit vsetvl. We pick up the default value according to prefer policy. */
-  return (bool) (get_prefer_mask_policy () & 0x1
-		 || (get_prefer_mask_policy () >> 1 & 0x1));
+  return (bool) (get_preferred_mask_policy () & 0x1
+		 || (get_preferred_mask_policy () >> 1 & 0x1));
 }
 
 /* Helper function to get TA operand.  */
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..72701fceb8c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vneg-template.h
@@ -0,0 +1,17 @@
+#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..1c6836742cf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-run.c
@@ -0,0 +1,33 @@
+/* { 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 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..19c78d6e49b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/unop/vnot-template.h
@@ -0,0 +1,21 @@
+#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 bc99cc0c3cf..54e35cb6c62 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -63,6 +63,8 @@ foreach op $AUTOVEC_TEST_OPTS {
     "" "$op"
   dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/binop/*.\[cS\]]] \
     "" "$op"
+  dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/unop/*.\[cS\]]] \
+    "" "$op"
 }
 
 # VLS-VLMAX tests
