public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: Richard Sandiford <richard.sandiford@arm.com>
To: gcc-patches@gcc.gnu.org
Subject: [6/6] Link imm uses for pattern stmts
Date: Tue, 28 Aug 2018 11:25:00 -0000	[thread overview]
Message-ID: <8736uyraw0.fsf@arm.com> (raw)
In-Reply-To: <87tvnerb5m.fsf@arm.com> (Richard Sandiford's message of "Tue, 28	Aug 2018 12:19:33 +0100")

One of the warts of the vectoriser IR is that it doesn't link SSA name
uses for pattern statements, leading to complicated special cases in
vect_mark_stmts_to_be_vectorized and (especially) vect_detect_hybrid_slp.
It also makes it harder to check how an SSA name is used after pattern
replacement (something I need for a later patch).

This patch adds a mode in which tree-ssa-operands.c can update
statements in the same non-invasive way as for debug statements.
It then uses this mode to update pattern statements when adding
them to a vec_basic_block, so that pattern statements become
even more like statements that existed from the outset.


2018-08-28  Richard Sandiford  <richard.sandiford@arm.com>

gcc/
	* tree-ssa-operands.h (update_stmt_operands): Add a transparent_p
	argument.
	* tree-ssa-operands.c (opf_transparent, opf_sticky): New macros.
	(get_mem_ref_operands, get_tmr_operands): Preserve opf_sticky
	rather than just opf_no_vops.
	(get_expr_operands): Preserve opf_sticky bits in the use flags.
	Assert that opf_no_vops and opf_transparent are already set
	for the debug statements.  Use opf_transparent rather than
	is_gimple_debug when deciding whether to mark something as
	having its address taken.
	(parse_ssa_operands): Add a transparent_p argument.  Set the
	opf_no_vops and opf_transparent flags when the argument is true,
	or when dealing with debug statements.  Check opf_no_vops before
	adding vuses and vdefs.
	(build_ssa_operands): Add a transparent_p argument and pass it to
	parse_ssa_operands.
	(verify_ssa_operands): Update call to parse_ssa_operands.
	(update_stmt_operands): Add a transparent_p argument and pass it to
	build_ssa_operands.
	* gimple-ssa.h (update_stmt, update_stmt_if_modified)
	(update_stmt_fn): Add an optional transparent_p parameter and
	update call to update_stmt_operands.
	* tree-vect-slp.c (vect_detect_hybrid_slp_1): Delete.
	(vect_detect_hybrid_slp_2): Likewise.
	(vect_detect_hybrid_slp): Don't treat pattern statements specially.
	* tree-vect-stmts.c (vect_mark_stmts_to_be_vectorized): Likewise.
	(vect_remove_dead_scalar_stmts): Remove pattern statements from
	the containing vec_info.
	* tree-vectorizer.h (vec_info::add_pattern_stmt_to_block): Declare.
	* tree-vectorizer.c (vec_basic_block::add_to_end)
	(vec_basic_block::add_before): Call add_pattern_stmt_to_block.
	(vec_basic_block::remove, vec_info::remove_stmt): Call
	remove_pattern_stmt_from_block.
	(vec_basic_block::add_pattern_stmt_to_block): New function.
	(remove_pattern_stmt_from_block): Likewise.
	(vec_info::free_stmt_vec_info): Handle pattern statements.
	(vec_info::lookup_single_use): Accept pattern statements
	as well as original statements.  Ignore uses in statements
	that have been replaced by a pattern statement.
	* tree-vect-patterns.c (vect_init_pattern_stmt): Don't call
	gimple_set_bb.
	(vect_look_through_possible_promotion): Use vinfo->lookup_single_use
	instead of has_single_use.  Track single uses for pattern statements
	too.

Index: gcc/tree-ssa-operands.h
===================================================================
--- gcc/tree-ssa-operands.h	2018-05-02 08:37:32.405761509 +0100
+++ gcc/tree-ssa-operands.h	2018-08-28 12:05:19.262917177 +0100
@@ -94,7 +94,7 @@ extern void init_ssa_operands (struct fu
 extern void fini_ssa_operands (struct function *);
 extern bool verify_ssa_operands (struct function *, gimple *stmt);
 extern void free_stmt_operands (struct function *, gimple *);
-extern void update_stmt_operands (struct function *, gimple *);
+extern void update_stmt_operands (struct function *, gimple *, bool);
 extern void swap_ssa_operands (gimple *, tree *, tree *);
 extern bool verify_imm_links (FILE *f, tree var);
 
Index: gcc/tree-ssa-operands.c
===================================================================
--- gcc/tree-ssa-operands.c	2018-08-28 11:25:46.242879876 +0100
+++ gcc/tree-ssa-operands.c	2018-08-28 12:05:19.262917177 +0100
@@ -99,6 +99,14 @@ #define opf_not_non_addressable (1 << 4)
 /* Operand is having its address taken.  */
 #define opf_address_taken (1 << 5)
 
+/* Operand must have no effect on code generation.  This is used for
+   debug statements, and also for statements that a pass has no intention
+   of adding to the block in their current form.  */
+#define opf_transparent (1 << 6)
+
+/* Flags that must never be dropped.  */
+#define opf_sticky (opf_no_vops | opf_transparent)
+
 /* Array for building all the use operands.  */
 static vec<tree *> build_uses;
 
@@ -590,7 +598,7 @@ get_mem_ref_operands (struct function *f
   /* If requested, add a USE operand for the base pointer.  */
   get_expr_operands (fn, stmt, pptr,
 		     opf_non_addressable | opf_use
-		     | (flags & (opf_no_vops|opf_not_non_addressable)));
+		     | (flags & (opf_sticky | opf_not_non_addressable)));
 }
 
 
@@ -605,11 +613,11 @@ get_tmr_operands (struct function *fn, g
 
   /* First record the real operands.  */
   get_expr_operands (fn, stmt,
-		     &TMR_BASE (expr), opf_use | (flags & opf_no_vops));
+		     &TMR_BASE (expr), opf_use | (flags & opf_sticky));
   get_expr_operands (fn, stmt,
-		     &TMR_INDEX (expr), opf_use | (flags & opf_no_vops));
+		     &TMR_INDEX (expr), opf_use | (flags & opf_sticky));
   get_expr_operands (fn, stmt,
-		     &TMR_INDEX2 (expr), opf_use | (flags & opf_no_vops));
+		     &TMR_INDEX2 (expr), opf_use | (flags & opf_sticky));
 
   add_virtual_operand (fn, stmt, flags);
 }
