diff --git a/gcc/config.gcc b/gcc/config.gcc
index 606d3a8513e..efd53965c9a 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -544,7 +544,7 @@ pru-*-*)
 riscv*)
 	cpu_type=riscv
 	extra_objs="riscv-builtins.o riscv-c.o riscv-sr.o riscv-shorten-memrefs.o riscv-selftests.o riscv-string.o"
-	extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o"
+	extra_objs="${extra_objs} riscv-v.o riscv-vsetvl.o riscv-vector-costs.o riscv-avlprop.o"
 	extra_objs="${extra_objs} riscv-vector-builtins.o riscv-vector-builtins-shapes.o riscv-vector-builtins-bases.o"
 	extra_objs="${extra_objs} thead.o"
 	d_target_objs="riscv-d.o"
diff --git a/gcc/config/riscv/riscv-avlprop.cc b/gcc/config/riscv/riscv-avlprop.cc
new file mode 100644
index 00000000000..bf3becd8371
--- /dev/null
+++ b/gcc/config/riscv/riscv-avlprop.cc
@@ -0,0 +1,350 @@
+/* AVL propagation pass for RISC-V 'V' Extension for GNU compiler.
+   Copyright (C) 2023-2023 Free Software Foundation, Inc.
+   Contributed by Juzhe Zhong (juzhe.zhong@rivai.ai), RiVAI Technologies Ltd.
+
+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/>.  */
+
+/* Pre-RA RTL_SSA-based pass propagates AVL for RVV instructions.
+   A standalone AVL propagation pass is designed because:
+
+     - Better code maintain:
+       Current LCM-based VSETVL pass is so complicated that codes
+       there will become even harder to maintain. A straight forward
+       AVL propagation PASS is much easier to maintain.
+
+     - Reduce scalar register pressure:
+       A type of AVL propagation is we propagate AVL from NON-VLMAX
+       instruction to VLMAX instruction.
+       Note: VLMAX instruction should be ignore tail elements (TA)
+       and the result should be used by the NON-VLMAX instruction.
+       This optimization is mostly for auto-vectorization codes:
+
+	  vsetvli r136, r137      --- SELECT_VL
+	  vle8.v (use avl = r136) --- IFN_MASK_LEN_LOAD
+	  vadd.vv (use VLMAX)     --- PLUS_EXPR
+	  vse8.v (use avl = r136) --- IFN_MASK_LEN_STORE
+
+	NO AVL propation:
+
+	  vsetvli a5, a4, ta
+	  vle8.v v1
+	  vsetvli t0, zero, ta
+	  vadd.vv v2, v1, v1
+	  vse8.v v2
+
+	We can propagate the AVL to 'vadd.vv' since its result
+	is consumed by a 'vse8.v' which has AVL = a5 and its
+	tail elements are agnostic.
+
+       We DON'T do this optimization on VSETVL pass since it is a
+       post-RA pass that consumed 't0' already wheras a standalone
+       pre-RA AVL propagation pass allows us elide the consumption
+       of the pseudo register of 't0' then we can reduce scalar
+       register pressure.
+
+     - More AVL propagation opportunities:
+       A pre-RA pass is more flexible for AVL REG def-use chain,
+       thus we will get more potential AVL propagation as long as
+       it doesn't increase the scalar register pressure.
+*/
+
+#define IN_TARGET_CODE 1
+#define INCLUDE_ALGORITHM
+#define INCLUDE_FUNCTIONAL
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "backend.h"
+#include "rtl.h"
+#include "target.h"
+#include "tree-pass.h"
+#include "df.h"
+#include "rtl-ssa.h"
+#include "cfgcleanup.h"
+#include "insn-attr.h"
+
+using namespace rtl_ssa;
+using namespace riscv_vector;
+
+/* The AVL propagation instructions and corresponding preferred AVL.
+   It will be updated during the analysis.  */
+static hash_map<insn_info *, rtx> *avlprops;
+
+const pass_data pass_data_avlprop = {
+  RTL_PASS,	 /* type */
+  "avlprop",	 /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_NONE,	 /* tv_id */
+  0,		 /* properties_required */
+  0,		 /* properties_provided */
+  0,		 /* properties_destroyed */
+  0,		 /* todo_flags_start */
+  0,		 /* todo_flags_finish */
+};
+
+class pass_avlprop : public rtl_opt_pass
+{
+public:
+  pass_avlprop (gcc::context *ctxt) : rtl_opt_pass (pass_data_avlprop, ctxt) {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *) final override
+  {
+    return TARGET_VECTOR && optimize > 0;
+  }
+  virtual unsigned int execute (function *) final override;
+}; // class pass_avlprop
+
+static void
+avlprop_init (void)
+{
+  calculate_dominance_info (CDI_DOMINATORS);
+  df_analyze ();
+  crtl->ssa = new function_info (cfun);
+  avlprops = new hash_map<insn_info *, rtx>;
+}
+
+static void
+avlprop_done (void)
+{
+  free_dominance_info (CDI_DOMINATORS);
+  if (crtl->ssa->perform_pending_updates ())
+    cleanup_cfg (0);
+  delete crtl->ssa;
+  crtl->ssa = nullptr;
+  delete avlprops;
+  avlprops = NULL;
+}
+
+/* Helper function to get AVL operand.  */
+static rtx
+get_avl (insn_info *insn, bool avlprop_p)
+{
+  if (get_attr_avl_type (insn->rtl ()) == INVALID_ATTRIBUTE
+      || get_attr_avl_type (insn->rtl ()) == VLS)
+    return NULL_RTX;
+  if (avlprop_p)
+    {
+      if (avlprops->get (insn))
+	return (*avlprops->get (insn));
+      else if (vlmax_avl_type_p (insn->rtl ()))
+	return RVV_VLMAX;
+    }
+  extract_insn_cached (insn->rtl ());
+  return recog_data.operand[get_attr_vl_op_idx (insn->rtl ())];
+}
+
+/* This is a straight forward pattern ALWAYS in paritial auto-vectorization:
+
+     VL = SELECT_AVL (AVL, ...)
+     V0 = MASK_LEN_LOAD (..., VL)
+     V1 = MASK_LEN_LOAD (..., VL)
+     V2 = V0 + V1 --- Missed LEN information.
+     MASK_LEN_STORE (..., V2, VL)
+
+   We prefer PLUS_EXPR (V0 + V1) instead of COND_LEN_ADD (V0, V1, dummy LEN)
+   because:
+
+     - Few code changes in Loop Vectorizer.
+     - Reuse the current clean flow of partial vectorization, That is, apply
+       predicate LEN or MASK into LOAD/STORE operations and other special
+       arithmetic operations (e.d. DIV), then do the whole vector register
+       operation if it DON'T affect the correctness.
+       Such flow is used by all other targets like x86, sve, s390, ... etc.
+     - PLUS_EXPR has better gimple optimizations than COND_LEN_ADD.
+
+   We propagate AVL from NON-VLMAX to VLMAX for gimple IR like PLUS_EXPR which
+   generates the VLMAX instruction due to missed LEN information. The later
+   VSETVL PASS will elided the redundant vsetvls.
+*/
+
+static rtx
+get_autovectorize_preferred_avl (insn_info *insn)
+{
+  if (!vlmax_avl_p (get_avl (insn, true)) || !tail_agnostic_p (insn->rtl ()))
+    return NULL_RTX;
+
+  rtx use_avl = NULL_RTX;
+  insn_info *avl_use_insn = nullptr;
+  unsigned int ratio
+    = calculate_ratio (get_sew (insn->rtl ()), get_vlmul (insn->rtl ()));
+  for (def_info *def : insn->defs ())
+    {
+      auto set = safe_dyn_cast<set_info *> (def);
+      if (!set || !set->is_reg ())
+	return NULL_RTX;
+      for (use_info *use : set->all_uses ())
+	{
+	  if (!use->is_in_nondebug_insn ())
+	    return NULL_RTX;
+	  insn_info *use_insn = use->insn ();
+	  /* FIXME: Stop AVL propagation if any USE is not a RVV real
+	     instruction. It should be totally enough for vectorized codes since
+	     they always locate at extended blocks.
+
+	     TODO: We can extend PHI checking for intrinsic codes if it
+	     necessary in the future.  */
+	  if (use_insn->is_artificial () || !has_vtype_op (use_insn->rtl ()))
+	    return NULL_RTX;
+	  if (!has_vl_op (use_insn->rtl ()))
+	    continue;
+
+	  rtx new_use_avl = get_avl (use_insn, true);
+	  if (!new_use_avl)
+	    return NULL_RTX;
+	  if (!use_avl)
+	    use_avl = new_use_avl;
+	  if (!rtx_equal_p (use_avl, new_use_avl)
+	      || calculate_ratio (get_sew (use_insn->rtl ()),
+				  get_vlmul (use_insn->rtl ()))
+		   != ratio
+	      || vlmax_avl_p (new_use_avl)
+	      || !tail_agnostic_p (use_insn->rtl ()))
+	    return NULL_RTX;
+	  if (!avl_use_insn)
+	    avl_use_insn = use_insn;
+	}
+    }
+
+  if (use_avl && register_operand (use_avl, Pmode))
+    {
+      gcc_assert (avl_use_insn);
+      // Find a definition at or neighboring INSN.
+      resource_info resource = full_register (REGNO (use_avl));
+      def_lookup dl1 = crtl->ssa->find_def (resource, insn);
+      def_lookup dl2 = crtl->ssa->find_def (resource, avl_use_insn);
+      if (dl1.matching_set () || dl2.matching_set ())
+	return NULL_RTX;
+      def_info *def1 = dl1.last_def_of_prev_group ();
+      def_info *def2 = dl2.last_def_of_prev_group ();
+      if (def1 != def2)
+	return NULL_RTX;
+      /* FIXME: We only all AVL propation within a block which should
+	 be totally enough for vectorized codes.
+
+	 TODO: We can enhance it here for intrinsic codes in the future
+	 if it is necessary.  */
+      if (def1->insn ()->bb () != insn->bb ()
+	  || def1->insn ()->compare_with (insn) >= 0)
+	return NULL_RTX;
+    }
+  return use_avl;
+}
+
+/* If we have a preferred AVL to propagate, return the AVL.
+   Otherwise, return NULL_RTX as we don't need have any preferred
+   AVL.  */
+
+static rtx
+get_preferred_avl (insn_info *insn)
+{
+  /* TODO: We only do AVL propagation for missed-LEN partial
+     autovectorization for now.  We could add more more AVL
+     propagation for intrinsic codes in the future.  */
+  return get_autovectorize_preferred_avl (insn);
+}
+
+/* Return the AVL TYPE operand index.  */
+static int
+get_avl_type_index (insn_info *insn)
+{
+  extract_insn_cached (insn->rtl ());
+  /* Except rounding mode patterns, AVL TYPE operand
+     is always the last operand.  */
+  if (find_access (insn->uses (), VXRM_REGNUM)
+      || find_access (insn->uses (), FRM_REGNUM))
+    return recog_data.n_operands - 2;
+  return recog_data.n_operands - 1;
+}
+
+/* Main entry point for this pass.  */
+unsigned int
+pass_avlprop::execute (function *)
+{
+  avlprop_init ();
+
+  /* Go through all the instructions looking for AVL that we could propagate. */
+
+  insn_info *next;
+  bool change_p = true;
+
+  while (change_p)
+    {
+      /* Iterate on each instruction until no more change need.  */
+      change_p = false;
+      for (insn_info *insn = crtl->ssa->first_insn (); insn; insn = next)
+	{
+	  next = insn->next_any_insn ();
+	  /* We only forward AVL to the instruction that has AVL/VL operand
+	     and can be optimized in RTL_SSA level.  */
+	  if (!insn->can_be_optimized () || !has_vl_op (insn->rtl ()))
+	    continue;
+
+	  rtx new_avl = get_preferred_avl (insn);
+	  if (new_avl)
+	    {
+	      gcc_assert (!vlmax_avl_p (new_avl));
+	      auto &update = avlprops->get_or_insert (insn);
+	      change_p = !rtx_equal_p (update, new_avl);
+	      update = new_avl;
+	    }
+	}
+    }
+
+  if (dump_file)
+    fprintf (dump_file, "\nNumber of successful AVL propagations: %d\n\n",
+	     (int) avlprops->elements ());
+
+  for (const auto iter : *avlprops)
+    {
+      rtx_insn *rinsn = iter.first->rtl ();
+      if (dump_file)
+	{
+	  fprintf (dump_file, "\nPropagating AVL: ");
+	  print_rtl_single (dump_file, iter.second);
+	  fprintf (dump_file, "into: ");
+	  print_rtl_single (dump_file, rinsn);
+	}
+      /* Replace AVL operand.  */
+      rtx new_pat
+	= simplify_replace_rtx (PATTERN (rinsn), get_avl (iter.first, false),
+				iter.second);
+      validate_change_or_fail (rinsn, &PATTERN (rinsn), new_pat, false);
+
+      /* Change AVL TYPE into NONVLMAX if it is VLMAX.  */
+      if (vlmax_avl_type_p (rinsn))
+	validate_change_or_fail (
+	  rinsn, recog_data.operand_loc[get_avl_type_index (iter.first)],
+	  get_avl_type_rtx (avl_type::NONVLMAX), false);
+      if (dump_file)
+	{
+	  fprintf (dump_file, "Successfully to match this instruction: ");
+	  print_rtl_single (dump_file, rinsn);
+	}
+    }
+
+  avlprop_done ();
+  return 0;
+}
+
+rtl_opt_pass *
+make_pass_avlprop (gcc::context *ctxt)
+{
+  return new pass_avlprop (ctxt);
+}
diff --git a/gcc/config/riscv/riscv-passes.def b/gcc/config/riscv/riscv-passes.def
index 4084122cf0a..b6260939d5c 100644
--- a/gcc/config/riscv/riscv-passes.def
+++ b/gcc/config/riscv/riscv-passes.def
@@ -18,4 +18,5 @@
    <http://www.gnu.org/licenses/>.  */
 
 INSERT_PASS_AFTER (pass_rtl_store_motion, 1, pass_shorten_memrefs);
