[1/3] cfg: Move make_forwarders_with_degenerate_phis to tree-cfg

Message ID 20251206193129.3365370-1-andrew.pinski@oss.qualcomm.com
State Committed
Commit 98667f7df0cffc6ca6bed13942b81c7a8483929f
Headers
Series [1/3] cfg: Move make_forwarders_with_degenerate_phis to tree-cfg |

Commit Message

Andrew Pinski Dec. 6, 2025, 7:31 p.m. UTC
  This moves make_forwarders_with_degenerate_phis to tree-cfg.cc
from tree-ssa-dce.cc to be able to use in a different pass.

Bootstrapped and tested on x86_64-linux-gnu.

gcc/ChangeLog:

	* tree-ssa-dce.cc (sort_phi_args): Move to tree-cfg.cc.
	(make_forwarders_with_degenerate_phis): Move to tree-cfg.cc.
	(perform_tree_ssa_dce): Update for the updated return type
	of make_forwarders_with_degenerate_phis.
	* tree-cfg.cc (sort_phi_args): Moved from tree-ssa-dce.cc.
	(make_forwarders_with_degenerate_phis): Moved from tree-ssa-dce.cc.
	Update return type to bool and return true if an edge was split.
	* tree-cfg.h (make_forwarders_with_degenerate_phis): New decl.

Signed-off-by: Andrew Pinski <andrew.pinski@oss.qualcomm.com>
---
 gcc/tree-cfg.cc     | 211 +++++++++++++++++++++++++++++++++++++++++++
 gcc/tree-cfg.h      |   1 +
 gcc/tree-ssa-dce.cc | 212 +-------------------------------------------
 3 files changed, 214 insertions(+), 210 deletions(-)
  

Patch

diff --git a/gcc/tree-cfg.cc b/gcc/tree-cfg.cc
index 1d20e6ab6ba..243740e8e21 100644
--- a/gcc/tree-cfg.cc
+++ b/gcc/tree-cfg.cc
@@ -10173,6 +10173,217 @@  make_pass_fixup_cfg (gcc::context *ctxt)
   return new pass_fixup_cfg (ctxt);
 }
 
