public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Lehua Ding <lehua.ding@rivai.ai>
To: gcc-patches@gcc.gnu.org
Cc: juzhe.zhong@rivai.ai, kito.cheng@gmail.com, rdapp.gcc@gmail.com,
	palmer@rivosinc.com, jeffreyalaw@gmail.com, lehua.ding@rivai.ai
Subject: [PATCH V3 01/11] RISC-V: P1: Refactor avl_info/vl_vtype_info/vector_insn_info/vector_block_info
Date: Thu, 19 Oct 2023 16:33:23 +0800	[thread overview]
Message-ID: <20231019083333.2052340-2-lehua.ding@rivai.ai> (raw)
In-Reply-To: <20231019083333.2052340-1-lehua.ding@rivai.ai>

gcc/ChangeLog:

	* config/riscv/riscv-vsetvl.cc (avl_info::avl_info): Removed.
	(avl_info::single_source_equal_p): Removed.
	(avl_info::multiple_source_equal_p): Removed.
	(avl_info::operator=): Removed.
	(avl_info::operator==): Removed.
	(avl_info::operator!=): Removed.
	(avl_info::has_non_zero_avl): Removed.
	(vl_vtype_info::vl_vtype_info): Removed.
	(vl_vtype_info::operator==): Removed.
	(vl_vtype_info::operator!=): Removed.
	(vl_vtype_info::same_avl_p): Removed.
	(vl_vtype_info::same_vtype_p): Removed.
	(enum demand_flags): New enum.
	(vl_vtype_info::same_vlmax_p): Removed.
	(vector_insn_info::operator>=): Removed.
	(enum class): New demand_type.
	(vector_insn_info::operator==): Removed.
	(vector_insn_info::parse_insn): Removed.
	(class vsetvl_info): New class.
	(vector_insn_info::compatible_p): Removed.
	(vector_insn_info::skip_avl_compatible_p): Removed.
	(vector_insn_info::compatible_avl_p): Removed.
	(vector_insn_info::compatible_vtype_p): Removed.
	(vector_insn_info::available_p): Removed.
	(vector_insn_info::fuse_avl): Removed.
	(vector_insn_info::fuse_sew_lmul): Removed.
	(vector_insn_info::fuse_tail_policy): Removed.
	(vector_insn_info::fuse_mask_policy): Removed.
	(vector_insn_info::local_merge): Removed.
	(vector_insn_info::global_merge): Removed.
	(vector_insn_info::get_avl_or_vl_reg): Removed.
	(vector_insn_info::update_fault_first_load_avl): Removed.
	(vlmul_to_str): Removed.
	(policy_to_str): Removed.
	(vector_insn_info::dump): Removed.
	(class vsetvl_block_info): New class.

---
 gcc/config/riscv/riscv-vsetvl.cc | 1401 +++++++++++++-----------------
 1 file changed, 602 insertions(+), 799 deletions(-)

diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc
index 4b06d93e7f9..8908071dc0d 100644
--- a/gcc/config/riscv/riscv-vsetvl.cc
+++ b/gcc/config/riscv/riscv-vsetvl.cc
@@ -1581,827 +1581,630 @@ vsetvl_dominated_by_p (const basic_block cfg_bb,
   return true;
 }
 
-avl_info::avl_info (const avl_info &other)
-{
-  m_value = other.get_value ();
-  m_source = other.get_source ();
-}
-
-avl_info::avl_info (rtx value_in, set_info *source_in)
-  : m_value (value_in), m_source (source_in)
-{}
-
-bool
-avl_info::single_source_equal_p (const avl_info &other) const
-{
-  set_info *set1 = m_source;
-  set_info *set2 = other.get_source ();
-  insn_info *insn1 = extract_single_source (set1);
-  insn_info *insn2 = extract_single_source (set2);
-  if (!insn1 || !insn2)
-    return false;
-  return source_equal_p (insn1, insn2);
-}
-
-bool
-avl_info::multiple_source_equal_p (const avl_info &other) const
-{
-  /* When the def info is same in RTL_SSA namespace, it's safe
-     to consider they are avl compatible.  */
-  if (m_source == other.get_source ())
-    return true;
-
-  /* We only consider handle PHI node.  */
-  if (!m_source->insn ()->is_phi () || !other.get_source ()->insn ()->is_phi ())
-    return false;
-
-  phi_info *phi1 = as_a<phi_info *> (m_source);
-  phi_info *phi2 = as_a<phi_info *> (other.get_source ());
-
-  if (phi1->is_degenerate () && phi2->is_degenerate ())
-    {
-      /* Degenerate PHI means the PHI node only have one input.  */
-
-      /* If both PHI nodes have the same single input in use list.
-	 We consider they are AVL compatible.  */
-      if (phi1->input_value (0) == phi2->input_value (0))
-	return true;
-    }
-  /* TODO: We can support more optimization cases in the future.  */
-  return false;
-}
-
-avl_info &
-avl_info::operator= (const avl_info &other)
-{
-  m_value = other.get_value ();
-  m_source = other.get_source ();
-  return *this;
-}
-
-bool
-avl_info::operator== (const avl_info &other) const
-{
-  if (!m_value)
-    return !other.get_value ();
-  if (!other.get_value ())
-    return false;
-
-  if (GET_CODE (m_value) != GET_CODE (other.get_value ()))
-    return false;
-
-  /* Handle CONST_INT AVL.  */
-  if (CONST_INT_P (m_value))
-    return INTVAL (m_value) == INTVAL (other.get_value ());
-
-  /* Handle VLMAX AVL.  */
-  if (vlmax_avl_p (m_value))
-    return vlmax_avl_p (other.get_value ());
-  if (vlmax_avl_p (other.get_value ()))
-    return false;
-
-  /* If any source is undef value, we think they are not equal.  */
-  if (!m_source || !other.get_source ())
-    return false;
-
-  /* If both sources are single source (defined by a single real RTL)
-     and their definitions are same.  */
-  if (single_source_equal_p (other))
-    return true;
-
-  return multiple_source_equal_p (other);
-}
-
-bool
-avl_info::operator!= (const avl_info &other) const
-{
-  return !(*this == other);
-}
-
-bool
-avl_info::has_non_zero_avl () const
-{
-  if (has_avl_imm ())
-    return INTVAL (get_value ()) > 0;
-  if (has_avl_reg ())
-    return vlmax_avl_p (get_value ());
-  return false;
-}
-
-/* Initialize VL/VTYPE information.  */
-vl_vtype_info::vl_vtype_info (avl_info avl_in, uint8_t sew_in,
-			      enum vlmul_type vlmul_in, uint8_t ratio_in,
-			      bool ta_in, bool ma_in)
-  : m_avl (avl_in), m_sew (sew_in), m_vlmul (vlmul_in), m_ratio (ratio_in),
-    m_ta (ta_in), m_ma (ma_in)
-{
-  gcc_assert (valid_sew_p (m_sew) && "Unexpected SEW");
-}
-
-bool
-vl_vtype_info::operator== (const vl_vtype_info &other) const
-{
-  return same_avl_p (other) && m_sew == other.get_sew ()
-	 && m_vlmul == other.get_vlmul () && m_ta == other.get_ta ()
-	 && m_ma == other.get_ma () && m_ratio == other.get_ratio ();
-}
-
-bool
-vl_vtype_info::operator!= (const vl_vtype_info &other) const
-{
-  return !(*this == other);
-}
-
-bool
-vl_vtype_info::same_avl_p (const vl_vtype_info &other) const
-{
-  /* We need to compare both RTL and SET. If both AVL are CONST_INT.
-     For example, const_int 3 and const_int 4, we need to compare
-     RTL. If both AVL are REG and their REGNO are same, we need to
-     compare SET.  */
-  return get_avl () == other.get_avl ()
-	 && get_avl_source () == other.get_avl_source ();
-}
-
-bool
-vl_vtype_info::same_vtype_p (const vl_vtype_info &other) const
-{
-  return get_sew () == other.get_sew () && get_vlmul () == other.get_vlmul ()
-	 && get_ta () == other.get_ta () && get_ma () == other.get_ma ();
-}
+/* 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
+   require SEW and LMUL to be fixed.
+   Therefore, if the former RVV instruction needs DEMAND_RATIO_P and the latter
+   instruction needs DEMAND_SEW_LMUL_P and its SEW/LMUL is the same as that of
+   the former instruction, then we can make the minimu demand of the former
+   instruction strict to DEMAND_SEW_LMUL_P, and its required SEW and LMUL are
+   the SEW and LMUL of the latter instruction, and the vsetvl instruction
+   generated according to the new demand can also be used for the latter
+   instruction, so there is no need to insert a separate vsetvl instruction for
+   the latter instruction.  */
+enum demand_flags : unsigned
+{
+  DEMAND_EMPTY_P = 0,
+  DEMAND_SEW_P = 1 << 0,
+  DEMAND_LMUL_P = 1 << 1,
+  DEMAND_RATIO_P = 1 << 2,
+  DEMAND_GE_SEW_P = 1 << 3,
+  DEMAND_TAIL_POLICY_P = 1 << 4,
+  DEMAND_MASK_POLICY_P = 1 << 5,
+  DEMAND_AVL_P = 1 << 6,
+  DEMAND_NON_ZERO_AVL_P = 1 << 7,
+};
 
