tree-optimization/113373 - work around early exit vect missing LC PHI

Message ID 20240116144859.C27C13861839@sourceware.org
State New
Headers
Series tree-optimization/113373 - work around early exit vect missing LC PHI |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 success Testing passed
linaro-tcwg-bot/tcwg_gcc_check--master-arm success Testing passed
linaro-tcwg-bot/tcwg_gcc_check--master-aarch64 success Testing passed

Commit Message

Richard Biener Jan. 16, 2024, 2:43 p.m. UTC
  The following makes reduction epilogue code generation handle missing
LC PHIs for the reductions, in particular also avoid replacing results
on one exit with epilogue result from another one (but not avoiding
generation of dead epilogues yet).  The proper fix should be eventually
to create the missing LC PHIs of course.

Bootstrapped and tested on x86_64-unknown-linux-gnu, waiting for
the pre-checkin CI.

	PR tree-optimization/113373
	* tree-vect-loop.cc (vect_create_epilog_for_reduction): Only
	replace LC PHI results.  Handle merge PHIs as seen for
	early breaks which miss the LC PHIs for the reduction
	results.

	* gcc.dg/vect/vect-early-break_104-pr113373.c: New testcase.
---
 .../vect/vect-early-break_104-pr113373.c      | 19 ++++++
 gcc/tree-vect-loop.cc                         | 67 +++++++++++--------
 2 files changed, 59 insertions(+), 27 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vect/vect-early-break_104-pr113373.c
  

Patch

diff --git a/gcc/testsuite/gcc.dg/vect/vect-early-break_104-pr113373.c b/gcc/testsuite/gcc.dg/vect/vect-early-break_104-pr113373.c
new file mode 100644
index 00000000000..1601aafb3e6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/vect-early-break_104-pr113373.c
@@ -0,0 +1,19 @@ 
+/* { dg-do compile } */
+/* { dg-add-options vect_early_break } */
+/* { dg-require-effective-target vect_early_break } */
+
+struct asCArray {
+  unsigned *array;
+  int length;
+};
+unsigned asCReaderTranslateFunction(struct asCArray b, unsigned t)
+{
+  int size = 0;
+  for (unsigned num; num < t; num++)
+  {
+    if (num >= b.length)
+      __builtin_abort();
+    size += b.array[num];
+  }
+  return size;
+}
diff --git a/gcc/tree-vect-loop.cc b/gcc/tree-vect-loop.cc
index fedecd620e9..1c1b59dc5db 100644
--- a/gcc/tree-vect-loop.cc
+++ b/gcc/tree-vect-loop.cc
@@ -6013,7 +6013,6 @@  vect_create_epilog_for_reduction (loop_vec_info loop_vinfo,
   gimple_stmt_iterator exit_gsi;
   tree new_temp = NULL_TREE, new_name, new_scalar_dest;
   gimple *epilog_stmt = NULL;
-  gimple *exit_phi;
   tree bitsize;
   tree def;
   tree orig_name, scalar_result;
@@ -6024,7 +6023,6 @@  vect_create_epilog_for_reduction (loop_vec_info loop_vinfo,
   int j, i;
   vec<tree> &scalar_results = reduc_info->reduc_scalar_results;
   unsigned int group_size = 1, k;
-  auto_vec<gimple *> phis;
   /* SLP reduction without reduction chain, e.g.,
      # a1 = phi <a2, a0>
      # b1 = phi <b2, b0>
@@ -6937,44 +6935,59 @@  vect_create_epilog_for_reduction (loop_vec_info loop_vinfo,
           use <s_out4> */
 
   gcc_assert (live_out_stmts.size () == scalar_results.length ());
+  auto_vec<gphi *> phis;
   for (k = 0; k < live_out_stmts.size (); k++)
     {
       stmt_vec_info scalar_stmt_info = vect_orig_stmt (live_out_stmts[k]);
       scalar_dest = gimple_get_lhs (scalar_stmt_info->stmt);
 
-      phis.create (3);
       /* Find the loop-closed-use at the loop exit of the original scalar
          result.  (The reduction result is expected to have two immediate uses,
          one at the latch block, and one at the loop exit).  For double
-         reductions we are looking for exit phis of the outer loop.  */
-      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, scalar_dest)
-        {
-          if (!flow_bb_inside_loop_p (loop, gimple_bb (USE_STMT (use_p))))
+	 reductions we are looking for exit phis of the outer loop.
+	 ???  For early-breaks we mess up scalar LC SSA form so also match
+	 a PHI in a merge block and replace that PHIs use on the correct
+	 edge.  */
+      FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, scalar_dest)
+	{
+	  if (is_gimple_debug (use_stmt))
+	    continue;
+	  else if (!flow_bb_inside_loop_p (loop, gimple_bb (use_stmt)))
 	    {
-	      if (!is_gimple_debug (USE_STMT (use_p)))
-		phis.safe_push (USE_STMT (use_p));
+	      if (gimple_bb (use_stmt) == loop_exit->dest)
+		phis.safe_push (as_a <gphi *> (use_stmt));
+	      else if (gimple_code (use_stmt) == GIMPLE_PHI)
+		{
+		  /* ???  This is the case running into a merge PHI with
+		     a missing LC PHI for early exit vectorization.  Replace
+		     only the merge argument corresponding to loop_exit.  */
+		  FOR_EACH_IMM_USE_ON_STMT (use_p, imm_iter)
+		    if (gimple_phi_arg_edge (as_a <gphi *> (use_stmt),
+					     phi_arg_index_from_use (use_p))
+			  ->src == loop_exit->dest)
+		      SET_USE (use_p, scalar_results[k]);
+		  update_stmt (use_stmt);
+		}
 	    }
-          else
-            {
-              if (double_reduc && gimple_code (USE_STMT (use_p)) == GIMPLE_PHI)
-                {
-                  tree phi_res = PHI_RESULT (USE_STMT (use_p));
+	  else if (double_reduc && gimple_code (use_stmt) == GIMPLE_PHI)
+	    {
+	      tree phi_res = PHI_RESULT (use_stmt);
 
-                  FOR_EACH_IMM_USE_FAST (phi_use_p, phi_imm_iter, phi_res)
-                    {
-                      if (!flow_bb_inside_loop_p (loop,
-                                             gimple_bb (USE_STMT (phi_use_p)))
-			  && !is_gimple_debug (USE_STMT (phi_use_p)))
-                        phis.safe_push (USE_STMT (phi_use_p));
-                    }
-                }
-            }
-        }
+	      FOR_EACH_IMM_USE_FAST (phi_use_p, phi_imm_iter, phi_res)
+		{
+		  if (!flow_bb_inside_loop_p (outer_loop,
+					      gimple_bb (USE_STMT (phi_use_p)))
+		      && !is_gimple_debug (USE_STMT (phi_use_p)))
+		    phis.safe_push (as_a <gphi *> (USE_STMT (phi_use_p)));
+		}
+	    }
+	}
 
+      gphi *exit_phi;
       FOR_EACH_VEC_ELT (phis, i, exit_phi)
         {
-          /* Replace the uses:  */
-          orig_name = PHI_RESULT (exit_phi);
+	  /* Replace the uses:  */
+	  orig_name = gimple_phi_result (exit_phi);
 
 	  /* Look for a single use at the target of the skip edge.  */
 	  if (unify_with_main_loop_p)
@@ -6995,7 +7008,7 @@  vect_create_epilog_for_reduction (loop_vec_info loop_vinfo,
 	    }
         }
 
-      phis.release ();
+      phis.truncate (0);
     }
 }