On Fri, 27 May 2016, Jan Hubicka wrote: > Hi, > this patch adds infrastructure to tree-ssa-loop-niter to record likely upper > bounds. > The basic idea is that it is easier to get likely bounds that 100% safe > bounds or > realistic estimates and the bound can be effectively used to trim down > optimizations > that are good idea only for large trip counts. This patch only updates the > infrastructure. I have two followup patches. First turns current optimizers to > use the bound (and adds testcase) and second enables loop peeling at -O3 and > makes > us to peel in cases where we would fully unroll if the loop bound was safe. > This improves some benchmarks, like John the ripper. > > Currently likely upper bounds are derived in two cases > 1) for arrays we can't prove to be non-trailing > 2) for array accesses in conditional. I.e. > int a[3]; > for (int i = 0; t(); i++) > if (q()) > a[i]++; > It is easy to add more cases, for example when the only unbounded loopback > path contains > unlikely edge. > > Bootstrapped/regtested x86_64-linux, OK?
likely_max_loop_iterations misses a function comment. Ugh, one more widest_int in struct loop ... (oh well). Given that (on x86_64) sizeof(widest_int) == 40 and sizeof(tree_int_cst) == 24 (ok, that's cheating, it's with just one HWI for the number) it looks appealing to change the storage of these to 'tree' ... (as a followup, using uint128_type_node or so or whatever largest integer type a target supports). Another option is to add a GCed wide_int that we can "allocate" - you can do this already by having a GTY HWI array and length and using wi::from_buffer (). That way you'd avoid defining any tree type. Ok with the comment added. Thanks, Richard. > Honza > > * cfgloop.c (record_niter_bound): Record likely upper bounds. > (likely_max_stmt_executions_int, get_likely_max_loop_iterations, > get_likely_max_loop_iterations_int): New. > * cfgloop.h (struct loop): Add nb_iterations_likely_upper_bound, > any_likely_upper_bound. > (get_likely_max_loop_iterations_int, get_likely_max_loop_iterations): > Declare. > * cfgloopmanip.c (copy_loop_info): Copy likely upper bounds. > * loop-unroll.c (unroll_loop_constant_iterations): Update likely > upper bound. > (unroll_loop_constant_iterations): Likewise. > (unroll_loop_runtime_iterations): Likewise. > * lto-streamer-in.c (input_cfg): Stream likely upper bounds. > * lto-streamer-out.c (output_cfg): Likewise. > * tree-ssa-loop-ivcanon.c (try_peel_loop): Update likely upper > bounds. > (canonicalize_loop_induction_variables): Dump likely upper bounds. > * tree-ssa-loop-niter.c (record_estimate): Record likely upper bounds. > (likely_max_loop_iterations): New. > (likely_max_loop_iterations_int): New. > (likely_max_stmt_executions): New. > * tree-ssa-loop-niter.h (likely_max_loop_iterations, > likely_max_loop_iterations_int, likely_max_stmt_executions_int, > likely_max_stmt_executions): Declare. > Index: cfgloop.c > =================================================================== > --- cfgloop.c (revision 236762) > +++ cfgloop.c (working copy) > @@ -1790,6 +1790,11 @@ record_niter_bound (struct loop *loop, c > { > loop->any_upper_bound = true; > loop->nb_iterations_upper_bound = i_bound; > + if (!loop->any_likely_upper_bound) > + { > + loop->any_likely_upper_bound = true; > + loop->nb_iterations_likely_upper_bound = i_bound; > + } > } > if (realistic > && (!loop->any_estimate > @@ -1798,6 +1803,13 @@ record_niter_bound (struct loop *loop, c > loop->any_estimate = true; > loop->nb_iterations_estimate = i_bound; > } > + if (!realistic > + && (!loop->any_likely_upper_bound > + || wi::ltu_p (i_bound, loop->nb_iterations_likely_upper_bound))) > + { > + loop->any_likely_upper_bound = true; > + loop->nb_iterations_likely_upper_bound = i_bound; > + } > > /* If an upper bound is smaller than the realistic estimate of the > number of iterations, use the upper bound instead. */ > @@ -1806,6 +1818,11 @@ record_niter_bound (struct loop *loop, c > && wi::ltu_p (loop->nb_iterations_upper_bound, > loop->nb_iterations_estimate)) > loop->nb_iterations_estimate = loop->nb_iterations_upper_bound; > + if (loop->any_upper_bound > + && loop->any_likely_upper_bound > + && wi::ltu_p (loop->nb_iterations_upper_bound, > + loop->nb_iterations_likely_upper_bound)) > + loop->nb_iterations_likely_upper_bound = loop->nb_iterations_upper_bound; > } > > /* Similar to get_estimated_loop_iterations, but returns the estimate only > @@ -1847,6 +1864,25 @@ max_stmt_executions_int (struct loop *lo > return snit < 0 ? -1 : snit; > } > > +/* Returns an likely upper bound on the number of executions of statements > + in the LOOP. For statements before the loop exit, this exceeds > + the number of execution of the latch by one. */ > + > +HOST_WIDE_INT > +likely_max_stmt_executions_int (struct loop *loop) > +{ > + HOST_WIDE_INT nit = get_likely_max_loop_iterations_int (loop); > + HOST_WIDE_INT snit; > + > + if (nit == -1) > + return -1; > + > + snit = (HOST_WIDE_INT) ((unsigned HOST_WIDE_INT) nit + 1); > + > + /* If the computation overflows, return -1. */ > + return snit < 0 ? -1 : snit; > +} > + > /* Sets NIT to the estimated number of executions of the latch of the > LOOP. If we have no reliable estimate, the function returns false, > otherwise > returns true. */ > @@ -1899,6 +1935,40 @@ get_max_loop_iterations_int (struct loop > return -1; > > if (!wi::fits_shwi_p (nit)) > + return -1; > + hwi_nit = nit.to_shwi (); > + > + return hwi_nit < 0 ? -1 : hwi_nit; > +} > + > +/* Sets NIT to an upper bound for the maximum number of executions of the > + latch of the LOOP. If we have no reliable estimate, the function returns > + false, otherwise returns true. */ > + > +bool > +get_likely_max_loop_iterations (struct loop *loop, widest_int *nit) > +{ > + if (!loop->any_likely_upper_bound) > + return false; > + > + *nit = loop->nb_iterations_likely_upper_bound; > + return true; > +} > + > +/* Similar to get_max_loop_iterations, but returns the estimate only > + if it fits to HOST_WIDE_INT. If this is not the case, or the estimate > + on the number of iterations of LOOP could not be derived, returns -1. */ > + > +HOST_WIDE_INT > +get_likely_max_loop_iterations_int (struct loop *loop) > +{ > + widest_int nit; > + HOST_WIDE_INT hwi_nit; > + > + if (!get_likely_max_loop_iterations (loop, &nit)) > + return -1; > + > + if (!wi::fits_shwi_p (nit)) > return -1; > hwi_nit = nit.to_shwi (); > > Index: cfgloop.h > =================================================================== > --- cfgloop.h (revision 236762) > +++ cfgloop.h (working copy) > @@ -160,6 +160,8 @@ struct GTY ((chain_next ("%h.next"))) lo > valid if any_upper_bound is true. */ > widest_int nb_iterations_upper_bound; > > + widest_int nb_iterations_likely_upper_bound; > + > /* An integer giving an estimate on nb_iterations. Unlike > nb_iterations_upper_bound, there is no guarantee that it is at least > nb_iterations. */ > @@ -167,6 +169,7 @@ struct GTY ((chain_next ("%h.next"))) lo > > bool any_upper_bound; > bool any_estimate; > + bool any_likely_upper_bound; > > /* True if the loop can be parallel. */ > bool can_be_parallel; > @@ -776,8 +779,10 @@ loop_outermost (struct loop *loop) > extern void record_niter_bound (struct loop *, const widest_int &, bool, > bool); > extern HOST_WIDE_INT get_estimated_loop_iterations_int (struct loop *); > extern HOST_WIDE_INT get_max_loop_iterations_int (struct loop *); > +extern HOST_WIDE_INT get_likely_max_loop_iterations_int (struct loop *); > extern bool get_estimated_loop_iterations (struct loop *loop, widest_int > *nit); > extern bool get_max_loop_iterations (struct loop *loop, widest_int *nit); > +extern bool get_likely_max_loop_iterations (struct loop *loop, widest_int > *nit); > extern int bb_loop_depth (const_basic_block); > > /* Converts VAL to widest_int. */ > Index: cfgloopmanip.c > =================================================================== > --- cfgloopmanip.c (revision 236762) > +++ cfgloopmanip.c (working copy) > @@ -1016,6 +1016,9 @@ copy_loop_info (struct loop *loop, struc > gcc_checking_assert (!target->any_upper_bound && !target->any_estimate); > target->any_upper_bound = loop->any_upper_bound; > target->nb_iterations_upper_bound = loop->nb_iterations_upper_bound; > + target->any_likely_upper_bound = loop->any_likely_upper_bound; > + target->nb_iterations_likely_upper_bound > + = loop->nb_iterations_likely_upper_bound; > target->any_estimate = loop->any_estimate; > target->nb_iterations_estimate = loop->nb_iterations_estimate; > target->estimate_state = loop->estimate_state; > Index: loop-unroll.c > =================================================================== > --- loop-unroll.c (revision 236762) > +++ loop-unroll.c (working copy) > @@ -523,6 +523,11 @@ unroll_loop_constant_iterations (struct > loop->nb_iterations_estimate -= exit_mod; > else > loop->any_estimate = false; > + if (loop->any_likely_upper_bound > + && wi::leu_p (exit_mod, loop->nb_iterations_likely_upper_bound)) > + loop->nb_iterations_likely_upper_bound -= exit_mod; > + else > + loop->any_likely_upper_bound = false; > } > > bitmap_set_bit (wont_exit, 1); > @@ -566,6 +571,11 @@ unroll_loop_constant_iterations (struct > loop->nb_iterations_estimate -= exit_mod + 1; > else > loop->any_estimate = false; > + if (loop->any_likely_upper_bound > + && wi::leu_p (exit_mod + 1, > loop->nb_iterations_likely_upper_bound)) > + loop->nb_iterations_likely_upper_bound -= exit_mod + 1; > + else > + loop->any_likely_upper_bound = false; > desc->noloop_assumptions = NULL_RTX; > > bitmap_set_bit (wont_exit, 0); > @@ -619,6 +629,9 @@ unroll_loop_constant_iterations (struct > if (loop->any_estimate) > loop->nb_iterations_estimate > = wi::udiv_trunc (loop->nb_iterations_estimate, max_unroll + 1); > + if (loop->any_likely_upper_bound) > + loop->nb_iterations_likely_upper_bound > + = wi::udiv_trunc (loop->nb_iterations_likely_upper_bound, max_unroll + > 1); > desc->niter_expr = GEN_INT (desc->niter); > > /* Remove the edges. */ > @@ -1059,6 +1072,9 @@ unroll_loop_runtime_iterations (struct l > if (loop->any_estimate) > loop->nb_iterations_estimate > = wi::udiv_trunc (loop->nb_iterations_estimate, max_unroll + 1); > + if (loop->any_likely_upper_bound) > + loop->nb_iterations_likely_upper_bound > + = wi::udiv_trunc (loop->nb_iterations_likely_upper_bound, max_unroll + > 1); > if (exit_at_end) > { > desc->niter_expr = > @@ -1070,6 +1086,11 @@ unroll_loop_runtime_iterations (struct l > --loop->nb_iterations_estimate; > else > loop->any_estimate = false; > + if (loop->any_likely_upper_bound > + && loop->nb_iterations_likely_upper_bound != 0) > + --loop->nb_iterations_likely_upper_bound; > + else > + loop->any_likely_upper_bound = false; > } > > if (dump_file) > Index: lto-streamer-in.c > =================================================================== > --- lto-streamer-in.c (revision 236762) > +++ lto-streamer-in.c (working copy) > @@ -835,6 +835,9 @@ input_cfg (struct lto_input_block *ib, s > loop->any_upper_bound = streamer_read_hwi (ib); > if (loop->any_upper_bound) > loop->nb_iterations_upper_bound = streamer_read_wi (ib); > + loop->any_likely_upper_bound = streamer_read_hwi (ib); > + if (loop->any_likely_upper_bound) > + loop->nb_iterations_likely_upper_bound = streamer_read_wi (ib); > loop->any_estimate = streamer_read_hwi (ib); > if (loop->any_estimate) > loop->nb_iterations_estimate = streamer_read_wi (ib); > Index: lto-streamer-out.c > =================================================================== > --- lto-streamer-out.c (revision 236762) > +++ lto-streamer-out.c (working copy) > @@ -1925,6 +1925,9 @@ output_cfg (struct output_block *ob, str > streamer_write_hwi (ob, loop->any_upper_bound); > if (loop->any_upper_bound) > streamer_write_wi (ob, loop->nb_iterations_upper_bound); > + streamer_write_hwi (ob, loop->any_likely_upper_bound); > + if (loop->any_likely_upper_bound) > + streamer_write_wi (ob, loop->nb_iterations_likely_upper_bound); > streamer_write_hwi (ob, loop->any_estimate); > if (loop->any_estimate) > streamer_write_wi (ob, loop->nb_iterations_estimate); > Index: tree-ssa-loop-ivcanon.c > =================================================================== > --- tree-ssa-loop-ivcanon.c (revision 236762) > +++ tree-ssa-loop-ivcanon.c (working copy) > @@ -1036,6 +1036,8 @@ try_peel_loop (struct loop *loop, > } > if (loop->any_upper_bound) > loop->nb_iterations_upper_bound -= npeel; > + if (loop->any_likely_upper_bound) > + loop->nb_iterations_likely_upper_bound -= npeel; > loop->nb_iterations_estimate = 0; > /* Make sure to mark loop cold so we do not try to peel it more. */ > scale_loop_profile (loop, 1, 0); > @@ -1107,6 +1109,12 @@ canonicalize_loop_induction_variables (s > fprintf (dump_file, "Loop %d iterates at most %i times.\n", loop->num, > (int)maxiter); > } > + if (dump_file && (dump_flags & TDF_DETAILS) > + && likely_max_loop_iterations_int (loop) >= 0) > + { > + fprintf (dump_file, "Loop likely %d iterates at most %i times.\n", > loop->num, > + (int)likely_max_loop_iterations_int (loop)); > + } > > /* Remove exits that are known to be never taken based on loop bound. > Needs to be called after compilation of max_loop_iterations_int that > Index: tree-ssa-loop-niter.c > =================================================================== > --- tree-ssa-loop-niter.c (revision 236762) > +++ tree-ssa-loop-niter.c (working copy) > @@ -2954,8 +2958,6 @@ record_estimate (struct loop *loop, tree > realistic = false; > else > gcc_checking_assert (i_bound == wi::to_widest (bound)); > - if (!upper && !realistic) > - return; > > /* If we have a guaranteed upper bound, record it in the appropriate > list, unless this is an !is_exit bound (i.e. undefined behavior in > @@ -2977,7 +2979,7 @@ record_estimate (struct loop *loop, tree > /* If statement is executed on every path to the loop latch, we can > directly > infer the upper bound on the # of iterations of the loop. */ > if (!dominated_by_p (CDI_DOMINATORS, loop->latch, gimple_bb (at_stmt))) > - return; > + upper = false; > > /* Update the number of iteration estimates according to the bound. > If at_stmt is an exit then the loop latch is executed at most BOUND > times, > @@ -3850,6 +3852,37 @@ max_loop_iterations_int (struct loop *lo > return hwi_nit < 0 ? -1 : hwi_nit; > } > > +bool > +likely_max_loop_iterations (struct loop *loop, widest_int *nit) > +{ > + /* When SCEV information is available, try to update loop iterations > + estimate. Otherwise just return whatever we recorded earlier. */ > + if (scev_initialized_p ()) > + estimate_numbers_of_iterations_loop (loop); > + > + return get_likely_max_loop_iterations (loop, nit); > +} > + > +/* Similar to max_loop_iterations, but returns the estimate only > + if it fits to HOST_WIDE_INT. If this is not the case, or the estimate > + on the number of iterations of LOOP could not be derived, returns -1. */ > + > +HOST_WIDE_INT > +likely_max_loop_iterations_int (struct loop *loop) > +{ > + widest_int nit; > + HOST_WIDE_INT hwi_nit; > + > + if (!likely_max_loop_iterations (loop, &nit)) > + return -1; > + > + if (!wi::fits_shwi_p (nit)) > + return -1; > + hwi_nit = nit.to_shwi (); > + > + return hwi_nit < 0 ? -1 : hwi_nit; > +} > + > /* Returns an estimate for the number of executions of statements > in the LOOP. For statements before the loop exit, this exceeds > the number of execution of the latch by one. */ > @@ -3869,7 +3902,7 @@ estimated_stmt_executions_int (struct lo > return snit < 0 ? -1 : snit; > } > > -/* Sets NIT to the estimated maximum number of executions of the latch of the > +/* Sets NIT to the maximum number of executions of the latch of the > LOOP, plus one. If we have no reliable estimate, the function returns > false, otherwise returns true. */ > > @@ -3882,6 +3915,25 @@ max_stmt_executions (struct loop *loop, > return false; > > nit_minus_one = *nit; > + > + *nit += 1; > + > + return wi::gtu_p (*nit, nit_minus_one); > +} > + > +/* Sets NIT to the estimated maximum number of executions of the latch of the > + LOOP, plus one. If we have no likely estimate, the function returns > + false, otherwise returns true. */ > + > +bool > +likely_max_stmt_executions (struct loop *loop, widest_int *nit) > +{ > + widest_int nit_minus_one; > + > + if (!likely_max_loop_iterations (loop, nit)) > + return false; > + > + nit_minus_one = *nit; > > *nit += 1; > > Index: tree-ssa-loop-niter.h > =================================================================== > --- tree-ssa-loop-niter.h (revision 236762) > +++ tree-ssa-loop-niter.h (working copy) > @@ -35,9 +35,13 @@ extern bool estimated_loop_iterations (s > extern HOST_WIDE_INT estimated_loop_iterations_int (struct loop *); > extern bool max_loop_iterations (struct loop *, widest_int *); > extern HOST_WIDE_INT max_loop_iterations_int (struct loop *); > +extern bool likely_max_loop_iterations (struct loop *, widest_int *); > +extern HOST_WIDE_INT likely_max_loop_iterations_int (struct loop *); > extern HOST_WIDE_INT max_stmt_executions_int (struct loop *); > +extern HOST_WIDE_INT likely_max_stmt_executions_int (struct loop *); > extern HOST_WIDE_INT estimated_stmt_executions_int (struct loop *); > extern bool max_stmt_executions (struct loop *, widest_int *); > +extern bool likely_max_stmt_executions (struct loop *, widest_int *); > extern bool estimated_stmt_executions (struct loop *, widest_int *); > extern void estimate_numbers_of_iterations (void); > extern bool stmt_dominates_stmt_p (gimple *, gimple *); > > -- Richard Biener <rguent...@suse.de> SUSE LINUX GmbH, GF: Felix Imendoerffer, Jane Smithard, Graham Norton, HRB 21284 (AG Nuernberg)