/* Information attached to loop. */
struct loop_data
{
- struct tree_niter_desc niter;
- /* Number of iterations. */
-
unsigned regs_used; /* Number of registers used. */
};
/* The currently optimized loop. */
struct loop *current_loop;
+ /* Numbers of iterations for all exits of the current loop. */
+ htab_t niters;
+
/* The size of version_info array allocated. */
unsigned version_info_size;
}
}
+/* Element of the table in that we cache the numbers of iterations obtained
+ from exits of the loop. */
+
+struct nfe_cache_elt
+{
+ /* The edge for that the number of iterations is cached. */
+ edge exit;
+
+ /* True if the # of iterations was succesfully determined. */
+ bool valid_p;
+
+ /* Description of # of iterations. */
+ struct tree_niter_desc niter;
+};
+
+/* Hash function for nfe_cache_elt E. */
+
+static hashval_t
+nfe_hash (const void *e)
+{
+ const struct nfe_cache_elt *elt = e;
+
+ return htab_hash_pointer (elt->exit);
+}
+
+/* Equality function for nfe_cache_elt E1 and edge E2. */
+
+static int
+nfe_eq (const void *e1, const void *e2)
+{
+ const struct nfe_cache_elt *elt1 = e1;
+
+ return elt1->exit == e2;
+}
+
+/* Returns structure describing number of iterations determined from
+ EXIT of DATA->current_loop, or NULL if something goes wrong. */
+
+static struct tree_niter_desc *
+niter_for_exit (struct ivopts_data *data, edge exit)
+{
+ struct nfe_cache_elt *nfe_desc;
+ PTR *slot;
+
+ slot = htab_find_slot_with_hash (data->niters, exit,
+ htab_hash_pointer (exit),
+ INSERT);
+
+ if (!*slot)
+ {
+ nfe_desc = xmalloc (sizeof (struct nfe_cache_elt));
+ nfe_desc->exit = exit;
+ nfe_desc->valid_p = number_of_iterations_exit (data->current_loop,
+ exit, &nfe_desc->niter);
+ *slot = nfe_desc;
+ }
+ else
+ nfe_desc = *slot;
+
+ if (!nfe_desc->valid_p)
+ return NULL;
+
+ return &nfe_desc->niter;
+}
+
+/* Returns structure describing number of iterations determined from
+ single dominating exit of DATA->current_loop, or NULL if something
+ goes wrong. */
+
+static struct tree_niter_desc *
+niter_for_single_dom_exit (struct ivopts_data *data)
+{
+ edge exit = single_dom_exit (data->current_loop);
+
+ if (!exit)
+ return NULL;
+
+ return niter_for_exit (data, exit);
+}
+
/* Initializes data structures used by the iv optimization pass, stored
in DATA. LOOPS is the loop tree. */
data->relevant = BITMAP_XMALLOC ();
data->important_candidates = BITMAP_XMALLOC ();
data->max_inv_id = 0;
+ data->niters = htab_create (10, nfe_hash, nfe_eq, free);
for (i = 1; i < loops->num; i++)
if (loops->parray[i])
free (body);
}
-/* Determine the number of iterations of the current loop. */
-
-static void
-determine_number_of_iterations (struct ivopts_data *data)
-{
- struct loop *loop = data->current_loop;
- edge exit = single_dom_exit (loop);
-
- if (!exit)
- return;
-
- number_of_iterations_exit (loop, exit, &loop_data (loop)->niter);
-}
-
/* For each ssa name defined in LOOP determines whether it is an induction
variable and if so, its initial value and step. */
find_induction_variables (struct ivopts_data *data)
{
unsigned i;
- struct loop *loop = data->current_loop;
bitmap_iterator bi;
if (!find_bivs (data))
find_givs (data);
mark_bivs (data);
- determine_number_of_iterations (data);
if (dump_file && (dump_flags & TDF_DETAILS))
{
- if (loop_data (loop)->niter.niter)
+ struct tree_niter_desc *niter;
+
+ niter = niter_for_single_dom_exit (data);
+
+ if (niter)
{
fprintf (dump_file, " number of iterations ");
- print_generic_expr (dump_file, loop_data (loop)->niter.niter,
- TDF_SLIM);
+ print_generic_expr (dump_file, niter->niter, TDF_SLIM);
fprintf (dump_file, "\n");
fprintf (dump_file, " may be zero if ");
- print_generic_expr (dump_file, loop_data (loop)->niter.may_be_zero,
- TDF_SLIM);
- fprintf (dump_file, "\n");
-
- fprintf (dump_file, " bogus unless ");
- print_generic_expr (dump_file, loop_data (loop)->niter.assumptions,
- TDF_SLIM);
+ print_generic_expr (dump_file, niter->may_be_zero, TDF_SLIM);
fprintf (dump_file, "\n");
fprintf (dump_file, "\n");
};
add_iv_outer_candidates (struct ivopts_data *data, struct iv_use *use)
{
struct tree_niter_desc *niter;
- struct loop *loop = data->current_loop;
/* We must know where we exit the loop and how many times does it roll. */
- if (!single_dom_exit (loop))
- return;
-
- niter = &loop_data (loop)->niter;
- if (!niter->niter
- || !operand_equal_p (niter->assumptions, boolean_true_node, 0)
- || !operand_equal_p (niter->may_be_zero, boolean_false_node, 0))
+ niter = niter_for_single_dom_exit (data);
+ if (!niter
+ || !zero_p (niter->may_be_zero))
return;
add_candidate_1 (data, NULL, NULL, false, IP_NORMAL, use, NULL_TREE);
return val;
}
+/* Returns period of induction variable iv. */
+
+static tree
+iv_period (struct iv *iv)
+{
+ tree step = iv->step, period, type;
+ tree pow2div;
+
+ gcc_assert (step && TREE_CODE (step) == INTEGER_CST);
+
+ /* Period of the iv is gcd (step, type range). Since type range is power
+ of two, it suffices to determine the maximum power of two that divides
+ step. */
+ pow2div = num_ending_zeros (step);
+ type = unsigned_type_for (TREE_TYPE (step));
+
+ period = build_low_bits_mask (type,
+ (TYPE_PRECISION (type)
+ - tree_low_cst (pow2div, 1)));
+
+ return period;
+}
+
/* Check whether it is possible to express the condition in USE by comparison
of candidate CAND. If so, store the comparison code to COMPARE and the
value compared with to BOUND. */
static bool
-may_eliminate_iv (struct loop *loop,
+may_eliminate_iv (struct ivopts_data *data,
struct iv_use *use, struct iv_cand *cand,
enum tree_code *compare, tree *bound)
{
basic_block ex_bb;
edge exit;
- struct tree_niter_desc niter, new_niter;
- tree wider_type, type, base;
+ struct tree_niter_desc *niter;
+ tree nit, nit_type;
+ tree wider_type, period, per_type;
+ struct loop *loop = data->current_loop;
/* For now works only for exits that dominate the loop latch. TODO -- extend
for other conditions inside loop body. */
if (flow_bb_inside_loop_p (loop, exit->dest))
return false;
- niter.niter = NULL_TREE;
- number_of_iterations_exit (loop, exit, &niter);
- if (!niter.niter
- || !integer_nonzerop (niter.assumptions)
- || !integer_zerop (niter.may_be_zero))
+ niter = niter_for_exit (data, exit);
+ if (!niter
+ || !zero_p (niter->may_be_zero))
return false;
- if (exit->flags & EDGE_TRUE_VALUE)
- *compare = EQ_EXPR;
- else
- *compare = NE_EXPR;
-
- *bound = cand_value_at (loop, cand, use->stmt, niter.niter);
+ nit = niter->niter;
+ nit_type = TREE_TYPE (nit);
- /* Let us check there is not some problem with overflows, by checking that
- the number of iterations is unchanged. */
- base = cand->iv->base;
- type = TREE_TYPE (base);
- if (stmt_after_increment (loop, cand, use->stmt))
- base = fold (build2 (PLUS_EXPR, type, base, cand->iv->step));
-
- new_niter.niter = NULL_TREE;
- number_of_iterations_cond (TREE_TYPE (cand->iv->base), base,
- cand->iv->step, NE_EXPR, *bound, NULL_TREE,
- &new_niter);
- if (!new_niter.niter
- || !integer_nonzerop (new_niter.assumptions)
- || !integer_zerop (new_niter.may_be_zero))
+ /* Determine whether we may use the variable to test whether niter iterations
+ elapsed. This is the case iff the period of the induction variable is
+ greater than the number of iterations. */
+ period = iv_period (cand->iv);
+ if (!period)
return false;
+ per_type = TREE_TYPE (period);
+
+ wider_type = TREE_TYPE (period);
+ if (TYPE_PRECISION (nit_type) < TYPE_PRECISION (per_type))
+ wider_type = per_type;
+ else
+ wider_type = nit_type;
- wider_type = TREE_TYPE (new_niter.niter);
- if (TYPE_PRECISION (wider_type) < TYPE_PRECISION (TREE_TYPE (niter.niter)))
- wider_type = TREE_TYPE (niter.niter);
- if (!operand_equal_p (fold_convert (wider_type, niter.niter),
- fold_convert (wider_type, new_niter.niter), 0))
+ if (!integer_nonzerop (fold (build2 (GE_EXPR, boolean_type_node,
+ fold_convert (wider_type, period),
+ fold_convert (wider_type, nit)))))
return false;
+ if (exit->flags & EDGE_TRUE_VALUE)
+ *compare = EQ_EXPR;
+ else
+ *compare = NE_EXPR;
+
+ *bound = cand_value_at (loop, cand, use->stmt, nit);
return true;
}
return false;
}
- if (may_eliminate_iv (data->current_loop, use, cand, &compare, &bound))
+ if (may_eliminate_iv (data, use, cand, &compare, &bound))
{
bitmap depends_on = NULL;
unsigned cost = force_var_cost (data, bound, &depends_on);
a direct computation. If so, the formula is stored to *VALUE. */
static bool
-may_replace_final_value (struct loop *loop, struct iv_use *use, tree *value)
+may_replace_final_value (struct ivopts_data *data, struct iv_use *use,
+ tree *value)
{
+ struct loop *loop = data->current_loop;
edge exit;
struct tree_niter_desc *niter;
gcc_assert (dominated_by_p (CDI_DOMINATORS, exit->src,
bb_for_stmt (use->stmt)));
- niter = &loop_data (loop)->niter;
- if (!niter->niter
- || !operand_equal_p (niter->assumptions, boolean_true_node, 0)
- || !operand_equal_p (niter->may_be_zero, boolean_false_node, 0))
+ niter = niter_for_single_dom_exit (data);
+ if (!niter
+ || !zero_p (niter->may_be_zero))
return false;
*value = iv_value (use->iv, niter->niter);
if (!cand->iv)
{
- if (!may_replace_final_value (loop, use, &value))
+ if (!may_replace_final_value (data, use, &value))
{
set_use_iv_cost (data, use, cand, INFTY, NULL);
return false;
block_stmt_iterator bsi = bsi_for_stmt (use->stmt);
enum tree_code compare;
- if (may_eliminate_iv (data->current_loop,
- use, cand, &compare, &bound))
+ if (may_eliminate_iv (data, use, cand, &compare, &bound))
{
op = force_gimple_operand (unshare_expr (bound), &stmts,
true, NULL_TREE);
{
if (!cand->iv)
{
- bool ok = may_replace_final_value (data->current_loop, use, &value);
+ bool ok = may_replace_final_value (data, use, &value);
gcc_assert (ok);
}
else
unsigned i, j;
bitmap_iterator bi;
+ htab_empty (data->niters);
+
EXECUTE_IF_SET_IN_BITMAP (data->relevant, 0, i, bi)
{
struct version_info *info;
free (data->version_info);
BITMAP_XFREE (data->relevant);
BITMAP_XFREE (data->important_candidates);
+ htab_delete (data->niters);
VARRAY_FREE (decl_rtl_to_reset);
VARRAY_FREE (data->iv_uses);
/* Remove the ivs that are unused after rewriting. */
remove_unused_ivs (data);
- loop_commit_inserts ();
-
/* We have changed the structure of induction variables; it might happen
that definitions in the scev database refer to some of them that were
eliminated. */
return (TREE_INT_CST_LOW (arg) != 0 || TREE_INT_CST_HIGH (arg) != 0);
}
-/* Returns number of zeros at the end of binary representation of X.
-
- ??? Use ffs if available? */
-
-static tree
-num_ending_zeros (tree x)
-{
- unsigned HOST_WIDE_INT fr, nfr;
- unsigned num, abits;
- tree type = TREE_TYPE (x);
-
- if (TREE_INT_CST_LOW (x) == 0)
- {
- num = HOST_BITS_PER_WIDE_INT;
- fr = TREE_INT_CST_HIGH (x);
- }
- else
- {
- num = 0;
- fr = TREE_INT_CST_LOW (x);
- }
-
- for (abits = HOST_BITS_PER_WIDE_INT / 2; abits; abits /= 2)
- {
- nfr = fr >> abits;
- if (nfr << abits == fr)
- {
- num += abits;
- fr = nfr;
- }
- }
-
- if (num > TYPE_PRECISION (type))
- num = TYPE_PRECISION (type);
-
- return build_int_cst_type (type, num);
-}
-
/* Returns inverse of X modulo 2^s, where MASK = 2^s-1. */
static tree
return integer_onep (niter->assumptions);
}
+/* Try to determine the number of iterations of LOOP. If we succeed,
+ expression giving number of iterations is returned and *EXIT is
+ set to the edge from that the information is obtained. Otherwise
+ chrec_dont_know is returned. */
+
+tree
+find_loop_niter (struct loop *loop, edge *exit)
+{
+ unsigned n_exits, i;
+ edge *exits = get_loop_exit_edges (loop, &n_exits);
+ edge ex;
+ tree niter = NULL_TREE, aniter;
+ struct tree_niter_desc desc;
+
+ *exit = NULL;
+ for (i = 0; i < n_exits; i++)
+ {
+ ex = exits[i];
+ if (!just_once_each_iteration_p (loop, ex->src))
+ continue;
+
+ if (!number_of_iterations_exit (loop, ex, &desc))
+ continue;
+
+ if (nonzero_p (desc.may_be_zero))
+ {
+ /* We exit in the first iteration through this exit.
+ We won't find anything better. */
+ niter = build_int_cst_type (unsigned_type_node, 0);
+ *exit = ex;
+ break;
+ }
+
+ if (!zero_p (desc.may_be_zero))
+ continue;
+
+ aniter = desc.niter;
+
+ if (!niter)
+ {
+ /* Nothing recorded yet. */
+ niter = aniter;
+ *exit = ex;
+ continue;
+ }
+
+ /* Prefer constants, the lower the better. */
+ if (TREE_CODE (aniter) != INTEGER_CST)
+ continue;
+
+ if (TREE_CODE (niter) != INTEGER_CST)
+ {
+ niter = aniter;
+ *exit = ex;
+ continue;
+ }
+
+ if (tree_int_cst_lt (aniter, niter))
+ {
+ niter = aniter;
+ *exit = ex;
+ continue;
+ }
+ }
+ free (exits);
+
+ return niter ? niter : chrec_dont_know;
+}
+
/*
Analysis of a number of iterations of a loop by a brute-force evaluation.
continue;
aniter = loop_niter_by_eval (loop, ex);
- if (chrec_contains_undetermined (aniter)
- || TREE_CODE (aniter) != INTEGER_CST)
+ if (chrec_contains_undetermined (aniter))
continue;
if (niter
- && !nonzero_p (fold (build2 (LT_EXPR, boolean_type_node,
- aniter, niter))))
+ && !tree_int_cst_lt (aniter, niter))
continue;
niter = aniter;