+
+/* Sort PHI argument values for make_forwarders_with_degenerate_phis.  */
+
+static int
+sort_phi_args (const void *a_, const void *b_)
+{
+  auto *a = (const std::pair<edge, hashval_t> *) a_;
+  auto *b = (const std::pair<edge, hashval_t> *) b_;
+  hashval_t ha = a->second;
+  hashval_t hb = b->second;
+  if (ha < hb)
+    return -1;
+  else if (ha > hb)
+    return 1;
+  else if (a->first->dest_idx < b->first->dest_idx)
+    return -1;
+  else if (a->first->dest_idx > b->first->dest_idx)
+    return 1;
+  else
+    return 0;
+}
+
+/* Look for a non-virtual PHIs and make a forwarder block when all PHIs
+   have the same argument on a set of edges.  This is to not consider
+   control dependences of individual edges for same values but only for
+   the common set.  Returns true if changed the CFG.  */
+
+bool
+make_forwarders_with_degenerate_phis (function *fn)
+{
+  bool didsomething = false;
+
+  basic_block bb;
+  FOR_EACH_BB_FN (bb, fn)
+    {
+      /* Only PHIs with three or more arguments have opportunities.  */
+      if (EDGE_COUNT (bb->preds) < 3)
+	continue;
+      /* Do not touch loop headers or blocks with abnormal predecessors.
+	 ???  This is to avoid creating valid loops here, see PR103458.
+	 We might want to improve things to either explicitely add those
+	 loops or at least consider blocks with no backedges.  */
+      if (bb->loop_father->header == bb
+	  || bb_has_abnormal_pred (bb))
+	continue;
+
+      /* Take one PHI node as template to look for identical
+	 arguments.  Build a vector of candidates forming sets
+	 of argument edges with equal values.  Note optimality
+	 depends on the particular choice of the template PHI
+	 since equal arguments are unordered leaving other PHIs
+	 with more than one set of equal arguments within this
+	 argument range unsorted.  We'd have to break ties by
+	 looking at other PHI nodes.  */
+      gphi_iterator gsi = gsi_start_nonvirtual_phis (bb);
+      if (gsi_end_p (gsi))
+	continue;
+      gphi *phi = gsi.phi ();
+      auto_vec<std::pair<edge, hashval_t>, 8> args;
+      bool need_resort = false;
+      for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
+	{
+	  edge e = gimple_phi_arg_edge (phi, i);
+	  /* Skip abnormal edges since we cannot redirect them.  */
+	  if (e->flags & EDGE_ABNORMAL)
+	    continue;
+	  /* Skip loop exit edges when we are in loop-closed SSA form
+	     since the forwarder we'd create does not have a PHI node.  */
+	  if (loops_state_satisfies_p (LOOP_CLOSED_SSA)
+	      && loop_exit_edge_p (e->src->loop_father, e))
+	    continue;
+
+	  tree arg = gimple_phi_arg_def (phi, i);
+	  if (!CONSTANT_CLASS_P (arg) && TREE_CODE (arg) != SSA_NAME)
+	    need_resort = true;
+	  args.safe_push (std::make_pair (e, iterative_hash_expr (arg, 0)));
+	}
+      if (args.length () < 2)
+	continue;
+      args.qsort (sort_phi_args);
+      /* The above sorting can be different between -g and -g0, as e.g. decls
+	 can have different uids (-g could have bigger gaps in between them).
+	 So, only use that to determine which args are equal, then change
+	 second from hash value to smallest dest_idx of the edges which have
+	 equal argument and sort again.  If all the phi arguments are
+	 constants or SSA_NAME, there is no need for the second sort, the hash
+	 values are stable in that case.  */
+      hashval_t hash = args[0].second;
+      args[0].second = args[0].first->dest_idx;
+      bool any_equal = false;
+      for (unsigned i = 1; i < args.length (); ++i)
+	if (hash == args[i].second
+	    && operand_equal_p (PHI_ARG_DEF_FROM_EDGE (phi, args[i - 1].first),
+				PHI_ARG_DEF_FROM_EDGE (phi, args[i].first)))
+	  {
+	    args[i].second = args[i - 1].second;
+	    any_equal = true;
+	  }
+	else
+	  {
+	    hash = args[i].second;
+	    args[i].second = args[i].first->dest_idx;
+	  }
+      if (!any_equal)
+	continue;
+      if (need_resort)
+	args.qsort (sort_phi_args);
+
+      /* From the candidates vector now verify true candidates for
+	 forwarders and create them.  */
+      gphi *vphi = get_virtual_phi (bb);
+      unsigned start = 0;
+      while (start < args.length () - 1)
+	{
+	  unsigned i;
+	  for (i = start + 1; i < args.length (); ++i)
+	    if (args[start].second != args[i].second)
+	      break;
+	  /* args[start]..args[i-1] are equal.  */
+	  if (start != i - 1)
+	    {
+	      /* Check all PHI nodes for argument equality
+	         except for vops.  */
+	      bool equal = true;
+	      gphi_iterator gsi2 = gsi;
+	      gsi_next (&gsi2);
+	      for (; !gsi_end_p (gsi2); gsi_next (&gsi2))
+		{
+		  gphi *phi2 = gsi2.phi ();
+		  if (virtual_operand_p (gimple_phi_result (phi2)))
+		    continue;
+		  tree start_arg
+		    = PHI_ARG_DEF_FROM_EDGE (phi2, args[start].first);
+		  for (unsigned j = start + 1; j < i; ++j)
+		    {
+		      if (!operand_equal_p (start_arg,
+					    PHI_ARG_DEF_FROM_EDGE
+					      (phi2, args[j].first)))
+			{
+			  /* Another PHI might have a shorter set of
+			     equivalent args.  Go for that.  */
+			  i = j;
+			  if (j == start + 1)
+			    equal = false;
+			  break;
+			}
+		    }
+		  if (!equal)
+		    break;
+		}
+	      if (equal)
+		{
+		  /* If we are asked to forward all edges the block
+		     has all degenerate PHIs.  Do nothing in that case.  */
+		  if (start == 0
+		      && i == args.length ()
+		      && args.length () == gimple_phi_num_args (phi))
+		    break;
+		  /* Instead of using make_forwarder_block we are
+		     rolling our own variant knowing that the forwarder
+		     does not need PHI nodes apart from eventually
+		     a virtual one.  */
+		  auto_vec<tree, 8> vphi_args;
+		  if (vphi)
+		    {
+		      vphi_args.reserve_exact (i - start);
+		      for (unsigned j = start; j < i; ++j)
+			vphi_args.quick_push
+			  (PHI_ARG_DEF_FROM_EDGE (vphi, args[j].first));
+		    }
+		  free_dominance_info (fn, CDI_DOMINATORS);
+		  basic_block forwarder = split_edge (args[start].first);
+		  profile_count count = profile_count::zero ();
+		  bool irr = false;
+		  for (unsigned j = start + 1; j < i; ++j)
+		    {
+		      edge e = args[j].first;
+		      if (e->flags & EDGE_IRREDUCIBLE_LOOP)
+			irr = true;
+		      redirect_edge_and_branch_force (e, forwarder);
+		      redirect_edge_var_map_clear (e);
+		      count += e->count ();
+		    }
+		  forwarder->count = count;
+		  if (irr)
+		    {
+		      forwarder->flags |= BB_IRREDUCIBLE_LOOP;
+		      single_succ_edge (forwarder)->flags
+			|= EDGE_IRREDUCIBLE_LOOP;
+		    }
+
+		  if (vphi)
+		    {
+		      tree def = copy_ssa_name (vphi_args[0]);
+		      gphi *vphi_copy = create_phi_node (def, forwarder);
+		      for (unsigned j = start; j < i; ++j)
+			add_phi_arg (vphi_copy, vphi_args[j - start],
+				     args[j].first, UNKNOWN_LOCATION);
+		      SET_PHI_ARG_DEF
+			(vphi, single_succ_edge (forwarder)->dest_idx, def);
+		    }
+		  didsomething = true;
+		}
+	    }
+	  /* Continue searching for more opportunities.  */
+	  start = i;
+	}
+    }
+  return didsomething;
+}
+
 /* Garbage collection support for edge_def.  */
 
 extern void gt_ggc_mx (tree&);
