From: Zdenek Dvorak Date: Sat, 18 Dec 2004 20:22:52 +0000 (+0100) Subject: re PR tree-optimization/18800 (ivopt missed) X-Git-Tag: releases/gcc-4.0.0~2072 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=36f5ada19abb481dff1a9e973f20e4dc77b8b979;p=thirdparty%2Fgcc.git re PR tree-optimization/18800 (ivopt missed) PR tree-optimization/18800 * params.def (PARAM_IV_ALWAYS_PRUNE_CAND_SET_BOUND): New parameter. * tree-ssa-loop-ivopts.c (struct iv_ca): Add n_cands field. (ALWAYS_PRUNE_CAND_SET_BOUND): New macro. (iv_ca_set_no_cp, iv_ca_set_cp, iv_ca_new): Update n_cands field. (iv_ca_delta_join, iv_ca_delta_reverse, iv_ca_n_cands, iv_ca_prune): New functions. (iv_ca_extend): Return number of candidates in the set. (try_add_cand_for): Add argument to iv_ca_extend calls. (try_improve_iv_set): Use iv_ca_prune. * doc/invoke.texi (iv-always-prune-cand-set-bound): Document. From-SVN: r92363 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 1f8b54728553..e6851c99ce54 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -2,6 +2,20 @@ * stor-layout.c (layout_decl): Use unshare_expr, not unsave_expr. +2004-12-18 Zdenek Dvorak + + PR tree-optimization/18800 + * params.def (PARAM_IV_ALWAYS_PRUNE_CAND_SET_BOUND): New parameter. + * tree-ssa-loop-ivopts.c (struct iv_ca): Add n_cands field. + (ALWAYS_PRUNE_CAND_SET_BOUND): New macro. + (iv_ca_set_no_cp, iv_ca_set_cp, iv_ca_new): Update n_cands field. + (iv_ca_delta_join, iv_ca_delta_reverse, iv_ca_n_cands, iv_ca_prune): + New functions. + (iv_ca_extend): Return number of candidates in the set. + (try_add_cand_for): Add argument to iv_ca_extend calls. + (try_improve_iv_set): Use iv_ca_prune. + * doc/invoke.texi (iv-always-prune-cand-set-bound): Document. + 2004-12-18 Zdenek Dvorak PR rtl-optimization/19001 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 8316bec704b9..5ba632e7561b 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -5478,6 +5478,11 @@ if there are more candidates, to avoid quadratic time complexity. The induction variable optimizations give up on loops that contain more induction variable uses. +@item iv-always-prune-cand-set-bound +If number of candidates in the set is smaller than this value, +we always try to remove unnecessary ivs from the set during its +optimization when a new iv is added to the set. + @item max-iterations-to-track The maximum number of iterations of a loop the brute force algorithm diff --git a/gcc/params.def b/gcc/params.def index 48ad6d7ee1e5..7ac263cdc246 100644 --- a/gcc/params.def +++ b/gcc/params.def @@ -347,6 +347,14 @@ DEFPARAM(PARAM_IV_MAX_CONSIDERED_USES, "Bound on number of iv uses in loop optimized in iv optimizations", 250, 0, 0) +/* If there are at most this number of ivs in the set, try removing unnecessary + ivs from the set always. */ + +DEFPARAM(PARAM_IV_ALWAYS_PRUNE_CAND_SET_BOUND, + "iv-always-prune-cand-set-bound", + "If number of candidates in the set is smaller, we always try to remove unused ivs during its optimization", + 10, 0, 0) + /* The product of the next two is used to decide whether or not to use .GLOBAL_VAR. See tree-dfa.c. */ DEFPARAM(PARAM_GLOBAL_VAR_THRESHOLD, diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c index 8727db863144..9c5aad3920fa 100644 --- a/gcc/tree-ssa-loop-ivopts.c +++ b/gcc/tree-ssa-loop-ivopts.c @@ -244,6 +244,9 @@ struct iv_ca /* The candidates used. */ bitmap cands; + /* The number of candidates in the set. */ + unsigned n_cands; + /* Total number of registers needed. */ unsigned n_regs; @@ -288,6 +291,12 @@ struct iv_ca_delta #define MAX_CONSIDERED_USES \ ((unsigned) PARAM_VALUE (PARAM_IV_MAX_CONSIDERED_USES)) +/* If there are at most this number of ivs in the set, try removing unnecessary + ivs from the set always. */ + +#define ALWAYS_PRUNE_CAND_SET_BOUND \ + ((unsigned) PARAM_VALUE (PARAM_IV_ALWAYS_PRUNE_CAND_SET_BOUND)) + /* The list of trees for that the decl_rtl field must be reset is stored here. */ @@ -3661,6 +3670,7 @@ iv_ca_set_no_cp (struct ivopts_data *data, struct iv_ca *ivs, /* Do not count the pseudocandidates. */ if (cp->cand->iv) ivs->n_regs--; + ivs->n_cands--; ivs->cand_cost -= cp->cand->cost; } @@ -3710,6 +3720,7 @@ iv_ca_set_cp (struct ivopts_data *data, struct iv_ca *ivs, /* Do not count the pseudocandidates. */ if (cp->cand->iv) ivs->n_regs++; + ivs->n_cands++; ivs->cand_cost += cp->cand->cost; } @@ -3806,6 +3817,27 @@ iv_ca_delta_add (struct iv_use *use, struct cost_pair *old_cp, return change; } +/* Joins two lists of changes L1 and L2. Destructive -- old lists + are rewritten. */ + +static struct iv_ca_delta * +iv_ca_delta_join (struct iv_ca_delta *l1, struct iv_ca_delta *l2) +{ + struct iv_ca_delta *last; + + if (!l2) + return l1; + + if (!l1) + return l2; + + for (last = l1; last->next_change; last = last->next_change) + continue; + last->next_change = l2; + + return l1; +} + /* Returns candidate by that USE is expressed in IVS. */ static struct cost_pair * @@ -3814,6 +3846,28 @@ iv_ca_cand_for_use (struct iv_ca *ivs, struct iv_use *use) return ivs->cand_for_use[use->id]; } +/* Reverse the list of changes DELTA, forming the inverse to it. */ + +static struct iv_ca_delta * +iv_ca_delta_reverse (struct iv_ca_delta *delta) +{ + struct iv_ca_delta *act, *next, *prev = NULL; + struct cost_pair *tmp; + + for (act = delta; act; act = next) + { + next = act->next_change; + act->next_change = prev; + prev = act; + + tmp = act->old_cp; + act->old_cp = act->new_cp; + act->new_cp = tmp; + } + + return prev; +} + /* Commit changes in DELTA to IVS. If FORWARD is false, the changes are reverted instead. */ @@ -3822,23 +3876,21 @@ iv_ca_delta_commit (struct ivopts_data *data, struct iv_ca *ivs, struct iv_ca_delta *delta, bool forward) { struct cost_pair *from, *to; + struct iv_ca_delta *act; - for (; delta; delta = delta->next_change) - { - if (forward) - { - from = delta->old_cp; - to = delta->new_cp; - } - else - { - from = delta->new_cp; - to = delta->old_cp; - } + if (!forward) + delta = iv_ca_delta_reverse (delta); - gcc_assert (iv_ca_cand_for_use (ivs, delta->use) == from); - iv_ca_set_cp (data, ivs, delta->use, to); + for (act = delta; act; act = act->next_change) + { + from = act->old_cp; + to = act->new_cp; + gcc_assert (iv_ca_cand_for_use (ivs, act->use) == from); + iv_ca_set_cp (data, ivs, act->use, to); } + + if (!forward) + iv_ca_delta_reverse (delta); } /* Returns true if CAND is used in IVS. */ @@ -3849,6 +3901,14 @@ iv_ca_cand_used_p (struct iv_ca *ivs, struct iv_cand *cand) return ivs->n_cand_uses[cand->id] > 0; } +/* Returns number of induction variable candidates in the set IVS. */ + +static unsigned +iv_ca_n_cands (struct iv_ca *ivs) +{ + return ivs->n_cands; +} + /* Free the list of changes DELTA. */ static void @@ -3877,6 +3937,7 @@ iv_ca_new (struct ivopts_data *data) nw->cand_for_use = xcalloc (n_iv_uses (data), sizeof (struct cost_pair *)); nw->n_cand_uses = xcalloc (n_iv_cands (data), sizeof (unsigned)); nw->cands = BITMAP_XMALLOC (); + nw->n_cands = 0; nw->n_regs = 0; nw->cand_use_cost = 0; nw->cand_cost = 0; @@ -3920,11 +3981,13 @@ iv_ca_dump (struct ivopts_data *data, FILE *file, struct iv_ca *ivs) } /* Try changing candidate in IVS to CAND for each use. Return cost of the - new set, and store differences in DELTA. */ + new set, and store differences in DELTA. Number of induction variables + in the new set is stored to N_IVS. */ static unsigned iv_ca_extend (struct ivopts_data *data, struct iv_ca *ivs, - struct iv_cand *cand, struct iv_ca_delta **delta) + struct iv_cand *cand, struct iv_ca_delta **delta, + unsigned *n_ivs) { unsigned i, cost; struct iv_use *use; @@ -3955,6 +4018,8 @@ iv_ca_extend (struct ivopts_data *data, struct iv_ca *ivs, iv_ca_delta_commit (data, ivs, *delta, true); cost = iv_ca_cost (ivs); + if (n_ivs) + *n_ivs = iv_ca_n_cands (ivs); iv_ca_delta_commit (data, ivs, *delta, false); return cost; @@ -4044,6 +4109,55 @@ iv_ca_narrow (struct ivopts_data *data, struct iv_ca *ivs, return cost; } +/* Try optimizing the set of candidates IVS by removing candidates different + from to EXCEPT_CAND from it. Return cost of the new set, and store + differences in DELTA. */ + +static unsigned +iv_ca_prune (struct ivopts_data *data, struct iv_ca *ivs, + struct iv_cand *except_cand, struct iv_ca_delta **delta) +{ + bitmap_iterator bi; + struct iv_ca_delta *act_delta, *best_delta; + unsigned i, best_cost, acost; + struct iv_cand *cand; + + best_delta = NULL; + best_cost = iv_ca_cost (ivs); + + EXECUTE_IF_SET_IN_BITMAP (ivs->cands, 0, i, bi) + { + cand = iv_cand (data, i); + + if (cand == except_cand) + continue; + + acost = iv_ca_narrow (data, ivs, cand, &act_delta); + + if (acost < best_cost) + { + best_cost = acost; + iv_ca_delta_free (&best_delta); + best_delta = act_delta; + } + else + iv_ca_delta_free (&act_delta); + } + + if (!best_delta) + { + *delta = NULL; + return best_cost; + } + + /* Recurse to possibly remove other unnecessary ivs. */ + iv_ca_delta_commit (data, ivs, best_delta, true); + best_cost = iv_ca_prune (data, ivs, except_cand, delta); + iv_ca_delta_commit (data, ivs, best_delta, false); + *delta = iv_ca_delta_join (best_delta, *delta); + return best_cost; +} + /* Tries to extend the sets IVS in the best possible way in order to express the USE. */ @@ -4088,7 +4202,7 @@ try_add_cand_for (struct ivopts_data *data, struct iv_ca *ivs, continue; iv_ca_set_cp (data, ivs, use, cp); - act_cost = iv_ca_extend (data, ivs, cand, &act_delta); + act_cost = iv_ca_extend (data, ivs, cand, &act_delta, NULL); iv_ca_set_no_cp (data, ivs, use); act_delta = iv_ca_delta_add (use, NULL, cp, act_delta); @@ -4121,7 +4235,7 @@ try_add_cand_for (struct ivopts_data *data, struct iv_ca *ivs, act_delta = NULL; iv_ca_set_cp (data, ivs, use, cp); - act_cost = iv_ca_extend (data, ivs, cand, &act_delta); + act_cost = iv_ca_extend (data, ivs, cand, &act_delta, NULL); iv_ca_set_no_cp (data, ivs, use); act_delta = iv_ca_delta_add (use, iv_ca_cand_for_use (ivs, use), cp, act_delta); @@ -4168,25 +4282,36 @@ get_initial_solution (struct ivopts_data *data) static bool try_improve_iv_set (struct ivopts_data *data, struct iv_ca *ivs) { - unsigned i, acost, best_cost = iv_ca_cost (ivs); - struct iv_ca_delta *best_delta = NULL, *act_delta; + unsigned i, acost, best_cost = iv_ca_cost (ivs), n_ivs; + struct iv_ca_delta *best_delta = NULL, *act_delta, *tmp_delta; struct iv_cand *cand; - /* Try altering the set of induction variables by one. */ + /* Try extending the set of induction variables by one. */ for (i = 0; i < n_iv_cands (data); i++) { cand = iv_cand (data, i); if (iv_ca_cand_used_p (ivs, cand)) - acost = iv_ca_narrow (data, ivs, cand, &act_delta); - else - acost = iv_ca_extend (data, ivs, cand, &act_delta); + continue; + + acost = iv_ca_extend (data, ivs, cand, &act_delta, &n_ivs); + if (!act_delta) + continue; + + /* If we successfully added the candidate and the set is small enough, + try optimizing it by removing other candidates. */ + if (n_ivs <= ALWAYS_PRUNE_CAND_SET_BOUND) + { + iv_ca_delta_commit (data, ivs, act_delta, true); + acost = iv_ca_prune (data, ivs, cand, &tmp_delta); + iv_ca_delta_commit (data, ivs, act_delta, false); + act_delta = iv_ca_delta_join (act_delta, tmp_delta); + } if (acost < best_cost) { best_cost = acost; - if (best_delta) - iv_ca_delta_free (&best_delta); + iv_ca_delta_free (&best_delta); best_delta = act_delta; } else @@ -4194,9 +4319,17 @@ try_improve_iv_set (struct ivopts_data *data, struct iv_ca *ivs) } if (!best_delta) - return false; + { + /* Try removing the candidates from the set instead. */ + best_cost = iv_ca_prune (data, ivs, NULL, &best_delta); + + /* Nothing more we can do. */ + if (!best_delta) + return false; + } iv_ca_delta_commit (data, ivs, best_delta, true); + gcc_assert (best_cost == iv_ca_cost (ivs)); iv_ca_delta_free (&best_delta); return true; }