/* Predictive commoning.
- Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2007, 2008, 2009 Free Software Foundation, Inc.
This file is part of GCC.
/* Data references (or phi nodes that carry data reference values across
loop iterations). */
-typedef struct dref
+typedef struct dref_d
{
/* The reference itself. */
struct data_reference *ref;
/* For combination chains, the operator and the two chains that are
combined, and the type of the result. */
- enum tree_code operator;
+ enum tree_code op;
tree rslt_type;
struct chain *ch1, *ch2;
if (chain->type == CT_COMBINATION)
{
fprintf (file, " equal to %p %s %p in type ",
- (void *) chain->ch1, op_symbol_code (chain->operator),
+ (void *) chain->ch1, op_symbol_code (chain->op),
(void *) chain->ch2);
print_generic_expr (file, chain->rslt_type, TDF_SLIM);
fprintf (file, "\n");
comps[ca] = comp;
}
- dataref = XCNEW (struct dref);
+ dataref = XCNEW (struct dref_d);
dataref->ref = dr;
dataref->stmt = DR_STMT (dr);
dataref->offset = double_int_zero;
comp = &act->next;
else
{
+ dref ref;
+ unsigned i;
+
*comp = act->next;
+ for (i = 0; VEC_iterate (dref, act->refs, i, ref); i++)
+ free (ref);
release_component (act);
}
}
gcc_assert (double_int_scmp (root->offset, ref->offset) <= 0);
dist = double_int_add (ref->offset, double_int_neg (root->offset));
if (double_int_ucmp (uhwi_to_double_int (MAX_DISTANCE), dist) <= 0)
- return;
+ {
+ free (ref);
+ return;
+ }
gcc_assert (double_int_fits_in_uhwi_p (dist));
VEC_safe_push (dref, heap, chain->refs, ref);
aff_tree diff, base, step;
double_int off;
- if (!DR_BASE_ADDRESS (ref))
- return false;
-
/* Both REF and ROOT must be accessing the same object. */
if (!operand_equal_p (DR_BASE_ADDRESS (ref), DR_BASE_ADDRESS (root), 0))
return false;
memset (&init_dr, 0, sizeof (struct data_reference));
DR_REF (&init_dr) = init_ref;
DR_STMT (&init_dr) = phi;
- dr_analyze_innermost (&init_dr);
+ if (!dr_analyze_innermost (&init_dr))
+ return NULL;
if (!valid_initializer_p (&init_dr, ref->distance + 1, root->ref))
return NULL;
static void
insert_looparound_copy (chain_p chain, dref ref, gimple phi)
{
- dref nw = XCNEW (struct dref), aref;
+ dref nw = XCNEW (struct dref_d), aref;
unsigned i;
nw->stmt = phi;
}
/* Replace the reference in statement STMT with temporary variable
- NEW. If SET is true, NEW is instead initialized to the value of
+ NEW_TREE. If SET is true, NEW_TREE is instead initialized to the value of
the reference in the statement. IN_LHS is true if the reference
is in the lhs of STMT, false if it is in rhs. */
static void
-replace_ref_with (gimple stmt, tree new, bool set, bool in_lhs)
+replace_ref_with (gimple stmt, tree new_tree, bool set, bool in_lhs)
{
tree val;
gimple new_stmt;
remove_phi_node (&psi, false);
/* Turn the phi node into GIMPLE_ASSIGN. */
- new_stmt = gimple_build_assign (val, new);
+ new_stmt = gimple_build_assign (val, new_tree);
gsi_insert_before (&bsi, new_stmt, GSI_NEW_STMT);
return;
}
bsi = gsi_for_stmt (stmt);
- /* If we do not need to initialize NEW, just replace the use of OLD. */
+ /* If we do not need to initialize NEW_TREE, just replace the use of OLD. */
if (!set)
{
gcc_assert (!in_lhs);
- gimple_assign_set_rhs_from_tree (&bsi, new);
+ gimple_assign_set_rhs_from_tree (&bsi, new_tree);
stmt = gsi_stmt (bsi);
update_stmt (stmt);
return;
val = gimple_assign_lhs (stmt);
}
- new_stmt = gimple_build_assign (new, unshare_expr (val));
+ new_stmt = gimple_build_assign (new_tree, unshare_expr (val));
gsi_insert_after (&bsi, new_stmt, GSI_NEW_STMT);
}
else
return NULL_TREE;
- ok = simple_iv (loop, first_stmt (loop->header), idx, &iv, true);
+ ok = simple_iv (loop, loop, idx, &iv, true);
if (!ok)
return NULL_TREE;
iv.base = expand_simple_operations (iv.base);
tree e1 = get_init_expr (chain->ch1, index);
tree e2 = get_init_expr (chain->ch2, index);
- return fold_build2 (chain->operator, chain->rslt_type, e1, e2);
+ return fold_build2 (chain->op, chain->rslt_type, e1, e2);
}
else
return VEC_index (tree, chain->inits, index);
void
mark_virtual_ops_for_renaming (gimple stmt)
{
- ssa_op_iter iter;
tree var;
if (gimple_code (stmt) == GIMPLE_PHI)
}
update_stmt (stmt);
-
- FOR_EACH_SSA_TREE_OPERAND (var, stmt, iter, SSA_OP_ALL_VIRTUALS)
- {
- if (TREE_CODE (var) == SSA_NAME)
- var = SSA_NAME_VAR (var);
- mark_sym_for_renaming (var);
- }
-}
-
-/* Calls mark_virtual_ops_for_renaming for all members of LIST. */
-
-static void
-mark_virtual_ops_for_renaming_list (gimple_seq list)
-{
- gimple_stmt_iterator gsi;
-
- for (gsi = gsi_start (list); !gsi_end_p (gsi); gsi_next (&gsi))
- mark_virtual_ops_for_renaming (gsi_stmt (gsi));
+ if (gimple_vuse (stmt))
+ mark_sym_for_renaming (gimple_vop (cfun));
}
/* Returns a new temporary variable used for the I-th variable carrying
init = force_gimple_operand (init, &stmts, true, NULL_TREE);
if (stmts)
- {
- mark_virtual_ops_for_renaming_list (stmts);
- gsi_insert_seq_on_edge_immediate (entry, stmts);
- }
+ gsi_insert_seq_on_edge_immediate (entry, stmts);
phi = create_phi_node (var, loop->header);
SSA_NAME_DEF_STMT (var) = phi;
- add_phi_arg (phi, init, entry);
- add_phi_arg (phi, next, latch);
+ add_phi_arg (phi, init, entry, UNKNOWN_LOCATION);
+ add_phi_arg (phi, next, latch, UNKNOWN_LOCATION);
}
}
init = force_gimple_operand (init, &stmts, written, NULL_TREE);
if (stmts)
- {
- mark_virtual_ops_for_renaming_list (stmts);
- gsi_insert_seq_on_edge_immediate (entry, stmts);
- }
+ gsi_insert_seq_on_edge_immediate (entry, stmts);
if (written)
{
next = VEC_index (tree, *vars, 1);
phi = create_phi_node (var, loop->header);
SSA_NAME_DEF_STMT (var) = phi;
- add_phi_arg (phi, init, entry);
- add_phi_arg (phi, next, latch);
+ add_phi_arg (phi, init, entry, UNKNOWN_LOCATION);
+ add_phi_arg (phi, next, latch, UNKNOWN_LOCATION);
}
else
{
execute_pred_commoning (loop, dta->chains, dta->tmp_vars);
}
-/* Returns true if we can and should unroll LOOP FACTOR times. Number
- of iterations of the loop is returned in NITER. */
-
-static bool
-should_unroll_loop_p (struct loop *loop, unsigned factor,
- struct tree_niter_desc *niter)
-{
- edge exit;
-
- if (factor == 1)
- return false;
-
- /* Check whether unrolling is possible. We only want to unroll loops
- for that we are able to determine number of iterations. We also
- want to split the extra iterations of the loop from its end,
- therefore we require that the loop has precisely one
- exit. */
-
- exit = single_dom_exit (loop);
- if (!exit)
- return false;
-
- if (!number_of_iterations_exit (loop, exit, niter, false))
- return false;
-
- /* And of course, we must be able to duplicate the loop. */
- if (!can_duplicate_loop_p (loop))
- return false;
-
- /* The final loop should be small enough. */
- if (tree_num_loop_insns (loop, &eni_size_weights) * factor
- > (unsigned) PARAM_VALUE (PARAM_MAX_UNROLLED_INSNS))
- return false;
-
- return true;
-}
-
/* Base NAME and all the names in the chain of phi nodes that use it
on variable VAR. The phi nodes are recognized by being in the copies of
the header of the LOOP. */
new_chain = XCNEW (struct chain);
new_chain->type = CT_COMBINATION;
- new_chain->operator = op;
+ new_chain->op = op;
new_chain->ch1 = ch1;
new_chain->ch2 = ch2;
new_chain->rslt_type = rslt_type;
for (i = 0; (VEC_iterate (dref, ch1->refs, i, r1)
&& VEC_iterate (dref, ch2->refs, i, r2)); i++)
{
- nw = XCNEW (struct dref);
+ nw = XCNEW (struct dref_d);
nw->stmt = stmt_combining_refs (r1, r2);
nw->distance = r1->distance;
}
}
-/* Sets alias information based on data reference DR for REF,
- if necessary. */
-
-static void
-set_alias_info (tree ref, struct data_reference *dr)
-{
- tree var;
- tree tag = DR_SYMBOL_TAG (dr);
-
- gcc_assert (tag != NULL_TREE);
-
- ref = get_base_address (ref);
- if (!ref || !INDIRECT_REF_P (ref))
- return;
-
- var = SSA_NAME_VAR (TREE_OPERAND (ref, 0));
- if (var_ann (var)->symbol_mem_tag)
- return;
-
- if (!MTAG_P (tag))
- new_type_alias (var, tag, ref);
- else
- var_ann (var)->symbol_mem_tag = tag;
-}
-
/* Prepare initializers for CHAIN in LOOP. Returns false if this is
impossible because one of these initializers may trap, true otherwise. */
init = force_gimple_operand (init, &stmts, false, NULL_TREE);
if (stmts)
- {
- mark_virtual_ops_for_renaming_list (stmts);
- gsi_insert_seq_on_edge_immediate (entry, stmts);
- }
- set_alias_info (init, dr);
+ gsi_insert_seq_on_edge_immediate (entry, stmts);
VEC_replace (tree, chain->inits, i, init);
}
that its number of iterations is divisible by the factor. */
unroll_factor = determine_unroll_factor (chains);
scev_reset ();
- unroll = should_unroll_loop_p (loop, unroll_factor, &desc);
+ unroll = (unroll_factor > 1
+ && can_unroll_loop_p (loop, unroll_factor, &desc));
exit = single_dom_exit (loop);
/* Execute the predictive commoning transformations, and possibly unroll the
initialize_original_copy_tables ();
FOR_EACH_LOOP (li, loop, LI_ONLY_INNERMOST)
- {
- unrolled |= tree_predictive_commoning_loop (loop);
- }
+ if (optimize_loop_for_speed_p (loop))
+ {
+ unrolled |= tree_predictive_commoning_loop (loop);
+ }
if (unrolled)
{