> Am 19.05.2023 um 10:06 schrieb Jakub Jelinek <ja...@redhat.com>:
> 
> Hi!
> 
> In the pattern recognition of signed __builtin_mul_overflow{,_p} we
> check for result of unsigned division (which follows unsigned
> multiplication) being equality compared against one of the multiplication's
> argument (the one not used in the division) and check for the comparison
> to be done against same precision cast of the argument (because
> division's result is unsigned and the argument is signed).
> But as shown in this PR, one can write it equally as comparison done in
> the signed type, i.e. compare division's result cast to corresponding
> signed type against the argument.
> 
> The following patch handles even those cases.
> 
> Bootstrapped/regtested on x86_64-linux, i686-linux, aarch64-linux and
> powerpc64le-linux, ok for trunk?

Ok.

Richard 

> 2023-05-19  Jakub Jelinek  <ja...@redhat.com>
> 
>    PR tree-optimization/105776
>    * tree-ssa-math-opts.cc (arith_overflow_check_p): If cast_stmt is
>    non-NULL, allow division statement to have a cast as single imm use
>    rather than comparison/condition.
>    (match_arith_overflow): In that case remove the cast stmt in addition
>    to the division statement.
> 
>    * gcc.target/i386/pr105776.c: New test.
> 
> --- gcc/tree-ssa-math-opts.cc.jj    2023-05-18 14:57:13.216409685 +0200
> +++ gcc/tree-ssa-math-opts.cc    2023-05-18 15:45:34.077177053 +0200
> @@ -3802,6 +3802,21 @@ arith_overflow_check_p (gimple *stmt, gi
>       use_operand_p use;
>       if (!single_imm_use (divlhs, &use, &cur_use_stmt))
>    return 0;
> +      if (cast_stmt && gimple_assign_cast_p (cur_use_stmt))
> +    {
> +      tree cast_lhs = gimple_assign_lhs (cur_use_stmt);
> +      if (INTEGRAL_TYPE_P (TREE_TYPE (cast_lhs))
> +          && TYPE_UNSIGNED (TREE_TYPE (cast_lhs))
> +          && (TYPE_PRECISION (TREE_TYPE (cast_lhs))
> +          == TYPE_PRECISION (TREE_TYPE (divlhs)))
> +          && single_imm_use (cast_lhs, &use, &cur_use_stmt))
> +        {
> +          cast_stmt = NULL;
> +          divlhs = cast_lhs;
> +        }
> +      else
> +        return 0;
> +    }
>     }
>   if (gimple_code (cur_use_stmt) == GIMPLE_COND)
>     {
> @@ -4390,6 +4405,16 @@ match_arith_overflow (gimple_stmt_iterat
>      gimple_stmt_iterator gsi2 = gsi_for_stmt (orig_use_stmt);
>      maybe_optimize_guarding_check (mul_stmts, use_stmt, orig_use_stmt,
>                     cfg_changed);
> +      use_operand_p use;
> +      gimple *cast_stmt;
> +      if (single_imm_use (gimple_assign_lhs (orig_use_stmt), &use,
> +                  &cast_stmt)
> +          && gimple_assign_cast_p (cast_stmt))
> +        {
> +          gimple_stmt_iterator gsi3 = gsi_for_stmt (cast_stmt);
> +          gsi_remove (&gsi3, true);
> +          release_ssa_name (gimple_assign_lhs (cast_stmt));
> +        }
>      gsi_remove (&gsi2, true);
>      release_ssa_name (gimple_assign_lhs (orig_use_stmt));
>    }
> --- gcc/testsuite/gcc.target/i386/pr105776.c.jj    2023-05-18 
> 15:57:15.570218802 +0200
> +++ gcc/testsuite/gcc.target/i386/pr105776.c    2023-05-18 15:56:55.273506918 
> +0200
> @@ -0,0 +1,43 @@
> +/* PR tree-optimization/105776 */
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-optimized -masm=att" } */
> +/* { dg-final { scan-tree-dump-times " = \.MUL_OVERFLOW " 5 "optimized" } } 
> */
> +/* { dg-final { scan-assembler-times "\timull\t" 5 } } */
> +/* { dg-final { scan-assembler-times "\tsetno\t" 5 } } */
> +
> +int
> +foo (unsigned x, unsigned y)
> +{
> +  unsigned int r = x * y;
> +  return !x || ((int) r / (int) x) == (int) y;
> +}
> +
> +int
> +bar (unsigned x, unsigned y)
> +{
> +  return !x || ((int) (x * y) / (int) x) == (int) y;
> +}
> +
> +int
> +baz (unsigned x, unsigned y)
> +{
> +  if (x == 0)
> +    return 1;
> +  return ((int) (x * y) / (int) x) == y;
> +}
> +
> +int
> +qux (unsigned x, unsigned y, unsigned *z)
> +{
> +  unsigned int r = x * y;
> +  *z = r;
> +  return !x || ((int) r / (int) x) == (int) y;
> +}
> +
> +int
> +corge (unsigned x, unsigned y, unsigned *z)
> +{
> +  unsigned int r = x * y;
> +  *z = r;
> +  return !x || ((int) r / (int) x) == y;
> +}
> 
>    Jakub
> 

Reply via email to