+INSERT_PASS_AFTER (pass_split_all_insns, 1, pass_avlprop);
 INSERT_PASS_BEFORE (pass_fast_rtl_dce, 1, pass_vsetvl);
diff --git a/gcc/config/riscv/riscv-protos.h b/gcc/config/riscv/riscv-protos.h
index 6cb9d459ee9..2b09ec9ea9e 100644
--- a/gcc/config/riscv/riscv-protos.h
+++ b/gcc/config/riscv/riscv-protos.h
@@ -156,6 +156,7 @@ extern void riscv_parse_arch_string (const char *, struct gcc_options *, locatio
 extern bool riscv_hard_regno_rename_ok (unsigned, unsigned);
 
 rtl_opt_pass * make_pass_shorten_memrefs (gcc::context *ctxt);
+rtl_opt_pass * make_pass_avlprop (gcc::context *ctxt);
 rtl_opt_pass * make_pass_vsetvl (gcc::context *ctxt);
 
 /* Routines implemented in riscv-string.c.  */
@@ -559,6 +560,15 @@ bool cmp_lmul_le_one (machine_mode);
 bool cmp_lmul_gt_one (machine_mode);
 bool gather_scatter_valid_offset_mode_p (machine_mode);
 bool vls_mode_valid_p (machine_mode);
+bool has_vtype_op (rtx_insn *);
+bool has_vl_op (rtx_insn *);
+bool tail_agnostic_p (rtx_insn *);
+void validate_change_or_fail (rtx, rtx *, rtx, bool);
+bool vlmax_avl_type_p (rtx_insn *);
+bool vlmax_avl_p (rtx);
+uint8_t get_sew (rtx_insn *);
+enum vlmul_type get_vlmul (rtx_insn *);
+bool const_vlmax_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 e39a9507803..473622ac321 100644
--- a/gcc/config/riscv/riscv-v.cc
+++ b/gcc/config/riscv/riscv-v.cc
@@ -56,7 +56,7 @@ using namespace riscv_vector;
 namespace riscv_vector {
 
 /* Return true if vlmax is constant value and can be used in vsetivl.  */
-static bool
+bool
 const_vlmax_p (machine_mode mode)
 {
   poly_uint64 nuints = GET_MODE_NUNITS (mode);
@@ -298,14 +298,6 @@ public:
 	      len = force_reg (Pmode, len);
 	    vls_p = true;
 	  }
-	else if (const_vlmax_p (vtype_mode))
-	  {
-	    /* Optimize VLS-VLMAX code gen, we can use vsetivli instead of
-	       the vsetvli to obtain the value of vlmax.  */
-	    poly_uint64 nunits = GET_MODE_NUNITS (vtype_mode);
-	    len = gen_int_mode (nunits, Pmode);
-	    vls_p = true;
-	  }
 	else if (can_create_pseudo_p ())
 	  {
 	    len = gen_reg_rtx (Pmode);
@@ -4435,4 +4427,78 @@ expand_popcount (rtx *ops)
   emit_move_insn (dst, x4);
 }
 
+/* Return true if it is an RVV instruction depends on VTYPE global
+   status register.  */
+bool
+has_vtype_op (rtx_insn *rinsn)
+{
+  return recog_memoized (rinsn) >= 0 && get_attr_has_vtype_op (rinsn);
+}
+
+/* Return true if it is an RVV instruction depends on VL global
+   status register.  */
+bool
+has_vl_op (rtx_insn *rinsn)
+{
+  return recog_memoized (rinsn) >= 0 && get_attr_has_vl_op (rinsn);
+}
+
+/* Get default tail policy.  */
+static bool
+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));
+}
+
+/* Helper function to get TA operand.  */
+bool
+tail_agnostic_p (rtx_insn *rinsn)
+{
+  /* If it doesn't have TA, we return agnostic by default.  */
+  extract_insn_cached (rinsn);
+  int ta = get_attr_ta (rinsn);
+  return ta == INVALID_ATTRIBUTE ? get_default_ta () : IS_AGNOSTIC (ta);
+}
+
+/* Change insn and Assert the change always happens.  */
+void
+validate_change_or_fail (rtx object, rtx *loc, rtx new_rtx, bool in_group)
+{
+  bool change_p = validate_change (object, loc, new_rtx, in_group);
+  gcc_assert (change_p);
+}
+
+/* Return true if it is VLMAX AVL TYPE.  */
+bool
+vlmax_avl_type_p (rtx_insn *rinsn)
+{
+  return get_attr_avl_type (rinsn) == VLMAX;
+}
+
+/* Return true if RTX is RVV VLMAX AVL.  */
+bool
+vlmax_avl_p (rtx x)
+{
+  return x && rtx_equal_p (x, RVV_VLMAX);
+}
+
+/* Helper function to get SEW operand. We always have SEW value for
+   all RVV instructions that have VTYPE OP.  */
+uint8_t
+get_sew (rtx_insn *rinsn)
+{
+  return get_attr_sew (rinsn);
+}
+
+/* Helper function to get VLMUL operand. We always have VLMUL value for
+   all RVV instructions that have VTYPE OP. */
+enum vlmul_type
+get_vlmul (rtx_insn *rinsn)
+{
+  return (enum vlmul_type) get_attr_vlmul (rinsn);
+}
+
 } // namespace riscv_vector
diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc
index e9dd669de98..f2f19e423bf 100644
--- a/gcc/config/riscv/riscv-vsetvl.cc
+++ b/gcc/config/riscv/riscv-vsetvl.cc
@@ -255,28 +255,6 @@ policy_to_str (bool agnostic_p)
   return agnostic_p ? "agnostic" : "undisturbed";
 }
 
-static bool
-vlmax_avl_p (rtx x)
-{
-  return x && rtx_equal_p (x, RVV_VLMAX);
-}
-
-/* Return true if it is an RVV instruction depends on VTYPE global
-   status register.  */
-static bool
-has_vtype_op (rtx_insn *rinsn)
-{
-  return recog_memoized (rinsn) >= 0 && get_attr_has_vtype_op (rinsn);
-}
-
-/* Return true if it is an RVV instruction depends on VL global
-   status register.  */
-static bool
-has_vl_op (rtx_insn *rinsn)
-{
-  return recog_memoized (rinsn) >= 0 && get_attr_has_vl_op (rinsn);
-}
-
 /* Return true if the instruction ignores VLMUL field of VTYPE.  */
 static bool
 ignore_vlmul_insn_p (rtx_insn *rinsn)
@@ -365,36 +343,22 @@ get_avl (rtx_insn *rinsn)
 
   if (!has_vl_op (rinsn))
     return NULL_RTX;
