[V2,05/14] RISC-V: P5: combine phase 1 and 2

Message ID 20231017113500.1160997-6-lehua.ding@rivai.ai
State Unresolved
Headers
Series Refactor and cleanup vsetvl pass |

Checks

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

Commit Message

Lehua Ding Oct. 17, 2023, 11:34 a.m. UTC
  This sub-patch combine phase 1 and 2 to use the new demand system and
delay the insert of vsetvl insn into phase 4.

gcc/ChangeLog:

	* config/riscv/riscv-vsetvl.cc (pre_vsetvl::fuse_local_vsetvl_info): New.
	(pass_vsetvl::compute_local_backward_infos): Removed.
	(pass_vsetvl::need_vsetvl): Removed.
	(pass_vsetvl::transfer_before): Removed.
	(pass_vsetvl::transfer_after): Removed.
	(pass_vsetvl::emit_local_forward_vsetvls): Removed.

---
 gcc/config/riscv/riscv-vsetvl.cc | 269 ++++++++++++++-----------------
 1 file changed, 123 insertions(+), 146 deletions(-)

--
2.36.3
  

Comments

juzhe.zhong@rivai.ai Oct. 18, 2023, 4:07 a.m. UTC | #1
LGTM on algorithm of local analysis.



juzhe.zhong@rivai.ai
 
From: Lehua Ding
Date: 2023-10-17 19:34
To: gcc-patches
CC: juzhe.zhong; kito.cheng; rdapp.gcc; palmer; jeffreyalaw; lehua.ding
Subject: [PATCH V2 05/14] RISC-V: P5: combine phase 1 and 2
This sub-patch combine phase 1 and 2 to use the new demand system and
delay the insert of vsetvl insn into phase 4.
 
gcc/ChangeLog:
 
* config/riscv/riscv-vsetvl.cc (pre_vsetvl::fuse_local_vsetvl_info): New.
(pass_vsetvl::compute_local_backward_infos): Removed.
(pass_vsetvl::need_vsetvl): Removed.
(pass_vsetvl::transfer_before): Removed.
(pass_vsetvl::transfer_after): Removed.
(pass_vsetvl::emit_local_forward_vsetvls): Removed.
 
---
gcc/config/riscv/riscv-vsetvl.cc | 269 ++++++++++++++-----------------
1 file changed, 123 insertions(+), 146 deletions(-)
 
diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc
index 3f07fde782f..33bdcec04d8 100644
--- a/gcc/config/riscv/riscv-vsetvl.cc
+++ b/gcc/config/riscv/riscv-vsetvl.cc
@@ -2669,6 +2669,129 @@ public:
   }
};
 
