[PATCH] gimple-match, gimple-fold: After PROP_gimple_lvec is set, punt for vector stmts that veclower would need to lower [PR98287]

Richard Sandiford richard.sandiford@arm.com
Tue Feb 2 09:38:09 GMT 2021


Jakub Jelinek via Gcc-patches <gcc-patches@gcc.gnu.org> writes:
> Hi!
>
> The following testcase ICEs, because after the veclower pass which is the
> last point which lowers unsupported vector operations to supported ones
> (or scalars) match.pd simplifies a supported vector operation into
> unsupported one (vec << 1 >> 1 into vec & { ~1, ... }).
> Guarding each match.pd pattern that could do it manually would be IMHO a
> nightmare and it could affect hundreds of them, so this patch instead
> performs the verification and punting in the infrastructure (of course only
> in PROP_gimple_lvec state which is set after the vector lowering).
> The function attempts to match expand_vector_operations_1 (except I haven't
> added VEC_PERM_EXPR, VEC_COND_EXPR and COND_EXPR cases there, so those
> aren't checked and can be added later if we find it a problem).
>
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
>
> 2021-02-02  Jakub Jelinek  <jakub@redhat.com>
>
> 	PR tree-optimization/98287
> 	* gimple-match.h (check_gimple_lvec): New declaration.
> 	* gimple-match-head.c (check_gimple_lvec): New function.
> 	(maybe_push_res_to_seq): Use it.
> 	* gimple-fold.c: Include tree-pass.h.
> 	(replace_stmt_with_simplification): Use it.
>
> 	* gcc.dg/pr98287.c: New test.
>
> --- gcc/gimple-match.h.jj	2021-01-04 10:25:38.456238093 +0100
> +++ gcc/gimple-match.h	2021-02-01 13:19:30.393860766 +0100
> @@ -335,6 +335,7 @@ extern tree (*mprts_hook) (gimple_match_
>  
>  bool gimple_simplify (gimple *, gimple_match_op *, gimple_seq *,
>  		      tree (*)(tree), tree (*)(tree));
> +bool check_gimple_lvec (gimple_match_op *);
>  tree maybe_push_res_to_seq (gimple_match_op *, gimple_seq *,
>  			    tree res = NULL_TREE);
>  void maybe_build_generic_op (gimple_match_op *);
> --- gcc/gimple-match-head.c.jj	2021-01-16 19:46:53.511672837 +0100
> +++ gcc/gimple-match-head.c	2021-02-01 13:18:58.676225427 +0100
> @@ -549,6 +549,109 @@ build_call_internal (internal_fn fn, gim
>  				     res_op->op_or_null (4));
>  }
>  
> +/* In PROP_gimple_lvec mode, perform extra checking if RES_OP and return
> +   true if RES_OP is not appropriate - would require vector operations that
> +   would need to be lowered before expansion.  */
> +
> +bool
> +check_gimple_lvec (gimple_match_op *res_op)

Guess this is personal preference, but the return value seems inverted.
I'd have expected true if something is OK and false if something isn't.

> +{
> +  enum tree_code code = res_op->code;
> +  enum gimple_rhs_class rhs_class = get_gimple_rhs_class (code);
> +  if (rhs_class != GIMPLE_UNARY_RHS && rhs_class != GIMPLE_BINARY_RHS)
> +    return false;
> +
> +  tree rhs1 = res_op->op_or_null (0);
> +  tree rhs2 = res_op->op_or_null (1);
> +  tree type = res_op->type;
> +
> +  if (!VECTOR_TYPE_P (type) || !VECTOR_TYPE_P (TREE_TYPE (rhs1)))
> +    return false;
> +
> +  /* A scalar operation pretending to be a vector one.  */
> +  if (VECTOR_BOOLEAN_TYPE_P (type)
> +      && !VECTOR_MODE_P (TYPE_MODE (type))
> +      && TYPE_MODE (type) != BLKmode
> +      && (TREE_CODE_CLASS (code) != tcc_comparison
> +	  || (VECTOR_BOOLEAN_TYPE_P (TREE_TYPE (rhs1))
> +	      && !VECTOR_MODE_P (TYPE_MODE (TREE_TYPE (rhs1)))
> +	      && TYPE_MODE (TREE_TYPE (rhs1)) != BLKmode)))
> +    return false;
> +
> +  machine_mode mode = TYPE_MODE (type);
> +  optab op;
> +  switch (code)
> +    {
> +    CASE_CONVERT:
> +    case FLOAT_EXPR:
> +    case FIX_TRUNC_EXPR:
> +    case VIEW_CONVERT_EXPR:
> +      return false;
> +
> +    case VEC_UNPACK_FLOAT_HI_EXPR:
> +    case VEC_UNPACK_FLOAT_LO_EXPR:
> +    case VEC_PACK_FLOAT_EXPR:
> +      return false;
> +
> +    case WIDEN_SUM_EXPR:
> +    case VEC_WIDEN_PLUS_HI_EXPR:
> +    case VEC_WIDEN_PLUS_LO_EXPR:
> +    case VEC_WIDEN_MINUS_HI_EXPR:
> +    case VEC_WIDEN_MINUS_LO_EXPR:
> +    case VEC_WIDEN_MULT_HI_EXPR:
> +    case VEC_WIDEN_MULT_LO_EXPR:
> +    case VEC_WIDEN_MULT_EVEN_EXPR:
> +    case VEC_WIDEN_MULT_ODD_EXPR:
> +    case VEC_UNPACK_HI_EXPR:
> +    case VEC_UNPACK_LO_EXPR:
> +    case VEC_UNPACK_FIX_TRUNC_HI_EXPR:
> +    case VEC_UNPACK_FIX_TRUNC_LO_EXPR:
> +    case VEC_PACK_TRUNC_EXPR:
> +    case VEC_PACK_SAT_EXPR:
> +    case VEC_PACK_FIX_TRUNC_EXPR:
> +    case VEC_WIDEN_LSHIFT_HI_EXPR:
> +    case VEC_WIDEN_LSHIFT_LO_EXPR:
> +      return false;
> +
> +    case LSHIFT_EXPR:
> +    case RSHIFT_EXPR:
> +    case LROTATE_EXPR:
> +    case RROTATE_EXPR:
> +      if (!VECTOR_MODE_P (mode))
> +	return true;
> +      if (!VECTOR_INTEGER_TYPE_P (TREE_TYPE (rhs2)))
> +	{
> +	  op = optab_for_tree_code (code, type, optab_scalar);
> +	  if (op && optab_handler (op, mode) != CODE_FOR_nothing)
> +	    return false;
> +	}
> +      op = optab_for_tree_code (code, type, optab_vector);
> +      if (op && optab_handler (op, mode) != CODE_FOR_nothing)
> +	return false;
> +      return true;
> +
> +    case MULT_HIGHPART_EXPR:
> +      if (!VECTOR_MODE_P (mode)
> +	  || !can_mult_highpart_p (mode, TYPE_UNSIGNED (type)))
> +	return true;
> +      return false;
> +
> +    default:
> +      if (!VECTOR_MODE_P (mode))
> +	return true;
> +      op = optab_for_tree_code (code, type, optab_default);
> +      if (op == unknown_optab
> +	  && code == NEGATE_EXPR
> +	  && INTEGRAL_TYPE_P (TREE_TYPE (type)))
> +	op = optab_for_tree_code (MINUS_EXPR, type, optab_default);
> +      if (op && optab_handler (op, mode) != CODE_FOR_nothing)
> +	return false;
> +      return true;

This doesn't look right for things like SVE comparisons, where the
result is a VECTOR_BOOLEAN_TYPE_P with MODE_VECTOR_BOOL and where
the inputs are something else.  I guess it might also affect FP
comparisons on most targets.

So I think it would be worth separating out comparisons, even if we
just accept them unconditionally to start with.

Thanks,
Richard

> +    }
> +
> +  return false;
> +}
> +
>  /* Push the exploded expression described by RES_OP as a statement to
>     SEQ if necessary and return a gimple value denoting the value of the
>     expression.  If RES is not NULL then the result will be always RES
> @@ -597,6 +700,12 @@ maybe_push_res_to_seq (gimple_match_op *
>  
>    if (res_op->code.is_tree_code ())
>      {
> +      if (VECTOR_TYPE_P (res_op->type)
> +	  && cfun
> +	  && (cfun->curr_properties & PROP_gimple_lvec) != 0
> +	  && check_gimple_lvec (res_op))
> +	return NULL_TREE;
> +
>        if (!res)
>  	{
>  	  if (gimple_in_ssa_p (cfun))
> --- gcc/gimple-fold.c.jj	2021-01-22 11:41:56.510499898 +0100
> +++ gcc/gimple-fold.c	2021-02-01 13:22:11.992002840 +0100
> @@ -66,6 +66,7 @@ along with GCC; see the file COPYING3.
>  #include "tree-vector-builder.h"
>  #include "tree-ssa-strlen.h"
>  #include "varasm.h"
> +#include "tree-pass.h"
>  
>  enum strlen_range_kind {
>    /* Compute the exact constant string length.  */
> @@ -5678,6 +5679,11 @@ replace_stmt_with_simplification (gimple
>        if (!inplace
>  	  || gimple_num_ops (stmt) > get_gimple_rhs_num_ops (res_op->code))
>  	{
> +	  if (VECTOR_TYPE_P (res_op->type)
> +	      && cfun
> +	      && (cfun->curr_properties & PROP_gimple_lvec) != 0
> +	      && check_gimple_lvec (res_op))
> +	    return false;
>  	  maybe_build_generic_op (res_op);
>  	  gimple_assign_set_rhs_with_ops (gsi, res_op->code,
>  					  res_op->op_or_null (0),
> --- gcc/testsuite/gcc.dg/pr98287.c.jj	2021-02-01 13:32:22.735981006 +0100
> +++ gcc/testsuite/gcc.dg/pr98287.c	2021-02-01 13:32:01.155229122 +0100
> @@ -0,0 +1,19 @@
> +/* PR tree-optimization/98287 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fno-tree-ccp -fno-tree-forwprop -Wno-psabi -w" } */
> +
> +typedef unsigned long __attribute__((__vector_size__ (8))) V;
> +V v;
> +
> +static __attribute__((noinline, noclone)) V
> +bar (unsigned short s)
> +{
> +  return v >> s << s | v >> s >> 63;
> +}
> +
> +unsigned long
> +foo (void)
> +{
> +  V x = bar (1);
> +  return x[0];
> +}
>
> 	Jakub


More information about the Gcc-patches mailing list