-bool
-vl_vtype_info::same_vlmax_p (const vl_vtype_info &other) const
-{
-  return get_ratio () == other.get_ratio ();
-}
+/* We split the demand information into three parts. They are sew and lmul
+   related (sew_lmul_demand_type), tail and mask policy related
+   (policy_demand_type) and avl related (avl_demand_type). Then we define three
+   interfaces avaiable_with, compatible_p and merge. avaiable_with is
+   used to determine whether the two vsetvl infos prev_info and next_info are
+   available or not. If prev_info is available for next_info, it means that the
+   RVV insn corresponding to next_info on the path from prev_info to next_info
+   can be used without inserting a separate vsetvl instruction. compatible_p
+   is used to determine whether prev_info is compatible with next_info, and if
+   so, merge can be used to merge the stricter demand information from
+   next_info into prev_info so that prev_info becomes available to next_info.
+ */
 
-/* Compare the compatibility between Dem1 and Dem2.
-   If Dem1 > Dem2, Dem1 has bigger compatibility then Dem2
-   meaning Dem1 is easier be compatible with others than Dem2
-   or Dem2 is stricter than Dem1.
-   For example, Dem1 (demand SEW + LMUL) > Dem2 (demand RATIO).  */
-bool
-vector_insn_info::operator>= (const vector_insn_info &other) const
+enum class sew_lmul_demand_type : unsigned
 {
-  if (support_relaxed_compatible_p (*this, other))
-    {
-      unsigned array_size = sizeof (unavailable_conds) / sizeof (demands_cond);
-      /* Bypass AVL unavailable cases.  */
-      for (unsigned i = 2; i < array_size; i++)
-	if (unavailable_conds[i].pair.match_cond_p (this->get_demands (),
-						    other.get_demands ())
-	    && unavailable_conds[i].incompatible_p (*this, other))
-	  return false;
-      return true;
-    }
-
-  if (!other.compatible_p (static_cast<const vl_vtype_info &> (*this)))
-    return false;
-  if (!this->compatible_p (static_cast<const vl_vtype_info &> (other)))
-    return true;
-
-  if (*this == other)
-    return true;
-
-  for (const auto &cond : unavailable_conds)
-    if (cond.pair.match_cond_p (this->get_demands (), other.get_demands ())
-	&& cond.incompatible_p (*this, other))
-      return false;
-
-  return true;
-}
+  sew_lmul = demand_flags::DEMAND_SEW_P | demand_flags::DEMAND_LMUL_P,
+  ratio_only = demand_flags::DEMAND_RATIO_P,
+  sew_only = demand_flags::DEMAND_SEW_P,
+  ge_sew = demand_flags::DEMAND_GE_SEW_P,
+  ratio_and_ge_sew
+  = demand_flags::DEMAND_RATIO_P | demand_flags::DEMAND_GE_SEW_P,
+};
 
-bool
-vector_insn_info::operator== (const vector_insn_info &other) const
+enum class policy_demand_type : unsigned
 {
-  gcc_assert (!uninit_p () && !other.uninit_p ()
-	      && "Uninitialization should not happen");
-
-  /* Empty is only equal to another Empty.  */
-  if (empty_p ())
-    return other.empty_p ();
-  if (other.empty_p ())
-    return empty_p ();
-
-  /* Unknown is only equal to another Unknown.  */
-  if (unknown_p ())
-    return other.unknown_p ();
-  if (other.unknown_p ())
-    return unknown_p ();
-
-  for (size_t i = 0; i < NUM_DEMAND; i++)
-    if (m_demands[i] != other.demand_p ((enum demand_type) i))
-      return false;
-
-  /* We should consider different INSN demands as different
-     expression.  Otherwise, we will be doing incorrect vsetvl
-     elimination.  */
-  if (m_insn != other.get_insn ())
-    return false;
-
-  if (!same_avl_p (other))
-    return false;
-
-  /* If the full VTYPE is valid, check that it is the same.  */
-  return same_vtype_p (other);
-}
+  tail_mask_policy
+  = demand_flags::DEMAND_TAIL_POLICY_P | demand_flags::DEMAND_MASK_POLICY_P,
+  tail_policy_only = demand_flags::DEMAND_TAIL_POLICY_P,
+  mask_policy_only = demand_flags::DEMAND_MASK_POLICY_P,
+  ignore_policy = demand_flags::DEMAND_EMPTY_P,
+};
 
-void
-vector_insn_info::parse_insn (rtx_insn *rinsn)
+enum class avl_demand_type : unsigned
 {
-  *this = vector_insn_info ();
-  if (!NONDEBUG_INSN_P (rinsn))
-    return;
-  if (optimize == 0 && !has_vtype_op (rinsn))
-    return;
-  gcc_assert (!vsetvl_discard_result_insn_p (rinsn));
-  m_state = VALID;
-  extract_insn_cached (rinsn);
-  rtx avl = ::get_avl (rinsn);
-  m_avl = avl_info (avl, nullptr);
-  m_sew = ::get_sew (rinsn);
-  m_vlmul = ::get_vlmul (rinsn);
-  m_ta = tail_agnostic_p (rinsn);
-  m_ma = mask_agnostic_p (rinsn);
-}
+  avl = demand_flags::DEMAND_AVL_P,
+  non_zero_avl = demand_flags::DEMAND_NON_ZERO_AVL_P,
+  ignore_avl = demand_flags::DEMAND_EMPTY_P,
+};
 
