aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-loop-ivopts.c
diff options
context:
space:
mode:
authorZdenek Dvorak <dvorakz@suse.cz>2004-12-18 21:22:52 +0100
committerZdenek Dvorak <rakdver@gcc.gnu.org>2004-12-18 20:22:52 +0000
commit36f5ada19abb481dff1a9e973f20e4dc77b8b979 (patch)
treebe8c1c0278641ae18ae9aa16fd05df79f9533593 /gcc/tree-ssa-loop-ivopts.c
parentf54ff900373c7406b665588b2af845868b4a1872 (diff)
downloadgcc-36f5ada19abb481dff1a9e973f20e4dc77b8b979.zip
gcc-36f5ada19abb481dff1a9e973f20e4dc77b8b979.tar.gz
gcc-36f5ada19abb481dff1a9e973f20e4dc77b8b979.tar.bz2
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
Diffstat (limited to 'gcc/tree-ssa-loop-ivopts.c')
-rw-r--r--gcc/tree-ssa-loop-ivopts.c187
1 files changed, 160 insertions, 27 deletions
diff --git a/gcc/tree-ssa-loop-ivopts.c b/gcc/tree-ssa-loop-ivopts.c
index 8727db8..9c5aad3 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;
}