This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Adapt a couple of scalar comparison match.pd optimizations for vector comparisons against uniform vectors (PR target/88152, take 2)


On Thu, 29 Nov 2018, Jakub Jelinek wrote:

> On Thu, Nov 29, 2018 at 10:31:06AM +0100, Jakub Jelinek wrote:
> > On Thu, Nov 29, 2018 at 10:22:15AM +0100, Richard Biener wrote:
> > > OK.  I didn't spent a lot of time trying to see if we can merge the
> > > scalar and vector variants but I trust you did ;)
> > 
> > Yeah, sadly it is too different, even if we were to introduce a predicate
> > whether a tree is either INTEGER_CST, or VECTOR_CST where uniform_vector_p
> > is non-NULL and INTEGER_CST, e.g. because we need to use build_vector_from_val
> > and take care of the sometimes vector, sometimes element types.
> 
> Actually, it isn't that bad.
> So, would you prefer something like this instead (untested so far)?

Yes.

> Any better suggestions for the 2 new functions?  Just don't want to make
> them much longer as that causes formatting issues.

They look good as-is.

Richard.

> 2018-11-29  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR target/88152
> 	* tree.h (build_uniform_cst, uniform_integer_cst_p): Declare.
> 	* tree.c (build_uniform_cst, uniform_integer_cst_p): New functions.
> 	* match.pd (define_predicates): Add uniform_integer_cst_p.
> 	(cmp @0 INTEGER_CST@1, cmp (convert?@2 @0) INTEGER_CST@1): Adjust
> 	so that it works also for vector comparisons with uniform constants
> 	with INTEGER_CST element.
> 
> 	* g++.dg/tree-ssa/pr88152-1.C: New test.
> 	* g++.dg/tree-ssa/pr88152-2.C: New test.
> 
> --- gcc/tree.h.jj	2018-11-23 20:00:29.591224109 +0100
> +++ gcc/tree.h	2018-11-29 11:06:41.258362258 +0100
> @@ -4182,6 +4182,7 @@ extern tree build_int_cst_type (tree, po
>  extern tree make_vector (unsigned, unsigned CXX_MEM_STAT_INFO);
>  extern tree build_vector_from_ctor (tree, vec<constructor_elt, va_gc> *);
>  extern tree build_vector_from_val (tree, tree);
> +extern tree build_uniform_cst (tree, tree);
>  extern tree build_vec_series (tree, tree, tree);
>  extern tree build_index_vector (tree, poly_uint64, poly_uint64);
>  extern void recompute_constructor_flags (tree);
> @@ -4492,6 +4493,12 @@ extern tree vector_cst_elt (const_tree,
>  
>  extern tree uniform_vector_p (const_tree);
>  
> +/* If the argument is INTEGER_CST, return it.  If the argument is vector
> +   with all elements the same INTEGER_CST, return that INTEGER_CST.  Otherwise
> +   return NULL_TREE.  */
> +
> +extern tree uniform_integer_cst_p (tree);
> +
>  /* Given a CONSTRUCTOR CTOR, return the element values as a vector.  */
>  
>  extern vec<tree, va_gc> *ctor_to_vec (tree);
> --- gcc/tree.c.jj	2018-11-23 20:00:29.590224125 +0100
> +++ gcc/tree.c	2018-11-29 11:07:12.569839152 +0100
> @@ -1906,6 +1906,18 @@ build_vector_from_val (tree vectype, tre
>      }
>  }
>  
> +/* If TYPE is not a vector type, just return SC, otherwise return
> +   build_vector_from_val (TYPE, SC).  */
> +
> +tree
> +build_uniform_cst (tree type, tree sc)
> +{
> +  if (!VECTOR_TYPE_P (type))
> +    return sc;
> +
> +  return build_vector_from_val (type, sc);
> +}
> +
>  /* Build a vector series of type TYPE in which element I has the value
>     BASE + I * STEP.  The result is a constant if BASE and STEP are constant
>     and a VEC_SERIES_EXPR otherwise.  */
> @@ -11210,6 +11222,26 @@ uniform_vector_p (const_tree vec)
>      }
>  
>    return NULL_TREE;
> +}
> +
> +/* If the argument is INTEGER_CST, return it.  If the argument is vector
> +   with all elements the same INTEGER_CST, return that INTEGER_CST.  Otherwise
> +   return NULL_TREE.  */
> +
> +tree
> +uniform_integer_cst_p (tree t)
> +{
> +  if (TREE_CODE (t) == INTEGER_CST)
> +    return t;
> +
> +  if (VECTOR_TYPE_P (TREE_TYPE (t)))
> +    {
> +      t = uniform_vector_p (t);
> +      if (t && TREE_CODE (t) == INTEGER_CST)
> +	return t;
> +    }
> +
> +  return NULL_TREE;
>  }
>  
>  /* Build an empty statement at location LOC.  */
> --- gcc/match.pd.jj	2018-11-29 08:41:21.229948339 +0100
> +++ gcc/match.pd	2018-11-29 11:04:56.325115332 +0100
> @@ -34,6 +34,7 @@ (define_predicates
>     tree_expr_nonzero_p
>     integer_valued_real_p
>     integer_pow2p
> +   uniform_integer_cst_p
>     HONOR_NANS)
>  
>  /* Operator lists.  */
> @@ -3107,16 +3108,22 @@ (define_operator_list COND_TERNARY
>  (for cmp  (le gt)
>       acmp (lt ge)
>   (simplify
> -  (cmp @0 INTEGER_CST@1)
> -  (if (tree_int_cst_sgn (@1) == -1)
> -   (acmp @0 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) + 1); }))))
> +  (cmp @0 uniform_integer_cst_p@1)
> +  (with { tree cst = uniform_integer_cst_p (@1); }
> +   (if (tree_int_cst_sgn (cst) == -1)
> +     (acmp @0 { build_uniform_cst (TREE_TYPE (@1),
> +				   wide_int_to_tree (TREE_TYPE (cst),
> +						     wi::to_wide (cst)
> +						     + 1)); })))))
>  (for cmp  (ge lt)
>       acmp (gt le)
>   (simplify
> -  (cmp @0 INTEGER_CST@1)
> -  (if (tree_int_cst_sgn (@1) == 1)
> -   (acmp @0 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) - 1); }))))
> -
> +  (cmp @0 uniform_integer_cst_p@1)
> +  (with { tree cst = uniform_integer_cst_p (@1); }
> +   (if (tree_int_cst_sgn (cst) == 1)
> +    (acmp @0 { build_uniform_cst (TREE_TYPE (@1),
> +				  wide_int_to_tree (TREE_TYPE (cst),
> +				  wi::to_wide (cst) - 1)); })))))
>  
>  /* We can simplify a logical negation of a comparison to the
>     inverted comparison.  As we cannot compute an expression
> @@ -3934,19 +3941,22 @@ (define_operator_list COND_TERNARY
>   /* Comparisons with the highest or lowest possible integer of
>      the specified precision will have known values.  */
>   (simplify
> -  (cmp (convert?@2 @0) INTEGER_CST@1)
> -  (if ((INTEGRAL_TYPE_P (TREE_TYPE (@1)) || POINTER_TYPE_P (TREE_TYPE (@1)))
> +  (cmp (convert?@2 @0) uniform_integer_cst_p@1)
> +  (if ((INTEGRAL_TYPE_P (TREE_TYPE (@1))
> +	|| POINTER_TYPE_P (TREE_TYPE (@1))
> +	|| VECTOR_INTEGER_TYPE_P (TREE_TYPE (@1)))
>         && tree_nop_conversion_p (TREE_TYPE (@2), TREE_TYPE (@0)))
>     (with
>      {
> -      tree arg1_type = TREE_TYPE (@1);
> +      tree cst = uniform_integer_cst_p (@1);
> +      tree arg1_type = TREE_TYPE (cst);
>        unsigned int prec = TYPE_PRECISION (arg1_type);
>        wide_int max = wi::max_value (arg1_type);
>        wide_int signed_max = wi::max_value (prec, SIGNED);
>        wide_int min = wi::min_value (arg1_type);
>      }
>      (switch
> -     (if (wi::to_wide (@1) == max)
> +     (if (wi::to_wide (cst) == max)
>        (switch
>         (if (cmp == GT_EXPR)
>  	{ constant_boolean_node (false, type); })
> @@ -3956,7 +3966,7 @@ (define_operator_list COND_TERNARY
>  	{ constant_boolean_node (true, type); })
>         (if (cmp == LT_EXPR)
>  	(ne @2 @1))))
> -     (if (wi::to_wide (@1) == min)
> +     (if (wi::to_wide (cst) == min)
>        (switch
>         (if (cmp == LT_EXPR)
>          { constant_boolean_node (false, type); })
> @@ -3966,19 +3976,31 @@ (define_operator_list COND_TERNARY
>          { constant_boolean_node (true, type); })
>         (if (cmp == GT_EXPR)
>          (ne @2 @1))))
> -     (if (wi::to_wide (@1) == max - 1)
> +     (if (wi::to_wide (cst) == max - 1)
>        (switch
>         (if (cmp == GT_EXPR)
> -	(eq @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) + 1); }))
> +	(eq @2 { build_uniform_cst (TREE_TYPE (@1),
> +				    wide_int_to_tree (TREE_TYPE (cst),
> +						      wi::to_wide (cst)
> +						      + 1)); }))
>         (if (cmp == LE_EXPR)
> -	(ne @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) + 1); }))))
> -     (if (wi::to_wide (@1) == min + 1)
> +	(ne @2 { build_uniform_cst (TREE_TYPE (@1),
> +				    wide_int_to_tree (TREE_TYPE (cst),
> +						      wi::to_wide (cst)
> +						      + 1)); }))))
> +     (if (wi::to_wide (cst) == min + 1)
>        (switch
>         (if (cmp == GE_EXPR)
> -        (ne @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) - 1); }))
> +        (ne @2 { build_uniform_cst (TREE_TYPE (@1),
> +				    wide_int_to_tree (TREE_TYPE (cst),
> +						      wi::to_wide (cst)
> +						      - 1)); }))
>         (if (cmp == LT_EXPR)
> -        (eq @2 { wide_int_to_tree (TREE_TYPE (@1), wi::to_wide (@1) - 1); }))))
> -     (if (wi::to_wide (@1) == signed_max
> +        (eq @2 { build_uniform_cst (TREE_TYPE (@1),
> +				    wide_int_to_tree (TREE_TYPE (cst),
> +						      wi::to_wide (cst)
> +						      - 1)); }))))
> +     (if (wi::to_wide (cst) == signed_max
>  	  && TYPE_UNSIGNED (arg1_type)
>  	  /* We will flip the signedness of the comparison operator
>  	     associated with the mode of @1, so the sign bit is
> @@ -3990,10 +4012,16 @@ (define_operator_list COND_TERNARY
>        /* The following case also applies to X < signed_max+1
>  	 and X >= signed_max+1 because previous transformations.  */
>        (if (cmp == LE_EXPR || cmp == GT_EXPR)
> -       (with { tree st = signed_type_for (arg1_type); }
> -        (if (cmp == LE_EXPR)
> -	 (ge (convert:st @0) { build_zero_cst (st); })
> -	 (lt (convert:st @0) { build_zero_cst (st); }))))))))))
> +       (with { tree st = signed_type_for (TREE_TYPE (@1)); }
> +       	(switch
> +	 (if (cst == @1 && cmp == LE_EXPR)
> +	  (ge (convert:st @0) { build_zero_cst (st); }))
> +	 (if (cst == @1 && cmp == GT_EXPR)
> +	  (lt (convert:st @0) { build_zero_cst (st); }))
> +	 (if (cmp == LE_EXPR)
> +	  (ge (view_convert:st @0) { build_zero_cst (st); }))
> +	 (if (cmp == GT_EXPR)
> +	  (lt (view_convert:st @0) { build_zero_cst (st); })))))))))))
>  
>  (for cmp (unordered ordered unlt unle ungt unge uneq ltgt)
>   /* If the second operand is NaN, the result is constant.  */
> --- gcc/testsuite/g++.dg/tree-ssa/pr88152-1.C.jj	2018-11-29 08:54:30.535773479 +0100
> +++ gcc/testsuite/g++.dg/tree-ssa/pr88152-1.C	2018-11-29 11:15:17.206742541 +0100
> @@ -0,0 +1,55 @@
> +// PR target/88152
> +// { dg-do compile }
> +// { dg-options "-O2 -std=c++14 -fdump-tree-forwprop1" }
> +// { dg-final { scan-tree-dump-times " (?:<|>=) \{ 0\[, ]" 120 "forwprop1" } }
> +
> +template <typename T, int N>
> +using V [[gnu::vector_size (sizeof (T) * N)]] = T;
> +
> +void *foo ();
> +
> +template <typename T, int N, T max, T maxp1>
> +__attribute__((noipa)) void
> +test_uns ()
> +{
> +  V<T, N> *x = (V<T, N> *) foo ();
> +  x[1] = x[0] > max;
> +  x[3] = x[2] >= maxp1;
> +  x[5] = x[4] <= max;
> +  x[7] = x[6] < maxp1;
> +}
> +
> +template <typename T, int N>
> +__attribute__((noipa)) void
> +test ()
> +{
> +  V<T, N> *x = (V<T, N> *) foo ();
> +  x[1] = x[0] >= 0;
> +  x[3] = x[2] > -1;
> +  x[5] = x[4] < 0;
> +  x[7] = x[6] <= -1;
> +}
> +
> +template <int N>
> +__attribute__((noipa)) void
> +tests ()
> +{
> +  test_uns<unsigned char, N, __SCHAR_MAX__, 1U + __SCHAR_MAX__> ();
> +  test<signed char, N> ();
> +  test_uns<unsigned short int, N, __SHRT_MAX__, 1U + __SHRT_MAX__> ();
> +  test<short int, N> ();
> +  test_uns<unsigned int, N, __INT_MAX__, 1U + __INT_MAX__> ();
> +  test<int, N> ();
> +  test_uns<unsigned long int, N, __LONG_MAX__, 1UL + __LONG_MAX__> ();
> +  test<long int, N> ();
> +  test_uns<unsigned long long int, N, __LONG_LONG_MAX__, 1ULL + __LONG_LONG_MAX__> ();
> +  test<long long int, N> ();
> +}
> +
> +void
> +all_tests ()
> +{
> +  tests<1> ();
> +  tests<2> ();
> +  tests<8> ();
> +}
> --- gcc/testsuite/g++.dg/tree-ssa/pr88152-2.C.jj	2018-11-29 11:04:08.741910282 +0100
> +++ gcc/testsuite/g++.dg/tree-ssa/pr88152-2.C	2018-11-29 09:20:51.844365763 +0100
> @@ -0,0 +1,85 @@
> +// PR target/88152
> +// { dg-do compile { target int32 } }
> +// { dg-options "-O2 -Wno-psabi -fdump-tree-forwprop1" }
> +// { dg-final { scan-tree-dump-not " (?:>|>=|<|<=) \{ 214748364\[67]" "forwprop1" } }
> +// { dg-final { scan-tree-dump-not " (?:>|>=|<|<=) \{ -214748364\[78]" "forwprop1" } }
> +// { dg-final { scan-tree-dump-times "return \{ 0, 0, 0, 0 \}" 2 "forwprop1" } }
> +// { dg-final { scan-tree-dump-times "return \{ -1, -1, -1, -1 \}" 2 "forwprop1" } }
> +// { dg-final { scan-tree-dump-times " == \{ 2147483647, 2147483647, 2147483647, 2147483647 \}" 2 "forwprop1" } }
> +// { dg-final { scan-tree-dump-times " != \{ 2147483647, 2147483647, 2147483647, 2147483647 \}" 2 "forwprop1" } }
> +// { dg-final { scan-tree-dump-times " == \{ -2147483648, -2147483648, -2147483648, -2147483648 \}" 2 "forwprop1" } }
> +// { dg-final { scan-tree-dump-times " != \{ -2147483648, -2147483648, -2147483648, -2147483648 \}" 2 "forwprop1" } }
> +
> +typedef int V __attribute__((vector_size (16)));
> +
> +V
> +f1 (V a)
> +{
> +  return a > __INT_MAX__;
> +}
> +
> +V
> +f2 (V a)
> +{
> +  return a >= __INT_MAX__;
> +}
> +
> +V
> +f3 (V a)
> +{
> +  return a < __INT_MAX__;
> +}
> +
> +V
> +f4 (V a)
> +{
> +  return a <= __INT_MAX__;
> +}
> +
> +V
> +f5 (V a)
> +{
> +  return a > -__INT_MAX__ - 1;
> +}
> +
> +V
> +f6 (V a)
> +{
> +  return a >= -__INT_MAX__ - 1;
> +}
> +
> +V
> +f7 (V a)
> +{
> +  return a < -__INT_MAX__ - 1;
> +}
> +
> +V
> +f8 (V a)
> +{
> +  return a <= -__INT_MAX__ - 1;
> +}
> +
> +V
> +f9 (V a)
> +{
> +  return a > __INT_MAX__ - 1;
> +}
> +
> +V
> +f10 (V a)
> +{
> +  return a <= __INT_MAX__ - 1;
> +}
> +
> +V
> +f11 (V a)
> +{
> +  return a >= -__INT_MAX__;
> +}
> +
> +V
> +f12 (V a)
> +{
> +  return a < -__INT_MAX__;
> +}
> 
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]