-void
-vector_insn_info::parse_insn (insn_info *insn)
+class vsetvl_info
 {
-  *this = vector_insn_info ();
-
-  /* Return if it is debug insn for the consistency with optimize == 0.  */
-  if (insn->is_debug_insn ())
-    return;
+private:
+  insn_info *m_insn;
+  bb_info *m_bb;
+  rtx m_avl;
+  rtx m_vl;
+  set_info *m_avl_def;
+  uint8_t m_sew;
+  uint8_t m_max_sew;
+  vlmul_type m_vlmul;
+  uint8_t m_ratio;
+  bool m_ta;
+  bool m_ma;
+
+  sew_lmul_demand_type m_sew_lmul_demand;
+  policy_demand_type m_policy_demand;
+  avl_demand_type m_avl_demand;
+
+  enum class state_type
+  {
+    UNINITIALIZED,
+    VALID,
+    UNKNOWN,
+    EMPTY,
+  };
+  state_type m_state;
+
+  bool m_delete;
+  bool m_change_vtype_only;
+  insn_info *m_read_vl_insn;
+  bool m_vl_used_by_non_rvv_insn;
 
-  /* We set it as unknown since we don't what will happen in CALL or ASM.  */
-  if (insn->is_call () || insn->is_asm ())
-    {
-      set_unknown ();
+public:
+  vsetvl_info ()
+    : m_insn (nullptr), m_bb (nullptr), m_avl (NULL_RTX), m_vl (NULL_RTX),
+      m_avl_def (nullptr), m_sew (0), m_max_sew (0), m_vlmul (LMUL_RESERVED),
+      m_ratio (0), m_ta (false), m_ma (false),
+      m_sew_lmul_demand (sew_lmul_demand_type::sew_lmul),
+      m_policy_demand (policy_demand_type::tail_mask_policy),
+      m_avl_demand (avl_demand_type::avl), m_state (state_type::UNINITIALIZED),
+      m_delete (false), m_change_vtype_only (false), m_read_vl_insn (nullptr),
+      m_vl_used_by_non_rvv_insn (false)
+  {}
+
+  vsetvl_info (insn_info *insn) : vsetvl_info () { parse_insn (insn); }
+
+  vsetvl_info (rtx_insn *insn) : vsetvl_info () { parse_insn (insn); }
+
+  void set_avl (rtx avl) { m_avl = avl; }
+  void set_vl (rtx vl) { m_vl = vl; }
+  void set_avl_def (set_info *avl_def) { m_avl_def = avl_def; }
+  void set_sew (uint8_t sew) { m_sew = sew; }
+  void set_vlmul (vlmul_type vlmul) { m_vlmul = vlmul; }
+  void set_ratio (uint8_t ratio) { m_ratio = ratio; }
+  void set_ta (bool ta) { m_ta = ta; }
+  void set_ma (bool ma) { m_ma = ma; }
+  void set_delete () { m_delete = true; }
+  void set_bb (bb_info *bb) { m_bb = bb; }
+  void set_max_sew (uint8_t max_sew) { m_max_sew = max_sew; }
+  void set_change_vtype_only () { m_change_vtype_only = true; }
+  void set_read_vl_insn (insn_info *insn) { m_read_vl_insn = insn; }
+
+  rtx get_avl () const { return m_avl; }
+  rtx get_vl () const { return m_vl; }
+  set_info *get_avl_def () const { return m_avl_def; }
+  uint8_t get_sew () const { return m_sew; }
+  vlmul_type get_vlmul () const { return m_vlmul; }
+  uint8_t get_ratio () const { return m_ratio; }
+  bool get_ta () const { return m_ta; }
+  bool get_ma () const { return m_ma; }
+  insn_info *get_insn () const { return m_insn; }
+  bool delete_p () const { return m_delete; }
+  bb_info *get_bb () const { return m_bb; }
+  uint8_t get_max_sew () const { return m_max_sew; }
+  insn_info *get_read_vl_insn () const { return m_read_vl_insn; }
+  bool vl_use_by_non_rvv_insn_p () const { return m_vl_used_by_non_rvv_insn; }
+
+  bool has_imm_avl () const { return m_avl && CONST_INT_P (m_avl); }
+  bool has_vlmax_avl () const { return vlmax_avl_p (m_avl); }
+  bool has_nonvlmax_reg_avl () const
+  {
+    return m_avl && REG_P (m_avl) && !has_vlmax_avl ();
+  }
+  bool has_non_zero_avl () const
+  {
+    if (has_imm_avl ())
+      return INTVAL (m_avl) > 0;
+    return has_vlmax_avl ();
+  }
+  bool has_vl () const
+  {
+    /* The VL operand can only be either a NULL_RTX or a register.   */
+    gcc_assert (!m_vl || REG_P (m_vl));
+    return m_vl != NULL_RTX;
+  }
+  bool has_same_ratio (const vsetvl_info &other) const
+  {
+    return get_ratio () == other.get_ratio ();
+  }
+
+  /* The block of INSN isn't always same as the block of the VSETVL_INFO,
+      meaning we may have 'get_insn ()->bb () != get_bb ()'.
+
+	E.g.  BB 2 (Empty) ---> BB 3 (VALID, has rvv insn 1)
+
+     BB 2 has empty VSETVL_INFO, wheras BB 3 has VSETVL_INFO that satisfies
+     get_insn ()->bb () == get_bb (). In earliest fusion, we may fuse bb 3 and
+     bb 2 so that the 'get_bb ()' of BB2 VSETVL_INFO will be BB2 wheras the
+     'get_insn ()' of BB2 VSETVL INFO will be the rvv insn 1 (which is located
+     at BB3).  */
+  bool insn_inside_bb_p () const { return get_insn ()->bb () == get_bb (); }
+  void update_avl (const vsetvl_info &other)
+  {
+    m_avl = other.get_avl ();
+    m_vl = other.get_vl ();
+    m_avl_def = other.get_avl_def ();
+  }
+
+  bool uninit_p () const { return m_state == state_type::UNINITIALIZED; }
+  bool valid_p () const { return m_state == state_type::VALID; }
+  bool unknown_p () const { return m_state == state_type::UNKNOWN; }
+  bool empty_p () const { return m_state == state_type::EMPTY; }
+  bool change_vtype_only_p () const { return m_change_vtype_only; }
+
+  void set_valid () { m_state = state_type::VALID; }
+  void set_unknown () { m_state = state_type::UNKNOWN; }
+  void set_empty () { m_state = state_type::EMPTY; }
+
+  void set_sew_lmul_demand (sew_lmul_demand_type demand)
+  {
+    m_sew_lmul_demand = demand;
+  }
+  void set_policy_demand (policy_demand_type demand)
+  {
+    m_policy_demand = demand;
+  }
+  void set_avl_demand (avl_demand_type demand) { m_avl_demand = demand; }
+
+  sew_lmul_demand_type get_sew_lmul_demand () const
+  {
+    return m_sew_lmul_demand;
+  }
+  policy_demand_type get_policy_demand () const { return m_policy_demand; }
+  avl_demand_type get_avl_demand () const { return m_avl_demand; }
+
+  void normalize_demand (unsigned demand_flags)
+  {
+    switch (demand_flags
+	    & (DEMAND_SEW_P | DEMAND_LMUL_P | DEMAND_RATIO_P | DEMAND_GE_SEW_P))
+      {
+      case (unsigned) sew_lmul_demand_type::sew_lmul:
+	m_sew_lmul_demand = sew_lmul_demand_type::sew_lmul;
+	break;
+      case (unsigned) sew_lmul_demand_type::ratio_only:
+	m_sew_lmul_demand = sew_lmul_demand_type::ratio_only;
+	break;
+      case (unsigned) sew_lmul_demand_type::sew_only:
+	m_sew_lmul_demand = sew_lmul_demand_type::sew_only;
+	break;
+      case (unsigned) sew_lmul_demand_type::ge_sew:
+	m_sew_lmul_demand = sew_lmul_demand_type::ge_sew;
+	break;
+      case (unsigned) sew_lmul_demand_type::ratio_and_ge_sew:
+	m_sew_lmul_demand = sew_lmul_demand_type::ratio_and_ge_sew;
+	break;
+      default:
+	gcc_unreachable ();
+      }
+
+    switch (demand_flags & (DEMAND_TAIL_POLICY_P | DEMAND_MASK_POLICY_P))
+      {
+      case (unsigned) policy_demand_type::tail_mask_policy:
+	m_policy_demand = policy_demand_type::tail_mask_policy;
+	break;
+      case (unsigned) policy_demand_type::tail_policy_only:
+	m_policy_demand = policy_demand_type::tail_policy_only;
+	break;
+      case (unsigned) policy_demand_type::mask_policy_only:
+	m_policy_demand = policy_demand_type::mask_policy_only;
+	break;
+      case (unsigned) policy_demand_type::ignore_policy:
+	m_policy_demand = policy_demand_type::ignore_policy;
+	break;
+      default:
+	gcc_unreachable ();
+      }
+
+    switch (demand_flags & (DEMAND_AVL_P | DEMAND_NON_ZERO_AVL_P))
+      {
+      case (unsigned) avl_demand_type::avl:
+	m_avl_demand = avl_demand_type::avl;
+	break;
+      case (unsigned) avl_demand_type::non_zero_avl:
+	m_avl_demand = avl_demand_type::non_zero_avl;
+	break;
+      case (unsigned) avl_demand_type::ignore_avl:
+	m_avl_demand = avl_demand_type::ignore_avl;
+	break;
+      default:
+	gcc_unreachable ();
+      }
+  }
+
+  void parse_insn (rtx_insn *rinsn)
+  {
+    if (!NONDEBUG_INSN_P (rinsn))
       return;
-    }
-
-  /* If this is something that updates VL/VTYPE that we don't know about, set
-     the state to unknown.  */
-  if (!vector_config_insn_p (insn->rtl ()) && !has_vtype_op (insn->rtl ())
-      && (find_access (insn->defs (), VL_REGNUM)
-	  || find_access (insn->defs (), VTYPE_REGNUM)))
-    {
-      set_unknown ();
+    if (optimize == 0 && !has_vtype_op (rinsn))
       return;
-    }
-
-  if (!vector_config_insn_p (insn->rtl ()) && !has_vtype_op (insn->rtl ()))
-    return;
-
-  /* Warning: This function has to work on both the lowered (i.e. post
-     emit_local_forward_vsetvls) and pre-lowering forms.  The main implication
-     of this is that it can't use the value of a SEW, VL, or Policy operand as
-     they might be stale after lowering.  */
-  vl_vtype_info::operator= (get_vl_vtype_info (insn));
-  m_insn = insn;
-  m_state = VALID;
-  if (vector_config_insn_p (insn->rtl ()))
-    {
-      m_demands[DEMAND_AVL] = true;
-      m_demands[DEMAND_RATIO] = true;
+    gcc_assert (!vsetvl_discard_result_insn_p (rinsn));
+    set_valid ();
+    extract_insn_cached (rinsn);
+    m_avl = ::get_avl (rinsn);
+    if (has_vlmax_avl () || vsetvl_insn_p (rinsn))
+      m_vl = ::get_vl (rinsn);
+    m_sew = ::get_sew (rinsn);
+    m_vlmul = ::get_vlmul (rinsn);
+    m_ta = tail_agnostic_p (rinsn);
+    m_ma = mask_agnostic_p (rinsn);
+  }
+
+  void parse_insn (insn_info *insn)
+  {
+    m_insn = insn;
+    m_bb = insn->bb ();
+    /* Return if it is debug insn for the consistency with optimize == 0.  */
+    if (insn->is_debug_insn ())
       return;
-    }
-
-  if (has_vl_op (insn->rtl ()))
-    m_demands[DEMAND_AVL] = true;
-
-  if (get_attr_ratio (insn->rtl ()) != INVALID_ATTRIBUTE)
-    m_demands[DEMAND_RATIO] = true;
-  else
-    {
-      /* TODO: By default, if it doesn't demand RATIO, we set it
-	 demand SEW && LMUL both. Some instructions may demand SEW
-	 only and ignore LMUL, will fix it later.  */
-      m_demands[DEMAND_SEW] = true;
-      if (!ignore_vlmul_insn_p (insn->rtl ()))
-	m_demands[DEMAND_LMUL] = true;
-    }
-
-  if (get_attr_ta (insn->rtl ()) != INVALID_ATTRIBUTE)
-    m_demands[DEMAND_TAIL_POLICY] = true;
-  if (get_attr_ma (insn->rtl ()) != INVALID_ATTRIBUTE)
-    m_demands[DEMAND_MASK_POLICY] = true;
-
-  if (vector_config_insn_p (insn->rtl ()))
-    return;
-
-  if (scalar_move_insn_p (insn->rtl ()))
-    {
-      if (m_avl.has_non_zero_avl ())
-	m_demands[DEMAND_NONZERO_AVL] = true;
-      if (m_ta)
-	m_demands[DEMAND_GE_SEW] = true;
-    }
-
-  if (!m_avl.has_avl_reg () || vlmax_avl_p (get_avl ()) || !m_avl.get_source ())
-    return;
-  if (!m_avl.get_source ()->insn ()->is_real ()
-      && !m_avl.get_source ()->insn ()->is_phi ())
-    return;
-
-  insn_info *def_insn = extract_single_source (m_avl.get_source ());
-  if (!def_insn || !vsetvl_insn_p (def_insn->rtl ()))
-    return;
-
-  vector_insn_info new_info;
-  new_info.parse_insn (def_insn);
-  if (!same_vlmax_p (new_info) && !scalar_move_insn_p (insn->rtl ()))
-    return;
-
-  if (new_info.has_avl ())
-    {
-      if (new_info.has_avl_imm ())
-	set_avl_info (avl_info (new_info.get_avl (), nullptr));
-      else
-	{
-	  if (vlmax_avl_p (new_info.get_avl ()))
-	    set_avl_info (avl_info (new_info.get_avl (), get_avl_source ()));
-	  else
-	    {
-	      /* Conservatively propagate non-VLMAX AVL of user vsetvl:
-		 1. The user vsetvl should be same block with the rvv insn.
-		 2. The user vsetvl is the only def insn of rvv insn.
-		 3. The AVL is not modified between def-use chain.
-		 4. The VL is only used by insn within EBB.
-	       */
-	      bool modified_p = false;
-	      for (insn_info *i = def_insn->next_nondebug_insn ();
-		   real_insn_and_same_bb_p (i, get_insn ()->bb ());
-		   i = i->next_nondebug_insn ())
-		{
-		  /* Consider this following sequence:
-
-		       insn 1: vsetvli a5,a3,e8,mf4,ta,mu
-		       insn 2: vsetvli zero,a5,e32,m1,ta,ma
-		       ...
-		       vle32.v v1,0(a1)
-		       vsetvli a2,zero,e32,m1,ta,ma
-		       vadd.vv v1,v1,v1
-		       vsetvli zero,a5,e32,m1,ta,ma
-		       vse32.v v1,0(a0)
-		       ...
-		       insn 3: sub     a3,a3,a5
-		       ...
-
-		       We can local AVL propagate "a3" from insn 1 to insn 2
-		       if no insns between insn 1 and insn 2 modify "a3 even
-		       though insn 3 modifies "a3".
-		       Otherwise, we can't perform local AVL propagation.
-
-		       Early break if we reach the insn 2.  */
-		  if (!before_p (i, insn))
-		    break;
-		  if (find_access (i->defs (), REGNO (new_info.get_avl ())))
-		    {
-		      modified_p = true;
-		      break;
-		    }
-		}
-
-	      bool has_live_out_use = false;
-	      for (use_info *use : m_avl.get_source ()->all_uses ())
-		{
-		  if (use->is_live_out_use ())
-		    {
-		      has_live_out_use = true;
-		      break;
-		    }
-		}
-	      if (!modified_p && !has_live_out_use
-		  && def_insn == m_avl.get_source ()->insn ()
-		  && m_insn->bb () == def_insn->bb ())
-		set_avl_info (new_info.get_avl_info ());
-	    }
-	}
-    }
-
-  if (scalar_move_insn_p (insn->rtl ()) && m_avl.has_non_zero_avl ())
-    m_demands[DEMAND_NONZERO_AVL] = true;
-}
-
-bool
-vector_insn_info::compatible_p (const vector_insn_info &other) const
-{
-  gcc_assert (valid_or_dirty_p () && other.valid_or_dirty_p ()
-	      && "Can't compare invalid demanded infos");
-
-  for (const auto &cond : incompatible_conds)
-    if (cond.dual_incompatible_p (*this, other))
-      return false;
-  return true;
-}
-
-bool
-vector_insn_info::skip_avl_compatible_p (const vector_insn_info &other) const
-{
-  gcc_assert (valid_or_dirty_p () && other.valid_or_dirty_p ()
-	      && "Can't compare invalid demanded infos");
-  unsigned array_size = sizeof (incompatible_conds) / sizeof (demands_cond);
-  /* Bypass AVL incompatible cases.  */
-  for (unsigned i = 1; i < array_size; i++)
-    if (incompatible_conds[i].dual_incompatible_p (*this, other))
-      return false;
-  return true;
-}
-
-bool
-vector_insn_info::compatible_avl_p (const vl_vtype_info &other) const
-{
-  gcc_assert (valid_or_dirty_p () && "Can't compare invalid vl_vtype_info");
-  gcc_assert (!unknown_p () && "Can't compare AVL in unknown state");
-  if (!demand_p (DEMAND_AVL))
-    return true;
-  if (demand_p (DEMAND_NONZERO_AVL) && other.has_non_zero_avl ())
-    return true;
-  return get_avl_info () == other.get_avl_info ();
-}
-
-bool
-vector_insn_info::compatible_avl_p (const avl_info &other) const
-{
-  gcc_assert (valid_or_dirty_p () && "Can't compare invalid vl_vtype_info");
-  gcc_assert (!unknown_p () && "Can't compare AVL in unknown state");
-  gcc_assert (demand_p (DEMAND_AVL) && "Can't compare AVL undemand state");
-  if (!demand_p (DEMAND_AVL))
-    return true;
-  if (demand_p (DEMAND_NONZERO_AVL) && other.has_non_zero_avl ())
-    return true;
-  return get_avl_info () == other;
-}
-
-bool
-vector_insn_info::compatible_vtype_p (const vl_vtype_info &other) const
-{
-  gcc_assert (valid_or_dirty_p () && "Can't compare invalid vl_vtype_info");
-  gcc_assert (!unknown_p () && "Can't compare VTYPE in unknown state");
-  if (demand_p (DEMAND_SEW))
-    {
-      if (!demand_p (DEMAND_GE_SEW) && m_sew != other.get_sew ())
-	return false;
-      if (demand_p (DEMAND_GE_SEW) && m_sew > other.get_sew ())
-	return false;
-    }
-  if (demand_p (DEMAND_LMUL) && m_vlmul != other.get_vlmul ())
-    return false;
-  if (demand_p (DEMAND_RATIO) && m_ratio != other.get_ratio ())
-    return false;
-  if (demand_p (DEMAND_TAIL_POLICY) && m_ta != other.get_ta ())
-    return false;
-  if (demand_p (DEMAND_MASK_POLICY) && m_ma != other.get_ma ())
-    return false;
-  return true;
-}
-
-/* Determine whether the vector instructions requirements represented by
-   Require are compatible with the previous vsetvli instruction represented
-   by this.  INSN is the instruction whose requirements we're considering.  */
-bool
-vector_insn_info::compatible_p (const vl_vtype_info &curr_info) const
-{
-  gcc_assert (!uninit_p () && "Can't handle uninitialized info");
-  if (empty_p ())
-    return false;
-
-  /* Nothing is compatible with Unknown.  */
-  if (unknown_p ())
-    return false;
-
-  /* If the instruction doesn't need an AVLReg and the SEW matches, consider
-     it compatible.  */
-  if (!demand_p (DEMAND_AVL))
-    if (m_sew == curr_info.get_sew ())
-      return true;
-
-  return compatible_avl_p (curr_info) && compatible_vtype_p (curr_info);
-}
 
-bool
-vector_insn_info::available_p (const vector_insn_info &other) const
-{
-  return *this >= other;
-}
-
-void
-vector_insn_info::fuse_avl (const vector_insn_info &info1,
-			    const vector_insn_info &info2)
-{
-  set_insn (info1.get_insn ());
-  if (info1.demand_p (DEMAND_AVL))
-    {
-      if (info1.demand_p (DEMAND_NONZERO_AVL))
-	{
-	  if (info2.demand_p (DEMAND_AVL)
-	      && !info2.demand_p (DEMAND_NONZERO_AVL))
-	    {
-	      set_avl_info (info2.get_avl_info ());
-	      set_demand (DEMAND_AVL, true);
-	      set_demand (DEMAND_NONZERO_AVL, false);
-	      return;
-	    }
-	}
-      set_avl_info (info1.get_avl_info ());
-      set_demand (DEMAND_NONZERO_AVL, info1.demand_p (DEMAND_NONZERO_AVL));
-    }
-  else
-    {
-      set_avl_info (info2.get_avl_info ());
-      set_demand (DEMAND_NONZERO_AVL, info2.demand_p (DEMAND_NONZERO_AVL));
-    }
-  set_demand (DEMAND_AVL,
-	      info1.demand_p (DEMAND_AVL) || info2.demand_p (DEMAND_AVL));
-}
-
-void
-vector_insn_info::fuse_sew_lmul (const vector_insn_info &info1,
-				 const vector_insn_info &info2)
-{
-  /* We need to fuse sew && lmul according to demand info:
-
-     1. GE_SEW.
-     2. SEW.
-     3. LMUL.
-     4. RATIO.  */
-  if (same_sew_lmul_demand_p (info1.get_demands (), info2.get_demands ()))
-    {
-      set_demand (DEMAND_SEW, info2.demand_p (DEMAND_SEW));
-      set_demand (DEMAND_LMUL, info2.demand_p (DEMAND_LMUL));
-      set_demand (DEMAND_RATIO, info2.demand_p (DEMAND_RATIO));
-      set_demand (DEMAND_GE_SEW, info2.demand_p (DEMAND_GE_SEW));
-      set_sew (info2.get_sew ());
-      set_vlmul (info2.get_vlmul ());
-      set_ratio (info2.get_ratio ());
+    /* We set it as unknown since we don't what will happen in CALL or ASM.  */
+    if (insn->is_call () || insn->is_asm ())
+      {
+	set_unknown ();
+	return;
+      }
+
+    /* If this is something that updates VL/VTYPE that we don't know about, set
+       the state to unknown.  */
+    if (!vector_config_insn_p (insn->rtl ()) && !has_vtype_op (insn->rtl ())
+	&& (find_access (insn->defs (), VL_REGNUM)
+	    || find_access (insn->defs (), VTYPE_REGNUM)))
+      {
+	set_unknown ();
+	return;
+      }
+
+    if (!vector_config_insn_p (insn->rtl ()) && !has_vtype_op (insn->rtl ()))
+      /* uninitialized */
       return;
-    }
-  for (const auto &rule : fuse_rules)
-    {
-      if (rule.pair.match_cond_p (info1.get_demands (), info2.get_demands ()))
-	{
-	  set_demand (DEMAND_SEW, rule.demand_sew_p);
-	  set_demand (DEMAND_LMUL, rule.demand_lmul_p);
-	  set_demand (DEMAND_RATIO, rule.demand_ratio_p);
-	  set_demand (DEMAND_GE_SEW, rule.demand_ge_sew_p);
-	  set_sew (rule.new_sew (info1, info2));
-	  set_vlmul (rule.new_vlmul (info1, info2));
-	  set_ratio (rule.new_ratio (info1, info2));
-	  return;
-	}
-      if (rule.pair.match_cond_p (info2.get_demands (), info1.get_demands ()))
-	{
-	  set_demand (DEMAND_SEW, rule.demand_sew_p);
-	  set_demand (DEMAND_LMUL, rule.demand_lmul_p);
-	  set_demand (DEMAND_RATIO, rule.demand_ratio_p);
-	  set_demand (DEMAND_GE_SEW, rule.demand_ge_sew_p);
-	  set_sew (rule.new_sew (info2, info1));
-	  set_vlmul (rule.new_vlmul (info2, info1));
-	  set_ratio (rule.new_ratio (info2, info1));
-	  return;
-	}
-    }
-  gcc_unreachable ();
-}
-
-void
-vector_insn_info::fuse_tail_policy (const vector_insn_info &info1,
-				    const vector_insn_info &info2)
-{
-  if (info1.demand_p (DEMAND_TAIL_POLICY))
-    {
-      set_ta (info1.get_ta ());
-      demand (DEMAND_TAIL_POLICY);
-    }
-  else if (info2.demand_p (DEMAND_TAIL_POLICY))
-    {
-      set_ta (info2.get_ta ());
-      demand (DEMAND_TAIL_POLICY);
-    }
-  else
-    set_ta (get_default_ta ());
-}
 
-void
-vector_insn_info::fuse_mask_policy (const vector_insn_info &info1,
-				    const vector_insn_info &info2)
-{
-  if (info1.demand_p (DEMAND_MASK_POLICY))
-    {
-      set_ma (info1.get_ma ());
-      demand (DEMAND_MASK_POLICY);
-    }
-  else if (info2.demand_p (DEMAND_MASK_POLICY))
-    {
-      set_ma (info2.get_ma ());
-      demand (DEMAND_MASK_POLICY);
-    }
-  else
-    set_ma (get_default_ma ());
-}
-
-vector_insn_info
-vector_insn_info::local_merge (const vector_insn_info &merge_info) const
-{
-  if (!vsetvl_insn_p (get_insn ()->rtl ()) && *this != merge_info)
-    gcc_assert (this->compatible_p (merge_info)
-		&& "Can't merge incompatible demanded infos");
-
-  vector_insn_info new_info;
-  new_info.set_valid ();
-  /* For local backward data flow, we always update INSN && AVL as the
-     latest INSN and AVL so that we can keep track status of each INSN.  */
-  new_info.fuse_avl (merge_info, *this);
-  new_info.fuse_sew_lmul (*this, merge_info);
-  new_info.fuse_tail_policy (*this, merge_info);
-  new_info.fuse_mask_policy (*this, merge_info);
-  return new_info;
-}
-
-vector_insn_info
-vector_insn_info::global_merge (const vector_insn_info &merge_info,
-				unsigned int bb_index) const
-{
-  if (!vsetvl_insn_p (get_insn ()->rtl ()) && *this != merge_info)
-    gcc_assert (this->compatible_p (merge_info)
-		&& "Can't merge incompatible demanded infos");
-
-  vector_insn_info new_info;
-  new_info.set_valid ();
-
-  /* For global data flow, we should keep original INSN and AVL if they
-  valid since we should keep the life information of each block.
-
-  For example:
-    bb 0 -> bb 1.
-  We should keep INSN && AVL of bb 1 since we will eventually emit
-  vsetvl instruction according to INSN and AVL of bb 1.  */
-  new_info.fuse_avl (*this, merge_info);
-  /* Recompute the AVL source whose block index is equal to BB_INDEX.  */
-  if (new_info.get_avl_source ()
-      && new_info.get_avl_source ()->insn ()->is_phi ()
-      && new_info.get_avl_source ()->bb ()->index () != bb_index)
-    {
-      hash_set<set_info *> sets
-	= get_all_sets (new_info.get_avl_source (), true, true, true);
-      new_info.set_avl_source (nullptr);
-      bool can_find_set_p = false;
-      set_info *first_set = nullptr;
-      for (set_info *set : sets)
-	{
-	  if (!first_set)
-	    first_set = set;
-	  if (set->bb ()->index () == bb_index)
-	    {
-	      gcc_assert (!can_find_set_p);
-	      new_info.set_avl_source (set);
-	      can_find_set_p = true;
-	    }
-	}
-      if (!can_find_set_p && sets.elements () == 1
-	  && first_set->insn ()->is_real ())
-	new_info.set_avl_source (first_set);
-    }
-
-  /* Make sure VLMAX AVL always has a set_info the get VL.  */
-  if (vlmax_avl_p (new_info.get_avl ()))
-    {
-      if (this->get_avl_source ())
-	new_info.set_avl_source (this->get_avl_source ());
-      else
-	{
-	  gcc_assert (merge_info.get_avl_source ());
-	  new_info.set_avl_source (merge_info.get_avl_source ());
-	}
-    }
-
-  new_info.fuse_sew_lmul (*this, merge_info);
-  new_info.fuse_tail_policy (*this, merge_info);
-  new_info.fuse_mask_policy (*this, merge_info);
-  return new_info;
-}
-
-/* Wrapper helps to return the AVL or VL operand for the
-   vector_insn_info. Return AVL if the AVL is not VLMAX.
-   Otherwise, return the VL operand.  */
-rtx
-vector_insn_info::get_avl_or_vl_reg (void) const
-{
-  gcc_assert (has_avl_reg ());
-  if (!vlmax_avl_p (get_avl ()))
-    return get_avl ();
-
-  rtx_insn *rinsn = get_insn ()->rtl ();
-  if (has_vl_op (rinsn) || vsetvl_insn_p (rinsn))
-    {
-      rtx vl = ::get_vl (rinsn);
-      /* For VLMAX, we should make sure we get the
-	 REG to emit 'vsetvl VL,zero' since the 'VL'
-	 should be the REG according to RVV ISA.  */
-      if (REG_P (vl))
-	return vl;
-    }
-
-  /* We always has avl_source if it is VLMAX AVL.  */
-  gcc_assert (get_avl_source ());
-  return get_avl_reg_rtx ();
-}
+    set_valid ();
+
+    m_avl = ::get_avl (insn->rtl ());
+    if (m_avl)
+      {
+	if (vsetvl_insn_p (insn->rtl ()) || has_vlmax_avl ())
+	  m_vl = ::get_vl (insn->rtl ());
+
+	if (has_nonvlmax_reg_avl ())
+	  m_avl_def = find_access (insn->uses (), REGNO (m_avl))->def ();
+      }
+
+    m_sew = ::get_sew (insn->rtl ());
+    m_vlmul = ::get_vlmul (insn->rtl ());
+    m_ratio = get_attr_ratio (insn->rtl ());
+    /* when get_attr_ratio is invalid, this kind of instructions
+       doesn't care about ratio. However, we still need this value
+       in demand info backward analysis.  */
+    if (m_ratio == INVALID_ATTRIBUTE)
+      m_ratio = calculate_ratio (m_sew, m_vlmul);
+    m_ta = tail_agnostic_p (insn->rtl ());
+    m_ma = mask_agnostic_p (insn->rtl ());
+
+    /* If merge operand is undef value, we prefer agnostic.  */
+    int merge_op_idx = get_attr_merge_op_idx (insn->rtl ());
+    if (merge_op_idx != INVALID_ATTRIBUTE
+	&& satisfies_constraint_vu (recog_data.operand[merge_op_idx]))
+      {
+	m_ta = true;
+	m_ma = true;
+      }
+
+    /* Determine the demand info of the RVV insn.  */
+    m_max_sew = get_max_int_sew ();
+    unsigned demand_flags = 0;
+    if (vector_config_insn_p (insn->rtl ()))
+      {
+	demand_flags |= demand_flags::DEMAND_AVL_P;
+	demand_flags |= demand_flags::DEMAND_RATIO_P;
+      }
+    else
+      {
+	if (has_vl_op (insn->rtl ()))
+	  {
+	    if (scalar_move_insn_p (insn->rtl ()))
+	      {
+		/* If the avl for vmv.s.x comes from the vsetvl instruction, we
+		   don't know if the avl is non-zero, so it is set to
+		   DEMAND_AVL_P for now. it may be corrected to
+		   DEMAND_NON_ZERO_AVL_P later when more information is
+		   available.
+		 */
+		if (has_non_zero_avl ())
+		  demand_flags |= demand_flags::DEMAND_NON_ZERO_AVL_P;
+		else
+		  demand_flags |= demand_flags::DEMAND_AVL_P;
+	      }
+	    else
+	      demand_flags |= demand_flags::DEMAND_AVL_P;
+	  }
 
-bool
-vector_insn_info::update_fault_first_load_avl (insn_info *insn)
-{
-  // Update AVL to vl-output of the fault first load.
-  const insn_info *read_vl = get_forward_read_vl_insn (insn);
-  if (read_vl)
-    {
-      rtx vl = SET_DEST (PATTERN (read_vl->rtl ()));
-      def_info *def = find_access (read_vl->defs (), REGNO (vl));
-      set_info *set = safe_dyn_cast<set_info *> (def);
-      set_avl_info (avl_info (vl, set));
-      set_insn (insn);
-      return true;
-    }
-  return false;
-}
+	if (get_attr_ratio (insn->rtl ()) != INVALID_ATTRIBUTE)
+	  demand_flags |= demand_flags::DEMAND_RATIO_P;
+	else
+	  {
+	    if (scalar_move_insn_p (insn->rtl ()) && m_ta)
+	      {
+		demand_flags |= demand_flags::DEMAND_GE_SEW_P;
+		m_max_sew = get_attr_type (insn->rtl ()) == TYPE_VFMOVFV
+			      ? get_max_float_sew ()
+			      : get_max_int_sew ();
+	      }
+	    else
+	      demand_flags |= demand_flags::DEMAND_SEW_P;
+
+	    if (!ignore_vlmul_insn_p (insn->rtl ()))
+	      demand_flags |= demand_flags::DEMAND_LMUL_P;
+	  }
 
-static const char *
-vlmul_to_str (vlmul_type vlmul)
-{
-  switch (vlmul)
-    {
-    case LMUL_1:
-      return "m1";
-    case LMUL_2:
-      return "m2";
-    case LMUL_4:
-      return "m4";
-    case LMUL_8:
-      return "m8";
-    case LMUL_RESERVED:
-      return "INVALID LMUL";
-    case LMUL_F8:
-      return "mf8";
-    case LMUL_F4:
-      return "mf4";
-    case LMUL_F2:
-      return "mf2";
+	if (!m_ta)
+	  demand_flags |= demand_flags::DEMAND_TAIL_POLICY_P;
+	if (!m_ma)
+	  demand_flags |= demand_flags::DEMAND_MASK_POLICY_P;
+      }
+
+    normalize_demand (demand_flags);
+
+    /* Optimize AVL from the vsetvl instruction.  */
+    insn_info *def_insn = extract_single_source (get_avl_def ());
+    if (def_insn && vsetvl_insn_p (def_insn->rtl ()))
+      {
+	vsetvl_info def_info = vsetvl_info (def_insn);
+	if ((scalar_move_insn_p (insn->rtl ())
+	     || def_info.get_ratio () == get_ratio ())
+	    && (def_info.has_vlmax_avl () || def_info.has_imm_avl ()))
+	  {
+	    update_avl (def_info);
+	    if (scalar_move_insn_p (insn->rtl ()) && has_non_zero_avl ())
+	      m_avl_demand = avl_demand_type::non_zero_avl;
+	  }
+      }
+
+    /* Determine if dest operand(vl) has been used by non-RVV instructions.  */
+    if (has_vl ())
+      {
+	const hash_set<use_info *> vl_uses
+	  = get_all_real_uses (get_insn (), REGNO (get_vl ()));
+	for (use_info *use : vl_uses)
+	  {
+	    gcc_assert (use->insn ()->is_real ());
+	    rtx_insn *rinsn = use->insn ()->rtl ();
+	    if (!has_vl_op (rinsn)
+		|| count_regno_occurrences (rinsn, REGNO (get_vl ())) != 1)
+	      {
+		m_vl_used_by_non_rvv_insn = true;
+		break;
+	      }
+	    rtx avl = ::get_avl (rinsn);
+	    if (!avl || REGNO (get_vl ()) != REGNO (avl))
+	      {
+		m_vl_used_by_non_rvv_insn = true;
+		break;
+	      }
+	  }
+      }
 
-    default:
+    /* Collect the read vl insn for the fault-only-first rvv loads.  */
+    if (fault_first_load_p (insn->rtl ()))
+      {
+	for (insn_info *i = insn->next_nondebug_insn ();
+	     i->bb () == insn->bb (); i = i->next_nondebug_insn ())
+	  {
+	    if (find_access (i->defs (), VL_REGNUM))
+	      break;
+	    if (i->rtl () && read_vl_insn_p (i->rtl ()))
+	      {
+		m_read_vl_insn = i;
+		break;
+	      }
+	  }
+      }
+  }
+
+  /* Returns the corresponding vsetvl rtx pat.  */
+  rtx get_vsetvl_pat (bool ignore_vl = false) const
+  {
+    rtx avl = get_avl ();
+    /* if optimization == 0 and the instruction is vmv.x.s/vfmv.f.s,
+       set the value of avl to (const_int 0) so that VSETVL PASS will
+       insert vsetvl correctly.*/
+    if (!get_avl ())
+      avl = GEN_INT (0);
+    rtx sew = gen_int_mode (get_sew (), Pmode);
+    rtx vlmul = gen_int_mode (get_vlmul (), Pmode);
+    rtx ta = gen_int_mode (get_ta (), Pmode);
+    rtx ma = gen_int_mode (get_ma (), Pmode);
+
+    if (change_vtype_only_p ())
+      return gen_vsetvl_vtype_change_only (sew, vlmul, ta, ma);
+    else if (has_vl () && !ignore_vl)
+      return gen_vsetvl (Pmode, get_vl (), avl, sew, vlmul, ta, ma);
+    else
+      return gen_vsetvl_discard_result (Pmode, avl, sew, vlmul, ta, ma);
+  }
+
+  bool operator== (const vsetvl_info &other) const
+  {
+    gcc_assert (!uninit_p () && !other.uninit_p ()
+		&& "Uninitialization should not happen");
+
+    if (empty_p ())
+      return other.empty_p ();
+    if (unknown_p ())
+      return other.unknown_p ();
+
+    return get_insn () == other.get_insn () && get_bb () == other.get_bb ()
+	   && get_avl () == other.get_avl () && get_vl () == other.get_vl ()
+	   && get_avl_def () == other.get_avl_def ()
+	   && get_sew () == other.get_sew ()
+	   && get_vlmul () == other.get_vlmul () && get_ta () == other.get_ta ()
+	   && get_ma () == other.get_ma ()
+	   && get_avl_demand () == other.get_avl_demand ()
+	   && get_sew_lmul_demand () == other.get_sew_lmul_demand ()
+	   && get_policy_demand () == other.get_policy_demand ();
+  }
+
+  void dump (FILE *file, const char *indent = "") const
+  {
+    if (uninit_p ())
+      {
+	fprintf (file, "UNINITIALIZED.\n");
+	return;
+      }
+    else if (unknown_p ())
+      {
+	fprintf (file, "UNKNOWN.\n");
+	return;
+      }
+    else if (empty_p ())
+      {
+	fprintf (file, "EMPTY.\n");
+	return;
+      }
+    else if (valid_p ())
+      fprintf (file, "VALID (insn %u, bb %u)%s\n", get_insn ()->uid (),
+	       get_bb ()->index (), delete_p () ? " (deleted)" : "");
+    else
       gcc_unreachable ();
-    }
-}
 
-static const char *
-policy_to_str (bool agnostic_p)
-{
-  return agnostic_p ? "agnostic" : "undisturbed";
-}
+    fprintf (file, "%sDemand fields:", indent);
+    if (m_sew_lmul_demand == sew_lmul_demand_type::sew_lmul)
+      fprintf (file, " demand_sew_lmul");
+    else if (m_sew_lmul_demand == sew_lmul_demand_type::ratio_only)
+      fprintf (file, " demand_ratio_only");
+    else if (m_sew_lmul_demand == sew_lmul_demand_type::sew_only)
+      fprintf (file, " demand_sew_only");
+    else if (m_sew_lmul_demand == sew_lmul_demand_type::ge_sew)
+      fprintf (file, " demand_ge_sew");
+    else if (m_sew_lmul_demand == sew_lmul_demand_type::ratio_and_ge_sew)
+      fprintf (file, " demand_ratio_and_ge_sew");
+
+    if (m_policy_demand == policy_demand_type::tail_mask_policy)
+      fprintf (file, " demand_tail_mask_policy");
+    else if (m_policy_demand == policy_demand_type::tail_policy_only)
+      fprintf (file, " demand_tail_policy_only");
+    else if (m_policy_demand == policy_demand_type::mask_policy_only)
+      fprintf (file, " demand_mask_policy_only");
+
+    if (m_avl_demand == avl_demand_type::avl)
+      fprintf (file, " demand_avl");
+    else if (m_avl_demand == avl_demand_type::non_zero_avl)
+      fprintf (file, " demand_non_zero_avl");
+    fprintf (file, "\n");
+
+    fprintf (file, "%sSEW=%d, ", indent, get_sew ());
+    fprintf (file, "VLMUL=%s, ", vlmul_to_str (get_vlmul ()));
+    fprintf (file, "RATIO=%d, ", get_ratio ());
+    fprintf (file, "MAX_SEW=%d\n", get_max_sew ());
+
+    fprintf (file, "%sTAIL_POLICY=%s, ", indent, policy_to_str (get_ta ()));
+    fprintf (file, "MASK_POLICY=%s\n", policy_to_str (get_ma ()));
+
+    fprintf (file, "%sAVL=", indent);
+    print_rtl_single (file, get_avl ());
+    fprintf (file, "%sVL=", indent);
+    print_rtl_single (file, get_vl ());
+    if (change_vtype_only_p ())
+      fprintf (file, "%schange vtype only\n", indent);
+    if (get_read_vl_insn ())
+      fprintf (file, "%sread_vl_insn: insn %u\n", indent,
+	       get_read_vl_insn ()->uid ());
+    if (vl_use_by_non_rvv_insn_p ())
+      fprintf (file, "%suse_by_non_rvv_insn=true\n", indent);
+  }
+};
 
