[PATCH] phiopt: Improve minmax optimization [PR95699]

Richard Biener rguenther@suse.de
Thu Jun 18 09:59:26 GMT 2020


On Thu, 18 Jun 2020, Jakub Jelinek wrote:

> Hi!
> 
> As discussed in the PR, the
> x < 0x80000000U to (int) x >= 0
> optimization stands in the way of minmax_replacement optimization,
> so for comparisons with most of the constants it works well, but when the
> above mentioned optimization triggers, it is unable to do it.
> The match.pd (cond (cmp (convert? x) c1) (op x c2) c3) -> (op (minmax x c1) c2)
> optimization is able to look through that and this patch
> teaches minmax_replacement about it too.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

I wonder if we can leverage gimple_build or gimple_match_op::resimplify
to move the actual pattern matching to match.pd completely in at least
part of phiopt?  We'd feed a COND_EXPR to the matcher and similar
to maybe_fold_comparisons_from_match_pd we'd need one "on stack"
GIMPLE stmt for the comparison to avoid building it as GENERIC tree
(which for COND_EXPR would of course also work up to now).

Thanks,
Richard.

> 2020-06-18  Jakub Jelinek  <jakub@redhat.com>
> 
> 	PR tree-optimization/95699
> 	* tree-ssa-phiopt.c (minmax_replacement): Treat (signed int)x < 0
> 	as x > INT_MAX and (signed int)x >= 0 as x <= INT_MAX.  Move variable
> 	declarations to the statements that set them where possible.
> 
> 	* gcc.dg/tree-ssa/pr95699.c: New test.
> 
> --- gcc/tree-ssa-phiopt.c.jj	2020-06-05 10:42:40.792893013 +0200
> +++ gcc/tree-ssa-phiopt.c	2020-06-17 13:36:20.600659487 +0200
> @@ -1363,22 +1363,21 @@ minmax_replacement (basic_block cond_bb,
>  		    edge e0, edge e1, gimple *phi,
>  		    tree arg0, tree arg1)
>  {
> -  tree result, type, rhs;
> -  gcond *cond;
> +  tree result;
>    edge true_edge, false_edge;
> -  enum tree_code cmp, minmax, ass_code;
> -  tree smaller, alt_smaller, larger, alt_larger, arg_true, arg_false;
> +  enum tree_code minmax, ass_code;
> +  tree smaller, larger, arg_true, arg_false;
>    gimple_stmt_iterator gsi, gsi_from;
>  
> -  type = TREE_TYPE (PHI_RESULT (phi));
> +  tree type = TREE_TYPE (PHI_RESULT (phi));
>  
>    /* The optimization may be unsafe due to NaNs.  */
>    if (HONOR_NANS (type) || HONOR_SIGNED_ZEROS (type))
>      return false;
>  
> -  cond = as_a <gcond *> (last_stmt (cond_bb));
> -  cmp = gimple_cond_code (cond);
> -  rhs = gimple_cond_rhs (cond);
> +  gcond *cond = as_a <gcond *> (last_stmt (cond_bb));
> +  enum tree_code cmp = gimple_cond_code (cond);
> +  tree rhs = gimple_cond_rhs (cond);
>  
>    /* Turn EQ/NE of extreme values to order comparisons.  */
>    if ((cmp == NE_EXPR || cmp == EQ_EXPR)
> @@ -1401,8 +1400,8 @@ minmax_replacement (basic_block cond_bb,
>  
>    /* This transformation is only valid for order comparisons.  Record which
>       operand is smaller/larger if the result of the comparison is true.  */
> -  alt_smaller = NULL_TREE;
> -  alt_larger = NULL_TREE;
> +  tree alt_smaller = NULL_TREE;
> +  tree alt_larger = NULL_TREE;
>    if (cmp == LT_EXPR || cmp == LE_EXPR)
>      {
>        smaller = gimple_cond_lhs (cond);
> @@ -1463,6 +1462,50 @@ minmax_replacement (basic_block cond_bb,
>    else
>      return false;
>  
> +  /* Handle the special case of (signed_type)x < 0 being equivalent
> +     to x > MAX_VAL(signed_type) and (signed_type)x >= 0 equivalent
> +     to x <= MAX_VAL(signed_type).  */
> +  if ((cmp == GE_EXPR || cmp == LT_EXPR)
> +      && INTEGRAL_TYPE_P (type)
> +      && TYPE_UNSIGNED (type)
> +      && integer_zerop (rhs))
> +    {
> +      tree op = gimple_cond_lhs (cond);
> +      if (TREE_CODE (op) == SSA_NAME
> +	  && INTEGRAL_TYPE_P (TREE_TYPE (op))
> +	  && !TYPE_UNSIGNED (TREE_TYPE (op)))
> +	{
> +	  gimple *def_stmt = SSA_NAME_DEF_STMT (op);
> +	  if (gimple_assign_cast_p (def_stmt))
> +	    {
> +	      tree op1 = gimple_assign_rhs1 (def_stmt);
> +	      if (INTEGRAL_TYPE_P (TREE_TYPE (op1))
> +		  && TYPE_UNSIGNED (TREE_TYPE (op1))
> +		  && (TYPE_PRECISION (TREE_TYPE (op))
> +		      == TYPE_PRECISION (TREE_TYPE (op1)))
> +		  && useless_type_conversion_p (type, TREE_TYPE (op1)))
> +		{
> +		  wide_int w1 = wi::max_value (TREE_TYPE (op));
> +		  wide_int w2 = wi::add (w1, 1);
> +		  if (cmp == LT_EXPR)
> +		    {
> +		      larger = op1;
> +		      smaller = wide_int_to_tree (TREE_TYPE (op1), w1);
> +		      alt_smaller = wide_int_to_tree (TREE_TYPE (op1), w2);
> +		      alt_larger = NULL_TREE;
> +		    }
> +		  else
> +		    {
> +		      smaller = op1;
> +		      larger = wide_int_to_tree (TREE_TYPE (op1), w1);
> +		      alt_larger = wide_int_to_tree (TREE_TYPE (op1), w2);
> +		      alt_smaller = NULL_TREE;
> +		    }
> +		}
> +	    }
> +	}
> +    }
> +
>    /* We need to know which is the true edge and which is the false
>        edge so that we know if have abs or negative abs.  */
>    extract_true_false_edges_from_block (cond_bb, &true_edge, &false_edge);
> --- gcc/testsuite/gcc.dg/tree-ssa/pr95699.c.jj	2020-06-17 13:45:31.308686080 +0200
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr95699.c	2020-06-17 13:44:29.715577853 +0200
> @@ -0,0 +1,39 @@
> +/* PR tree-optimization/95699 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized" } */
> +/* { dg-final { scan-tree-dump "MAX_EXPR <\[^>\n\r]*9223372036854775807\[^>\n\r]*>" "optimized" } } */
> +/* { dg-final { scan-tree-dump "MAX_EXPR <\[^>\n\r]*9223372036854775808\[^>\n\r]*>" "optimized" } } */
> +/* { dg-final { scan-tree-dump "MIN_EXPR <\[^>\n\r]*9223372036854775807\[^>\n\r]*>" "optimized" } } */
> +/* { dg-final { scan-tree-dump "MIN_EXPR <\[^>\n\r]*9223372036854775808\[^>\n\r]*>" "optimized" } } */
> +
> +unsigned long long
> +f1 (unsigned long long x)
> +{
> +  if (x < 0x7fffffffffffffffULL)
> +    x = 0x7fffffffffffffffULL;
> +  return x;
> +}
> +
> +unsigned long long
> +f2 (unsigned long long x)
> +{
> +  if (x < 0x8000000000000000ULL)
> +    x = 0x8000000000000000ULL;
> +  return x;
> +}
> +
> +unsigned long long
> +f3 (unsigned long long x)
> +{
> +  if (x >= 0x7fffffffffffffffULL)
> +    x = 0x7fffffffffffffffULL;
> +  return x;
> +}
> +
> +unsigned long long
> +f4 (unsigned long long x)
> +{
> +  if (x >= 0x8000000000000000ULL)
> +    x = 0x8000000000000000ULL;
> +  return x;
> +}
> 
> 	Jakub
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)


More information about the Gcc-patches mailing list