@@ -703,14 +711,14 @@ get_expr_operands (struct function *fn,
   enum tree_code code;
   enum tree_code_class codeclass;
   tree expr = *expr_p;
-  int uflags = opf_use;
+  int uflags = opf_use | (flags & opf_sticky);
+  gcc_checking_assert (!is_gimple_debug (stmt)
+		       || ((flags & opf_no_vops)
+			   && (flags & opf_transparent)));
 
   if (expr == NULL)
     return;
 
-  if (is_gimple_debug (stmt))
-    uflags |= (flags & opf_no_vops);
-
   code = TREE_CODE (expr);
   codeclass = TREE_CODE_CLASS (code);
 
@@ -723,7 +731,7 @@ get_expr_operands (struct function *fn,
 	 resolution).  */
       if ((!(flags & opf_non_addressable)
 	   || (flags & opf_not_non_addressable))
-	  && !is_gimple_debug (stmt))
+	  && !(flags & opf_transparent))
 	mark_address_taken (TREE_OPERAND (expr, 0));
 
       /* Otherwise, there may be variables referenced inside but there
@@ -885,43 +893,50 @@ get_expr_operands (struct function *fn,
 
 
 /* Parse STMT looking for operands.  When finished, the various
-   build_* operand vectors will have potential operands in them.  */
+   build_* operand vectors will have potential operands in them.
+   TRANSPARENT_P as for update_stmt_operands.  */
 
 static void