-void
-vector_insn_info::dump (FILE *file) const
-{
-  fprintf (file, "[");
-  if (uninit_p ())
-    fprintf (file, "UNINITIALIZED,");
-  else if (valid_p ())
-    fprintf (file, "VALID,");
-  else if (unknown_p ())
-    fprintf (file, "UNKNOWN,");
-  else if (empty_p ())
-    fprintf (file, "EMPTY,");
-  else
-    fprintf (file, "DIRTY,");
-
-  fprintf (file, "Demand field={%d(VL),", demand_p (DEMAND_AVL));
-  fprintf (file, "%d(DEMAND_NONZERO_AVL),", demand_p (DEMAND_NONZERO_AVL));
-  fprintf (file, "%d(SEW),", demand_p (DEMAND_SEW));
-  fprintf (file, "%d(DEMAND_GE_SEW),", demand_p (DEMAND_GE_SEW));
-  fprintf (file, "%d(LMUL),", demand_p (DEMAND_LMUL));
-  fprintf (file, "%d(RATIO),", demand_p (DEMAND_RATIO));
-  fprintf (file, "%d(TAIL_POLICY),", demand_p (DEMAND_TAIL_POLICY));
-  fprintf (file, "%d(MASK_POLICY)}\n", demand_p (DEMAND_MASK_POLICY));
-
-  fprintf (file, "AVL=");
-  print_rtl_single (file, get_avl ());
-  fprintf (file, "SEW=%d,", get_sew ());
-  fprintf (file, "VLMUL=%s,", vlmul_to_str (get_vlmul ()));
-  fprintf (file, "RATIO=%d,", get_ratio ());
-  fprintf (file, "TAIL_POLICY=%s,", policy_to_str (get_ta ()));
-  fprintf (file, "MASK_POLICY=%s", policy_to_str (get_ma ()));
-  fprintf (file, "]\n");
-
-  if (valid_p ())
-    {
-      if (get_insn ())
-	{
-	  fprintf (file, "The real INSN=");
-	  print_rtl_single (file, get_insn ()->rtl ());
-	}
-    }
-}
+class vsetvl_block_info
+{
+public:
+  /* The static execute probability of the demand info.  */
+  profile_probability probability;
+
+  auto_vec<vsetvl_info> infos;
+  vsetvl_info m_info;
+  bb_info *m_bb;
+
+  bool full_available;
+
+  vsetvl_block_info () : m_bb (nullptr), full_available (false)
+  {
+    infos.safe_grow_cleared (0);
+    m_info.set_empty ();
+  }
+  vsetvl_block_info (const vsetvl_block_info &other)
+    : probability (other.probability), infos (other.infos.copy ()),
+      m_info (other.m_info), m_bb (other.m_bb)
+  {}
+
+  vsetvl_info &get_entry_info ()
+  {
+    gcc_assert (!empty_p ());
+    return infos.is_empty () ? m_info : infos[0];
+  }
+  vsetvl_info &get_exit_info ()
+  {
+    gcc_assert (!empty_p ());
+    return infos.is_empty () ? m_info : infos[infos.length () - 1];
+  }
+  const vsetvl_info &get_entry_info () const
+  {
+    gcc_assert (!empty_p ());
+    return infos.is_empty () ? m_info : infos[0];
+  }
+  const vsetvl_info &get_exit_info () const
+  {
+    gcc_assert (!empty_p ());
+    return infos.is_empty () ? m_info : infos[infos.length () - 1];
+  }
+
+  bool empty_p () const { return infos.is_empty () && !has_info (); }
+  bool has_info () const { return !m_info.empty_p (); }
+  void set_info (const vsetvl_info &info)
+  {
+    gcc_assert (infos.is_empty ());
+    m_info = info;
+    m_info.set_bb (m_bb);
+  }
+  void set_empty_info () { m_info.set_empty (); }
+};
 
 vector_infos_manager::vector_infos_manager ()
 {
-- 
2.36.3


  reply	other threads:[~2023-10-19  8:33 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-10-19  8:33 [PATCH V3 00/11] Refactor and cleanup vsetvl pass Lehua Ding
2023-10-19  8:33 ` Lehua Ding [this message]
2023-10-19  8:33 ` [PATCH V3 02/11] RISC-V: P2: Refactor and cleanup demand system Lehua Ding
2023-10-19  8:33 ` [PATCH V3 03/11] RISC-V: P3: Refactor vector_infos_manager Lehua Ding
2023-10-19  8:33 ` [PATCH V3 04/11] RISC-V: P4: move method from pass_vsetvl to pre_vsetvl Lehua Ding
2023-10-19  8:33 ` [PATCH V3 05/11] RISC-V: P5: Combine phase 1 and 2 Lehua Ding
2023-10-19  8:33 ` [PATCH V3 06/11] RISC-V: P6: Add computing reaching definition data flow Lehua Ding
2023-10-19  8:33 ` [PATCH V3 07/11] RISC-V: P7: Move earliest fuse and lcm code to pre_vsetvl class Lehua Ding
2023-10-19  8:33 ` [PATCH V3 08/11] RISC-V: P8: Refactor emit-vsetvl phase and delete post optimization Lehua Ding
2023-10-19  8:33 ` [PATCH V3 09/11] RISC-V: P9: Cleanup and reorganize helper functions Lehua Ding
2023-10-19  8:33 ` [PATCH V3 10/11] RISC-V: P10: Delete riscv-vsetvl.h and adjust riscv-vsetvl.def Lehua Ding
2023-10-19  8:33 ` [PATCH V3 11/11] RISC-V: P11: Adjust and add testcases Lehua Ding
2023-10-19  8:38 ` [PATCH V3 00/11] Refactor and cleanup vsetvl pass Robin Dapp
2023-10-19  8:43   ` Lehua Ding
2023-10-19  8:50 ` 钟居哲
2023-10-19 18:04   ` Patrick O'Neill
2023-10-20  2:20     ` Lehua Ding
2023-10-20  3:58     ` Lehua Ding
2023-10-23 18:30       ` Patrick O'Neill
2023-10-23 21:41         ` 钟居哲
2023-10-23 22:46           ` Patrick O'Neill
2023-10-23 22:50             ` 钟居哲
2023-10-23 23:42               ` Patrick O'Neill
2023-10-24  0:51                 ` juzhe.zhong
2023-10-24  1:01                   ` Patrick O'Neill
2023-10-24  2:27                     ` juzhe.zhong

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20231019083333.2052340-2-lehua.ding@rivai.ai \
    --to=lehua.ding@rivai.ai \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jeffreyalaw@gmail.com \
    --cc=juzhe.zhong@rivai.ai \
    --cc=kito.cheng@gmail.com \
    --cc=palmer@rivosinc.com \
    --cc=rdapp.gcc@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).