> -----Original Message----- > From: Bin.Cheng [mailto:amker.ch...@gmail.com] > Sent: Monday, December 09, 2013 1:15 PM > To: Jeff Law > Cc: Bin Cheng; gcc-patches List > Subject: Re: [PATCH PR41488]Recognize more induction variables by > simplifying PEELED chrec in scalar evolution > > On Mon, Dec 9, 2013 at 12:00 PM, Jeff Law <l...@redhat.com> wrote: > > On 12/06/13 19:44, Bin.Cheng wrote: > >>> > >>> Right. Based on reading the archives, it looks like this stuff > >>> is/was generated by PRE. I also suspect jump threading can create > >>> them. There was talk of throttling PRE to leave things in a form > >>> that the IV analysis could more easily digest, but I'm not sure if > >>> that was ever completed. > >> > >> > >> Also could just because it is coded in that way, just as the case I > >> added in patch. I found real examples from ggc-page.c in GCC. > >> But it's always good to cleanup input of an optimization, I presume > >> that's why Richard tried to move IVOPT later before. > > > > Certainly. That possibility was mentioned as well in either 41488 or > > elsewhere in my research. > > > > > >>> > >>> I assume tree_to_aff_combination_expand is relatively expensive, > >>> thus the two approaches, one which avoids > tree_to_aff_combination_expand. > >> > >> Considering the dump of case in the patch: > > > > [ snip ] > > So it's also a case using the affine stuff gets you get a simpler > > interface to express the value in terms you may be able match. > Yeah. > > > > > > >> > >> Another question, is it acceptable to add an parameter for > >> tree_to_aff_combination_expand to limit the number of recursive call > >> for it? Thus we don't need to expand to leaf node every time. > > > > If there's a compelling reason to limit the recursion, then I'd think > > such a parameter would be reasonable. > Not for now. Just come up this idea given that some recent patches also use > the interface to get back trace information and it's expensive. Maybe > Richard have some comment here too. > > > > > > > > >> > >>> > >>> > >>> In add_old_iv_candidates, is it the case that the only time > >>> SSA_NAME_DEF_STMT (def) is another PHI node is when it's one of > >>> these affine > >> > >> > >> I suppose. Actually IVOPT make an assert on IP_ORIGINAL candidates > >> in function rewrite_use_nonlinear_expr, like: > > > > Well, the reason I ask is after your patch we'd be ignoring anything > > where SSA_NAME_DEF_STMT (def) is a PHI node and not a PEELED_CHREC. > I > > want to make sure there aren't other expected cases where > > SSA_NAME_DEF_STMT (def) is a PHI that we'd want to call > add_candidate_1 for. > > > > It sounds like there aren't other cases you'd expect to see here where > > SSA_NAME_DEF_STMT (defFFF) is a PHI. > Yes. > > > > > > >> IVOPT adds original cand and tries to keep it the original IV is > >> because it does have an updating statement. For IVs picked up by > >> this patch, it doesn't have stepping statement, so no need/way to > >> leaving it untouched. It will be represented by candidates for IVs > >> from which it is peeled. > > > > Understood. Thanks for clarifying. The patch is fine for the trunk. > Thanks very much for reviewing. Since Sebastian hasn't added any > comments, I will change the patch as suggested by Richard before, then > retest it, and check in the new version if it's ok. > Hi, This is the new version patch computing the difference in tree affine then comparing against integer_zero_node. Bootstrap and test on current upstream. I will commit it if there is no other objection.
Thanks, bin > > > > jeff > > > > -- > Best Regards.
Index: gcc/tree-scalar-evolution.c =================================================================== --- gcc/tree-scalar-evolution.c (revision 205688) +++ gcc/tree-scalar-evolution.c (working copy) @@ -280,6 +280,8 @@ along with GCC; see the file COPYING3. If not see #include "tree-ssa.h" #include "cfgloop.h" #include "tree-chrec.h" +#include "pointer-set.h" +#include "tree-affine.h" #include "tree-scalar-evolution.h" #include "dumpfile.h" #include "params.h" @@ -1380,7 +1382,67 @@ follow_ssa_edge (struct loop *loop, gimple def, gi } +/* Pointer map used when simplifying PEELED_CHREC into POLYNOMIAL_CHREC. */ +static pointer_map_t *peeled_chrec_map; +/* Simplify PEELED_CHREC represented by (init_cond, arg) in LOOP. + Handle below case and return the corresponding POLYNOMIAL_CHREC: + + # i_17 = PHI <i_13(5), 0(3)> + # _20 = PHI <_5(5), start_4(D)(3)> + ... + i_13 = i_17 + 1; + _5 = start_4(D) + i_13; + + Though variable _20 appears as a PEELED_CHREC in the form of + (start_4, _5)_LOOP, it's a POLYNOMIAL_CHREC like {start_4, 1}_LOOP. + + See PR41488. */ + +static tree +simplify_peeled_chrec (struct loop *loop, tree arg, tree init_cond) +{ + aff_tree aff1, aff2; + tree ev, left, right, type, step_val; + + ev = instantiate_parameters (loop, analyze_scalar_evolution (loop, arg)); + if (ev == NULL_TREE || TREE_CODE (ev) != POLYNOMIAL_CHREC) + return chrec_dont_know; + + left = CHREC_LEFT (ev); + right = CHREC_RIGHT (ev); + type = TREE_TYPE (left); + step_val = chrec_fold_plus (type, init_cond, right); + + /* Transform (init, {left, right}_LOOP)_LOOP to {init, right}_LOOP + if "left" equals to "init + right". */ + if (operand_equal_p (left, step_val, 0)) + { + if (dump_file && (dump_flags & TDF_SCEV)) + fprintf (dump_file, "Simplify PEELED_CHREC into POLYNOMIAL_CHREC.\n"); + + return build_polynomial_chrec (loop->num, init_cond, right); + } + + /* Try harder to check if they are equal. */ + tree_to_aff_combination_expand (left, type, &aff1, &peeled_chrec_map); + tree_to_aff_combination_expand (step_val, type, &aff2, &peeled_chrec_map); + aff_combination_scale (&aff2, double_int_minus_one); + aff_combination_add (&aff1, &aff2); + left = fold_convert (type, aff_combination_to_tree (&aff1)); + + /* Transform (init, {left, right}_LOOP)_LOOP to {init, right}_LOOP + if "left" equals to "init + right". */ + if (operand_equal_p (left, integer_zero_node, 0)) + { + if (dump_file && (dump_flags & TDF_SCEV)) + fprintf (dump_file, "Simplify PEELED_CHREC into POLYNOMIAL_CHREC.\n"); + + return build_polynomial_chrec (loop->num, init_cond, right); + } + return chrec_dont_know; +} + /* Given a LOOP_PHI_NODE, this function determines the evolution function from LOOP_PHI_NODE to LOOP_PHI_NODE in the loop. */ @@ -1392,6 +1454,7 @@ analyze_evolution_in_loop (gimple loop_phi_node, tree evolution_function = chrec_not_analyzed_yet; struct loop *loop = loop_containing_stmt (loop_phi_node); basic_block bb; + static bool simplify_peeled_chrec_p = true; if (dump_file && (dump_flags & TDF_SCEV)) { @@ -1442,7 +1505,19 @@ analyze_evolution_in_loop (gimple loop_phi_node, all the other iterations it has the value of ARG. For the moment, PEELED_CHREC nodes are not built. */ if (res != t_true) - ev_fn = chrec_dont_know; + { + ev_fn = chrec_dont_know; + /* Try to recognize POLYNOMIAL_CHREC which appears in + the form of PEELED_CHREC, but guard the process with + a bool variable to keep the analyzer from infinite + recurrence for real PEELED_RECs. */ + if (simplify_peeled_chrec_p && TREE_CODE (arg) == SSA_NAME) + { + simplify_peeled_chrec_p = false; + ev_fn = simplify_peeled_chrec (loop, arg, init_cond); + simplify_peeled_chrec_p = true; + } + } /* When there are multiple back edges of the loop (which in fact never happens currently, but nevertheless), merge their evolutions. */ @@ -3086,6 +3161,8 @@ scev_initialize (void) initialize_scalar_evolutions_analyzer (); + peeled_chrec_map = pointer_map_create (); + FOR_EACH_LOOP (loop, 0) { loop->nb_iterations = NULL_TREE; @@ -3122,6 +3199,12 @@ scev_reset (void) scev_reset_htab (); + if (peeled_chrec_map) + { + pointer_map_destroy (peeled_chrec_map); + peeled_chrec_map = NULL; + } + if (!current_loops) return; @@ -3209,6 +3292,11 @@ scev_finalize (void) return; htab_delete (scalar_evolution_info); scalar_evolution_info = NULL; + if (peeled_chrec_map) + { + pointer_map_destroy (peeled_chrec_map); + peeled_chrec_map = NULL; + } } /* Returns true if the expression EXPR is considered to be too expensive Index: gcc/testsuite/gcc.dg/tree-ssa/scev-7.c =================================================================== --- gcc/testsuite/gcc.dg/tree-ssa/scev-7.c (revision 0) +++ gcc/testsuite/gcc.dg/tree-ssa/scev-7.c (revision 0) @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-sccp-scev" } */ + +struct struct_t +{ + int* data; +}; + +void foo (struct struct_t* sp, int start, int end) +{ + int i; + + for (i = 1000; i+start > end; i--) + sp->data[i+start] = 0; +} + +/* { dg-final { scan-tree-dump-times "Simplify PEELED_CHREC into POLYNOMIAL_CHREC" 1 "sccp" } } */ +/* { dg-final { cleanup-tree-dump "sccp" } } */ Index: gcc/testsuite/gcc.dg/pr41488.c =================================================================== --- gcc/testsuite/gcc.dg/pr41488.c (revision 0) +++ gcc/testsuite/gcc.dg/pr41488.c (revision 0) @@ -0,0 +1,18 @@ +/* { dg-do compile } */ +/* { dg-options "-O2 -fdump-tree-sccp-scev" } */ + +struct struct_t +{ + int* data; +}; + +void foo (struct struct_t* sp, int start, int end) +{ + int i; + + for (i = 0; i+start < end; i++) + sp->data[i+start] = 0; +} + +/* { dg-final { scan-tree-dump-times "Simplify PEELED_CHREC into POLYNOMIAL_CHREC" 1 "sccp" } } */ +/* { dg-final { cleanup-tree-dump "sccp" } } */ Index: gcc/tree-ssa-loop-ivopts.c =================================================================== --- gcc/tree-ssa-loop-ivopts.c (revision 205688) +++ gcc/tree-ssa-loop-ivopts.c (working copy) @@ -2526,11 +2526,19 @@ add_old_iv_candidates (struct ivopts_data *data, s /* Additionally record the possibility of leaving the original iv untouched. */ def = PHI_ARG_DEF_FROM_EDGE (phi, loop_latch_edge (data->current_loop)); - cand = add_candidate_1 (data, - iv->base, iv->step, true, IP_ORIGINAL, NULL, - SSA_NAME_DEF_STMT (def)); - cand->var_before = iv->ssa_name; - cand->var_after = def; + /* Don't add candidate if it's from another PHI node because + it's an affine iv appearing in the form of PEELED_CHREC. */ + phi = SSA_NAME_DEF_STMT (def); + if (gimple_code (phi) != GIMPLE_PHI) + { + cand = add_candidate_1 (data, + iv->base, iv->step, true, IP_ORIGINAL, NULL, + SSA_NAME_DEF_STMT (def)); + cand->var_before = iv->ssa_name; + cand->var_after = def; + } + else + gcc_assert (gimple_bb (phi) == data->current_loop->header); } }