-  if (get_attr_avl_type (rinsn) == VLMAX)
-    return RVV_VLMAX;
-  extract_insn_cached (rinsn);
-  return recog_data.operand[get_attr_vl_op_idx (rinsn)];
-}
 
-/* Helper function to get SEW operand. We always have SEW value for
-   all RVV instructions that have VTYPE OP.  */
-static uint8_t
-get_sew (rtx_insn *rinsn)
-{
-  return get_attr_sew (rinsn);
-}
-
-/* Helper function to get VLMUL operand. We always have VLMUL value for
-   all RVV instructions that have VTYPE OP. */
-static enum vlmul_type
-get_vlmul (rtx_insn *rinsn)
-{
-  return (enum vlmul_type) get_attr_vlmul (rinsn);
-}
+  extract_insn_cached (rinsn);
+  if (vlmax_avl_type_p (rinsn))
+    {
+      if (BYTES_PER_RISCV_VECTOR.is_constant ())
+	{
+	  for (int i = 0; i < recog_data.n_operands; i++)
+	    if (GET_MODE_CLASS (recog_data.operand_mode[i]) == MODE_VECTOR_BOOL
+		&& const_vlmax_p (recog_data.operand_mode[i]))
+	      return gen_int_mode (GET_MODE_NUNITS (recog_data.operand_mode[i]),
+				   Pmode);
+	}
+      return RVV_VLMAX;
+    }
 
