On Wed, 27 Nov 2024, Jakub Jelinek wrote:

> Hi!
> 
> As the pr117692.c testcase shows, the generalized pattern can introduce
> UB when there wasn't any.
> The old pattern was I believe correct, it is as if in the new
> pattern C3 was always 1 and I don't see how that could have introduced
> UB.
> But if type is signed and C3 (aka factor) isn't 1 and for + X and C2
> could have different sign or for - X and C2 could have the same sign,
> when doing the addition/subtraction first the absolute value could
> decrease, while if first multiplying by C3 we could invoke UB already
> during that multiplication.
> 
> The following patch fixes it by going through the casts to utype if
> ranger (get_range_pos_neg) detects the sign compared to sign of C2
> (INTEGER_CST) could be the same or could be different depending on op
> because then the absolute value will not increase.
> 
> Other possibility (perhaps as another check if this check doesn't succeed)
> would be to test whether X * C3 could actually overflow.
> vr-values.cc has check_for_binary_op_overflow (currently not exported)
> which I think does what we'd need to check, if it returns true and sets
> ovf to false.
> 
> Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

OK.

As improvement, if required we could do the range evaluation or
perform the simplified arithmetic in an unsigned type and cast back.

Thanks,
Richard.

> 2024-11-27  Jakub Jelinek  <ja...@redhat.com>
> 
>       PR tree-optimization/117692
>       * tree.cc (get_range_pos_neg): Adjust function comment, use
>       non-negative instead of positive.
>       * match.pd
>       (((X /[ex] C1) +- C2) * (C1 * C3) -> (X * C3) +- (C1 * C2 * C3)):
>       Use casts to utype if type is signed, factor isn't 1 and
>       C1 and C2 could have different sign for + or could have the
>       same sign for -.
> 
>       * gcc.dg/tree-ssa/mulexactdiv-5.c: Expect 8 nop_exprs.
>       * gcc.dg/tree-ssa/pr117692.c: New test.
> 
> --- gcc/tree.cc.jj    2024-11-23 13:00:31.615980802 +0100
> +++ gcc/tree.cc       2024-11-26 13:50:45.910803860 +0100
> @@ -14510,8 +14510,8 @@ verify_type (const_tree t)
>  
>  
>  /* Return 1 if ARG interpreted as signed in its precision is known to be
> -   always positive or 2 if ARG is known to be always negative, or 3 if
> -   ARG may be positive or negative.  */
> +   always non-negative or 2 if ARG is known to be always negative, or 3 if
> +   ARG may be non-negative or negative.  */
>  
>  int
>  get_range_pos_neg (tree arg)
> --- gcc/match.pd.jj   2024-11-26 09:37:32.563906412 +0100
> +++ gcc/match.pd      2024-11-26 18:36:33.037742888 +0100
> @@ -5577,7 +5577,15 @@ DEFINE_INT_AND_FLOAT_ROUND_FN (RINT)
>         && TREE_CODE (@3) == INTEGER_CST
>         && (mul = wi::mul (wi::to_wide (@2), wi::to_wide (@3),
>                            TYPE_SIGN (type), &overflow),
> -           !overflow))
> +           !overflow)
> +       && (TYPE_UNSIGNED (type)
> +           /* Not using unsigned arithmetics is unsafe if factor
> +              isn't 1 and if for op plus @0 and @2 could have different
> +              sign or for op minus @0 and @2 could have the same sign.  */
> +           || known_eq (factor, 1)
> +           || (get_range_pos_neg (@0)
> +               | (((op == PLUS_EXPR) ^ (tree_int_cst_sgn (@2) < 0))
> +                  ? 1 : 2)) != 3))
>        (op (mult @0 { wide_int_to_tree (type, factor); })
>         { wide_int_to_tree (type, mul); })
>        (with { tree utype = unsigned_type_for (type); }
> --- gcc/testsuite/gcc.dg/tree-ssa/mulexactdiv-5.c.jj  2024-10-24 
> 18:53:41.438042287 +0200
> +++ gcc/testsuite/gcc.dg/tree-ssa/mulexactdiv-5.c     2024-11-26 
> 14:25:07.507313308 +0100
> @@ -18,7 +18,7 @@ TEST_CMP (f4, 8, 4, 200)
>  
>  /* { dg-final { scan-tree-dump-not {<[a-z]*_div_expr,} "optimized" } } */
>  /* { dg-final { scan-tree-dump-not {<rshift_expr,} "optimized" } } */
> -/* { dg-final { scan-tree-dump-not {<nop_expr,} "optimized" } } */
> +/* { dg-final { scan-tree-dump-times {<nop_expr,} 8 "optimized" } } */
>  /* { dg-final { scan-tree-dump {<mult_expr, [^,]*, [^,]*, 3,} "optimized" } 
> } */
>  /* { dg-final { scan-tree-dump {<mult_expr, [^,]*, [^,]*, 5,} "optimized" } 
> } */
>  /* { dg-final { scan-tree-dump {<mult_expr, [^,]*, [^,]*, 20,} "optimized" } 
> } */
> --- gcc/testsuite/gcc.dg/tree-ssa/pr117692.c.jj       2024-11-26 
> 14:16:46.689274363 +0100
> +++ gcc/testsuite/gcc.dg/tree-ssa/pr117692.c  2024-11-26 14:18:55.161491240 
> +0100
> @@ -0,0 +1,17 @@
> +/* PR tree-optimization/117692 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-vrp1" } */
> +/* { dg-final { scan-tree-dump " \\\* 25;" "vrp1" } } */
> +/* { dg-final { scan-tree-dump " \\\+ 800;" "vrp1" } } */
> +/* { dg-final { scan-tree-dump " = \\\(unsigned int\\\) " "vrp1" } } */
> +/* { dg-final { scan-tree-dump " = \\\(int\\\) " "vrp1" } } */
> +
> +int
> +foo (int x)
> +{
> +  if (x & 7)
> +    __builtin_unreachable ();
> +  x /= 8;
> +  x += 4;
> +  return x * 200;
> +}
> 
>       Jakub
> 
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Ivo Totev, Andrew McDonald, Werner Knoblich; (HRB 36809, AG Nuernberg)

Reply via email to