+void
+pre_vsetvl::fuse_local_vsetvl_info ()
+{
+  reg_def_loc
+    = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), GP_REG_LAST + 1);
+  bitmap_vector_clear (reg_def_loc, last_basic_block_for_fn (cfun));
+  bitmap_ones (reg_def_loc[ENTRY_BLOCK_PTR_FOR_FN (cfun)->index]);
+
+  for (bb_info *bb : crtl->ssa->bbs ())
+    {
+      auto &block_info = get_block_info (bb);
+      block_info.m_bb = bb;
+      if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+   fprintf (dump_file, "  Try fuse basic block %d\n", bb->index ());
+ }
+      auto_vec<vsetvl_info> infos;
+      for (insn_info *insn : bb->real_nondebug_insns ())
+ {
+   vsetvl_info curr_info = vsetvl_info (insn);
+   if (curr_info.valid_p () || curr_info.unknown_p ())
+     infos.safe_push (curr_info);
+
+   /* Collecting GP registers modified by the current bb.  */
+   if (insn->is_real ())
+     for (def_info *def : insn->defs ())
+       if (def->is_reg () && GP_REG_P (def->regno ()))
+ bitmap_set_bit (reg_def_loc[bb->index ()], def->regno ());
+ }
+
+      vsetvl_info prev_info = vsetvl_info ();
+      prev_info.set_empty ();
+      for (auto &curr_info : infos)
+ {
+   if (prev_info.empty_p ())
+     prev_info = curr_info;
+   else if ((curr_info.unknown_p () && prev_info.valid_p ())
+    || (curr_info.valid_p () && prev_info.unknown_p ()))
+     {
+       block_info.infos.safe_push (prev_info);
+       prev_info = curr_info;
+     }
+   else if (curr_info.valid_p () && prev_info.valid_p ())
+     {
+       if (dem.available_with (prev_info, curr_info))
+ {
+   if (dump_file && (dump_flags & TDF_DETAILS))
+     {
+       fprintf (dump_file,
+        "    Ignore curr info since prev info "
+        "available with it:\n");
+       fprintf (dump_file, "      prev_info: ");
+       prev_info.dump (dump_file, "        ");
+       fprintf (dump_file, "      curr_info: ");
+       curr_info.dump (dump_file, "        ");
+       fprintf (dump_file, "\n");
+     }
+   if (!curr_info.use_by_non_rvv_insn_p ()
+       && vsetvl_insn_p (curr_info.get_insn ()->rtl ()))
+     delete_list.safe_push (curr_info);
+
+   if (curr_info.get_read_vl_insn ())
+     prev_info.set_read_vl_insn (curr_info.get_read_vl_insn ());
+ }
+       else if (dem.compatible_with (prev_info, curr_info))
+ {
+   if (dump_file && (dump_flags & TDF_DETAILS))
+     {
+       fprintf (dump_file, "    Fuse curr info since prev info "
+   "compatible with it:\n");
+       fprintf (dump_file, "      prev_info: ");
+       prev_info.dump (dump_file, "        ");
+       fprintf (dump_file, "      curr_info: ");
+       curr_info.dump (dump_file, "        ");
+     }
+   dem.merge_with (prev_info, curr_info);
+   if (curr_info.get_read_vl_insn ())
+     prev_info.set_read_vl_insn (curr_info.get_read_vl_insn ());
+   if (dump_file && (dump_flags & TDF_DETAILS))
+     {
+       fprintf (dump_file, "      prev_info after fused: ");
+       prev_info.dump (dump_file, "        ");
+       fprintf (dump_file, "\n");
+     }
+ }
+       else
+ {
+   if (dump_file && (dump_flags & TDF_DETAILS))
+     {
+       fprintf (dump_file,
+        "    Cannot fuse uncompatible infos:\n");
+       fprintf (dump_file, "      prev_info: ");
+       prev_info.dump (dump_file, "       ");
+       fprintf (dump_file, "      curr_info: ");
+       curr_info.dump (dump_file, "       ");
+     }
+   block_info.infos.safe_push (prev_info);
+   prev_info = curr_info;
+ }
+     }
+ }
+
+      if (prev_info.valid_p () || prev_info.unknown_p ())
+ block_info.infos.safe_push (prev_info);
+    }
+
+  avl_regs = sbitmap_alloc (GP_REG_LAST + 1);
+  bitmap_clear (avl_regs);
+  for (const bb_info *bb : crtl->ssa->bbs ())
+    {
+      vsetvl_block_info &block_info = get_block_info (bb);
+      if (block_info.empty_p ())
+ continue;
+
+      vsetvl_info &header_info = block_info.get_header_info ();
+      if (header_info.valid_p () && header_info.has_reg_avl ())
+ {
+   gcc_assert (GP_REG_P (REGNO (header_info.get_avl ())));
+   bitmap_set_bit (avl_regs, REGNO (header_info.get_avl ()));
+ }
+    }
+}
+
const pass_data pass_data_vsetvl = {
   RTL_PASS, /* type */
   "vsetvl", /* name */
@@ -2801,152 +2924,6 @@ make_pass_vsetvl (gcc::context *ctxt)
   return new pass_vsetvl (ctxt);
}
 
