[PATCH 2/5] vect: Use generalised accessors to build SLP nodes

Richard Biener richard.guenther@gmail.com
Fri Nov 12 19:11:39 GMT 2021


On November 12, 2021 6:59:22 PM GMT+01:00, Richard Sandiford via Gcc-patches <gcc-patches@gcc.gnu.org> wrote:
>This patch adds:
>
>- gimple_num_args
>- gimple_arg
>- gimple_arg_ptr
>
>for accessing rhs operands of an assignment, call or PHI.  This is
>similar to the existing gimple_get_lhs.
>
>I guess there's a danger that these routines could be overused,
>such as in cases where gimple_assign_rhs1 etc. would be more
>appropriate.  I think the routines are still worth having though.
>These days, most new operations are added as internal functions rather
>than tree codes, so it's useful to be able to handle assignments and
>calls in a consistent way.
>
>The patch also generalises the way that SLP child nodes map
>to gimple stmt operands.  This is useful for later patches.
>
>Regstrapped on aarch64-linux-gnu and x86_64-linux-gnu.  OK to install?

Nice.

Ok.
Thanks, 
Richard. 

>Richard
>
>
>gcc/
>	* gimple.h (gimple_num_args, gimple_arg, gimple_arg_ptr): New
>	functions.
>	* tree-vect-slp.c (cond_expr_maps, arg2_map): New variables.
>	(vect_get_operand_map): New function.
>	(vect_get_and_check_slp_defs): Fix outdated comment.
>	Use vect_get_operand_map and new gimple argument accessors.
>	(vect_build_slp_tree_2): Likewise.
>---
> gcc/gimple.h        |  38 ++++++++++++
> gcc/tree-vect-slp.c | 148 +++++++++++++++++++++++---------------------
> 2 files changed, 114 insertions(+), 72 deletions(-)
>
>diff --git a/gcc/gimple.h b/gcc/gimple.h
>index 3cde3cde7fe..f7fdefc5362 100644
>--- a/gcc/gimple.h
>+++ b/gcc/gimple.h
>@@ -4692,6 +4692,44 @@ gimple_phi_arg_has_location (const gphi *phi, size_t i)
>   return gimple_phi_arg_location (phi, i) != UNKNOWN_LOCATION;
> }
> 
>+/* Return the number of arguments that can be accessed by gimple_arg.  */
>+
>+static inline unsigned
>+gimple_num_args (const gimple *gs)
>+{
>+  if (auto phi = dyn_cast<const gphi *> (gs))
>+    return gimple_phi_num_args (phi);
>+  if (auto call = dyn_cast<const gcall *> (gs))
>+    return gimple_call_num_args (call);
>+  return gimple_num_ops (as_a <const gassign *> (gs)) - 1;
>+}
>+
>+/* GS must be an assignment, a call, or a PHI.
>+   If it's an assignment, return rhs operand I.
>+   If it's a call, return function argument I.
>+   If it's a PHI, return the value of PHI argument I.  */
>+
>+static inline tree
>+gimple_arg (const gimple *gs, unsigned int i)
>+{
>+  if (auto phi = dyn_cast<const gphi *> (gs))
>+    return gimple_phi_arg_def (phi, i);
>+  if (auto call = dyn_cast<const gcall *> (gs))
>+    return gimple_call_arg (call, i);
>+  return gimple_op (as_a <const gassign *> (gs), i + 1);
>+}
>+
>+/* Return a pointer to gimple_arg (GS, I).  */
>+
>+static inline tree *
>+gimple_arg_ptr (gimple *gs, unsigned int i)
>+{
>+  if (auto phi = dyn_cast<gphi *> (gs))
>+    return gimple_phi_arg_def_ptr (phi, i);
>+  if (auto call = dyn_cast<gcall *> (gs))
>+    return gimple_call_arg_ptr (call, i);
>+  return gimple_op_ptr (as_a <gassign *> (gs), i + 1);
>+}
> 
> /* Return the region number for GIMPLE_RESX RESX_STMT.  */
> 
>diff --git a/gcc/tree-vect-slp.c b/gcc/tree-vect-slp.c
>index f4123cf830a..2594ab7607f 100644
>--- a/gcc/tree-vect-slp.c
>+++ b/gcc/tree-vect-slp.c
>@@ -454,15 +454,57 @@ vect_def_types_match (enum vect_def_type dta, enum vect_def_type dtb)
> 	      && (dtb == vect_external_def || dtb == vect_constant_def)));
> }
> 
>+static const int cond_expr_maps[3][5] = {
>+  { 4, -1, -2, 1, 2 },
>+  { 4, -2, -1, 1, 2 },
>+  { 4, -1, -2, 2, 1 }
>+};
>+static const int arg2_map[] = { 1, 2 };
>+
>+/* For most SLP statements, there is a one-to-one mapping between
>+   gimple arguments and child nodes.  If that is not true for STMT,
>+   return an array that contains:
>+
>+   - the number of child nodes, followed by
>+   - for each child node, the index of the argument associated with that node.
>+     The special index -1 is the first operand of an embedded comparison and
>+     the special index -2 is the second operand of an embedded comparison.
>+
>+   SWAP is as for vect_get_and_check_slp_defs.  */
>+
>+static const int *
>+vect_get_operand_map (const gimple *stmt, unsigned char swap = 0)
>+{
>+  if (auto assign = dyn_cast<const gassign *> (stmt))
>+    {
>+      if (gimple_assign_rhs_code (assign) == COND_EXPR
>+	  && COMPARISON_CLASS_P (gimple_assign_rhs1 (assign)))
>+	return cond_expr_maps[swap];
>+    }
>+  gcc_assert (!swap);
>+  if (auto call = dyn_cast<const gcall *> (stmt))
>+    {
>+      if (gimple_call_internal_p (call))
>+	switch (gimple_call_internal_fn (call))
>+	  {
>+	  case IFN_MASK_LOAD:
>+	    return arg2_map;
>+
>+	  default:
>+	    break;
>+	  }
>+    }
>+  return nullptr;
>+}
>+
> /* Get the defs for the rhs of STMT (collect them in OPRNDS_INFO), check that
>    they are of a valid type and that they match the defs of the first stmt of
>    the SLP group (stored in OPRNDS_INFO).  This function tries to match stmts
>-   by swapping operands of STMTS[STMT_NUM] when possible.  Non-zero *SWAP
>-   indicates swap is required for cond_expr stmts.  Specifically, *SWAP
>+   by swapping operands of STMTS[STMT_NUM] when possible.  Non-zero SWAP
>+   indicates swap is required for cond_expr stmts.  Specifically, SWAP
>    is 1 if STMT is cond and operands of comparison need to be swapped;
>-   *SWAP is 2 if STMT is cond and code of comparison needs to be inverted.
>-   If there is any operand swap in this function, *SWAP is set to non-zero
>-   value.
>+   SWAP is 2 if STMT is cond and code of comparison needs to be inverted.
>+
>    If there was a fatal error return -1; if the error could be corrected by
>    swapping operands of father node of this one, return 1; if everything is
>    ok return 0.  */
>@@ -477,76 +519,48 @@ vect_get_and_check_slp_defs (vec_info *vinfo, unsigned char swap,
>   unsigned int i, number_of_oprnds;
>   enum vect_def_type dt = vect_uninitialized_def;
>   slp_oprnd_info oprnd_info;
>-  int first_op_idx = 1;
>   unsigned int commutative_op = -1U;
>-  bool first_op_cond = false;
>   bool first = stmt_num == 0;
> 
>+  if (!is_a<gcall *> (stmt_info->stmt)
>+      && !is_a<gassign *> (stmt_info->stmt)
>+      && !is_a<gphi *> (stmt_info->stmt))
>+    return -1;
>+
>+  number_of_oprnds = gimple_num_args (stmt_info->stmt);
>+  const int *map = vect_get_operand_map (stmt_info->stmt, swap);
>+  if (map)
>+    number_of_oprnds = *map++;
>   if (gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt))
>     {
>-      number_of_oprnds = gimple_call_num_args (stmt);
>-      first_op_idx = 3;
>       if (gimple_call_internal_p (stmt))
> 	{
> 	  internal_fn ifn = gimple_call_internal_fn (stmt);
> 	  commutative_op = first_commutative_argument (ifn);
>-
>-	  /* Masked load, only look at mask.  */
>-	  if (ifn == IFN_MASK_LOAD)
>-	    {
>-	      number_of_oprnds = 1;
>-	      /* Mask operand index.  */
>-	      first_op_idx = 5;
>-	    }
> 	}
>     }
>   else if (gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt))
>     {
>-      enum tree_code code = gimple_assign_rhs_code (stmt);
>-      number_of_oprnds = gimple_num_ops (stmt) - 1;
>-      /* Swap can only be done for cond_expr if asked to, otherwise we
>-	 could result in different comparison code to the first stmt.  */
>-      if (code == COND_EXPR
>-	  && COMPARISON_CLASS_P (gimple_assign_rhs1 (stmt)))
>-	{
>-	  first_op_cond = true;
>-	  number_of_oprnds++;
>-	}
>-      else
>-	commutative_op = commutative_tree_code (code) ? 0U : -1U;
>+      if (commutative_tree_code (gimple_assign_rhs_code (stmt)))
>+	commutative_op = 0;
>     }
>-  else if (gphi *stmt = dyn_cast <gphi *> (stmt_info->stmt))
>-    number_of_oprnds = gimple_phi_num_args (stmt);
>-  else
>-    return -1;
> 
>   bool swapped = (swap != 0);
>   bool backedge = false;
>-  gcc_assert (!swapped || first_op_cond);
>   enum vect_def_type *dts = XALLOCAVEC (enum vect_def_type, number_of_oprnds);
>   for (i = 0; i < number_of_oprnds; i++)
>     {
>-      if (first_op_cond)
>-	{
>-	  /* Map indicating how operands of cond_expr should be swapped.  */
>-	  int maps[3][4] = {{0, 1, 2, 3}, {1, 0, 2, 3}, {0, 1, 3, 2}};
>-	  int *map = maps[swap];
>-
>-	  if (i < 2)
>-	    oprnd = TREE_OPERAND (gimple_op (stmt_info->stmt,
>-					     first_op_idx), map[i]);
>-	  else
>-	    oprnd = gimple_op (stmt_info->stmt, map[i]);
>-	}
>-      else if (gphi *stmt = dyn_cast <gphi *> (stmt_info->stmt))
>+      int opno = map ? map[i] : int (i);
>+      if (opno < 0)
>+	oprnd = TREE_OPERAND (gimple_arg (stmt_info->stmt, 0), -1 - opno);
>+      else
> 	{
>-	  oprnd = gimple_phi_arg_def (stmt, i);
>-	  backedge = dominated_by_p (CDI_DOMINATORS,
>-				     gimple_phi_arg_edge (stmt, i)->src,
>-				     gimple_bb (stmt_info->stmt));
>+	  oprnd = gimple_arg (stmt_info->stmt, opno);
>+	  if (gphi *stmt = dyn_cast <gphi *> (stmt_info->stmt))
>+	    backedge = dominated_by_p (CDI_DOMINATORS,
>+				       gimple_phi_arg_edge (stmt, opno)->src,
>+				       gimple_bb (stmt_info->stmt));
> 	}
>-      else
>-	oprnd = gimple_op (stmt_info->stmt, first_op_idx + (swapped ? !i : i));
>       if (TREE_CODE (oprnd) == VIEW_CONVERT_EXPR)
> 	oprnd = TREE_OPERAND (oprnd, 0);
> 
>@@ -1140,9 +1154,7 @@ vect_build_slp_tree_1 (vec_info *vinfo, unsigned char *swap,
> 
> 	  if (need_same_oprnds)
> 	    {
>-	      tree other_op1 = (call_stmt
>-				? gimple_call_arg (call_stmt, 1)
>-				: gimple_assign_rhs2 (stmt));
>+	      tree other_op1 = gimple_arg (stmt, 1);
> 	      if (!operand_equal_p (first_op1, other_op1, 0))
> 		{
> 		  if (dump_enabled_p ())
>@@ -1601,19 +1613,15 @@ vect_build_slp_tree_2 (vec_info *vinfo, slp_tree node,
>   matches[0] = false;
> 
>   stmt_vec_info stmt_info = stmts[0];
>-  if (gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt))
>-    nops = gimple_call_num_args (stmt);
>-  else if (gassign *stmt = dyn_cast <gassign *> (stmt_info->stmt))
>-    {
>-      nops = gimple_num_ops (stmt) - 1;
>-      if (gimple_assign_rhs_code (stmt) == COND_EXPR)
>-	nops++;
>-    }
>-  else if (gphi *phi = dyn_cast <gphi *> (stmt_info->stmt))
>-    nops = gimple_phi_num_args (phi);
>-  else
>+  if (!is_a<gcall *> (stmt_info->stmt)
>+      && !is_a<gassign *> (stmt_info->stmt)
>+      && !is_a<gphi *> (stmt_info->stmt))
>     return NULL;
> 
>+  nops = gimple_num_args (stmt_info->stmt);
>+  if (const int *map = vect_get_operand_map (stmt_info->stmt))
>+    nops = map[0];
>+
>   /* If the SLP node is a PHI (induction or reduction), terminate
>      the recursion.  */
>   bool *skip_args = XALLOCAVEC (bool, nops);
>@@ -1684,11 +1692,7 @@ vect_build_slp_tree_2 (vec_info *vinfo, slp_tree node,
>       && DR_IS_READ (STMT_VINFO_DATA_REF (stmt_info)))
>     {
>       if (gcall *stmt = dyn_cast <gcall *> (stmt_info->stmt))
>-	{
>-	  /* Masked load.  */
>-	  gcc_assert (gimple_call_internal_p (stmt, IFN_MASK_LOAD));
>-	  nops = 1;
>-	}
>+	gcc_assert (gimple_call_internal_p (stmt, IFN_MASK_LOAD));
>       else
> 	{
> 	  *max_nunits = this_max_nunits;



More information about the Gcc-patches mailing list