diff --git a/gcc/tree-cfg.h b/gcc/tree-cfg.h
index 520bb3aefbd..2e01762f04b 100644
--- a/gcc/tree-cfg.h
+++ b/gcc/tree-cfg.h
@@ -114,6 +114,7 @@  extern edge gimple_switch_edge (function *, gswitch *, unsigned);
 extern edge gimple_switch_default_edge (function *, gswitch *);
 extern bool cond_only_block_p (basic_block);
 extern void copy_phi_arg_into_existing_phi (edge, edge, bool = false);
+extern bool make_forwarders_with_degenerate_phis (function *);
 
 /* Return true if the LHS of a call should be removed.  */
 
diff --git a/gcc/tree-ssa-dce.cc b/gcc/tree-ssa-dce.cc
index 317a0d6179b..9a9f6f93fce 100644
--- a/gcc/tree-ssa-dce.cc
+++ b/gcc/tree-ssa-dce.cc
@@ -1940,214 +1940,6 @@  tree_dce_done (bool aggressive)
   worklist.release ();
 }
 
-/* Sort PHI argument values for make_forwarders_with_degenerate_phis.  */
-
-static int
-sort_phi_args (const void *a_, const void *b_)
-{
-  auto *a = (const std::pair<edge, hashval_t> *) a_;
-  auto *b = (const std::pair<edge, hashval_t> *) b_;
-  hashval_t ha = a->second;
-  hashval_t hb = b->second;
-  if (ha < hb)
-    return -1;
-  else if (ha > hb)
-    return 1;
-  else if (a->first->dest_idx < b->first->dest_idx)
-    return -1;
-  else if (a->first->dest_idx > b->first->dest_idx)
-    return 1;
-  else
-    return 0;
-}
-
-/* Look for a non-virtual PHIs and make a forwarder block when all PHIs
-   have the same argument on a set of edges.  This is to not consider
-   control dependences of individual edges for same values but only for
-   the common set.  */
-
-static unsigned
-make_forwarders_with_degenerate_phis (function *fn)
-{
-  unsigned todo = 0;
-
-  basic_block bb;
-  FOR_EACH_BB_FN (bb, fn)
-    {
-      /* Only PHIs with three or more arguments have opportunities.  */
-      if (EDGE_COUNT (bb->preds) < 3)
-	continue;
-      /* Do not touch loop headers or blocks with abnormal predecessors.
-	 ???  This is to avoid creating valid loops here, see PR103458.
-	 We might want to improve things to either explicitely add those
-	 loops or at least consider blocks with no backedges.  */
-      if (bb->loop_father->header == bb
-	  || bb_has_abnormal_pred (bb))
-	continue;
-
-      /* Take one PHI node as template to look for identical
-	 arguments.  Build a vector of candidates forming sets
-	 of argument edges with equal values.  Note optimality
-	 depends on the particular choice of the template PHI
-	 since equal arguments are unordered leaving other PHIs
-	 with more than one set of equal arguments within this
-	 argument range unsorted.  We'd have to break ties by
-	 looking at other PHI nodes.  */
-      gphi_iterator gsi = gsi_start_nonvirtual_phis (bb);
-      if (gsi_end_p (gsi))
-	continue;
-      gphi *phi = gsi.phi ();
-      auto_vec<std::pair<edge, hashval_t>, 8> args;
-      bool need_resort = false;
-      for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
-	{
-	  edge e = gimple_phi_arg_edge (phi, i);
-	  /* Skip abnormal edges since we cannot redirect them.  */
-	  if (e->flags & EDGE_ABNORMAL)
-	    continue;
-	  /* Skip loop exit edges when we are in loop-closed SSA form
-	     since the forwarder we'd create does not have a PHI node.  */
-	  if (loops_state_satisfies_p (LOOP_CLOSED_SSA)
-	      && loop_exit_edge_p (e->src->loop_father, e))
-	    continue;
-
-	  tree arg = gimple_phi_arg_def (phi, i);
-	  if (!CONSTANT_CLASS_P (arg) && TREE_CODE (arg) != SSA_NAME)
-	    need_resort = true;
-	  args.safe_push (std::make_pair (e, iterative_hash_expr (arg, 0)));
-	}
-      if (args.length () < 2)
-	continue;
-      args.qsort (sort_phi_args);
-      /* The above sorting can be different between -g and -g0, as e.g. decls
-	 can have different uids (-g could have bigger gaps in between them).
-	 So, only use that to determine which args are equal, then change
-	 second from hash value to smallest dest_idx of the edges which have
-	 equal argument and sort again.  If all the phi arguments are
-	 constants or SSA_NAME, there is no need for the second sort, the hash
-	 values are stable in that case.  */
-      hashval_t hash = args[0].second;
-      args[0].second = args[0].first->dest_idx;
-      bool any_equal = false;
-      for (unsigned i = 1; i < args.length (); ++i)
-	if (hash == args[i].second
-	    && operand_equal_p (PHI_ARG_DEF_FROM_EDGE (phi, args[i - 1].first),
-				PHI_ARG_DEF_FROM_EDGE (phi, args[i].first)))
-	  {
-	    args[i].second = args[i - 1].second;
-	    any_equal = true;
-	  }
-	else
-	  {
-	    hash = args[i].second;
-	    args[i].second = args[i].first->dest_idx;
-	  }
-      if (!any_equal)
-	continue;
-      if (need_resort)
-	args.qsort (sort_phi_args);
-
-      /* From the candidates vector now verify true candidates for
-	 forwarders and create them.  */
-      gphi *vphi = get_virtual_phi (bb);
-      unsigned start = 0;
-      while (start < args.length () - 1)
-	{
-	  unsigned i;
-	  for (i = start + 1; i < args.length (); ++i)
-	    if (args[start].second != args[i].second)
-	      break;
-	  /* args[start]..args[i-1] are equal.  */
-	  if (start != i - 1)
-	    {
-	      /* Check all PHI nodes for argument equality.  */
-	      bool equal = true;
-	      gphi_iterator gsi2 = gsi;
-	      gsi_next (&gsi2);
-	      for (; !gsi_end_p (gsi2); gsi_next (&gsi2))
-		{
-		  gphi *phi2 = gsi2.phi ();
-		  if (virtual_operand_p (gimple_phi_result (phi2)))
-		    continue;
-		  tree start_arg
-		    = PHI_ARG_DEF_FROM_EDGE (phi2, args[start].first);
-		  for (unsigned j = start + 1; j < i; ++j)
-		    {
-		      if (!operand_equal_p (start_arg,
-					    PHI_ARG_DEF_FROM_EDGE
-					      (phi2, args[j].first)))
-			{
-			  /* Another PHI might have a shorter set of
-			     equivalent args.  Go for that.  */
-			  i = j;
-			  if (j == start + 1)
-			    equal = false;
-			  break;
-			}
-		    }
-		  if (!equal)
-		    break;
-		}
-	      if (equal)
-		{
-		  /* If we are asked to forward all edges the block
-		     has all degenerate PHIs.  Do nothing in that case.  */
-		  if (start == 0
-		      && i == args.length ()
-		      && args.length () == gimple_phi_num_args (phi))
-		    break;
-		  /* Instead of using make_forwarder_block we are
-		     rolling our own variant knowing that the forwarder
-		     does not need PHI nodes apart from eventually
-		     a virtual one.  */
-		  auto_vec<tree, 8> vphi_args;
-		  if (vphi)
-		    {
-		      vphi_args.reserve_exact (i - start);
-		      for (unsigned j = start; j < i; ++j)
-			vphi_args.quick_push
-			  (PHI_ARG_DEF_FROM_EDGE (vphi, args[j].first));
-		    }
-		  free_dominance_info (fn, CDI_DOMINATORS);
-		  basic_block forwarder = split_edge (args[start].first);
-		  profile_count count = profile_count::zero ();
-		  bool irr = false;
-		  for (unsigned j = start + 1; j < i; ++j)
-		    {
-		      edge e = args[j].first;
-		      if (e->flags & EDGE_IRREDUCIBLE_LOOP)
-			irr = true;
-		      redirect_edge_and_branch_force (e, forwarder);
-		      redirect_edge_var_map_clear (e);
-		      count += e->count ();
-		    }
-		  forwarder->count = count;
-		  if (irr)
-		    {
-		      forwarder->flags |= BB_IRREDUCIBLE_LOOP;
-		      single_succ_edge (forwarder)->flags
-			|= EDGE_IRREDUCIBLE_LOOP;
-		    }
-
-		  if (vphi)
-		    {
-		      tree def = copy_ssa_name (vphi_args[0]);
-		      gphi *vphi_copy = create_phi_node (def, forwarder);
-		      for (unsigned j = start; j < i; ++j)
-			add_phi_arg (vphi_copy, vphi_args[j - start],
-				     args[j].first, UNKNOWN_LOCATION);
-		      SET_PHI_ARG_DEF
-			(vphi, single_succ_edge (forwarder)->dest_idx, def);
-		    }
-		  todo |= TODO_cleanup_cfg;
-		}
-	    }
-	  /* Continue searching for more opportunities.  */
-	  start = i;
-	}
-    }
-  return todo;
-}
 
 /* Main routine to eliminate dead code.
 
@@ -2174,8 +1966,8 @@  perform_tree_ssa_dce (bool aggressive)
       scev_initialize ();
     }
 
-  if (aggressive)
-    todo |= make_forwarders_with_degenerate_phis (cfun);
+  if (aggressive && make_forwarders_with_degenerate_phis (cfun))
+    todo |= TODO_cleanup_cfg;
 
   calculate_dominance_info (CDI_DOMINATORS);