-/* Compute demanded information by backward data-flow analysis.  */
-void
-pass_vsetvl::compute_local_backward_infos (const bb_info *bb)
-{
-  vector_insn_info change;
-  change.set_empty ();
-
-  auto &block_info = m_vector_manager->vector_block_infos[bb->index ()];
-  block_info.reaching_out = change;
-
-  for (insn_info *insn : bb->reverse_real_nondebug_insns ())
-    {
-      auto &info = get_vector_info (insn);
-
-      if (info.uninit_p ())
- /* If it is uninitialized, propagate it directly.  */
- update_vector_info (insn, change);
-      else if (info.unknown_p ())
- change = info;
-      else
- {
-   gcc_assert (info.valid_p () && "Unexpected Invalid demanded info");
-   if (change.valid_p ())
-     {
-       if (!(propagate_avl_across_demands_p (change, info)
-     && !reg_available_p (insn, change))
-   && change.compatible_p (info))
- {
-   update_vector_info (insn, change.local_merge (info));
-   /* Fix PR109399, we should update user vsetvl instruction
-      if there is a change in demand fusion.  */
-   if (vsetvl_insn_p (insn->rtl ()))
-     change_vsetvl_insn (insn, info);
- }
-     }
-   change = info;
- }
-    }
-
-  block_info.local_dem = change;
-  if (block_info.local_dem.empty_p ())
-    block_info.reaching_out = block_info.local_dem;
-}
-
-/* Return true if a dem_info is required to transition from curr_info to
-   require before INSN.  */
-bool
-pass_vsetvl::need_vsetvl (const vector_insn_info &require,
-   const vector_insn_info &curr_info) const
-{
-  if (!curr_info.valid_p () || curr_info.unknown_p () || curr_info.uninit_p ())
-    return true;
-
-  if (require.compatible_p (static_cast<const vl_vtype_info &> (curr_info)))
-    return false;
-
-  return true;
-}
-
-/* Given an incoming state reaching INSN, modifies that state so that it is
-   minimally compatible with INSN.  The resulting state is guaranteed to be
-   semantically legal for INSN, but may not be the state requested by INSN.  */
-void
-pass_vsetvl::transfer_before (vector_insn_info &info, insn_info *insn) const
-{
-  if (!has_vtype_op (insn->rtl ()))
-    return;
-
-  const vector_insn_info require = get_vector_info (insn);
-  if (info.valid_p () && !need_vsetvl (require, info))
-    return;
-  info = require;
-}
-
-/* Given a state with which we evaluated insn (see transfer_before above for why
-   this might be different that the state insn requested), modify the state to
-   reflect the changes insn might make.  */
-void
-pass_vsetvl::transfer_after (vector_insn_info &info, insn_info *insn) const
-{
-  if (vector_config_insn_p (insn->rtl ()))
-    {
-      info = get_vector_info (insn);
-      return;
-    }
-
-  if (fault_first_load_p (insn->rtl ())
-      && info.update_fault_first_load_avl (insn))
-    return;
-
-  /* If this is something that updates VL/VTYPE that we don't know about, set
-     the state to unknown.  */
-  if (insn->is_call () || insn->is_asm ()
-      || find_access (insn->defs (), VL_REGNUM)
-      || find_access (insn->defs (), VTYPE_REGNUM))
-    info = vector_insn_info::get_unknown ();
-}
-
-/* Emit vsetvl within each block by forward data-flow analysis.  */
-void
-pass_vsetvl::emit_local_forward_vsetvls (const bb_info *bb)
-{
-  auto &block_info = m_vector_manager->vector_block_infos[bb->index ()];
-  if (block_info.local_dem.empty_p ())
-    return;
-
-  vector_insn_info curr_info;
-  for (insn_info *insn : bb->real_nondebug_insns ())
-    {
-      const vector_insn_info prev_info = curr_info;
-      enum vsetvl_type type = NUM_VSETVL_TYPE;
-      transfer_before (curr_info, insn);
-
-      if (has_vtype_op (insn->rtl ()))
- {
-   if (static_cast<const vl_vtype_info &> (prev_info)
-       != static_cast<const vl_vtype_info &> (curr_info))
-     {
-       const auto require = get_vector_info (insn);
-       if (!require.compatible_p (
-     static_cast<const vl_vtype_info &> (prev_info)))
- type = insert_vsetvl (EMIT_BEFORE, insn->rtl (), require,
-       prev_info);
-     }
- }
-
-      /* Fix the issue of following sequence:
- vsetivli zero, 5
- ....
- vsetvli zero, zero
- vmv.x.s (demand AVL = 8).
- ....
- incorrect: vsetvli zero, zero ===> Since the curr_info is AVL = 8.
- correct: vsetivli zero, 8
- vadd (demand AVL = 8).  */
-      if (type == VSETVL_VTYPE_CHANGE_ONLY)
- {
-   /* Update the curr_info to be real correct AVL.  */
-   curr_info.set_avl_info (prev_info.get_avl_info ());
- }
-      transfer_after (curr_info, insn);
-    }
-
-  block_info.reaching_out = curr_info;
-}
-
/* Assemble the candidates expressions for LCM.  */
void
pass_vsetvl::prune_expressions (void)
--
2.36.3
  

