/* Dead store elimination
- Copyright (C) 2004 Free Software Foundation, Inc.
+ Copyright (C) 2004, 2005 Free Software Foundation, Inc.
This file is part of GCC.
It may help to think of this as first moving the earlier store to
the point immediately before the later store. Again, the single
- use of the virtual defintion and the post-dominance relationship
+ use of the virtual definition and the post-dominance relationship
ensure that such movement would be safe. Clearly if there are
back to back stores, then the second is redundant.
static void fix_stmt_v_may_defs (tree, tree);
static void record_voperand_set (bitmap, bitmap *, unsigned int);
+static unsigned max_stmt_uid; /* Maximal uid of a statement. Uids to phi
+ nodes are assigned using the versions of
+ ssa names they define. */
+
+/* Returns uid of statement STMT. */
+
+static unsigned
+get_stmt_uid (tree stmt)
+{
+ if (TREE_CODE (stmt) == PHI_NODE)
+ return SSA_NAME_VERSION (PHI_RESULT (stmt)) + max_stmt_uid;
+
+ return stmt_ann (stmt)->uid;
+}
+
/* Function indicating whether we ought to include information for 'var'
when calculating immediate uses. For this pass we only want use
information for virtual variables. */
static void
fix_phi_uses (tree phi, tree stmt)
{
- stmt_ann_t ann = stmt_ann (stmt);
- v_may_def_optype v_may_defs;
- unsigned int i;
- int j;
-
+ use_operand_p use_p;
+ def_operand_p def_p;
+ ssa_op_iter iter;
+ int i;
+ edge e;
+ edge_iterator ei;
+
+ FOR_EACH_EDGE (e, ei, PHI_BB (phi)->preds)
+ if (e->flags & EDGE_ABNORMAL)
+ break;
+
get_stmt_operands (stmt);
- v_may_defs = V_MAY_DEF_OPS (ann);
- /* Walk each V_MAY_DEF in STMT. */
- for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
+ FOR_EACH_SSA_MAYDEF_OPERAND (def_p, use_p, stmt, iter)
{
- tree v_may_def = V_MAY_DEF_RESULT (v_may_defs, i);
+ tree v_may_def = DEF_FROM_PTR (def_p);
+ tree v_may_use = USE_FROM_PTR (use_p);
/* Find any uses in the PHI which match V_MAY_DEF and replace
them with the appropriate V_MAY_DEF_OP. */
- for (j = 0; j < PHI_NUM_ARGS (phi); j++)
- if (v_may_def == PHI_ARG_DEF (phi, j))
- PHI_ARG_DEF (phi, j) = V_MAY_DEF_OP (v_may_defs, i);
+ for (i = 0; i < PHI_NUM_ARGS (phi); i++)
+ if (v_may_def == PHI_ARG_DEF (phi, i))
+ {
+ SET_PHI_ARG_DEF (phi, i, v_may_use);
+ /* Update if the new phi argument is an abnormal phi. */
+ if (e != NULL)
+ SSA_NAME_OCCURS_IN_ABNORMAL_PHI (v_may_use) = 1;
+ }
}
}
static void
fix_stmt_v_may_defs (tree stmt1, tree stmt2)
{
- stmt_ann_t ann1 = stmt_ann (stmt1);
- stmt_ann_t ann2 = stmt_ann (stmt2);
- v_may_def_optype v_may_defs1;
- v_may_def_optype v_may_defs2;
- unsigned int i, j;
+ bool found = false;
+ ssa_op_iter iter1;
+ ssa_op_iter iter2;
+ use_operand_p use1_p, use2_p;
+ def_operand_p def1_p, def2_p;
get_stmt_operands (stmt1);
get_stmt_operands (stmt2);
- v_may_defs1 = V_MAY_DEF_OPS (ann1);
- v_may_defs2 = V_MAY_DEF_OPS (ann2);
/* Walk each V_MAY_DEF_OP in stmt1. */
- for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs1); i++)
+ FOR_EACH_SSA_MAYDEF_OPERAND (def1_p, use1_p, stmt1, iter1)
{
- tree v_may_def1 = V_MAY_DEF_OP (v_may_defs1, i);
+ tree use = USE_FROM_PTR (use1_p);
/* Find the appropriate V_MAY_DEF_RESULT in STMT2. */
- for (j = 0; j < NUM_V_MAY_DEFS (v_may_defs2); j++)
+ FOR_EACH_SSA_MAYDEF_OPERAND (def2_p, use2_p, stmt2, iter2)
{
- if (v_may_def1 == V_MAY_DEF_RESULT (v_may_defs2, j))
+ tree def = DEF_FROM_PTR (def2_p);
+ if (use == def)
{
/* Update. */
- *V_MAY_DEF_OP_PTR (v_may_defs1, i) =
- V_MAY_DEF_OP (v_may_defs2, j);
- break;
- }
+ SET_USE (use1_p, USE_FROM_PTR (use2_p));
+ found = true;
+ break;
+ }
}
-#ifdef ENABLE_CHECKING
- /* If we did not find a corresponding V_MAY_DEF_RESULT, then something
- has gone terribly wrong. */
- if (j == NUM_V_MAY_DEFS (v_may_defs2))
- abort ();
-#endif
-
+ /* If we did not find a corresponding V_MAY_DEF_RESULT,
+ then something has gone terribly wrong. */
+ gcc_assert (found);
}
}
if (NUM_V_MAY_DEFS (v_may_defs) == 0)
return;
- /* We know we have virtual definitions. If this is a MODIFY_EXPR, then
- record it into our table. */
- if (TREE_CODE (stmt) == MODIFY_EXPR
- && TREE_CODE (TREE_OPERAND (stmt, 1)) != CALL_EXPR)
+ /* We know we have virtual definitions. If this is a MODIFY_EXPR that's
+ not also a function call, then record it into our table. */
+ if (get_call_expr_in (stmt))
+ return;
+
+ if (ann->has_volatile_ops)
+ return;
+
+ if (TREE_CODE (stmt) == MODIFY_EXPR)
{
dataflow_t df = get_immediate_uses (stmt);
unsigned int num_uses = num_immediate_uses (df);
tree use;
tree skipped_phi;
-
/* If there are no uses then there is nothing left to do. */
if (num_uses == 0)
{
same block. */
while (num_uses == 1
&& TREE_CODE (use) == PHI_NODE
- && bitmap_bit_p (dse_gd->stores, stmt_ann (use)->uid))
+ && bitmap_bit_p (dse_gd->stores, get_stmt_uid (use)))
{
/* Record the first PHI we skip so that we can fix its
uses if we find that STMT is a dead store. */
/* If we have precisely one immediate use at this point, then we may
have found redundant store. */
if (num_uses == 1
- && bitmap_bit_p (dse_gd->stores, stmt_ann (use)->uid)
+ && bitmap_bit_p (dse_gd->stores, get_stmt_uid (use))
&& operand_equal_p (TREE_OPERAND (stmt, 0),
TREE_OPERAND (use, 0), 0))
{
This allows us to cascade dead stores. */
redirect_immediate_uses (stmt, skipped_phi ? skipped_phi : use);
+ /* Be sure to remove any dataflow information attached to
+ this statement. */
+ free_df_for_stmt (stmt);
+
+ /* And release any SSA_NAMEs set in this statement back to the
+ SSA_NAME manager. */
+ release_defs (stmt);
+
/* Finally remove the dead store. */
bsi_remove (&bsi);
}
if (need_imm_uses_for (PHI_RESULT (phi)))
record_voperand_set (dse_gd->stores,
&bd->stores,
- get_stmt_ann (phi)->uid);
+ get_stmt_uid (phi));
}
static void
struct dse_global_data *dse_gd = walk_data->global_data;
bitmap stores = dse_gd->stores;
unsigned int i;
+ bitmap_iterator bi;
/* Unwind the stores noted in this basic block. */
if (bd->stores)
- EXECUTE_IF_SET_IN_BITMAP (bd->stores, 0, i, bitmap_clear_bit (stores, i););
+ EXECUTE_IF_SET_IN_BITMAP (bd->stores, 0, i, bi)
+ {
+ bitmap_clear_bit (stores, i);
+ }
}
static void
{
struct dom_walk_data walk_data;
struct dse_global_data dse_gd;
- unsigned int uid = 0;
basic_block bb;
/* Create a UID for each statement in the function. Ordering of the
UIDs is not important for this pass. */
+ max_stmt_uid = 0;
FOR_EACH_BB (bb)
{
block_stmt_iterator bsi;
- tree phi;
for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
- stmt_ann (bsi_stmt (bsi))->uid = uid++;
-
- for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
- stmt_ann (phi)->uid = uid++;
+ stmt_ann (bsi_stmt (bsi))->uid = max_stmt_uid++;
}
/* We might consider making this a property of each pass so that it
walk_data.block_local_data_size = sizeof (struct dse_block_local_data);
/* This is the main hash table for the dead store elimination pass. */
- dse_gd.stores = BITMAP_XMALLOC ();
+ dse_gd.stores = BITMAP_ALLOC (NULL);
walk_data.global_data = &dse_gd;
/* Initialize the dominator walker. */
fini_walk_dominator_tree (&walk_data);
/* Release the main bitmap. */
- BITMAP_XFREE (dse_gd.stores);
+ BITMAP_FREE (dse_gd.stores);
/* Free dataflow information. It's probably out of date now anyway. */
free_df ();
NULL, /* next */
0, /* static_pass_number */
TV_TREE_DSE, /* tv_id */
- PROP_cfg | PROP_ssa, /* properties_required */
+ PROP_cfg | PROP_ssa
+ | PROP_alias, /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
TODO_dump_func | TODO_ggc_collect /* todo_flags_finish */
- | TODO_verify_ssa
+ | TODO_verify_ssa,
+ 0 /* letter */
};