-parse_ssa_operands (struct function *fn, gimple *stmt)
+parse_ssa_operands (struct function *fn, gimple *stmt, bool transparent_p)
 {
   enum gimple_code code = gimple_code (stmt);
   size_t i, n, start = 0;
+  int flags = (transparent_p || code == GIMPLE_DEBUG
+	       ? opf_no_vops | opf_transparent : 0);
 
   switch (code)
     {
     case GIMPLE_ASM:
+      /* Not supported yet (but could be if needed).  */
+      gcc_assert (!transparent_p);
       get_asm_stmt_operands (fn, as_a <gasm *> (stmt));
       break;
 
     case GIMPLE_TRANSACTION:
       /* The start of a transaction is a memory barrier.  */
-      add_virtual_operand (fn, stmt, opf_def | opf_use);
+      add_virtual_operand (fn, stmt, opf_def | opf_use | flags);
       break;
 
     case GIMPLE_DEBUG:
       if (gimple_debug_bind_p (stmt)
 	  && gimple_debug_bind_has_value_p (stmt))
 	get_expr_operands (fn, stmt, gimple_debug_bind_get_value_ptr (stmt),
-			   opf_use | opf_no_vops);
+			   opf_use | flags);
       break;
 
     case GIMPLE_RETURN:
-      append_vuse (gimple_vop (fn));
+      if (!(flags & opf_no_vops))
+	append_vuse (gimple_vop (fn));
       goto do_default;
 
     case GIMPLE_CALL:
       /* Add call-clobbered operands, if needed.  */
-      maybe_add_call_vops (fn, as_a <gcall *> (stmt));
+      if (!(flags & opf_no_vops))
+	maybe_add_call_vops (fn, as_a <gcall *> (stmt));
       /* FALLTHRU */
 
     case GIMPLE_ASSIGN:
-      get_expr_operands (fn, stmt, gimple_op_ptr (stmt, 0), opf_def);
+      get_expr_operands (fn, stmt, gimple_op_ptr (stmt, 0), opf_def | flags);
       start = 1;
       /* FALLTHRU */
 
@@ -929,22 +944,23 @@ parse_ssa_operands (struct function *fn,
     do_default:
       n = gimple_num_ops (stmt);
       for (i = start; i < n; i++)
-	get_expr_operands (fn, stmt, gimple_op_ptr (stmt, i), opf_use);
+	get_expr_operands (fn, stmt, gimple_op_ptr (stmt, i), opf_use | flags);
       break;
     }
 }
 
 
-/* Create an operands cache for STMT.  */
+/* Create an operands cache for STMT.  TRANSPARENT_P as for
+   update_stmt_operands.  */
 
 static void
-build_ssa_operands (struct function *fn, gimple *stmt)
+build_ssa_operands (struct function *fn, gimple *stmt, bool transparent_p)
 {
   /* Initially assume that the statement has no volatile operands.  */
   gimple_set_has_volatile_ops (stmt, false);
 
   start_ssa_stmt_operands ();
-  parse_ssa_operands (fn, stmt);
+  parse_ssa_operands (fn, stmt, transparent_p);
   finalize_ssa_stmt_operands (fn, stmt);
 }
 