Patch

diff --git a/gcc/config/riscv/riscv-vsetvl.cc b/gcc/config/riscv/riscv-vsetvl.cc
index 3f07fde782f..33bdcec04d8 100644
--- a/gcc/config/riscv/riscv-vsetvl.cc
+++ b/gcc/config/riscv/riscv-vsetvl.cc
@@ -2669,6 +2669,129 @@  public:
   }
 };

+void
+pre_vsetvl::fuse_local_vsetvl_info ()
+{
+  reg_def_loc
+    = sbitmap_vector_alloc (last_basic_block_for_fn (cfun), GP_REG_LAST + 1);
+  bitmap_vector_clear (reg_def_loc, last_basic_block_for_fn (cfun));
+  bitmap_ones (reg_def_loc[ENTRY_BLOCK_PTR_FOR_FN (cfun)->index]);
+
+  for (bb_info *bb : crtl->ssa->bbs ())
+    {
+      auto &block_info = get_block_info (bb);
+      block_info.m_bb = bb;
+      if (dump_file && (dump_flags & TDF_DETAILS))
+	{
+	  fprintf (dump_file, "  Try fuse basic block %d\n", bb->index ());
+	}
+      auto_vec<vsetvl_info> infos;
+      for (insn_info *insn : bb->real_nondebug_insns ())
+	{
+	  vsetvl_info curr_info = vsetvl_info (insn);
+	  if (curr_info.valid_p () || curr_info.unknown_p ())
+	    infos.safe_push (curr_info);
+
+	  /* Collecting GP registers modified by the current bb.  */
+	  if (insn->is_real ())
+	    for (def_info *def : insn->defs ())
+	      if (def->is_reg () && GP_REG_P (def->regno ()))
+		bitmap_set_bit (reg_def_loc[bb->index ()], def->regno ());
+	}
+
+      vsetvl_info prev_info = vsetvl_info ();
+      prev_info.set_empty ();
+      for (auto &curr_info : infos)
+	{
+	  if (prev_info.empty_p ())
+	    prev_info = curr_info;
+	  else if ((curr_info.unknown_p () && prev_info.valid_p ())
+		   || (curr_info.valid_p () && prev_info.unknown_p ()))
+	    {
+	      block_info.infos.safe_push (prev_info);
+	      prev_info = curr_info;
+	    }
+	  else if (curr_info.valid_p () && prev_info.valid_p ())
+	    {
+	      if (dem.available_with (prev_info, curr_info))
+		{
+		  if (dump_file && (dump_flags & TDF_DETAILS))
+		    {
+		      fprintf (dump_file,
+			       "    Ignore curr info since prev info "
+			       "available with it:\n");
+		      fprintf (dump_file, "      prev_info: ");
+		      prev_info.dump (dump_file, "        ");
+		      fprintf (dump_file, "      curr_info: ");
+		      curr_info.dump (dump_file, "        ");
+		      fprintf (dump_file, "\n");
+		    }
+		  if (!curr_info.use_by_non_rvv_insn_p ()
+		      && vsetvl_insn_p (curr_info.get_insn ()->rtl ()))
+		    delete_list.safe_push (curr_info);
+
+		  if (curr_info.get_read_vl_insn ())
+		    prev_info.set_read_vl_insn (curr_info.get_read_vl_insn ());
+		}
+	      else if (dem.compatible_with (prev_info, curr_info))
+		{
+		  if (dump_file && (dump_flags & TDF_DETAILS))
+		    {
+		      fprintf (dump_file, "    Fuse curr info since prev info "
+					  "compatible with it:\n");
+		      fprintf (dump_file, "      prev_info: ");
+		      prev_info.dump (dump_file, "        ");
+		      fprintf (dump_file, "      curr_info: ");
+		      curr_info.dump (dump_file, "        ");
+		    }
+		  dem.merge_with (prev_info, curr_info);
+		  if (curr_info.get_read_vl_insn ())
+		    prev_info.set_read_vl_insn (curr_info.get_read_vl_insn ());
+		  if (dump_file && (dump_flags & TDF_DETAILS))
+		    {
+		      fprintf (dump_file, "      prev_info after fused: ");
+		      prev_info.dump (dump_file, "        ");
+		      fprintf (dump_file, "\n");
+		    }
+		}
+	      else
+		{
+		  if (dump_file && (dump_flags & TDF_DETAILS))
+		    {
+		      fprintf (dump_file,
+			       "    Cannot fuse uncompatible infos:\n");
+		      fprintf (dump_file, "      prev_info: ");
+		      prev_info.dump (dump_file, "       ");
+		      fprintf (dump_file, "      curr_info: ");
+		      curr_info.dump (dump_file, "       ");
+		    }
+		  block_info.infos.safe_push (prev_info);
+		  prev_info = curr_info;
+		}
+	    }
+	}
+
+      if (prev_info.valid_p () || prev_info.unknown_p ())
+	block_info.infos.safe_push (prev_info);
+    }
+
+  avl_regs = sbitmap_alloc (GP_REG_LAST + 1);
+  bitmap_clear (avl_regs);
+  for (const bb_info *bb : crtl->ssa->bbs ())
+    {
+      vsetvl_block_info &block_info = get_block_info (bb);
+      if (block_info.empty_p ())
+	continue;
+
+      vsetvl_info &header_info = block_info.get_header_info ();
+      if (header_info.valid_p () && header_info.has_reg_avl ())
+	{
+	  gcc_assert (GP_REG_P (REGNO (header_info.get_avl ())));
+	  bitmap_set_bit (avl_regs, REGNO (header_info.get_avl ()));
+	}
+    }
+}
+
 const pass_data pass_data_vsetvl = {
   RTL_PASS,	 /* type */
   "vsetvl",	 /* name */
@@ -2801,152 +2924,6 @@  make_pass_vsetvl (gcc::context *ctxt)
   return new pass_vsetvl (ctxt);
 }

