diff --git a/gcc/config/riscv/riscv-modes.def b/gcc/config/riscv/riscv-modes.def
index 19a4f9fb3db..f897e560667 100644
--- a/gcc/config/riscv/riscv-modes.def
+++ b/gcc/config/riscv/riscv-modes.def
@@ -318,6 +318,9 @@ RVV_TUPLE_PARTIAL_MODES (6)
 RVV_TUPLE_PARTIAL_MODES (7)
 RVV_TUPLE_PARTIAL_MODES (8)
 
+/* VLS modes.  */
+VECTOR_MODES (INT, 16);       /* V16QI V8HI V4SI V2DI */
+
 /* TODO: According to RISC-V 'V' ISA spec, the maximun vector length can
    be 65536 for a single vector register which means the vector mode in
    GCC can be maximum = 65536 * 8 bits (LMUL=8).
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 0462f96c8d5..56f714bbfb5 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -261,6 +261,10 @@ enum frm_field_enum
 opt_machine_mode vectorize_related_mode (machine_mode, scalar_mode,
 					 poly_uint64);
 unsigned int autovectorize_vector_modes (vec<machine_mode> *, bool);
+machine_mode minimal_vla_mode (machine_mode);
+void
+vls_insn_expander (unsigned, int, rtx *, machine_mode, machine_mode);
+bool vls_mode_p (machine_mode);
 }
 
 /* We classify builtin types into two classes:
diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc
index a5715bb466c..f9fb8cd9be4 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -1697,4 +1697,71 @@ expand_vcond (rtx *ops)
     gen_vcond_mask (data_mode, data_mode, ops[0], ops[1], ops[2], mask));
 }
 
+/* Return the minimal containable VLA mode for MODE.  */
+
+machine_mode
+minimal_vla_mode (machine_mode mode)
+{
+  gcc_assert (GET_MODE_NUNITS (mode).is_constant ());
+  unsigned type_size = GET_MODE_NUNITS (mode).to_constant ();
+  poly_uint64 nunits = type_size * poly_uint64 (1, 1);
+  opt_machine_mode vla_mode = get_vector_mode (GET_MODE_INNER (mode), nunits);
+  return vla_mode.else_void ();
+}
+
+/* Return true if MODE is true VLS mode.  */
+
+bool
+vls_mode_p (machine_mode mode)
+{
+  switch (mode)
+    {
+    case E_V4SImode:
+    case E_V2DImode:
+    case E_V8HImode:
+    case E_V16QImode:
+      return true;
+    default:
+      return false;
+    }
+}
+
+/* Convert all OPERANDS to VLA_MODE.  */
+
+static void
+update_vls_mode (machine_mode vla_mode, unsigned n_operands, rtx *operands)
+{
+  unsigned i;
+  for (i = 0; i < n_operands; ++i)
+    {
+      switch (GET_CODE (operands[i]))
+	{
+	case REG:
+	  operands[i] = gen_rtx_REG (vla_mode, REGNO (operands[i]));
+	  break;
+	case MEM:
+	  operands[i] = change_address (operands[i], vla_mode, NULL_RTX);
+	  break;
+	default:
+	  gcc_unreachable ();
+	}
+    }
+}
+
+/* Expand VLS operation to VLA pattern.  */
+
+void
+vls_insn_expander (unsigned icode, int op_num, rtx *operands,
+		   machine_mode vls_mode, machine_mode vla_mode)
+{
+  update_vls_mode (vla_mode, /* n_operands */ op_num, operands);
+
+  poly_uint16 nunit = GET_MODE_NUNITS (vls_mode);
+
+  gcc_assert (nunit.is_constant ());
+
+  riscv_vector::emit_nonvlmax_insn (icode, op_num, operands,
+				    GEN_INT (nunit.to_constant ()));
+}
+
 } // namespace riscv_vector
diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 3954fc07a8b..2e14f2e0d53 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -1034,7 +1034,8 @@ riscv_v_ext_tuple_mode_p (machine_mode mode)
 static bool
 riscv_v_ext_mode_p (machine_mode mode)
 {
-  return riscv_v_ext_vector_mode_p (mode) || riscv_v_ext_tuple_mode_p (mode);
+  return riscv_v_ext_vector_mode_p (mode) || riscv_v_ext_tuple_mode_p (mode)
+	 || riscv_vector::vls_mode_p (mode);
 }
 
 /* Call from ADJUST_NUNITS in riscv-modes.def. Return the correct
@@ -1043,7 +1044,7 @@ riscv_v_ext_mode_p (machine_mode mode)
 poly_int64
 riscv_v_adjust_nunits (machine_mode mode, int scale)
 {
-  if (riscv_v_ext_mode_p (mode))
+  if (riscv_v_ext_mode_p (mode) && !riscv_vector::vls_mode_p (mode))
     return riscv_vector_chunks * scale;
   return scale;
 }
@@ -6059,6 +6060,22 @@ riscv_register_move_cost (machine_mode mode,
 static unsigned int
 riscv_hard_regno_nregs (unsigned int regno, machine_mode mode)
 {
+  if (riscv_vector::vls_mode_p (mode))
+    {
+      if (TARGET_MIN_VLEN)
+	{
+	  unsigned min_byte_per_vector_register = TARGET_MIN_VLEN / 8;
+	  unsigned mode_size = GET_MODE_SIZE (mode).to_constant ();
+
+	  if (min_byte_per_vector_register >= mode_size)
+	    return 1;
+
+	  return mode_size / min_byte_per_vector_register;
+	}
+      else
+	return 1;
+    }
+
   if (riscv_v_ext_vector_mode_p (mode))
     {
       /* Handle fractional LMUL, it only occupy part of vector register but
@@ -6148,6 +6165,10 @@ riscv_hard_regno_mode_ok (unsigned int regno, machine_mode mode)
 	 but for mask vector register, register numbers can be any number. */
       int lmul = 1;
       machine_mode rvv_mode = mode;
+
+      if (riscv_vector::vls_mode_p (mode))
+	rvv_mode = riscv_vector::minimal_vla_mode (mode);
+
       if (riscv_v_ext_tuple_mode_p (rvv_mode))
 	rvv_mode = riscv_vector::get_subpart_mode (rvv_mode);
       poly_int64 size = GET_MODE_SIZE (rvv_mode);