@@ -963,7 +979,7 @@ verify_ssa_operands (struct function *fn
   /* build_ssa_operands w/o finalizing them.  */
   gimple_set_has_volatile_ops (stmt, false);
   start_ssa_stmt_operands ();
-  parse_ssa_operands (fn, stmt);
+  parse_ssa_operands (fn, stmt, false);
 
   /* Now verify the built operands are the same as present in STMT.  */
   def = gimple_vdef (stmt);
@@ -1065,10 +1081,11 @@ free_stmt_operands (struct function *fn,
 }
 
 
-/* Get the operands of statement STMT.  */
+/* Get the operands of statement STMT.  TRANSPARENT_P says that opf_transparent
+   semantics should be used whatever form STMT happens to have.  */
 
 void
-update_stmt_operands (struct function *fn, gimple *stmt)
+update_stmt_operands (struct function *fn, gimple *stmt, bool transparent_p)
 {
   /* If update_stmt_operands is called before SSA is initialized, do
      nothing.  */
@@ -1078,7 +1095,7 @@ update_stmt_operands (struct function *f
   timevar_push (TV_TREE_OPS);
 
   gcc_assert (gimple_modified_p (stmt));
-  build_ssa_operands (fn, stmt);
+  build_ssa_operands (fn, stmt, transparent_p);
   gimple_set_modified (stmt, false);
 
   timevar_pop (TV_TREE_OPS);
Index: gcc/gimple-ssa.h
===================================================================
--- gcc/gimple-ssa.h	2018-05-02 08:37:33.501751141 +0100
+++ gcc/gimple-ssa.h	2018-08-28 12:05:19.262917177 +0100
@@ -164,36 +164,42 @@ gimple_vdef_op (gimple *g)
   return NULL_DEF_OPERAND_P;
 }
 
-/* Mark statement S as modified, and update it.  */
+/* Mark statement S as modified, and update it.  TRANSPARENT_P is true
+   if the update must have no effect on code generation, in much the
+   same way as for debug statements.  This means in particular that the
+   statement should not cause things to be marked addressable and should
+   not use virtual operands.  */
 
 static inline void
-update_stmt (gimple *s)
+update_stmt (gimple *s, bool transparent_p = false)
 {
   if (gimple_has_ops (s))
     {
       gimple_set_modified (s, true);
-      update_stmt_operands (cfun, s);
+      update_stmt_operands (cfun, s, transparent_p);
     }
 }
 
-/* Update statement S if it has been optimized.  */
+/* Update statement S if it has been optimized.  TRANSPARENT_P is as for
+   update_stmt.  */
 
 static inline void
-update_stmt_if_modified (gimple *s)
+update_stmt_if_modified (gimple *s, bool transparent_p = false)
 {
   if (gimple_modified_p (s))
-    update_stmt_operands (cfun, s);
+    update_stmt_operands (cfun, s, transparent_p);
 }
 
-/* Mark statement S as modified, and update it.  */
+/* Mark statement S as modified, and update it.  TRANSPARENT_P is as for
+   update_stmt.  */
 
 static inline void
-update_stmt_fn (struct function *fn, gimple *s)
+update_stmt_fn (struct function *fn, gimple *s, bool transparent_p = false)
 {
   if (gimple_has_ops (s))
     {
       gimple_set_modified (s, true);
-      update_stmt_operands (fn, s);
+      update_stmt_operands (fn, s, transparent_p);
     }
 }
 
Index: gcc/tree-vect-slp.c
===================================================================
--- gcc/tree-vect-slp.c	2018-08-28 12:05:16.522940287 +0100
+++ gcc/tree-vect-slp.c	2018-08-28 12:05:19.262917177 +0100
@@ -2302,50 +2302,6 @@ vect_detect_hybrid_slp_stmts (slp_tree n
       vect_detect_hybrid_slp_stmts (child, i, stype);
 }
 
-/* Helpers for vect_detect_hybrid_slp walking pattern stmt uses.  */
-
-static tree
-vect_detect_hybrid_slp_1 (tree *tp, int *, void *data)
-{
-  walk_stmt_info *wi = (walk_stmt_info *)data;
-  loop_vec_info loop_vinfo = (loop_vec_info) wi->info;
-
-  if (wi->is_lhs)
-    return NULL_TREE;
-
-  stmt_vec_info def_stmt_info = loop_vinfo->lookup_def (*tp);
-  if (def_stmt_info && PURE_SLP_STMT (def_stmt_info))
-    {
-      if (dump_enabled_p ())
-	{
-	  dump_printf_loc (MSG_NOTE, vect_location, "marking hybrid: ");
-	  dump_gimple_stmt (MSG_NOTE, TDF_SLIM, def_stmt_info->stmt, 0);
-	}
-      STMT_SLP_TYPE (def_stmt_info) = hybrid;
-    }
-
-  return NULL_TREE;
-}
-
-static tree
-vect_detect_hybrid_slp_2 (gimple_stmt_iterator *gsi, bool *handled,
-			  walk_stmt_info *wi)
-{
-  loop_vec_info loop_vinfo = (loop_vec_info) wi->info;
-  stmt_vec_info use_vinfo = loop_vinfo->lookup_stmt (gsi_stmt (*gsi));
-  /* If the stmt is in a SLP instance then this isn't a reason
-     to mark use definitions in other SLP instances as hybrid.  */
-  if (! STMT_SLP_TYPE (use_vinfo)
-      && (STMT_VINFO_RELEVANT (use_vinfo)
-	  || VECTORIZABLE_CYCLE_DEF (STMT_VINFO_DEF_TYPE (use_vinfo)))
-      && ! (gimple_code (gsi_stmt (*gsi)) == GIMPLE_PHI
-	    && STMT_VINFO_DEF_TYPE (use_vinfo) == vect_reduction_def))
-    ;
-  else
-    *handled = true;
-  return NULL_TREE;
-}
-
 /* Find stmts that must be both vectorized and SLPed.  */
 
 void
@@ -2357,22 +2313,7 @@ vect_detect_hybrid_slp (loop_vec_info lo
 
   DUMP_VECT_SCOPE ("vect_detect_hybrid_slp");
 
-  /* First walk all pattern stmt in the loop and mark defs of uses as
-     hybrid because immediate uses in them are not recorded.  */
-  vec_basic_block *vec_bb;
-  FOR_EACH_VEC_ELT (loop_vinfo->blocks, i, vec_bb)
-    FOR_EACH_VEC_BB_STMT (vec_bb, stmt_info)
-      if (is_pattern_stmt_p (stmt_info))
-	{
-	  walk_stmt_info wi;
-	  memset (&wi, 0, sizeof (wi));
-	  wi.info = loop_vinfo;
-	  gimple_stmt_iterator gsi = gsi_for_stmt (stmt_info->stmt);
-	  walk_gimple_stmt (&gsi, vect_detect_hybrid_slp_2,
-			    vect_detect_hybrid_slp_1, &wi);
-	}
-
-  /* Then walk the SLP instance trees marking stmts with uses in
+  /* Walk the SLP instance trees marking stmts with uses in
      non-SLP stmts as hybrid, also propagating hybrid down the
      SLP tree, collecting the above info on-the-fly.  */
   FOR_EACH_VEC_ELT (slp_instances, i, instance)
Index: gcc/tree-vect-stmts.c
===================================================================
--- gcc/tree-vect-stmts.c	2018-08-28 12:05:16.522940287 +0100
+++ gcc/tree-vect-stmts.c	2018-08-28 12:05:19.266917143 +0100
@@ -703,54 +703,13 @@ vect_mark_stmts_to_be_vectorized (loop_v
             break;
         }
 
-      if (is_pattern_stmt_p (stmt_vinfo))
-        {
-          /* Pattern statements are not inserted into the code, so
-             FOR_EACH_PHI_OR_STMT_USE optimizes their operands out, and we
-             have to scan the RHS or function arguments instead.  */
-	  if (gassign *assign = dyn_cast <gassign *> (stmt_vinfo->stmt))
-	    {
-	      enum tree_code rhs_code = gimple_assign_rhs_code (assign);
-	      tree op = gimple_assign_rhs1 (assign);
-
-	      i = 1;
-	      if (rhs_code == COND_EXPR && COMPARISON_CLASS_P (op))
-		{
-		  if (!process_use (stmt_vinfo, TREE_OPERAND (op, 0),
-				    loop_vinfo, relevant, &worklist, false)
-		      || !process_use (stmt_vinfo, TREE_OPERAND (op, 1),
-				       loop_vinfo, relevant, &worklist, false))
-		    return false;
-		  i = 2;
-		}
-	      for (; i < gimple_num_ops (assign); i++)
-		{
-		  op = gimple_op (assign, i);
-                  if (TREE_CODE (op) == SSA_NAME
-		      && !process_use (stmt_vinfo, op, loop_vinfo, relevant,
-				       &worklist, false))
-                    return false;
-                 }
-            }
-	  else if (gcall *call = dyn_cast <gcall *> (stmt_vinfo->stmt))
-	    {
-	      for (i = 0; i < gimple_call_num_args (call); i++)
-		{
-		  tree arg = gimple_call_arg (call, i);
-		  if (!process_use (stmt_vinfo, arg, loop_vinfo, relevant,
-				    &worklist, false))
-                    return false;
-		}
-	    }
-        }
-      else
-	FOR_EACH_PHI_OR_STMT_USE (use_p, stmt_vinfo->stmt, iter, SSA_OP_USE)
-          {
-            tree op = USE_FROM_PTR (use_p);
-	    if (!process_use (stmt_vinfo, op, loop_vinfo, relevant,
-			      &worklist, false))
-              return false;
-          }
+      FOR_EACH_PHI_OR_STMT_USE (use_p, stmt_vinfo->stmt, iter, SSA_OP_USE)
+	{
+	  tree op = USE_FROM_PTR (use_p);
+	  if (!process_use (stmt_vinfo, op, loop_vinfo, relevant,
+			    &worklist, false))
+	    return false;
+	}
 
       if (STMT_VINFO_GATHER_SCATTER_P (stmt_vinfo))
 	{
@@ -10849,7 +10808,9 @@ vect_remove_dead_scalar_stmts (vec_info
 	   stmt_info = prev_stmt_info)
 	{
 	  prev_stmt_info = stmt_info->prev;
-	  if (!is_pattern_stmt_p (stmt_info))
+	  if (is_pattern_stmt_p (stmt_info))
+	    vinfo->remove_stmt (stmt_info);
+	  else
 	    vect_maybe_remove_scalar_stmt (stmt_info);
 	}
     }
Index: gcc/tree-vectorizer.h
===================================================================
--- gcc/tree-vectorizer.h	2018-08-28 12:05:16.522940287 +0100
+++ gcc/tree-vectorizer.h	2018-08-28 12:05:19.266917143 +0100
@@ -193,6 +193,8 @@ #define SLP_TREE_DEF_TYPE(S)			 (S)->def
   stmt_vec_info last () const { return m_last; }
 
 private:
+  void add_pattern_stmt_to_block (stmt_vec_info);
+
   /* The block itself.  */
   basic_block m_bb;
 
Index: gcc/tree-vectorizer.c
===================================================================
--- gcc/tree-vectorizer.c	2018-08-28 12:05:14.014961439 +0100
+++ gcc/tree-vectorizer.c	2018-08-28 12:05:19.266917143 +0100
@@ -459,6 +459,9 @@ vec_basic_block::add_to_end (stmt_vec_in
   stmt_info->block = this;
   stmt_info->prev = m_last;
   m_last = stmt_info;
+
+  if (is_pattern_stmt_p (stmt_info))
+    add_pattern_stmt_to_block (stmt_info);
 }
 
 /* Add STMT_INFO to the block, inserting it before NEXT_STMT_INFO.  */
@@ -479,6 +482,34 @@ vec_basic_block::add_before (stmt_vec_in
   stmt_info->prev = next_stmt_info->prev;
   stmt_info->next = next_stmt_info;
   next_stmt_info->prev = stmt_info;
+
+  if (is_pattern_stmt_p (stmt_info))
+    add_pattern_stmt_to_block (stmt_info);
+}
+
+/* Record that pattern statement STMT_INFO has just been added to the
+   vec_basic_block.  Adding it to the underlying basic_block would be
+   problematic because we need to be able to duplicate the original
+   scalar code in the middle of vectorization.  Instead we just set the
+   statement's gimple_bb and link its SSA uses.  */
+
+void
+vec_basic_block::add_pattern_stmt_to_block (stmt_vec_info stmt_info)
+{
+  gimple_set_bb (stmt_info->stmt, m_bb);
+  update_stmt (stmt_info->stmt, true);
+  gcc_assert (!gimple_vdef (stmt_info->stmt));
+  gcc_assert (!gimple_vuse (stmt_info->stmt));
+}
+
+/* Record that STMT_INFO has been removed from its vec_basic_block.
+   Undo the effect of add_pattern_stmt_to_block.  */
+
+static void
+remove_pattern_stmt_from_block (stmt_vec_info stmt_info)
+{
+  gimple_set_bb (stmt_info->stmt, NULL);
+  delink_stmt_imm_use (stmt_info->stmt);
 }
 
 /* Remove STMT_INFO from the block.  */
@@ -497,6 +528,9 @@ vec_basic_block::remove (stmt_vec_info s
     m_last = stmt_info->prev;
   stmt_info->block = NULL;
   stmt_info->prev = stmt_info->next = NULL;
+
+  if (is_pattern_stmt_p (stmt_info))
+    remove_pattern_stmt_from_block (stmt_info);
 }
 \f
 /* Initialize the vec_info with kind KIND_IN and target cost data
@@ -610,12 +644,37 @@ vec_info::lookup_def (tree name)
 stmt_vec_info
 vec_info::lookup_single_use (stmt_vec_info stmt_info)
 {
-  tree lhs = gimple_get_lhs (stmt_info->stmt);
-  use_operand_p dummy;
-  gimple *use_stmt;
-  if (single_imm_use (lhs, &dummy, &use_stmt))
-    return lookup_stmt (use_stmt);
-  return NULL;
+  gimple *stmts[2] = { stmt_info->stmt, NULL };
+  unsigned int num_stmts = 1;
+  /* If STMT_INFO replaces one of the original scalar statements,
+     check for uses of that statement's results too, to simulate the
+     effect of vect_stmt_to_be_vectorized.  */
+  if (is_main_pattern_stmt_p (stmt_info))
+    stmts[num_stmts++] = STMT_VINFO_RELATED_STMT (stmt_info)->stmt;
+  stmt_vec_info result = NULL;
+  for (unsigned int i = 0; i < num_stmts; ++i)
+    {
+      use_operand_p use_p;
+      imm_use_iterator imm_iter;
+      tree lhs = gimple_get_lhs (stmts[i]);
+      FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
+	{
+	  gimple *use_stmt = USE_STMT (use_p);
+	  if (is_gimple_debug (use_stmt))
+	    continue;
+	  stmt_vec_info use_stmt_info = lookup_stmt (use_stmt);
+	  if (!use_stmt_info)
+	    return NULL;
+	  /* Ignore statements that have been replaced by a pattern
+	     and consider only the replacement statement.  */
+	  if (STMT_VINFO_IN_PATTERN_P (use_stmt_info))
+	    continue;
+	  if (result)
+	    return NULL;
+	  result = use_stmt_info;
+	}
+    }
+  return result;
 }
 
 /* Return vectorization information about DR.  */
@@ -650,16 +709,18 @@ vec_info::move_dr (stmt_vec_info new_stm
 void
 vec_info::remove_stmt (stmt_vec_info stmt_info)
 {
-  gcc_assert (!stmt_info->pattern_stmt_p);
   set_vinfo_for_stmt (stmt_info->stmt, NULL);
   gimple_stmt_iterator si = gsi_for_stmt (stmt_info->stmt);
   unlink_stmt_vdef (stmt_info->stmt);
-  if (is_a <gphi *> (stmt_info->stmt))
-    remove_phi_node (&si, true);
-  else
+  if (!is_pattern_stmt_p (stmt_info))
     {
-      gsi_remove (&si, true);
-      release_defs (stmt_info->stmt);
+      if (is_a <gphi *> (stmt_info->stmt))
+	remove_phi_node (&si, true);
+      else
+	{
+	  gsi_remove (&si, true);
+	  release_defs (stmt_info->stmt);
+	}
     }
   stmt_info->block->remove (stmt_info);
   free_stmt_vec_info (stmt_info);
@@ -749,12 +810,13 @@ vec_info::free_stmt_vec_infos (void)
 void
 vec_info::free_stmt_vec_info (stmt_vec_info stmt_info)
 {
-  if (stmt_info->pattern_stmt_p)
+  if (is_pattern_stmt_p (stmt_info))
     {
-      gimple_set_bb (stmt_info->stmt, NULL);
       tree lhs = gimple_get_lhs (stmt_info->stmt);
       if (lhs && TREE_CODE (lhs) == SSA_NAME)
 	release_ssa_name (lhs);
+      if (stmt_info->block)
+	remove_pattern_stmt_from_block (stmt_info);
     }
 
   STMT_VINFO_SAME_ALIGN_REFS (stmt_info).release ();
Index: gcc/tree-vect-patterns.c
===================================================================
--- gcc/tree-vect-patterns.c	2018-08-28 12:05:16.518940320 +0100
+++ gcc/tree-vect-patterns.c	2018-08-28 12:05:19.262917177 +0100
@@ -106,7 +106,6 @@ vect_init_pattern_stmt (gimple *pattern_
   stmt_vec_info pattern_stmt_info = vinfo->lookup_stmt (pattern_stmt);
   if (pattern_stmt_info == NULL)
     pattern_stmt_info = orig_stmt_info->vinfo->add_stmt (pattern_stmt);
-  gimple_set_bb (pattern_stmt, gimple_bb (orig_stmt_info->stmt));
 
   pattern_stmt_info->pattern_stmt_p = true;
   STMT_VINFO_RELATED_STMT (pattern_stmt_info) = orig_stmt_info;
@@ -412,11 +411,9 @@ vect_look_through_possible_promotion (ve
 	break;
       caster = def_stmt_info;
 
-      /* Ignore pattern statements, since we don't link uses for them.  */
       if (caster
 	  && single_use_p
-	  && !STMT_VINFO_RELATED_STMT (caster)
-	  && !has_single_use (res))
+	  && !vinfo->lookup_single_use (caster))
 	*single_use_p = false;
 
       gassign *assign = dyn_cast <gassign *> (def_stmt);

  parent reply	other threads:[~2018-08-28 11:25 UTC|newest]

Thread overview: 22+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-08-28 11:19 [0/6] Make vector pattern statements less special Richard Sandiford
2018-08-28 11:20 ` [1/6] Handle gphis in gimple_get_lhs Richard Sandiford
2018-08-28 18:22   ` Jeff Law
2018-08-28 11:21 ` [2/6] Make vec_info::lookup_single_use take a stmt_vec_info Richard Sandiford
2018-08-28 18:25   ` Jeff Law
2018-08-28 11:22 ` [3/6] Add a vec_basic_block structure Richard Sandiford
2018-08-28 22:38   ` Jeff Law
2018-08-28 11:23 ` [4/6] Make the vectoriser do its own DCE Richard Sandiford
2018-08-28 23:01   ` Jeff Law
2018-08-29  7:16     ` Richard Biener
2018-08-28 11:25 ` Richard Sandiford [this message]
2018-08-29  7:43   ` [6/6] Link imm uses for pattern stmts Richard Biener
2018-08-29  9:25     ` Richard Sandiford
2018-08-30 10:24       ` Richard Biener
2018-08-28 11:25 ` [5/6] Insert pattern statements into vec_basic_blocks Richard Sandiford
2018-08-28 23:16   ` Jeff Law
2018-08-29  7:18     ` Richard Biener
2018-08-29  7:55   ` Jakub Jelinek
2018-08-29  8:59     ` Richard Sandiford
2018-08-29  9:10       ` Jakub Jelinek
2018-08-29  9:22         ` Richard Biener
2018-08-29  9:38           ` Richard Sandiford

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=8736uyraw0.fsf@arm.com \
    --to=richard.sandiford@arm.com \
    --cc=gcc-patches@gcc.gnu.org \
    /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).