-/* Get default tail policy.  */
-static bool
-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 recog_data.operand[get_attr_vl_op_idx (rinsn)];
 }
 
 /* Get default mask policy.  */
@@ -407,16 +371,6 @@ get_default_ma ()
 		 || (get_prefer_mask_policy () >> 1 & 0x1));
 }
 
-/* Helper function to get TA operand.  */
-static bool
-tail_agnostic_p (rtx_insn *rinsn)
-{
-  /* If it doesn't have TA, we return agnostic by default.  */
-  extract_insn_cached (rinsn);
-  int ta = get_attr_ta (rinsn);
-  return ta == INVALID_ATTRIBUTE ? get_default_ta () : IS_AGNOSTIC (ta);
-}
-
 /* Helper function to get MA operand.  */
 static bool
 mask_agnostic_p (rtx_insn *rinsn)
@@ -696,14 +650,6 @@ has_no_uses (basic_block cfg_bb, rtx_insn *rinsn, int regno)
   return true;
 }
 
-/* Change insn and Assert the change always happens.  */
-static void
-validate_change_or_fail (rtx object, rtx *loc, rtx new_rtx, bool in_group)
-{
-  bool change_p = validate_change (object, loc, new_rtx, in_group);
-  gcc_assert (change_p);
-}
-
 /* This flags indicates the minimum demand of the vl and vtype values by the
    RVV instruction. For example, DEMAND_RATIO_P indicates that this RVV
    instruction only needs the SEW/LMUL ratio to remain the same, and does not
diff --git a/gcc/config/riscv/t-riscv b/gcc/config/riscv/t-riscv
index dd17056fe82..08de62853a6 100644
--- a/gcc/config/riscv/t-riscv
+++ b/gcc/config/riscv/t-riscv
@@ -69,6 +69,12 @@ riscv-vsetvl.o: $(srcdir)/config/riscv/riscv-vsetvl.cc \
 	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
 		$(srcdir)/config/riscv/riscv-vsetvl.cc
 
+riscv-avlprop.o: $(srcdir)/config/riscv/riscv-avlprop.cc \
+  $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) $(REGS_H) \
+  $(TARGET_H) tree-pass.h df.h rtl-ssa.h cfgcleanup.h insn-attr.h 
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) \
+		$(srcdir)/config/riscv/riscv-avlprop.cc
+
 riscv-vector-costs.o: $(srcdir)/config/riscv/riscv-vector-costs.cc \
   $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TARGET_H) $(FUNCTION_H) \
   $(TREE_H) basic-block.h $(RTL_H) gimple.h targhooks.h cfgloop.h \
diff --git a/gcc/config/riscv/vector.md b/gcc/config/riscv/vector.md
index ef91950178f..0c59d1b90bc 100644
--- a/gcc/config/riscv/vector.md
+++ b/gcc/config/riscv/vector.md
@@ -809,7 +809,7 @@
 			  V1HF,V2HF,V4HF,V8HF,V16HF,V32HF,V64HF,V128HF,V256HF,V512HF,V1024HF,V2048HF,
 			  V1SF,V2SF,V4SF,V8SF,V16SF,V32SF,V64SF,V128SF,V256SF,V512SF,V1024SF,
 			  V1DF,V2DF,V4DF,V8DF,V16DF,V32DF,V64DF,V128DF,V256DF,V512DF")
-	   (symbol_ref "riscv_vector::NONVLMAX")
+	   (symbol_ref "riscv_vector::VLS")
 	(eq_attr "type" "vlde,vldff,vste,vimov,vimov,vimov,vfmov,vext,vimerge,\
 			  vfsqrt,vfrecp,vfmerge,vfcvtitof,vfcvtftoi,vfwcvtitof,\
 			  vfwcvtftoi,vfwcvtftof,vfncvtitof,vfncvtftoi,vfncvtftof,\
diff --git a/gcc/testsuite/gcc.dg/vect/costmodel/riscv/rvv/dynamic-lmul4-5.c b/gcc/testsuite/gcc.dg/vect/costmodel/riscv/rvv/dynamic-lmul4-5.c
index 928a507a363..5278e4aa38f 100644
--- a/gcc/testsuite/gcc.dg/vect/costmodel/riscv/rvv/dynamic-lmul4-5.c
+++ b/gcc/testsuite/gcc.dg/vect/costmodel/riscv/rvv/dynamic-lmul4-5.c
@@ -39,7 +39,7 @@ void foo2 (int16_t *__restrict a,
     }
 }
 
-/* { dg-final { scan-assembler {e32,m4} } } */
+/* { dg-final { scan-assembler {e16,m2} } } */
 /* { dg-final { scan-assembler-not {csrr} } } */
 /* { dg-final { scan-tree-dump-times "Maximum lmul = 8" 1 "vect" } } */
 /* { dg-final { scan-tree-dump-times "Maximum lmul = 4" 1 "vect" } } */
