On Wed, 22 Dec 2021, Jiufu Guo wrote:

> Hi,
> 
> Normaly, estimate_numbers_of_iterations get/caculate niter first,
> and then invokes infer_loop_bounds_from_undefined. While in some case,
> after a few call stacks, estimate_numbers_of_iterations is invoked before
> niter is ready (e.g. before number_of_latch_executions returns).
> 
> e.g. number_of_latch_executions->...follow_ssa_edge_expr-->
>   --> estimate_numbers_of_iterations --> infer_loop_bounds_from_undefined.
> 
> Since niter is still not computed, call to infer_loop_bounds_from_undefined
> may not get final result.
> To avoid infer_loop_bounds_from_undefined to be called with interim state
> and avoid infer_loop_bounds_from_undefined generates interim data, during
> niter's computing, we could disable flag_aggressive_loop_optimizations.
> 
> Bootstrap and regtest pass on ppc64* and x86_64.  Is this ok for trunk?

So this is a optimality fix, not a correctness one?  I suppose the
estimates are computed/used from scev_probably_wraps_p via
loop_exits_before_overflow and ultimatively chrec_convert.

We have a call cycle here,

estimate_numbers_of_iterations -> number_of_latch_executions ->
... -> estimate_numbers_of_iterations

where the first estimate_numbers_of_iterations will make sure
the later call will immediately return.

I'm not sure what your patch tries to do - it seems to tackle
the case where we enter the cycle via number_of_latch_executions?
Why do we get "non-final" values?  idx_infer_loop_bounds resorts
to SCEV and thus may recurse again - to me it would be more
logical to try avoid recursing in number_of_latch_executions by
setting ->nb_iterations to something early, maybe chrec_dont_know,
to signal we're using something we're just trying to compute.

Richard.

> BR,
> Jiufu
> 
> gcc/ChangeLog:
> 
>       * tree-ssa-loop-niter.c (number_of_iterations_exit_assumptions):
>       Disable/restore flag_aggressive_loop_optimizations.
> 
> gcc/testsuite/ChangeLog:
> 
>       * gcc.dg/tree-ssa/scev-16.c: New test.
> 
> ---
>  gcc/tree-ssa-loop-niter.c               | 23 +++++++++++++++++++----
>  gcc/testsuite/gcc.dg/tree-ssa/scev-16.c | 20 ++++++++++++++++++++
>  2 files changed, 39 insertions(+), 4 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/scev-16.c
> 
> diff --git a/gcc/tree-ssa-loop-niter.c b/gcc/tree-ssa-loop-niter.c
> index 06954e437f5..51bb501019e 100644
> --- a/gcc/tree-ssa-loop-niter.c
> +++ b/gcc/tree-ssa-loop-niter.c
> @@ -2534,18 +2534,31 @@ number_of_iterations_exit_assumptions (class loop 
> *loop, edge exit,
>        && !POINTER_TYPE_P (type))
>      return false;
>  
> +  /* Before niter is calculated, avoid to analyze interim state. */
> +  int old_aggressive_loop_optimizations = flag_aggressive_loop_optimizations;
> +  flag_aggressive_loop_optimizations = 0;
> +
>    tree iv0_niters = NULL_TREE;
>    if (!simple_iv_with_niters (loop, loop_containing_stmt (stmt),
>                             op0, &iv0, safe ? &iv0_niters : NULL, false))
> -    return number_of_iterations_popcount (loop, exit, code, niter);
> +    {
> +      bool res = number_of_iterations_popcount (loop, exit, code, niter);
> +      flag_aggressive_loop_optimizations = old_aggressive_loop_optimizations;
> +      return res;
> +    }
>    tree iv1_niters = NULL_TREE;
>    if (!simple_iv_with_niters (loop, loop_containing_stmt (stmt),
>                             op1, &iv1, safe ? &iv1_niters : NULL, false))
> -    return false;
> +    {
> +      flag_aggressive_loop_optimizations = old_aggressive_loop_optimizations;
> +      return false;
> +    }
>    /* Give up on complicated case.  */
>    if (iv0_niters && iv1_niters)
> -    return false;
> -
> +    {
> +      flag_aggressive_loop_optimizations = old_aggressive_loop_optimizations;
> +      return false;
> +    }
>    /* We don't want to see undefined signed overflow warnings while
>       computing the number of iterations.  */
>    fold_defer_overflow_warnings ();
> @@ -2565,6 +2578,7 @@ number_of_iterations_exit_assumptions (class loop 
> *loop, edge exit,
>                                 only_exit_p, safe))
>      {
>        fold_undefer_and_ignore_overflow_warnings ();
> +      flag_aggressive_loop_optimizations = old_aggressive_loop_optimizations;
>        return false;
>      }
>  
> @@ -2608,6 +2622,7 @@ number_of_iterations_exit_assumptions (class loop 
> *loop, edge exit,
>                                              niter->may_be_zero);
>  
>    fold_undefer_and_ignore_overflow_warnings ();
> +  flag_aggressive_loop_optimizations = old_aggressive_loop_optimizations;
>  
>    /* If NITER has simplified into a constant, update MAX.  */
>    if (TREE_CODE (niter->niter) == INTEGER_CST)
> diff --git a/gcc/testsuite/gcc.dg/tree-ssa/scev-16.c 
> b/gcc/testsuite/gcc.dg/tree-ssa/scev-16.c
> new file mode 100644
> index 00000000000..708ffab88ca
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/tree-ssa/scev-16.c
> @@ -0,0 +1,20 @@
> +/* { dg-do compile } */
> +/* { dg-options "-O2 -fdump-tree-ivopts-scev" } */
> +
> +/* Expect scalar_evolution = {(int) start_7(D), +, 1}_1), instead
> +   (int) (short int) {(unsigned short) start_7(D), +, 1}_1 */
> +
> +int arr[1000];
> +
> +void
> +s2i (short start, short end)
> +{
> +  int res = 0;
> +  for (short i = start; i < end; i++)
> +    {
> +      int lv = i;
> +      arr[lv] += lv;
> +    }
> +}
> +
> +/* { dg-final { scan-tree-dump-times "scalar_evolution = \{\\(int\\) 
> start_\[0-9\]+\\(D\\), \\+, 1\}_1" 1 "ivopts" } } */
> 

-- 
Richard Biener <rguent...@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Ivo Totev; HRB 36809 (AG Nuernberg)

Reply via email to