-/* Compute demanded information by backward data-flow analysis.  */
-void
-pass_vsetvl::compute_local_backward_infos (const bb_info *bb)
-{
-  vector_insn_info change;
-  change.set_empty ();
-
-  auto &block_info = m_vector_manager->vector_block_infos[bb->index ()];
-  block_info.reaching_out = change;
-
-  for (insn_info *insn : bb->reverse_real_nondebug_insns ())
-    {
-      auto &info = get_vector_info (insn);
-
-      if (info.uninit_p ())
-	/* If it is uninitialized, propagate it directly.  */
-	update_vector_info (insn, change);
-      else if (info.unknown_p ())
-	change = info;
-      else
-	{
-	  gcc_assert (info.valid_p () && "Unexpected Invalid demanded info");
-	  if (change.valid_p ())
-	    {
-	      if (!(propagate_avl_across_demands_p (change, info)
-		    && !reg_available_p (insn, change))
-		  && change.compatible_p (info))
-		{
-		  update_vector_info (insn, change.local_merge (info));
-		  /* Fix PR109399, we should update user vsetvl instruction
-		     if there is a change in demand fusion.  */
-		  if (vsetvl_insn_p (insn->rtl ()))
-		    change_vsetvl_insn (insn, info);
-		}
-	    }
-	  change = info;
-	}
-    }
-
-  block_info.local_dem = change;
-  if (block_info.local_dem.empty_p ())
-    block_info.reaching_out = block_info.local_dem;
-}
-
-/* Return true if a dem_info is required to transition from curr_info to
-   require before INSN.  */
-bool
-pass_vsetvl::need_vsetvl (const vector_insn_info &require,
-			  const vector_insn_info &curr_info) const
-{
-  if (!curr_info.valid_p () || curr_info.unknown_p () || curr_info.uninit_p ())
-    return true;
-
-  if (require.compatible_p (static_cast<const vl_vtype_info &> (curr_info)))
-    return false;
-
-  return true;
-}
-
-/* Given an incoming state reaching INSN, modifies that state so that it is
-   minimally compatible with INSN.  The resulting state is guaranteed to be
-   semantically legal for INSN, but may not be the state requested by INSN.  */
-void
-pass_vsetvl::transfer_before (vector_insn_info &info, insn_info *insn) const
-{
-  if (!has_vtype_op (insn->rtl ()))
-    return;
-
-  const vector_insn_info require = get_vector_info (insn);
-  if (info.valid_p () && !need_vsetvl (require, info))
-    return;
-  info = require;
-}
-
-/* Given a state with which we evaluated insn (see transfer_before above for why
-   this might be different that the state insn requested), modify the state to
-   reflect the changes insn might make.  */
-void
-pass_vsetvl::transfer_after (vector_insn_info &info, insn_info *insn) const
-{
-  if (vector_config_insn_p (insn->rtl ()))
-    {
-      info = get_vector_info (insn);
-      return;
-    }
-
-  if (fault_first_load_p (insn->rtl ())
-      && info.update_fault_first_load_avl (insn))
-    return;
-
-  /* If this is something that updates VL/VTYPE that we don't know about, set
-     the state to unknown.  */
-  if (insn->is_call () || insn->is_asm ()
-      || find_access (insn->defs (), VL_REGNUM)
-      || find_access (insn->defs (), VTYPE_REGNUM))
-    info = vector_insn_info::get_unknown ();
-}
-
-/* Emit vsetvl within each block by forward data-flow analysis.  */
-void
-pass_vsetvl::emit_local_forward_vsetvls (const bb_info *bb)
-{
-  auto &block_info = m_vector_manager->vector_block_infos[bb->index ()];
-  if (block_info.local_dem.empty_p ())
-    return;
-
-  vector_insn_info curr_info;
-  for (insn_info *insn : bb->real_nondebug_insns ())
-    {
-      const vector_insn_info prev_info = curr_info;
-      enum vsetvl_type type = NUM_VSETVL_TYPE;
-      transfer_before (curr_info, insn);
-
-      if (has_vtype_op (insn->rtl ()))
-	{
-	  if (static_cast<const vl_vtype_info &> (prev_info)
-	      != static_cast<const vl_vtype_info &> (curr_info))
-	    {
-	      const auto require = get_vector_info (insn);
-	      if (!require.compatible_p (
-		    static_cast<const vl_vtype_info &> (prev_info)))
-		type = insert_vsetvl (EMIT_BEFORE, insn->rtl (), require,
-				      prev_info);
-	    }
-	}
-
-      /* Fix the issue of following sequence:
-	 vsetivli zero, 5
-	 ....
-	 vsetvli zero, zero
-	 vmv.x.s (demand AVL = 8).
-	 ....
-	 incorrect: vsetvli zero, zero ===> Since the curr_info is AVL = 8.
-	 correct: vsetivli zero, 8
-	 vadd (demand AVL = 8).  */
-      if (type == VSETVL_VTYPE_CHANGE_ONLY)
-	{
-	  /* Update the curr_info to be real correct AVL.  */
-	  curr_info.set_avl_info (prev_info.get_avl_info ());
-	}
-      transfer_after (curr_info, insn);
-    }
-
-  block_info.reaching_out = curr_info;
-}
-
 /* Assemble the candidates expressions for LCM.  */
 void
 pass_vsetvl::prune_expressions (void)