diff --git a/gcc/testsuite/gcc.dg/vect/costmodel/riscv/rvv/dynamic-lmul8-2.c b/gcc/testsuite/gcc.dg/vect/costmodel/riscv/rvv/dynamic-lmul8-2.c
index a50265fc1ec..1db2e073846 100644
--- a/gcc/testsuite/gcc.dg/vect/costmodel/riscv/rvv/dynamic-lmul8-2.c
+++ b/gcc/testsuite/gcc.dg/vect/costmodel/riscv/rvv/dynamic-lmul8-2.c
@@ -10,7 +10,7 @@ foo (int32_t *__restrict a, int16_t *__restrict b, int n)
     a[i] = a[i] + b[i];
 }
 
-/* { dg-final { scan-assembler {e32,m8} } } */
+/* { dg-final { scan-assembler {e16,m4} } } */
 /* { dg-final { scan-assembler-not {csrr} } } */
 /* { dg-final { scan-tree-dump-times "Maximum lmul = 8" 1 "vect" } } */
 /* { dg-final { scan-tree-dump-not "Maximum lmul = 4" "vect" } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-2.c
index eac7cbc757b..ca88d42cdf4 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/partial/select_vl-2.c
@@ -7,10 +7,11 @@
 /*
 ** foo:
 **	vsetivli\t[a-x0-9]+,\s*8,\s*e(8?|16?|32?|64),\s*m(1?|2?|4?|8?|f2?|f4?|f8),\s*t[au],\s*m[au]
+**	...
 **	vle32\.v\tv[0-9]+,0\([a-x0-9]+\)
 **	...
-**	vsetvli\t[a-x0-9]+,\s*[a-x0-9]+,\s*e(8?|16?|32?|64),\s*m(1?|2?|4?|8?|f2?|f4?|f8),\s*t[au],\s*m[au]
-**	add\t[a-x0-9]+,[a-x0-9]+,[a-x0-9]+
+**	vsetvli\tzero,\s*[a-x0-9]+,\s*e(8?|16?|32?|64),\s*m(1?|2?|4?|8?|f2?|f4?|f8),\s*t[au],\s*m[au]
+**	...
 **	vle32\.v\tv[0-9]+,0\([a-x0-9]+\)
 **	...
 */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-2.c
