summaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-pre.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/tree-ssa-pre.c')
-rw-r--r--gcc/tree-ssa-pre.c277
1 files changed, 174 insertions, 103 deletions
diff --git a/gcc/tree-ssa-pre.c b/gcc/tree-ssa-pre.c
index 267c2fcfea2..c1cbe0ca650 100644
--- a/gcc/tree-ssa-pre.c
+++ b/gcc/tree-ssa-pre.c
@@ -377,6 +377,9 @@ typedef struct bb_bitmap_sets
the current iteration. */
bitmap_set_t new_sets;
+ /* A cache for value_dies_in_block_x. */
+ bitmap expr_dies;
+
/* True if we have visited this block during ANTIC calculation. */
unsigned int visited:1;
@@ -392,7 +395,8 @@ typedef struct bb_bitmap_sets
#define ANTIC_IN(BB) ((bb_value_sets_t) ((BB)->aux))->antic_in
#define PA_IN(BB) ((bb_value_sets_t) ((BB)->aux))->pa_in
#define NEW_SETS(BB) ((bb_value_sets_t) ((BB)->aux))->new_sets
-#define BB_VISITED(BB) ((bb_value_sets_t) ((BB)->aux))->visited
+#define EXPR_DIES(BB) ((bb_value_sets_t) ((BB)->aux))->expr_dies
+#define BB_VISITED(BB) ((bb_value_sets_t) ((BB)->aux))->visited
#define BB_DEFERRED(BB) ((bb_value_sets_t) ((BB)->aux))->deferred
@@ -906,26 +910,42 @@ print_pre_expr (FILE *outfile, const pre_expr expr)
VEC_iterate (vn_reference_op_s, ref->operands, i, vro);
i++)
{
+ bool closebrace = false;
if (vro->opcode != SSA_NAME
&& TREE_CODE_CLASS (vro->opcode) != tcc_declaration)
- fprintf (outfile, "%s ", tree_code_name [vro->opcode]);
+ {
+ fprintf (outfile, "%s", tree_code_name [vro->opcode]);
+ if (vro->op0)
+ {
+ fprintf (outfile, "<");
+ closebrace = true;
+ }
+ }
if (vro->op0)
{
- if (vro->op1)
- fprintf (outfile, "<");
print_generic_expr (outfile, vro->op0, 0);
if (vro->op1)
{
fprintf (outfile, ",");
print_generic_expr (outfile, vro->op1, 0);
}
- if (vro->op1)
- fprintf (outfile, ">");
+ if (vro->op2)
+ {
+ fprintf (outfile, ",");
+ print_generic_expr (outfile, vro->op2, 0);
+ }
}
+ if (closebrace)
+ fprintf (outfile, ">");
if (i != VEC_length (vn_reference_op_s, ref->operands) - 1)
fprintf (outfile, ",");
}
fprintf (outfile, "}");
+ if (ref->vuse)
+ {
+ fprintf (outfile, "@");
+ print_generic_expr (outfile, ref->vuse, 0);
+ }
}
break;
}
@@ -1227,48 +1247,47 @@ do_unary:
return e;
}
-/* Translate the vuses in the VUSES vector backwards through phi nodes
- in PHIBLOCK, so that they have the value they would have in
- BLOCK. */
+/* Translate the VUSE backwards through phi nodes in PHIBLOCK, so that
+ it has the value it would have in BLOCK. */
-static VEC(tree, gc) *
-translate_vuses_through_block (VEC (tree, gc) *vuses,
- basic_block phiblock,
- basic_block block)
+static tree
+translate_vuse_through_block (VEC (vn_reference_op_s, heap) *operands,
+ tree vuse,
+ basic_block phiblock,
+ basic_block block)
{
- tree oldvuse;
- VEC(tree, gc) *result = NULL;
- int i;
+ gimple phi = SSA_NAME_DEF_STMT (vuse);
+ tree ref;
- for (i = 0; VEC_iterate (tree, vuses, i, oldvuse); i++)
+ if (gimple_bb (phi) != phiblock)
+ return vuse;
+
+ if (gimple_code (phi) == GIMPLE_PHI)
{
- gimple phi = SSA_NAME_DEF_STMT (oldvuse);
- if (gimple_code (phi) == GIMPLE_PHI
- && gimple_bb (phi) == phiblock)
- {
- edge e = find_edge (block, gimple_bb (phi));
- if (e)
- {
- tree def = PHI_ARG_DEF (phi, e->dest_idx);
- if (def != oldvuse)
- {
- if (!result)
- result = VEC_copy (tree, gc, vuses);
- VEC_replace (tree, result, i, def);
- }
- }
- }
+ edge e = find_edge (block, phiblock);
+ return PHI_ARG_DEF (phi, e->dest_idx);
}
- /* We avoid creating a new copy of the vuses unless something
- actually changed, so result can be NULL. */
- if (result)
+ if (!(ref = get_ref_from_reference_ops (operands)))
+ return NULL_TREE;
+
+ /* Use the alias-oracle to find either the PHI node in this block,
+ the first VUSE used in this block that is equivalent to vuse or
+ the first VUSE which definition in this block kills the value. */
+ while (!stmt_may_clobber_ref_p (phi, ref))
{
- sort_vuses (result);
- return result;
+ vuse = gimple_vuse (phi);
+ phi = SSA_NAME_DEF_STMT (vuse);
+ if (gimple_bb (phi) != phiblock)
+ return vuse;
+ if (gimple_code (phi) == GIMPLE_PHI)
+ {
+ edge e = find_edge (block, phiblock);
+ return PHI_ARG_DEF (phi, e->dest_idx);
+ }
}
- return vuses;
+ return NULL_TREE;
}
/* Like find_leader, but checks for the value existing in SET1 *or*
@@ -1540,8 +1559,8 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
{
vn_reference_t ref = PRE_EXPR_REFERENCE (expr);
VEC (vn_reference_op_s, heap) *operands = ref->operands;
- VEC (tree, gc) *vuses = ref->vuses;
- VEC (tree, gc) *newvuses = vuses;
+ tree vuse = ref->vuse;
+ tree newvuse = vuse;
VEC (vn_reference_op_s, heap) *newoperands = NULL;
bool changed = false;
unsigned int i;
@@ -1632,15 +1651,24 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
return NULL;
}
- newvuses = translate_vuses_through_block (vuses, phiblock, pred);
- changed |= newvuses != vuses;
+ if (vuse)
+ {
+ newvuse = translate_vuse_through_block (newoperands,
+ vuse, phiblock, pred);
+ if (newvuse == NULL_TREE)
+ {
+ VEC_free (vn_reference_op_s, heap, newoperands);
+ return NULL;
+ }
+ }
+ changed |= newvuse != vuse;
if (changed)
{
unsigned int new_val_id;
pre_expr constant;
- tree result = vn_reference_lookup_pieces (newvuses,
+ tree result = vn_reference_lookup_pieces (newvuse,
newoperands,
&newref, true);
if (newref)
@@ -1671,7 +1699,7 @@ phi_translate_1 (pre_expr expr, bitmap_set_t set1, bitmap_set_t set2,
new_val_id = get_next_value_id ();
VEC_safe_grow_cleared (bitmap_set_t, heap, value_expressions,
get_max_value_id() + 1);
- newref = vn_reference_insert_pieces (newvuses,
+ newref = vn_reference_insert_pieces (newvuse,
newoperands,
result, new_val_id);
newoperands = NULL;
@@ -1846,24 +1874,73 @@ bitmap_find_leader (bitmap_set_t set, unsigned int val, gimple stmt)
static bool
value_dies_in_block_x (pre_expr expr, basic_block block)
{
- int i;
- tree vuse;
- VEC (tree, gc) *vuses = PRE_EXPR_REFERENCE (expr)->vuses;
+ tree vuse = PRE_EXPR_REFERENCE (expr)->vuse;
+ vn_reference_t refx = PRE_EXPR_REFERENCE (expr);
+ gimple def;
+ tree ref = NULL_TREE;
+ gimple_stmt_iterator gsi;
+ unsigned id = get_expression_id (expr);
+ bool res = false;
- /* Conservatively, a value dies if it's vuses are defined in this
- block, unless they come from phi nodes (which are merge operations,
- rather than stores. */
- for (i = 0; VEC_iterate (tree, vuses, i, vuse); i++)
+ if (!vuse)
+ return false;
+
+ /* Lookup a previously calculated result. */
+ if (EXPR_DIES (block)
+ && bitmap_bit_p (EXPR_DIES (block), id * 2))
+ return bitmap_bit_p (EXPR_DIES (block), id * 2 + 1);
+
+ /* A memory expression {e, VUSE} dies in the block if there is a
+ statement that may clobber e. If, starting statement walk from the
+ top of the basic block, a statement uses VUSE there can be no kill
+ inbetween that use and the original statement that loaded {e, VUSE},
+ so we can stop walking. */
+ for (gsi = gsi_start_bb (block); !gsi_end_p (gsi); gsi_next (&gsi))
{
- gimple def = SSA_NAME_DEF_STMT (vuse);
+ tree def_vuse, def_vdef;
+ def = gsi_stmt (gsi);
+ def_vuse = gimple_vuse (def);
+ def_vdef = gimple_vdef (def);
- if (gimple_bb (def) != block)
+ /* Not a memory statement. */
+ if (!def_vuse)
continue;
- if (gimple_code (def) == GIMPLE_PHI)
- continue;
- return true;
+
+ /* Not a may-def. */
+ if (!def_vdef)
+ {
+ /* A load with the same VUSE, we're done. */
+ if (def_vuse == vuse)
+ break;
+
+ continue;
+ }
+
+ /* Init ref only if we really need it. */
+ if (ref == NULL_TREE)
+ {
+ if (!(ref = get_ref_from_reference_ops (refx->operands)))
+ {
+ res = true;
+ break;
+ }
+ }
+ /* If the statement may clobber expr, it dies. */
+ if (stmt_may_clobber_ref_p (def, ref))
+ {
+ res = true;
+ break;
+ }
}
- return false;
+
+ /* Remember the result. */
+ if (!EXPR_DIES (block))
+ EXPR_DIES (block) = BITMAP_ALLOC (&grand_bitmap_obstack);
+ bitmap_set_bit (EXPR_DIES (block), id * 2);
+ if (res)
+ bitmap_set_bit (EXPR_DIES (block), id * 2 + 1);
+
+ return res;
}
@@ -1925,7 +2002,7 @@ vro_valid_in_sets (bitmap_set_t set1, bitmap_set_t set2,
ONLY SET2 CAN BE NULL.
This means that we have a leader for each part of the expression
(if it consists of values), or the expression is an SSA_NAME.
- For loads/calls, we also see if the vuses are killed in this block.
+ For loads/calls, we also see if the vuse is killed in this block.
*/
static bool
@@ -1970,6 +2047,15 @@ valid_in_sets (bitmap_set_t set1, bitmap_set_t set2, pre_expr expr,
if (!vro_valid_in_sets (set1, set2, vro))
return false;
}
+ if (ref->vuse)
+ {
+ gimple def_stmt = SSA_NAME_DEF_STMT (ref->vuse);
+ if (!gimple_nop_p (def_stmt)
+ && gimple_bb (def_stmt) != block
+ && !dominated_by_p (CDI_DOMINATORS,
+ block, gimple_bb (def_stmt)))
+ return false;
+ }
return !value_dies_in_block_x (expr, block);
}
default:
@@ -3664,7 +3750,7 @@ compute_avail (void)
continue;
copy_reference_ops_from_call (stmt, &ops);
- vn_reference_lookup_pieces (shared_vuses_from_stmt (stmt),
+ vn_reference_lookup_pieces (gimple_vuse (stmt),
ops, &ref, false);
VEC_free (vn_reference_op_s, heap, ops);
if (!ref)
@@ -3740,7 +3826,7 @@ compute_avail (void)
vn_reference_op_t vro;
vn_reference_lookup (gimple_assign_rhs1 (stmt),
- shared_vuses_from_stmt (stmt),
+ gimple_vuse (stmt),
false, &ref);
if (!ref)
continue;
@@ -3834,16 +3920,18 @@ do_SCCVN_insertion (gimple stmt, tree ssa_vn)
static unsigned int
eliminate (void)
{
+ VEC (gimple, heap) *to_remove = NULL;
basic_block b;
unsigned int todo = 0;
+ gimple_stmt_iterator gsi;
+ gimple stmt;
+ unsigned i;
FOR_EACH_BB (b)
{
- gimple_stmt_iterator i;
-
- for (i = gsi_start_bb (b); !gsi_end_p (i);)
+ for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi))
{
- gimple stmt = gsi_stmt (i);
+ stmt = gsi_stmt (gsi);
/* Lookup the RHS of the expression, see if we have an
available computation for it. If so, replace the RHS with
@@ -3896,10 +3984,9 @@ eliminate (void)
print_gimple_stmt (dump_file, stmt, 0, 0);
}
pre_stats.eliminations++;
- propagate_tree_value_into_stmt (&i, sprime);
- stmt = gsi_stmt (i);
+ propagate_tree_value_into_stmt (&gsi, sprime);
+ stmt = gsi_stmt (gsi);
update_stmt (stmt);
- gsi_next (&i);
continue;
}
@@ -3945,8 +4032,8 @@ eliminate (void)
sprime = fold_convert (gimple_expr_type (stmt), sprime);
pre_stats.eliminations++;
- propagate_tree_value_into_stmt (&i, sprime);
- stmt = gsi_stmt (i);
+ propagate_tree_value_into_stmt (&gsi, sprime);
+ stmt = gsi_stmt (gsi);
update_stmt (stmt);
/* If we removed EH side effects from the statement, clean
@@ -3971,45 +4058,20 @@ eliminate (void)
tree rhs = gimple_assign_rhs1 (stmt);
tree val;
val = vn_reference_lookup (gimple_assign_lhs (stmt),
- shared_vuses_from_stmt (stmt),
- true, NULL);
+ gimple_vuse (stmt), true, NULL);
if (TREE_CODE (rhs) == SSA_NAME)
rhs = VN_INFO (rhs)->valnum;
if (val
&& operand_equal_p (val, rhs, 0))
{
- def_operand_p def;
- use_operand_p use;
- vuse_vec_p usevec;
- ssa_op_iter oi;
- imm_use_iterator ui;
- gimple use_stmt;
-
if (dump_file && (dump_flags & TDF_DETAILS))
{
- fprintf (dump_file, "Deleted dead store ");
+ fprintf (dump_file, "Deleted redundant store ");
print_gimple_stmt (dump_file, stmt, 0, 0);
}
- /* Propagate all may-uses to the uses of their defs. */
- FOR_EACH_SSA_VDEF_OPERAND (def, usevec, stmt, oi)
- {
- tree vuse = VUSE_ELEMENT_VAR (*usevec, 0);
- tree vdef = DEF_FROM_PTR (def);
-
- /* If the vdef is used in an abnormal PHI node we
- have to propagate that flag to the vuse as well. */
- if (SSA_NAME_OCCURS_IN_ABNORMAL_PHI (vdef))
- SSA_NAME_OCCURS_IN_ABNORMAL_PHI (vuse) = 1;
-
- FOR_EACH_IMM_USE_STMT (use_stmt, ui, vdef)
- FOR_EACH_IMM_USE_ON_STMT (use, ui)
- SET_USE (use, vuse);
- }
-
- gsi_remove (&i, true);
- release_defs (stmt);
- continue;
+ /* Queue stmt for removal. */
+ VEC_safe_push (gimple, heap, to_remove, stmt);
}
}
/* Visit COND_EXPRs and fold the comparison with the
@@ -4036,11 +4098,20 @@ eliminate (void)
todo = TODO_cleanup_cfg;
}
}
-
- gsi_next (&i);
}
}
+ /* We cannot remove stmts during BB walk, especially not release SSA
+ names there as this confuses the VN machinery. */
+ for (i = 0; VEC_iterate (gimple, to_remove, i, stmt); ++i)
+ {
+ gsi = gsi_for_stmt (stmt);
+ unlink_stmt_vdef (stmt);
+ gsi_remove (&gsi, true);
+ release_defs (stmt);
+ }
+ VEC_free (gimple, heap, to_remove);
+
return todo;
}
@@ -4341,7 +4412,7 @@ execute_pre (bool do_fre ATTRIBUTE_UNUSED)
static unsigned int
do_pre (void)
{
- return TODO_rebuild_alias | execute_pre (false);
+ return execute_pre (false);
}
static bool
@@ -4366,7 +4437,7 @@ struct gimple_opt_pass pass_pre =
| PROP_ssa | PROP_alias, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
- 0, /* todo_flags_start */
+ TODO_rebuild_alias, /* todo_flags_start */
TODO_update_ssa_only_virtuals | TODO_dump_func | TODO_ggc_collect
| TODO_verify_ssa /* todo_flags_finish */
}