On Thu, Jul 22, 2021 at 6:41 PM Richard Biener <rguent...@suse.de> wrote:
>
> This avoids using multiple_of_p in niter analysis when its behavior
Hmm, but this patch actually introduces one more call to
multiple_of_p, also it doesn't touch the below use:
if (niter->control.no_overflow && multiple_of_p (type, c, s))
  {
    niter->niter = fold_build2 (FLOOR_DIV_EXPR, niter_type, c, s);
    return true;
  }

> to assume the tested expression does not invoke integer overflow
> produces wrong niter analysis results.  For the cases multiple_of_p
> handles power-of-two values of bottom look safe which should also be
> the majority of cases we care about in addition to the constant case
> now handled explicitely.
>
> Bootstrapped and tested on x86_64-unknown-linux-gnu.
>
> I'm unsure how important a "perfect" solution is (rewriting
> multiple_of_p), and wonder whether this solution is preferable
I am still for this approach now, it only needs to be conservative,
rather than perfect, especially if there are not many breakages with a
conservative version multiple_of_p?

> for now (and especially for branches).  I've not yet tried
> to sanitize multiple_of_p plus use range info to prove
> no-overflow where TYPE_OVERFLOW_UNDEFINED doesn't tell us
> immediately.
>
> 2021-07-22  Richard Biener  <rguent...@suse.de>
>
>         PR tree-optimization/100499
>         * tree-ssa-loop-niter.c (number_of_iterations_ne): Restrict
>         multiple_of_p queries to power-of-two bottoms, handle
>         the all constant case inline.
>
>         * gcc.dg/torture/pr100499-1.c: New testcase.
>         * gcc.dg/torture/pr100499-2.c: Likewise.
> ---
>  gcc/testsuite/gcc.dg/torture/pr100499-1.c | 28 +++++++++++++++++++++++
>  gcc/testsuite/gcc.dg/torture/pr100499-2.c | 16 +++++++++++++
>  gcc/tree-ssa-loop-niter.c                 |  8 ++++++-
>  3 files changed, 51 insertions(+), 1 deletion(-)
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr100499-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/torture/pr100499-2.c
>
> diff --git a/gcc/testsuite/gcc.dg/torture/pr100499-1.c 
> b/gcc/testsuite/gcc.dg/torture/pr100499-1.c
> new file mode 100644
> index 00000000000..97ab6051554
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/pr100499-1.c
> @@ -0,0 +1,28 @@
> +/* { dg-do run } */
> +/* { dg-require-effective-target int32plus } */
> +
> +typedef __UINT16_TYPE__ uint16_t;
> +static uint16_t g_2823 = 0xEC75L;
> +static uint16_t g_116 = 0xBC07L;
> +
> +static uint16_t
> +safe_mul_func_uint16_t_u_u(uint16_t ui1, uint16_t ui2)
> +{
> +  return ((unsigned int)ui1) * ((unsigned int)ui2);
> +}
> +
> +int main (int argc, char* argv[])
> +{
> +  uint16_t l_2815 = 65535UL;
> +  uint16_t *l_2821 = &g_116;
> +  uint16_t *l_2822 = &g_2823;
> +
> +lbl_2826:
> +  l_2815 &= 0x9DEF1EAEL;
> +  if (+(safe_mul_func_uint16_t_u_u(((*l_2821) = l_2815), (--(*l_2822)))))
> +    goto lbl_2826;
> +
> +  if (g_2823 != 32768)
> +    __builtin_abort ();
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/torture/pr100499-2.c 
> b/gcc/testsuite/gcc.dg/torture/pr100499-2.c
> new file mode 100644
> index 00000000000..999f931806a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/torture/pr100499-2.c
> @@ -0,0 +1,16 @@
> +/* { dg-do run } */
> +
> +unsigned char ag = 55;
> +unsigned i;
> +int main()
> +{
> +  unsigned char c;
> +  unsigned char a = ag;
> +d:
> +  c = a-- * 52;
> +  if (c)
> +    goto d;
> +  if (a != 255)
> +    __builtin_abort ();
> +  return 0;
> +}
> diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
> index 1b5605c26b8..c6b953c5316 100644
> --- a/gcc/tree-ssa-loop-niter.c
> +++ b/gcc/tree-ssa-loop-niter.c
> @@ -1050,7 +1050,13 @@ number_of_iterations_ne (class loop *loop, tree type, 
> affine_iv *iv,
>       Note, for NE_EXPR, base equals to FINAL is a special case, in
>       which the loop exits immediately, and the iv does not overflow.  */
>    if (!niter->control.no_overflow
> -      && (integer_onep (s) || multiple_of_p (type, c, s)))
> +      && (integer_onep (s)
> +         || (poly_int_tree_p (c)
> +             && multiple_p (wi::to_poly_widest (c), wi::to_poly_widest (s)))
> +         /* ???  multiple_of_p assumes the expression 'c' does not overflow
> +            but that cannot be guaranteed, so we restrict 's' to power of
> +            two values where that should not be an issue.  See PR100499.  */
> +         || (integer_pow2p (s) && multiple_of_p (type, c, s))))
>      {
>        tree t, cond, new_c, relaxed_cond = boolean_false_node;
I (to be blamed) added this part of code to special handle cases like
pr34114, now I feel it's in the wrong direction.  Ideally this part of
code is unnecessary and conditions will be (it is now) incorporated
into niter->assumptions which should be simplified to 1/0
correspondingly.  The only problem is that assumptions are not
appropriately simplified.
Is it possible to incorporate a more powerful solver (like Z3) in GCC
for such cases, e.g., assumption simplification, multiple_of_p, etc..
Oh, we don't do SCEV analysis under assumptions either (LLVM does it),
which could be beneficial too.  Of course a solver is usually too
heavy so it has to be restricted in some way.

Thanks,
bin
>
> --
> 2.26.2

Reply via email to