@@ -7223,6 +7244,8 @@ riscv_vector_alignment (const_tree type)
 poly_uint64
 riscv_regmode_natural_size (machine_mode mode)
 {
+  if (riscv_vector::vls_mode_p (mode))
+    return GET_MODE_SIZE (mode);
   /* The natural size for RVV data modes is one RVV data vector,
      and similarly for predicates.  We can't independently modify
      anything smaller than that.  */
diff --git a/gcc/config/riscv/vector-iterators.md b/gcc/config/riscv/vector-iterators.md
index 70fb5b80b1b..650f2651c7d 100644
--- a/gcc/config/riscv/vector-iterators.md
+++ b/gcc/config/riscv/vector-iterators.md
@@ -84,6 +84,10 @@ (define_c_enum "unspec" [
   UNSPEC_MODIFY_VL
 ])
 
+(define_mode_iterator VLS [
+  V2DI V4SI V8HI V16QI
+])
+
 (define_mode_iterator V [
   (VNx1QI "TARGET_MIN_VLEN < 128") VNx2QI VNx4QI VNx8QI VNx16QI VNx32QI (VNx64QI "TARGET_MIN_VLEN > 32") (VNx128QI "TARGET_MIN_VLEN >= 128")
   (VNx1HI "TARGET_MIN_VLEN < 128") VNx2HI VNx4HI VNx8HI VNx16HI (VNx32HI "TARGET_MIN_VLEN > 32") (VNx64HI "TARGET_MIN_VLEN >= 128")
@@ -976,6 +980,7 @@ (define_mode_attr VM [
   (VNx2x4DF "VNx4BI") (VNx3x4DF "VNx4BI") (VNx4x4DF "VNx4BI")
   (VNx2x2DF "VNx2BI") (VNx3x2DF "VNx2BI") (VNx4x2DF "VNx2BI") (VNx5x2DF "VNx2BI") (VNx6x2DF "VNx2BI") (VNx7x2DF "VNx2BI") (VNx8x2DF "VNx2BI")
   (VNx2x1DF "VNx1BI") (VNx3x1DF "VNx1BI") (VNx4x1DF "VNx1BI") (VNx5x1DF "VNx1BI") (VNx6x1DF "VNx1BI") (VNx7x1DF "VNx1BI") (VNx8x1DF "VNx1BI")
+  (V2DI "V2BI") (V4SI "V4BI") (V8HI "V8BI") (V16QI "V16BI")
 ])
 
 (define_mode_attr vm [
@@ -1003,6 +1008,7 @@ (define_mode_attr vel [
   (VNx1DI "di") (VNx2DI "di") (VNx4DI "di") (VNx8DI "di") (VNx16DI "di")
   (VNx1SF "sf") (VNx2SF "sf") (VNx4SF "sf") (VNx8SF "sf") (VNx16SF "sf") (VNx32SF "sf")
   (VNx1DF "df") (VNx2DF "df") (VNx4DF "df") (VNx8DF "df") (VNx16DF "df")
+  (V2DI "di") (V4SI "si") (V8HI "hi") (V16QI "qi")
 ])
 
 (define_mode_attr VSUBEL [
diff --git a/gcc/config/riscv/vector-vls.md b/gcc/config/riscv/vector-vls.md
new file mode 100644
index 00000000000..af7e7a6c726
--- /dev/null
+++ b/gcc/config/riscv/vector-vls.md
@@ -0,0 +1,64 @@
+;; Machine description for vector length specific type operation with
+;; RISC-V 'V' Extension for GNU compiler.
+;; Copyright (C) 2023 Free Software Foundation, Inc.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_expand "mov<mode>"
+  [(set (match_operand:VLS 0 "nonimmediate_operand")
+	(match_operand:VLS 1 "vector_move_operand"))]
+  "TARGET_VECTOR"
+{
+  // TODO: Only allow register and memory now, we should allow legal
+  //       vector_const too.
+  if (MEM_P (operands[0]) && MEM_P (operands[1]))
+    operands[1] = force_reg (GET_MODE(operands[1]), operands[1]);
+})
+
+(define_insn_and_split "*mov<mode>"
+  [(set (match_operand:VLS 0 "nonimmediate_operand" "=vr,vr, m,vr")
+	(match_operand:VLS 1 "vector_move_operand"  " vr, m,vr,vi"))]
+  "TARGET_VECTOR &&
+   (register_operand (operands[0], <MODE>mode)
+    || register_operand (operands[1], <MODE>mode))"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  machine_mode vla_mode = riscv_vector::minimal_vla_mode (<MODE>mode);
+  riscv_vector::vls_insn_expander (
+    code_for_pred_mov (vla_mode), riscv_vector::RVV_UNOP, operands,
+    <MODE>mode, vla_mode);
+  DONE;
+})
+
+(define_insn_and_split "<optab><mode>3"
+  [(set (match_operand:VLS 0 "register_operand" "=vr")
+	(any_int_binop_no_shift:VLS
+	  (match_operand:VLS 1 "register_operand" "vr")
+	  (match_operand:VLS 2 "register_operand" "vr")))]
+  "TARGET_VECTOR"
+  "#"
+  "reload_completed"
+  [(const_int 0)]
+{
+  machine_mode vla_mode = riscv_vector::minimal_vla_mode (<MODE>mode);
+  riscv_vector::vls_insn_expander (
+    code_for_pred (<CODE>, vla_mode), riscv_vector::RVV_BINOP,
+    operands, <MODE>mode, vla_mode);
+  DONE;
+})
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index cd696da5d89..e3fd0807b22 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -25,6 +25,7 @@
 ;; - Intrinsics (https://github.com/riscv/rvv-intrinsic-doc)
 ;; - Auto-vectorization (autovec.md)
 ;; - Combine optimization (TBD)
+;; - VLS patterns (vector-vls.md)
 
 (include "vector-iterators.md")
 
@@ -8407,3 +8408,4 @@ (define_split
 )
 
 (include "autovec.md")
+(include "vector-vls.md")
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index bf03570b9cc..f6c56a63ada 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -77,5 +77,9 @@ foreach op $AUTOVEC_TEST_OPTS {
 dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/vls-vlmax/*.\[cS\]]] \
 	"-std=c99 -O3 -ftree-vectorize --param riscv-autovec-preference=fixed-vlmax" $CFLAGS
 
+# VLS test
+gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/vls/*.\[cS\]]] \
+	"" $CFLAGS
+
 # All done.
 dg-finish
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-template.h b/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-template.h
new file mode 100644
index 00000000000..0114c124646
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-template.h
@@ -0,0 +1,18 @@
+#include "vls-types.h"
+#define __BINOP(NAME, OP, VLS_TYPE, SCALAR_TYPE)		\
+void binop_##NAME##VLS_TYPE					\
+  (VLS_TYPE *src1, VLS_TYPE *src2, VLS_TYPE *dst)		\
+{								\
+    *dst = *src1 OP *src2;					\
+}
+
+#define BINOP(VLS_TYPE, SCALAR_TYPE)				\
+__BINOP (ADD, +, VLS_TYPE, SCALAR_TYPE)				\
+__BINOP (MUL, *, VLS_TYPE, SCALAR_TYPE)				\
+__BINOP (DIV, /, VLS_TYPE, SCALAR_TYPE)				\
+__BINOP (MOD, %, VLS_TYPE, SCALAR_TYPE)				\
+__BINOP (AND, &, VLS_TYPE, SCALAR_TYPE)				\
+__BINOP (IOR, |, VLS_TYPE, SCALAR_TYPE)				\
+__BINOP (XOR, ^, VLS_TYPE, SCALAR_TYPE)
+
+FOR_EACH_VLS_TYPE(BINOP)
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-v.c b/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-v.c
new file mode 100644
index 00000000000..78c1a19cfbf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-v.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv -mabi=lp64" } */
+
+#include "binop-template.h"
+
+/* { dg-final { scan-assembler {vsetivli\s+zero,16,e8,m1} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,8,e16,m1} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,4,e32,m1} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,2,e64,m1} } } */
+/* { dg-final { scan-assembler-times {vadd\.vv} 8} } */
+/* { dg-final { scan-assembler-times {vmul\.vv} 8} } */
+/* { dg-final { scan-assembler-times {vdiv\.vv} 4} } */
+/* { dg-final { scan-assembler-times {vdivu\.vv} 4 } } */
+/* { dg-final { scan-assembler-times {vrem\.vv} 4} } */
+/* { dg-final { scan-assembler-times {vremu\.vv} 4 } } */
+/* { dg-final { scan-assembler-times {vand\.vv} 8} } */
+/* { dg-final { scan-assembler-times {vor\.vv} 8 } } */
+/* { dg-final { scan-assembler-times {vxor\.vv} 8} } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-zve32x.c b/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-zve32x.c
new file mode 100644
index 00000000000..bca56ba32a5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-zve32x.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv32gc_zve32x -mabi=ilp32" } */
+
+#include "binop-template.h"
+
+/* { dg-final { scan-assembler {vsetivli\s+zero,16,e8,m4} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,8,e16,m4} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,4,e32,m4} } } */
+/* { dg-final { scan-assembler-not {vsetivli\s+zero,2,e64,m4} } } */
+/* { dg-final { scan-assembler-times {vadd\.vv} 6} } */
+/* { dg-final { scan-assembler-times {vmul\.vv} 6} } */
+/* { dg-final { scan-assembler-times {vdiv\.vv} 3} } */
+/* { dg-final { scan-assembler-times {vdivu\.vv} 3 } } */
+/* { dg-final { scan-assembler-times {vrem\.vv} 3} } */
+/* { dg-final { scan-assembler-times {vremu\.vv} 3 } } */
+/* { dg-final { scan-assembler-times {vand\.vv} 6} } */
+/* { dg-final { scan-assembler-times {vor\.vv} 6 } } */
+/* { dg-final { scan-assembler-times {vxor\.vv} 6} } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-zve64x.c b/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-zve64x.c
new file mode 100644
index 00000000000..45dcad12a93
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/binop-zve64x.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv32gc_zve64x -mabi=ilp32" } */
+
+#include "binop-template.h"
+
+/* { dg-final { scan-assembler {vsetivli\s+zero,16,e8,m2} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,8,e16,m2} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,4,e32,m2} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,2,e64,m2} } } */
+/* { dg-final { scan-assembler-times {vadd\.vv} 8} } */
+/* { dg-final { scan-assembler-times {vmul\.vv} 8} } */
+/* { dg-final { scan-assembler-times {vdiv\.vv} 4} } */
+/* { dg-final { scan-assembler-times {vdivu\.vv} 4 } } */
+/* { dg-final { scan-assembler-times {vrem\.vv} 4} } */
+/* { dg-final { scan-assembler-times {vremu\.vv} 4 } } */
+/* { dg-final { scan-assembler-times {vand\.vv} 8} } */
+/* { dg-final { scan-assembler-times {vor\.vv} 8 } } */
+/* { dg-final { scan-assembler-times {vxor\.vv} 8} } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-template.h b/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-template.h
new file mode 100644
index 00000000000..9ea0c7cb5dc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-template.h
@@ -0,0 +1,8 @@
+#include "vls-types.h"
+#define LOAD_STORE(VLS_TYPE, SCALAR_TYPE)			\
+void load_store_##VLS_TYPE (VLS_TYPE *src, VLS_TYPE *dst)	\
+{								\
+    *dst = *src;						\
+}
+
+FOR_EACH_VLS_TYPE(LOAD_STORE)
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-v.c b/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-v.c
new file mode 100644
index 00000000000..b8adcea70d6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-v.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv -mabi=lp64" } */
+
+#include "load-store-template.h"
+
+/* { dg-final { scan-assembler {vsetivli\s+zero,16,e8,m1} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,8,e16,m1} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,4,e32,m1} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,2,e64,m1} } } */
+/* { dg-final { scan-assembler-times {vle8\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vle16\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vle32\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vle64\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vse8\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vse16\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vse32\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vse64\.v} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-zve32x.c b/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-zve32x.c
new file mode 100644
index 00000000000..ef3426d00a1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-zve32x.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv32gc_zve32x -mabi=ilp32" } */
+
+#include "load-store-template.h"
+
+/* { dg-final { scan-assembler {vsetivli\s+zero,16,e8,m4} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,8,e16,m4} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,4,e32,m4} } } */
+/* { dg-final { scan-assembler-not {vsetivli\s+zero,2,e64,m4} } } */
+/* { dg-final { scan-assembler-times {vle8\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vle16\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vle32\.v} 2 } } */
+/* { dg-final { scan-assembler-not {vle64\.v} } } */
+/* { dg-final { scan-assembler-times {vse8\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vse16\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vse32\.v} 2 } } */
+/* { dg-final { scan-assembler-not {vse64\.v} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-zve64x.c b/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-zve64x.c
new file mode 100644
index 00000000000..e03220d89f8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/load-store-zve64x.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv32gc_zve64x -mabi=ilp32" } */
+
+#include "load-store-template.h"
+
+/* { dg-final { scan-assembler {vsetivli\s+zero,16,e8,m2} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,8,e16,m2} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,4,e32,m2} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,2,e64,m2} } } */
+/* { dg-final { scan-assembler-times {vle8\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vle16\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vle32\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vle64\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vse8\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vse16\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vse32\.v} 2 } } */
+/* { dg-final { scan-assembler-times {vse64\.v} 2 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/move-template.h b/gcc/testsuite/gcc.target/riscv/rvv/vls/move-template.h
new file mode 100644
index 00000000000..e328a42204c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/move-template.h
@@ -0,0 +1,13 @@
+#include "vls-types.h"
+
+#define MOVE(VLS_TYPE, SCALAR_TYPE)				\
+void move_##VLS_TYPE ()						\
+{								\
+    register VLS_TYPE src##VLS_TYPE __asm__ ("v0");		\
+    register VLS_TYPE dst##VLS_TYPE __asm__ ("v8");		\
+    __asm__ volatile ("#def" : "=vr"(src##VLS_TYPE));		\
+    dst##VLS_TYPE = src##VLS_TYPE;				\
+    __asm__ volatile ("#use" : : "vr"(dst##VLS_TYPE));		\
+}
+
+FOR_EACH_VLS_TYPE(MOVE)
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/move-v.c b/gcc/testsuite/gcc.target/riscv/rvv/vls/move-v.c
new file mode 100644
index 00000000000..91c89df098e
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/move-v.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv64gcv -mabi=lp64" } */
+
+#include "move-template.h"
+
+/* { dg-final { scan-assembler {vsetivli\s+zero,16,e8,m1} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,8,e16,m1} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,4,e32,m1} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,2,e64,m1} } } */
+/* { dg-final { scan-assembler-times {vmv\.v\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/move-zve32x.c b/gcc/testsuite/gcc.target/riscv/rvv/vls/move-zve32x.c
new file mode 100644
index 00000000000..175986edf15
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/move-zve32x.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv32gc_zve32x -mabi=ilp32" } */
+
+#include "move-template.h"
+
+/* { dg-final { scan-assembler {vsetivli\s+zero,16,e8,m4} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,8,e16,m4} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,4,e32,m4} } } */
+/* { dg-final { scan-assembler-not {vsetivli\s+zero,2,e64,m4} } } */
+/* { dg-final { scan-assembler-times {vmv\.v\.v} 6 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/move-zve64x.c b/gcc/testsuite/gcc.target/riscv/rvv/vls/move-zve64x.c
new file mode 100644
index 00000000000..2e574b1f3ee
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/move-zve64x.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-additional-options "-march=rv32gc_zve64x -mabi=ilp32" } */
+
+#include "move-template.h"
+
+/* { dg-final { scan-assembler {vsetivli\s+zero,16,e8,m2} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,8,e16,m2} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,4,e32,m2} } } */
+/* { dg-final { scan-assembler {vsetivli\s+zero,2,e64,m2} } } */
+/* { dg-final { scan-assembler-times {vmv\.v\.v} 8 } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/vls/vls-types.h b/gcc/testsuite/gcc.target/riscv/rvv/vls/vls-types.h
new file mode 100644
index 00000000000..302823b583f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/vls/vls-types.h
@@ -0,0 +1,42 @@
+#ifndef __VLS_TYPE_H
+#define __VLS_TYPE_H
+#include <stdint-gcc.h>
+
+typedef  int8_t int8x16_t __attribute__ ((vector_size (16)));
+typedef int16_t int16x8_t __attribute__ ((vector_size (16)));
+typedef int32_t int32x4_t __attribute__ ((vector_size (16)));
+typedef int64_t int64x2_t __attribute__ ((vector_size (16)));
+
+typedef  uint8_t uint8x16_t __attribute__ ((vector_size (16)));
+typedef uint16_t uint16x8_t __attribute__ ((vector_size (16)));
+typedef uint32_t uint32x4_t __attribute__ ((vector_size (16)));
+typedef uint64_t uint64x2_t __attribute__ ((vector_size (16)));
+
+
+#if __riscv_v_elen == 32
+
+#define FOR_EACH_VLS_TYPE(FUNC) \
+    FUNC (int8x16_t, int8_t) \
+    FUNC (int16x8_t, int16_t) \
+    FUNC (int32x4_t, int32_t) \
+    FUNC (uint8x16_t, uint8_t) \
+    FUNC (uint16x8_t, uint16_t) \
+    FUNC (uint32x4_t, uint32_t)
+
+#elif __riscv_v_elen == 64
+
+#define FOR_EACH_VLS_TYPE(FUNC) \
+    FUNC (int8x16_t, int8_t) \
+    FUNC (int16x8_t, int16_t) \
+    FUNC (int32x4_t, int32_t) \
+    FUNC (int64x2_t, int64_t) \
+    FUNC (uint8x16_t, uint8_t) \
+    FUNC (uint16x8_t, uint16_t) \
+    FUNC (uint32x4_t, uint32_t) \
+    FUNC (uint64x2_t, uint64_t)
+
+#else
+#error "zve* or v extension is required."
+#endif
+
+#endif
