computing PHI pruning heuristics. */
static htab_t def_blocks;
+/* Stack of trees used to restore the global currdefs to its original
+ state after completing rewriting of a block and its dominator children.
+
+ This varray is used in two contexts. The first is rewriting of _DECL
+ nodes into SSA_NAMEs. In that context it's elements have the
+ following properties:
+
+ An SSA_NAME indicates that the current definition of the underlying
+ variable should be set to the given SSA_NAME.
+
+ A _DECL node indicates that the underlying variable has no current
+ definition.
+
+ A NULL node is used to mark the last node associated with the
+ current block.
+
+
+ This varray is also used when rewriting an SSA_NAME which has multiple
+ definition sites into multiple SSA_NAMEs. In that context entries come
+ in pairs.
+
+ The top entry is an SSA_NAME and the top-1 entry is the
+ current value for that SSA_NAME.
+
+ A NULL node at the top entry is used to mark the last node associated
+ with the current block. */
+static varray_type block_defs_stack;
+
/* Global data to attach to the main dominator walk structure. */
struct mark_def_sites_global_data
{
sbitmap names_to_rename;
};
-struct rewrite_block_data
-{
- varray_type block_defs;
-};
-
/* Information stored for ssa names. */
struct ssa_name_info
/* Local functions. */
static void rewrite_finalize_block (struct dom_walk_data *, basic_block);
-static void rewrite_initialize_block_local_data (struct dom_walk_data *,
- basic_block, bool);
static void rewrite_initialize_block (struct dom_walk_data *, basic_block);
static void rewrite_add_phi_arguments (struct dom_walk_data *, basic_block);
static void mark_def_sites (struct dom_walk_data *walk_data,
definitions are restored to the names that were valid in the
dominator parent of BB. */
-/* Initialize the local stacks.
-
- BLOCK_DEFS is used to save all the existing reaching definitions for
- the new SSA names introduced in this block. Before registering a
- new definition for a variable, the existing reaching definition is
- pushed into this stack so that we can restore it in Step 5. */
-
-static void
-rewrite_initialize_block_local_data (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
- basic_block bb ATTRIBUTE_UNUSED,
- bool recycled ATTRIBUTE_UNUSED)
-{
- struct rewrite_block_data *bd
- = (struct rewrite_block_data *)VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
-
- /* We get cleared memory from the allocator, so if the memory is
- not cleared, then we are re-using a previously allocated entry. In
- that case, we can also re-use the underlying virtual arrays. Just
- make sure we clear them before using them! */
- gcc_assert (!recycled || !bd->block_defs || !(VARRAY_ACTIVE_SIZE (bd->block_defs) > 0));
-}
-
-
/* SSA Rewriting Step 1. Initialization, create a block local stack
of reaching definitions for new SSA names produced in this block
(BLOCK_DEFS). Register new definitions for every PHI node in the
block. */
static void
-rewrite_initialize_block (struct dom_walk_data *walk_data, basic_block bb)
+rewrite_initialize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
+ basic_block bb)
{
tree phi;
- struct rewrite_block_data *bd
- = (struct rewrite_block_data *)VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n\nRenaming block #%d\n\n", bb->index);
+ /* Mark the unwind point for this block. */
+ VARRAY_PUSH_TREE (block_defs_stack, NULL_TREE);
+
/* Step 1. Register new definitions for every PHI node in the block.
Conceptually, all the PHI nodes are executed in parallel and each PHI
node introduces a new version for the associated variable. */
{
tree result = PHI_RESULT (phi);
- register_new_def (result, &bd->block_defs);
+ register_new_def (result, &block_defs_stack);
}
}
into the stack pointed by BLOCK_DEFS_P. */
static void
-ssa_register_new_def (tree var, tree def, varray_type *block_defs_p)
+ssa_register_new_def (tree var, tree def)
{
tree currdef;
}
currdef = get_current_def (var);
- if (! *block_defs_p)
- VARRAY_TREE_INIT (*block_defs_p, 20, "block_defs");
/* Push the current reaching definition into *BLOCK_DEFS_P. This stack is
later used by the dominator tree callbacks to restore the reaching
definitions for all the variables defined in the block after a recursive
visit to all its immediately dominated blocks. */
- VARRAY_PUSH_TREE (*block_defs_p, var);
- VARRAY_PUSH_TREE (*block_defs_p, currdef);
+ VARRAY_PUSH_TREE (block_defs_stack, currdef);
+ VARRAY_PUSH_TREE (block_defs_stack, var);
/* Set the current reaching definition for VAR to be DEF. */
set_current_def (var, def);
ssa_rewrite_initialize_block (struct dom_walk_data *walk_data, basic_block bb)
{
tree phi, new_name;
- struct rewrite_block_data *bd
- = (struct rewrite_block_data *)VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
sbitmap names_to_rename = walk_data->global_data;
edge e;
bool abnormal_phi;
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n\nRenaming block #%d\n\n", bb->index);
+ /* Mark the unwind point for this block. */
+ VARRAY_PUSH_TREE (block_defs_stack, NULL_TREE);
+
for (e = bb->pred; e; e = e->pred_next)
if (e->flags & EDGE_ABNORMAL)
break;
else
new_name = result;
- ssa_register_new_def (result, new_name, &bd->block_defs);
+ ssa_register_new_def (result, new_name);
}
}
}
}
-/* SSA Rewriting Step 5. Restore the current reaching definition for each
- variable referenced in the block (in reverse order). */
+/* Similar to restore_vars_to_original_value, except that it restores
+ CURRDEFS to its original value. */
static void
-rewrite_finalize_block (struct dom_walk_data *walk_data,
+rewrite_finalize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
basic_block bb ATTRIBUTE_UNUSED)
{
- struct rewrite_block_data *bd
- = (struct rewrite_block_data *)VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
-
- /* Step 5. Restore the current reaching definition for each variable
- referenced in the block (in reverse order). */
- while (bd->block_defs && VARRAY_ACTIVE_SIZE (bd->block_defs) > 0)
+ /* Restore CURRDEFS to its original state. */
+ while (VARRAY_ACTIVE_SIZE (block_defs_stack) > 0)
{
- tree tmp = VARRAY_TOP_TREE (bd->block_defs);
+ tree tmp = VARRAY_TOP_TREE (block_defs_stack);
tree saved_def, var;
- VARRAY_POP (bd->block_defs);
+ VARRAY_POP (block_defs_stack);
+
+ if (tmp == NULL_TREE)
+ break;
+
+ /* If we recorded an SSA_NAME, then make the SSA_NAME the current
+ definition of its underlying variable. If we recorded anything
+ else, it must have been an _DECL node and its current reaching
+ definition must have been NULL. */
if (TREE_CODE (tmp) == SSA_NAME)
{
saved_def = tmp;
saved_def = NULL;
var = tmp;
}
-
+
set_current_def (var, saved_def);
}
}
/* Ditto, for rewriting ssa names. */
static void
-ssa_rewrite_finalize_block (struct dom_walk_data *walk_data,
+ssa_rewrite_finalize_block (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
basic_block bb ATTRIBUTE_UNUSED)
{
- struct rewrite_block_data *bd
- = (struct rewrite_block_data *)VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
/* Step 5. Restore the current reaching definition for each variable
referenced in the block (in reverse order). */
- while (bd->block_defs && VARRAY_ACTIVE_SIZE (bd->block_defs) > 0)
+ while (VARRAY_ACTIVE_SIZE (block_defs_stack) > 0)
{
- tree var;
- tree saved_def = VARRAY_TOP_TREE (bd->block_defs);
- VARRAY_POP (bd->block_defs);
+ tree var = VARRAY_TOP_TREE (block_defs_stack);
+ tree saved_def;
+
+ VARRAY_POP (block_defs_stack);
- var = VARRAY_TOP_TREE (bd->block_defs);
- VARRAY_POP (bd->block_defs);
+ if (var == NULL)
+ break;
+
+ saved_def = VARRAY_TOP_TREE (block_defs_stack);
+ VARRAY_POP (block_defs_stack);
set_current_def (var, saved_def);
}
definition of a variable when a new real or virtual definition is found. */
static void
-rewrite_stmt (struct dom_walk_data *walk_data,
+rewrite_stmt (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
basic_block bb ATTRIBUTE_UNUSED,
block_stmt_iterator si)
{
use_operand_p use_p;
def_operand_p def_p;
ssa_op_iter iter;
- struct rewrite_block_data *bd;
-
- bd = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
stmt = bsi_stmt (si);
ann = stmt_ann (stmt);
/* FIXME: We shouldn't be registering new defs if the variable
doesn't need to be renamed. */
- register_new_def (DEF_FROM_PTR (def_p), &bd->block_defs);
+ register_new_def (DEF_FROM_PTR (def_p), &block_defs_stack);
}
}
ssa_op_iter iter;
use_operand_p use_p;
def_operand_p def_p;
- struct rewrite_block_data *bd;
sbitmap names_to_rename = walk_data->global_data;
- bd = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
-
stmt = bsi_stmt (si);
ann = stmt_ann (stmt);
continue;
SET_DEF (def_p, duplicate_ssa_name (var, stmt));
- ssa_register_new_def (var, DEF_FROM_PTR (def_p), &bd->block_defs);
+ ssa_register_new_def (var, DEF_FROM_PTR (def_p));
}
}
}
currdef = get_current_def (var);
- if (! *block_defs_p)
- VARRAY_TREE_INIT (*block_defs_p, 20, "block_defs");
/* Push the current reaching definition into *BLOCK_DEFS_P. This stack is
later used by the dominator tree callbacks to restore the reaching
/* Setup callbacks for the generic dominator tree walker. */
walk_data.walk_stmts_backward = false;
walk_data.dom_direction = CDI_DOMINATORS;
- walk_data.initialize_block_local_data = rewrite_initialize_block_local_data;
+ walk_data.initialize_block_local_data = NULL;
walk_data.before_dom_children_before_stmts = rewrite_initialize_block;
walk_data.before_dom_children_walk_stmts = rewrite_stmt;
walk_data.before_dom_children_after_stmts = rewrite_add_phi_arguments;
walk_data.after_dom_children_walk_stmts = NULL;
walk_data.after_dom_children_after_stmts = rewrite_finalize_block;
walk_data.global_data = NULL;
- walk_data.block_local_data_size = sizeof (struct rewrite_block_data);
+ walk_data.block_local_data_size = 0;
+
+ VARRAY_TREE_INIT (block_defs_stack, 10, "Block DEFS Stack");
/* Initialize the dominator walker. */
init_walk_dominator_tree (&walk_data);
mark_def_sites_global_data.names_to_rename = snames_to_rename;
walk_data.global_data = &mark_def_sites_global_data;
+ VARRAY_TREE_INIT (block_defs_stack, 10, "Block DEFS Stack");
+
/* We do not have any local data. */
walk_data.block_local_data_size = 0;
/* Setup callbacks for the generic dominator tree walker. */
walk_data.walk_stmts_backward = false;
walk_data.dom_direction = CDI_DOMINATORS;
- walk_data.initialize_block_local_data
- = rewrite_initialize_block_local_data;
+ walk_data.initialize_block_local_data = NULL;
walk_data.before_dom_children_before_stmts = ssa_rewrite_initialize_block;
walk_data.before_dom_children_walk_stmts = ssa_rewrite_stmt;
walk_data.before_dom_children_after_stmts = ssa_rewrite_phi_arguments;
walk_data.after_dom_children_walk_stmts = NULL;
walk_data.after_dom_children_after_stmts = ssa_rewrite_finalize_block;
walk_data.global_data = snames_to_rename;
- walk_data.block_local_data_size = sizeof (struct rewrite_block_data);
+ walk_data.block_local_data_size = 0;
/* Initialize the dominator walker. */
init_walk_dominator_tree (&walk_data);
marker. */
static varray_type avail_exprs_stack;
+/* Stack of trees used to restore the global currdefs to its original
+ state after completing optimization of a block and its dominator children.
+
+ An SSA_NAME indicates that the current definition of the underlying
+ variable should be set to the given SSA_NAME.
+
+ A _DECL node indicates that the underlying variable has no current
+ definition.
+
+ A NULL node is used to mark the last node associated with the
+ current block. */
+varray_type block_defs_stack;
+
/* Stack of statements we need to rescan during finalization for newly
exposed variables.
in this basic block. We use this during finalization to know
which variables need their VRP data updated. */
varray_type vrp_variables;
-
- /* Array of tree pairs used to restore the global currdefs to its
- original state after completing optimization of a block and its
- dominator children. */
- varray_type block_defs;
};
struct eq_expr_value
static void restore_vars_to_original_value (varray_type locals,
unsigned limit,
varray_type table);
-static void restore_currdefs_to_original_value (varray_type locals,
- unsigned limit);
-static void register_definitions_for_stmt (tree, varray_type *);
+static void restore_currdefs_to_original_value (void);
+static void register_definitions_for_stmt (tree);
static edge single_incoming_edge_ignoring_loop_edges (basic_block);
/* Local version of fold that doesn't introduce cruft. */
/* Create our hash tables. */
avail_exprs = htab_create (1024, real_avail_expr_hash, avail_expr_eq, free);
VARRAY_TREE_INIT (avail_exprs_stack, 20, "Available expression stack");
+ VARRAY_TREE_INIT (block_defs_stack, 20, "Block DEFS stack");
VARRAY_TREE_INIT (const_and_copies, num_ssa_names, "const_and_copies");
nonzero_vars = BITMAP_XMALLOC ();
VARRAY_GENERIC_PTR_INIT (vrp_data, num_ssa_names, "vrp_data");
tree src = PHI_ARG_DEF_FROM_EDGE (phi, e);
tree dst = PHI_RESULT (phi);
record_const_or_copy (dst, src, &bd->const_and_copies);
- register_new_def (dst, &bd->block_defs);
+ register_new_def (dst, &block_defs_stack);
}
for (bsi = bsi_start (e->dest); ! bsi_end_p (bsi); bsi_next (&bsi))
the result of this statement is used later we can copy propagate
suitably. */
record_const_or_copy (lhs, cached_lhs, &bd->const_and_copies);
- register_new_def (lhs, &bd->block_defs);
+ register_new_def (lhs, &block_defs_stack);
}
/* If we stopped at a COND_EXPR or SWITCH_EXPR, then see if we know which
|| VARRAY_ACTIVE_SIZE (bd->nonzero_vars) == 0);
gcc_assert (!bd->vrp_variables
|| VARRAY_ACTIVE_SIZE (bd->vrp_variables) == 0);
- gcc_assert (!bd->block_defs
- || VARRAY_ACTIVE_SIZE (bd->block_defs) == 0);
}
}
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, "\n\nOptimizing block #%d\n\n", bb->index);
- /* Push a marker on AVAIL_EXPRS_STACK so that we know how far to unwind
- when we finalize this block. */
+ /* Push a marker on the stacks of local information so that we know how
+ far to unwind when we finalize this block. */
VARRAY_PUSH_TREE (avail_exprs_stack, NULL_TREE);
+ VARRAY_PUSH_TREE (block_defs_stack, NULL_TREE);
record_equivalences_from_incoming_edge (walk_data, bb);
/* Similar to restore_vars_to_original_value, except that it restores
CURRDEFS to its original value. */
static void
-restore_currdefs_to_original_value (varray_type locals, unsigned limit)
+restore_currdefs_to_original_value (void)
{
- if (!locals)
- return;
-
/* Restore CURRDEFS to its original state. */
- while (VARRAY_ACTIVE_SIZE (locals) > limit)
+ while (VARRAY_ACTIVE_SIZE (block_defs_stack) > 0)
{
- tree tmp = VARRAY_TOP_TREE (locals);
+ tree tmp = VARRAY_TOP_TREE (block_defs_stack);
tree saved_def, var;
- VARRAY_POP (locals);
+ VARRAY_POP (block_defs_stack);
+
+ if (tmp == NULL_TREE)
+ break;
/* If we recorded an SSA_NAME, then make the SSA_NAME the current
definition of its underlying variable. If we recorded anything
|| phi_nodes (true_edge->dest))
{
unsigned const_and_copies_limit;
- unsigned currdefs_limit;
const_and_copies_limit
= bd->const_and_copies ? VARRAY_ACTIVE_SIZE (bd->const_and_copies)
: 0;
- currdefs_limit
- = bd->block_defs ? VARRAY_ACTIVE_SIZE (bd->block_defs) : 0;
-
/* Push a marker onto the available expression stack so that we
unwind any expressions related to the TRUE arm before processing
the false arm below. */
VARRAY_PUSH_TREE (avail_exprs_stack, NULL_TREE);
+ VARRAY_PUSH_TREE (block_defs_stack, NULL_TREE);
/* Record any equivalences created by following this edge. */
if (TREE_CODE_CLASS (cond_code) == '<')
restore_vars_to_original_value (bd->const_and_copies,
const_and_copies_limit,
const_and_copies);
- restore_currdefs_to_original_value (bd->block_defs, currdefs_limit);
+ restore_currdefs_to_original_value ();
}
/* Similarly for the ELSE arm. */
remove_local_expressions_from_table ();
restore_nonzero_vars_to_original_value (bd->nonzero_vars, 0, nonzero_vars);
restore_vars_to_original_value (bd->const_and_copies, 0, const_and_copies);
- restore_currdefs_to_original_value (bd->block_defs, 0);
+ restore_currdefs_to_original_value ();
/* Remove VRP records associated with this basic block. They are no
longer valid.
even if we do not know its exact value. */
static void
-record_equivalences_from_phis (struct dom_walk_data *walk_data, basic_block bb)
+record_equivalences_from_phis (struct dom_walk_data *walk_data ATTRIBUTE_UNUSED,
+ basic_block bb)
{
- struct dom_walk_block_data *bd
- = VARRAY_TOP_GENERIC_PTR (walk_data->block_data_stack);
tree phi;
for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
if (i == PHI_NUM_ARGS (phi))
bitmap_set_bit (nonzero_vars, SSA_NAME_VERSION (PHI_RESULT (phi)));
- register_new_def (lhs, &bd->block_defs);
+ register_new_def (lhs, &block_defs_stack);
}
}
may_optimize_p,
ann);
- register_definitions_for_stmt (stmt, &bd->block_defs);
+ register_definitions_for_stmt (stmt);
/* If STMT is a COND_EXPR and it was modified, then we may know
where it goes. If that is the case, then mark the CFG as altered.
and CURRDEFS. */
static void
-register_definitions_for_stmt (tree stmt, varray_type *block_defs_p)
+register_definitions_for_stmt (tree stmt)
{
tree def;
ssa_op_iter iter;
/* FIXME: We shouldn't be registering new defs if the variable
doesn't need to be renamed. */
- register_new_def (def, block_defs_p);
+ register_new_def (def, &block_defs_stack);
}
}