diff mbox series

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

Message ID mpttughmf0l.fsf@arm.com
State Committed
Headers show
Series [1/5] vect: Use code_helper when building SLP nodes | expand

Commit Message

Richard Sandiford Nov. 12, 2021, 5:59 p.m. UTC
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?

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(-)

Comments

Richard Biener Nov. 12, 2021, 7:11 p.m. UTC | #1
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;
diff mbox series

Patch

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;