index 965365da4bb..13367423751 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-2.c
+++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/ternop/ternop_nofm-2.c
@@ -3,7 +3,6 @@
 
 #include "ternop-2.c"
 
-/* { dg-final { scan-assembler-times {\tvmacc\.vv} 8 } } */
 /* { dg-final { scan-assembler-times {\tvfma[c-d][c-d]\.vv} 9 } } */
 /* { dg-final { scan-tree-dump-times "COND_LEN_FMA" 9 "optimized" } } */
 /* { dg-final { scan-assembler-not {\tvmv} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/avlprop/pr111888-1.c b/gcc/testsuite/gcc.target/riscv/rvv/avlprop/pr111888-1.c
new file mode 100644
index 00000000000..b0d21650c3d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/avlprop/pr111888-1.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax -O3" } */
+
+void
+foo (int *__restrict a, int *__restrict b, int *__restrict c, int n)
+{
+  for (int i = 0; i < n; i++)
+    a[i] = b[i] + c[i];
+}
+
+/* { dg-final { scan-assembler-times {vsetvli} 1 } } */
+/* { dg-final { scan-assembler-not {vsetivli} } } */
+/* { dg-final { scan-assembler-times {vsetvli\s*[a-x0-9]+,\s*[a-x0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {vsetvli\s*[a-x0-9]+,\s*zero} } } */
+/* { dg-final { scan-assembler-not {vsetvli\s*zero} } } */
+/* { dg-final { scan-assembler-not {vsetivli\s*zero} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/avlprop/pr111888-2.c b/gcc/testsuite/gcc.target/riscv/rvv/avlprop/pr111888-2.c
new file mode 100644
index 00000000000..f2d8aa54b88
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/rvv/avlprop/pr111888-2.c
@@ -0,0 +1,33 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gcv -mabi=lp64d --param=riscv-autovec-preference=fixed-vlmax -O3" } */
+
+void
+foo (int *__restrict a, int *__restrict b, int *__restrict c,
+     int *__restrict a2, int *__restrict b2, int *__restrict c2,
+     int *__restrict a3, int *__restrict b3, int *__restrict c3,
+     int *__restrict a4, int *__restrict b4, int *__restrict c4,
+     int *__restrict a5, int *__restrict b5, int *__restrict c5,
+     int *__restrict d, int *__restrict d2, int *__restrict d3,
+     int *__restrict d4, int *__restrict d5, int n, int m)
+{
+  for (int i = 0; i < n; i++)
+    {
+      a[i] = b[i] + c[i];
+      a2[i] = b2[i] + c2[i];
+      a3[i] = b3[i] + c3[i];
+      a4[i] = b4[i] + c4[i];
+      a5[i] = a[i] + a4[i];
+      d[i] = a[i] - a2[i];
+      d2[i] = a2[i] * a[i];
+      d3[i] = a3[i] * a2[i];
+      d4[i] = a2[i] * d2[i];
+      d5[i] = a[i] * a2[i] * a3[i] * a4[i] * d[i];
+    }
+}
+
+/* { dg-final { scan-assembler-times {vsetvli} 1 } } */
+/* { dg-final { scan-assembler-not {vsetivli} } } */
+/* { dg-final { scan-assembler-times {vsetvli\s*[a-x0-9]+,\s*[a-x0-9]+} 1 } } */
+/* { dg-final { scan-assembler-not {vsetvli\s*[a-x0-9]+,\s*zero} } } */
+/* { dg-final { scan-assembler-not {vsetvli\s*zero} } } */
+/* { dg-final { scan-assembler-not {vsetivli\s*zero} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
index 674ba0d72b4..fc830f2cd4d 100644
--- a/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
+++ b/gcc/testsuite/gcc.target/riscv/rvv/rvv.exp
@@ -48,6 +48,8 @@ gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/vsetvl/*.\[cS\]]] \
 	"" $CFLAGS
 dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/*.\[cS\]]] \
 	"-O3 -ftree-vectorize" $CFLAGS
+dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/avlprop/*.\[cS\]]] \
+	"-O3 -ftree-vectorize -fno-vect-cost-model" $CFLAGS
 dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/vls/*.\[cS\]]] \
 	"-O3 -ftree-vectorize --param riscv-autovec-preference=scalable" $CFLAGS
 dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/autovec/struct/*.\[cS\]]] \
