Commit 40b178f4 by Richard Guenther Committed by Richard Biener

re PR tree-optimization/54489 (tree FRE uses an excessive amount of memory)

2012-09-12  Richard Guenther  <rguenther@suse.de>

	PR tree-optimization/54489
	* tree-ssa-pre.c: Include domwalk.h.
	(in_fre): Remove.
	(sccvn_valnum_from_value_id): New function.
	(debug_bitmap_sets_for): Simplify.
	(get_representative_for): Properly initialize the SCCVN valnum.
	(create_expression_by_pieces): Likewise.
	(insert_into_preds_of_block): Likewise.
	(can_PRE_operation): Remove.
	(make_values_for_phi): Simplify.
	(compute_avail): Likewise.
	(do_SCCVN_insertion): Remove.
	(eliminate_avail, eliminate_push_avail, eliminate_insert):
	New functions.
	(eliminate): Split and perform a domwalk.
	(eliminate_bb): Former eliminate part that is now dom-enter.
	(eliminate_leave_block): New function.
	(fini_eliminate): Likewise.
	(init_pre): Simplify.
	(fini_pre): Likewise.
	(execute_pre): Fold into do_pre and do_fre.
	(do_pre): Consume execute_pre.
	(do_fre): Likewise.
	* Makefile.in (tree-ssa-pre.o): Add domwalk.h dependency.

From-SVN: r191225
parent 0dadc271
2012-09-12 Richard Guenther <rguenther@suse.de>
PR tree-optimization/54489
* tree-ssa-pre.c: Include domwalk.h.
(in_fre): Remove.
(sccvn_valnum_from_value_id): New function.
(debug_bitmap_sets_for): Simplify.
(get_representative_for): Properly initialize the SCCVN valnum.
(create_expression_by_pieces): Likewise.
(insert_into_preds_of_block): Likewise.
(can_PRE_operation): Remove.
(make_values_for_phi): Simplify.
(compute_avail): Likewise.
(do_SCCVN_insertion): Remove.
(eliminate_avail, eliminate_push_avail, eliminate_insert):
New functions.
(eliminate): Split and perform a domwalk.
(eliminate_bb): Former eliminate part that is now dom-enter.
(eliminate_leave_block): New function.
(fini_eliminate): Likewise.
(init_pre): Simplify.
(fini_pre): Likewise.
(execute_pre): Fold into do_pre and do_fre.
(do_pre): Consume execute_pre.
(do_fre): Likewise.
* Makefile.in (tree-ssa-pre.o): Add domwalk.h dependency.
2012-09-12 Diego Novillo <dnovillo@google.com>
* vec.h: Remove compatibility notes for previous distinction
......
......@@ -2317,7 +2317,7 @@ tree-ssa-pre.o : tree-ssa-pre.c $(TREE_FLOW_H) $(CONFIG_H) \
$(TM_H) coretypes.h $(TREE_PASS_H) $(FLAGS_H) langhooks.h \
$(CFGLOOP_H) alloc-pool.h $(BASIC_BLOCK_H) $(BITMAP_H) $(HASH_TABLE_H) \
$(GIMPLE_H) $(TREE_INLINE_H) tree-iterator.h tree-ssa-sccvn.h $(PARAMS_H) \
$(DBGCNT_H) tree-scalar-evolution.h $(GIMPLE_PRETTY_PRINT_H)
$(DBGCNT_H) tree-scalar-evolution.h $(GIMPLE_PRETTY_PRINT_H) domwalk.h
tree-ssa-sccvn.o : tree-ssa-sccvn.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(TREE_H) $(DIAGNOSTIC_H) \
$(TM_H) coretypes.h dumpfile.h $(FLAGS_H) $(CFGLOOP_H) \
......
......@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-scalar-evolution.h"
#include "params.h"
#include "dbgcnt.h"
#include "domwalk.h"
/* TODO:
......@@ -351,8 +352,6 @@ get_or_alloc_expr_for_name (tree name)
return result;
}
static bool in_fre = false;
/* An unordered bitmap set. One bitmap tracks values, the other,
expressions. */
typedef struct bitmap_set
......@@ -637,6 +636,25 @@ get_expr_value_id (pre_expr expr)
}
}
/* Return a SCCVN valnum (SSA name or constant) for the PRE value-id VAL. */
static tree
sccvn_valnum_from_value_id (unsigned int val)
{
bitmap_iterator bi;
unsigned int i;
bitmap exprset = VEC_index (bitmap, value_expressions, val);
EXECUTE_IF_SET_IN_BITMAP (exprset, 0, i, bi)
{
pre_expr vexpr = expression_for_id (i);
if (vexpr->kind == NAME)
return VN_INFO (PRE_EXPR_NAME (vexpr))->valnum;
else if (vexpr->kind == CONSTANT)
return PRE_EXPR_CONSTANT (vexpr);
}
return NULL_TREE;
}
/* Remove an expression EXPR from a bitmapped set. */
static void
......@@ -1022,8 +1040,6 @@ DEBUG_FUNCTION void
debug_bitmap_sets_for (basic_block bb)
{
print_bitmap_set (stderr, AVAIL_OUT (bb), "avail_out", bb->index);
if (!in_fre)
{
print_bitmap_set (stderr, EXP_GEN (bb), "exp_gen", bb->index);
print_bitmap_set (stderr, PHI_GEN (bb), "phi_gen", bb->index);
print_bitmap_set (stderr, TMP_GEN (bb), "tmp_gen", bb->index);
......@@ -1031,7 +1047,6 @@ debug_bitmap_sets_for (basic_block bb)
if (do_partial_partial)
print_bitmap_set (stderr, PA_IN (bb), "pa_in", bb->index);
print_bitmap_set (stderr, NEW_SETS (bb), "new_sets", bb->index);
}
}
/* Print out the expressions that have VAL to OUTFILE. */
......@@ -1402,11 +1417,9 @@ get_representative_for (const pre_expr e)
that we will return. */
name = make_temp_ssa_name (get_expr_type (e), gimple_build_nop (), "pretmp");
VN_INFO_GET (name)->value_id = value_id;
if (e->kind == CONSTANT)
VN_INFO (name)->valnum = PRE_EXPR_CONSTANT (e);
else
VN_INFO (name)->valnum = sccvn_valnum_from_value_id (value_id);
if (VN_INFO (name)->valnum == NULL_TREE)
VN_INFO (name)->valnum = name;
add_to_value (value_id, get_or_alloc_expr_for_name (name));
if (dump_file)
{
......@@ -2563,23 +2576,6 @@ compute_antic (void)
sbitmap_free (changed_blocks);
}
/* Return true if OP is a tree which we can perform PRE on.
This may not match the operations we can value number, but in
a perfect world would. */
static bool
can_PRE_operation (tree op)
{
return UNARY_CLASS_P (op)
|| BINARY_CLASS_P (op)
|| COMPARISON_CLASS_P (op)
|| TREE_CODE (op) == MEM_REF
|| TREE_CODE (op) == COMPONENT_REF
|| TREE_CODE (op) == VIEW_CONVERT_EXPR
|| TREE_CODE (op) == CALL_EXPR
|| TREE_CODE (op) == ARRAY_REF;
}
/* Inserted expressions are placed onto this worklist, which is used
for performing quick dead code elimination of insertions we made
......@@ -3072,7 +3068,6 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
VN_INFO (forcedname)->value_id = get_next_value_id ();
nameexpr = get_or_alloc_expr_for_name (forcedname);
add_to_value (VN_INFO (forcedname)->value_id, nameexpr);
if (!in_fre)
bitmap_value_replace_in_set (NEW_SETS (block), nameexpr);
bitmap_value_replace_in_set (AVAIL_OUT (block), nameexpr);
}
......@@ -3097,9 +3092,12 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
we are creating the expression by pieces, and this particular piece of
the expression may have been represented. There is no harm in replacing
here. */
VN_INFO_GET (name)->valnum = name;
value_id = get_expr_value_id (expr);
VN_INFO (name)->value_id = value_id;
VN_INFO_GET (name)->value_id = value_id;
VN_INFO (name)->valnum = sccvn_valnum_from_value_id (value_id);
if (VN_INFO (name)->valnum == NULL_TREE)
VN_INFO (name)->valnum = name;
gcc_assert (VN_INFO (name)->valnum != NULL_TREE);
nameexpr = get_or_alloc_expr_for_name (name);
add_to_value (value_id, nameexpr);
if (NEW_SETS (block))
......@@ -3339,9 +3337,11 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
phi = create_phi_node (temp, block);
gimple_set_plf (phi, NECESSARY, false);
VN_INFO_GET (gimple_phi_result (phi))->valnum = gimple_phi_result (phi);
VN_INFO (gimple_phi_result (phi))->value_id = val;
bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (gimple_phi_result (phi)));
VN_INFO_GET (temp)->value_id = val;
VN_INFO (temp)->valnum = sccvn_valnum_from_value_id (val);
if (VN_INFO (temp)->valnum == NULL_TREE)
VN_INFO (temp)->valnum = temp;
bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (temp));
FOR_EACH_EDGE (pred, ei, block->preds)
{
pre_expr ae = VEC_index (pre_expr, avail, pred->dest_idx);
......@@ -3353,7 +3353,7 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
add_phi_arg (phi, PRE_EXPR_NAME (ae), pred, UNKNOWN_LOCATION);
}
newphi = get_or_alloc_expr_for_name (gimple_phi_result (phi));
newphi = get_or_alloc_expr_for_name (temp);
add_to_value (val, newphi);
/* The value should *not* exist in PHI_GEN, or else we wouldn't be doing
......@@ -3782,8 +3782,6 @@ add_to_exp_gen (basic_block block, tree op)
{
pre_expr result;
gcc_checking_assert (!in_fre);
if (TREE_CODE (op) == SSA_NAME && ssa_undefined_value_p (op))
return;
......@@ -3797,6 +3795,7 @@ static void
make_values_for_phi (gimple phi, basic_block block)
{
tree result = gimple_phi_result (phi);
unsigned i;
/* We have no need for virtual phis, as they don't represent
actual computations. */
......@@ -3806,9 +3805,6 @@ make_values_for_phi (gimple phi, basic_block block)
pre_expr e = get_or_alloc_expr_for_name (result);
add_to_value (get_expr_value_id (e), e);
bitmap_value_insert_into_set (AVAIL_OUT (block), e);
if (!in_fre)
{
unsigned i;
bitmap_insert_into_set (PHI_GEN (block), e);
for (i = 0; i < gimple_phi_num_args (phi); ++i)
{
......@@ -3819,7 +3815,6 @@ make_values_for_phi (gimple phi, basic_block block)
add_to_value (get_expr_value_id (e), e);
}
}
}
}
/* Compute the AVAIL set for all basic blocks.
......@@ -3855,7 +3850,6 @@ compute_avail (void)
e = get_or_alloc_expr_for_name (name);
add_to_value (get_expr_value_id (e), e);
if (!in_fre)
bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), e);
bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), e);
}
......@@ -3924,15 +3918,10 @@ compute_avail (void)
pre_expr e = get_or_alloc_expr_for_name (op);
add_to_value (get_expr_value_id (e), e);
if (!in_fre)
bitmap_insert_into_set (TMP_GEN (block), e);
bitmap_value_insert_into_set (AVAIL_OUT (block), e);
}
/* That's all we need to do when doing FRE. */
if (in_fre)
continue;
if (gimple_has_side_effects (stmt) || stmt_could_throw_p (stmt))
continue;
......@@ -4123,52 +4112,161 @@ compute_avail (void)
free (worklist);
}
/* Insert the expression for SSA_VN that SCCVN thought would be simpler
than the available expressions for it. The insertion point is
right before the first use in STMT. Returns the SSA_NAME that should
be used for replacement. */
/* Local state for the eliminate domwalk. */
static VEC (gimple, heap) *el_to_remove;
static VEC (gimple, heap) *el_to_update;
static unsigned int el_todo;
static VEC (tree, heap) *el_avail;
static VEC (tree, heap) *el_avail_stack;
/* Return a leader for OP that is available at the current point of the
eliminate domwalk. */
static tree
do_SCCVN_insertion (gimple stmt, tree ssa_vn)
eliminate_avail (tree op)
{
basic_block bb = gimple_bb (stmt);
gimple_stmt_iterator gsi;
gimple_seq stmts = NULL;
tree expr;
pre_expr e;
tree valnum = VN_INFO (op)->valnum;
if (TREE_CODE (valnum) == SSA_NAME)
{
if (SSA_NAME_IS_DEFAULT_DEF (valnum))
return valnum;
if (VEC_length (tree, el_avail) > SSA_NAME_VERSION (valnum))
return VEC_index (tree, el_avail, SSA_NAME_VERSION (valnum));
}
else if (is_gimple_min_invariant (valnum))
return valnum;
return NULL_TREE;
}
/* At the current point of the eliminate domwalk make OP available. */
/* First create a value expression from the expression we want
to insert and associate it with the value handle for SSA_VN. */
e = get_or_alloc_expr_for (vn_get_expr_for (ssa_vn));
if (e == NULL)
static void
eliminate_push_avail (tree op)
{
tree valnum = VN_INFO (op)->valnum;
if (TREE_CODE (valnum) == SSA_NAME)
{
if (VEC_length (tree, el_avail) <= SSA_NAME_VERSION (valnum))
VEC_safe_grow_cleared (tree, heap,
el_avail, SSA_NAME_VERSION (valnum) + 1);
VEC_replace (tree, el_avail, SSA_NAME_VERSION (valnum), op);
VEC_safe_push (tree, heap, el_avail_stack, op);
}
}
/* Insert the expression recorded by SCCVN for VAL at *GSI. Returns
the leader for the expression if insertion was successful. */
static tree
eliminate_insert (gimple_stmt_iterator *gsi, tree val)
{
tree expr = vn_get_expr_for (val);
if (!CONVERT_EXPR_P (expr)
&& TREE_CODE (expr) != VIEW_CONVERT_EXPR)
return NULL_TREE;
/* Then use create_expression_by_pieces to generate a valid
expression to insert at this point of the IL stream. */
expr = create_expression_by_pieces (bb, e, &stmts, stmt, NULL);
if (expr == NULL_TREE)
tree op = TREE_OPERAND (expr, 0);
tree leader = TREE_CODE (op) == SSA_NAME ? eliminate_avail (op) : op;
if (!leader)
return NULL_TREE;
gsi = gsi_for_stmt (stmt);
gsi_insert_seq_before (&gsi, stmts, GSI_SAME_STMT);
return expr;
tree res = make_temp_ssa_name (TREE_TYPE (val), NULL, "pretmp");
gimple tem = gimple_build_assign (res,
build1 (TREE_CODE (expr),
TREE_TYPE (expr), leader));
gsi_insert_before (gsi, tem, GSI_SAME_STMT);
VN_INFO_GET (res)->valnum = val;
if (TREE_CODE (leader) == SSA_NAME)
gimple_set_plf (SSA_NAME_DEF_STMT (leader), NECESSARY, true);
pre_stats.insertions++;
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Inserted ");
print_gimple_stmt (dump_file, tem, 0, 0);
}
return res;
}
/* Eliminate fully redundant computations. */
/* Perform elimination for the basic-block B during the domwalk. */
static unsigned int
eliminate (void)
static void
eliminate_bb (dom_walk_data *, basic_block b)
{
VEC (gimple, heap) *to_remove = NULL;
VEC (gimple, heap) *to_update = NULL;
basic_block b;
unsigned int todo = 0;
gimple_stmt_iterator gsi;
gimple stmt;
unsigned i;
FOR_EACH_BB (b)
/* Mark new bb. */
VEC_safe_push (tree, heap, el_avail_stack, NULL_TREE);
for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);)
{
gimple stmt, phi = gsi_stmt (gsi);
tree sprime = NULL_TREE, res = PHI_RESULT (phi);
gimple_stmt_iterator gsi2;
/* We want to perform redundant PHI elimination. Do so by
replacing the PHI with a single copy if possible.
Do not touch inserted, single-argument or virtual PHIs. */
if (gimple_phi_num_args (phi) == 1
|| virtual_operand_p (res))
{
gsi_next (&gsi);
continue;
}
sprime = eliminate_avail (res);
if (!sprime
|| sprime == res)
{
eliminate_push_avail (res);
gsi_next (&gsi);
continue;
}
else if (is_gimple_min_invariant (sprime))
{
if (!useless_type_conversion_p (TREE_TYPE (res),
TREE_TYPE (sprime)))
sprime = fold_convert (TREE_TYPE (res), sprime);
}
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Replaced redundant PHI node defining ");
print_generic_expr (dump_file, res, 0);
fprintf (dump_file, " with ");
print_generic_expr (dump_file, sprime, 0);
fprintf (dump_file, "\n");
}
remove_phi_node (&gsi, false);
if (inserted_exprs
&& !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))
&& TREE_CODE (sprime) == SSA_NAME)
gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
sprime = fold_convert (TREE_TYPE (res), sprime);
stmt = gimple_build_assign (res, sprime);
SSA_NAME_DEF_STMT (res) = stmt;
gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
gsi2 = gsi_after_labels (b);
gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
/* Queue the copy for eventual removal. */
VEC_safe_push (gimple, heap, el_to_remove, stmt);
/* If we inserted this PHI node ourself, it's not an elimination. */
if (inserted_exprs
&& bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
pre_stats.phis--;
else
pre_stats.eliminations++;
}
for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi))
{
tree lhs = NULL_TREE;
......@@ -4198,33 +4296,28 @@ eliminate (void)
&& (gimple_assign_rhs_code (stmt) != VAR_DECL
|| !is_global_var (rhs)
|| !DECL_HARD_REGISTER (rhs))))
&& !gimple_has_volatile_ops (stmt)
&& !has_zero_uses (lhs))
&& !gimple_has_volatile_ops (stmt))
{
tree sprime = NULL;
pre_expr lhsexpr = get_or_alloc_expr_for_name (lhs);
pre_expr sprimeexpr;
tree sprime;
gimple orig_stmt = stmt;
sprimeexpr = bitmap_find_leader (AVAIL_OUT (b),
get_expr_value_id (lhsexpr),
NULL);
if (sprimeexpr)
sprime = eliminate_avail (lhs);
if (!sprime)
{
if (sprimeexpr->kind == CONSTANT)
sprime = PRE_EXPR_CONSTANT (sprimeexpr);
else if (sprimeexpr->kind == NAME)
sprime = PRE_EXPR_NAME (sprimeexpr);
else
gcc_unreachable ();
/* If there is no existing usable leader but SCCVN thinks
it has an expression it wants to use as replacement,
insert that. */
tree val = VN_INFO (lhs)->valnum;
if (val != VN_TOP
&& TREE_CODE (val) == SSA_NAME
&& VN_INFO (val)->needs_insertion
&& (sprime = eliminate_insert (&gsi, val)) != NULL_TREE)
eliminate_push_avail (sprime);
}
else if (is_gimple_min_invariant (sprime))
{
/* If there is no existing leader but SCCVN knows this
value is constant, use that constant. */
if (!sprime && is_gimple_min_invariant (VN_INFO (lhs)->valnum))
{
sprime = VN_INFO (lhs)->valnum;
if (!useless_type_conversion_p (TREE_TYPE (lhs),
TREE_TYPE (sprime)))
sprime = fold_convert (TREE_TYPE (lhs), sprime);
......@@ -4255,18 +4348,10 @@ eliminate (void)
continue;
}
/* If there is no existing usable leader but SCCVN thinks
it has an expression it wants to use as replacement,
insert that. */
if (!sprime || sprime == lhs)
{
tree val = VN_INFO (lhs)->valnum;
if (val != VN_TOP
&& TREE_CODE (val) == SSA_NAME
&& VN_INFO (val)->needs_insertion
&& can_PRE_operation (vn_get_expr_for (val)))
sprime = do_SCCVN_insertion (stmt, val);
}
/* If there is no usable leader mark lhs as leader for its value. */
if (!sprime)
eliminate_push_avail (lhs);
if (sprime
&& sprime != lhs
&& (rhs == NULL_TREE
......@@ -4350,7 +4435,7 @@ eliminate (void)
}
/* Queue stmt for removal. */
VEC_safe_push (gimple, heap, to_remove, stmt);
VEC_safe_push (gimple, heap, el_to_remove, stmt);
}
}
/* Visit COND_EXPRs and fold the comparison with the
......@@ -4374,7 +4459,7 @@ eliminate (void)
else
gimple_cond_make_true (stmt);
update_stmt (stmt);
todo = TODO_cleanup_cfg;
el_todo = TODO_cleanup_cfg;
}
}
/* Visit indirect calls and turn them into direct calls if
......@@ -4409,12 +4494,12 @@ eliminate (void)
}
gimple_call_set_fn (stmt, fn);
VEC_safe_push (gimple, heap, to_update, stmt);
VEC_safe_push (gimple, heap, el_to_update, stmt);
/* When changing a call into a noreturn call, cfg cleanup
is needed to fix up the noreturn call. */
if (!was_noreturn && gimple_call_noreturn_p (stmt))
todo |= TODO_cleanup_cfg;
el_todo |= TODO_cleanup_cfg;
/* If we removed EH side-effects from the statement, clean
its EH information. */
......@@ -4439,91 +4524,59 @@ eliminate (void)
/* Changing an indirect call to a direct call may
have exposed different semantics. This may
require an SSA update. */
todo |= TODO_update_ssa_only_virtuals;
el_todo |= TODO_update_ssa_only_virtuals;
}
}
}
}
for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);)
{
gimple stmt, phi = gsi_stmt (gsi);
tree sprime = NULL_TREE, res = PHI_RESULT (phi);
pre_expr sprimeexpr, resexpr;
gimple_stmt_iterator gsi2;
/* We want to perform redundant PHI elimination. Do so by
replacing the PHI with a single copy if possible.
Do not touch inserted, single-argument or virtual PHIs. */
if (gimple_phi_num_args (phi) == 1
|| virtual_operand_p (res))
{
gsi_next (&gsi);
continue;
}
resexpr = get_or_alloc_expr_for_name (res);
sprimeexpr = bitmap_find_leader (AVAIL_OUT (b),
get_expr_value_id (resexpr), NULL);
if (sprimeexpr)
{
if (sprimeexpr->kind == CONSTANT)
sprime = PRE_EXPR_CONSTANT (sprimeexpr);
else if (sprimeexpr->kind == NAME)
sprime = PRE_EXPR_NAME (sprimeexpr);
else
gcc_unreachable ();
}
if (!sprime && is_gimple_min_invariant (VN_INFO (res)->valnum))
{
sprime = VN_INFO (res)->valnum;
if (!useless_type_conversion_p (TREE_TYPE (res),
TREE_TYPE (sprime)))
sprime = fold_convert (TREE_TYPE (res), sprime);
}
if (!sprime
|| sprime == res)
{
gsi_next (&gsi);
continue;
}
/* Make no longer available leaders no longer available. */
if (dump_file && (dump_flags & TDF_DETAILS))
{
fprintf (dump_file, "Replaced redundant PHI node defining ");
print_generic_expr (dump_file, res, 0);
fprintf (dump_file, " with ");
print_generic_expr (dump_file, sprime, 0);
fprintf (dump_file, "\n");
}
static void
eliminate_leave_block (dom_walk_data *, basic_block)
{
tree entry;
while ((entry = VEC_pop (tree, el_avail_stack)) != NULL_TREE)
VEC_replace (tree, el_avail,
SSA_NAME_VERSION (VN_INFO (entry)->valnum), NULL_TREE);
}
remove_phi_node (&gsi, false);
/* Eliminate fully redundant computations. */
if (!bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))
&& TREE_CODE (sprime) == SSA_NAME)
gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
static unsigned int
eliminate (void)
{
struct dom_walk_data walk_data;
gimple_stmt_iterator gsi;
gimple stmt;
unsigned i;
if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime)))
sprime = fold_convert (TREE_TYPE (res), sprime);
stmt = gimple_build_assign (res, sprime);
SSA_NAME_DEF_STMT (res) = stmt;
gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY));
need_eh_cleanup = BITMAP_ALLOC (NULL);
need_ab_cleanup = BITMAP_ALLOC (NULL);
gsi2 = gsi_after_labels (b);
gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT);
/* Queue the copy for eventual removal. */
VEC_safe_push (gimple, heap, to_remove, stmt);
/* If we inserted this PHI node ourself, it's not an elimination. */
if (bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)))
pre_stats.phis--;
else
pre_stats.eliminations++;
}
}
el_to_remove = NULL;
el_to_update = NULL;
el_todo = 0;
el_avail = NULL;
el_avail_stack = NULL;
walk_data.dom_direction = CDI_DOMINATORS;
walk_data.initialize_block_local_data = NULL;
walk_data.before_dom_children = eliminate_bb;
walk_data.after_dom_children = eliminate_leave_block;
walk_data.global_data = NULL;
walk_data.block_local_data_size = 0;
init_walk_dominator_tree (&walk_data);
walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
fini_walk_dominator_tree (&walk_data);
VEC_free (tree, heap, el_avail);
VEC_free (tree, heap, el_avail_stack);
/* We cannot remove stmts during BB walk, especially not release SSA
names there as this confuses the VN machinery. The stmts ending
up in to_remove are either stores or simple copies. */
FOR_EACH_VEC_ELT (gimple, to_remove, i, stmt)
up in el_to_remove are either stores or simple copies. */
FOR_EACH_VEC_ELT (gimple, el_to_remove, i, stmt)
{
tree lhs = gimple_assign_lhs (stmt);
tree rhs = gimple_assign_rhs1 (stmt);
......@@ -4539,7 +4592,8 @@ eliminate (void)
{
SET_USE (use_p, rhs);
update_stmt (use_stmt);
if (bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (lhs))
if (inserted_exprs
&& bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (lhs))
&& TREE_CODE (rhs) == SSA_NAME)
gimple_set_plf (SSA_NAME_DEF_STMT (rhs), NECESSARY, true);
}
......@@ -4553,21 +4607,43 @@ eliminate (void)
unlink_stmt_vdef (stmt);
if (gsi_remove (&gsi, true))
bitmap_set_bit (need_eh_cleanup, bb->index);
if (TREE_CODE (lhs) == SSA_NAME)
if (inserted_exprs
&& TREE_CODE (lhs) == SSA_NAME)
bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs));
release_defs (stmt);
}
}
VEC_free (gimple, heap, to_remove);
VEC_free (gimple, heap, el_to_remove);
/* We cannot update call statements with virtual operands during
SSA walk. This might remove them which in turn makes our
VN lattice invalid. */
FOR_EACH_VEC_ELT (gimple, to_update, i, stmt)
FOR_EACH_VEC_ELT (gimple, el_to_update, i, stmt)
update_stmt (stmt);
VEC_free (gimple, heap, to_update);
VEC_free (gimple, heap, el_to_update);
return todo;
return el_todo;
}
/* Perform CFG cleanups made necessary by elimination. */
static void
fini_eliminate (void)
{
bool do_eh_cleanup = !bitmap_empty_p (need_eh_cleanup);
bool do_ab_cleanup = !bitmap_empty_p (need_ab_cleanup);
if (do_eh_cleanup)
gimple_purge_all_dead_eh_edges (need_eh_cleanup);
if (do_ab_cleanup)
gimple_purge_all_dead_abnormal_call_edges (need_ab_cleanup);
BITMAP_FREE (need_eh_cleanup);
BITMAP_FREE (need_ab_cleanup);
if (do_eh_cleanup || do_ab_cleanup)
cleanup_tree_cfg ();
}
/* Borrow a bit of tree-ssa-dce.c for the moment.
......@@ -4767,7 +4843,7 @@ my_rev_post_order_compute (int *post_order, bool include_entry_exit)
/* Initialize data structures used by PRE. */
static void
init_pre (bool do_fre)
init_pre (void)
{
basic_block bb;
......@@ -4779,8 +4855,6 @@ init_pre (bool do_fre)
get_max_value_id() + 1);
name_to_id = NULL;
in_fre = do_fre;
inserted_exprs = BITMAP_ALLOC (NULL);
connect_infinite_loops_to_exit ();
......@@ -4804,28 +4878,19 @@ init_pre (bool do_fre)
sizeof (struct pre_expr_d), 30);
FOR_ALL_BB (bb)
{
if (!do_fre)
{
EXP_GEN (bb) = bitmap_set_new ();
PHI_GEN (bb) = bitmap_set_new ();
TMP_GEN (bb) = bitmap_set_new ();
}
AVAIL_OUT (bb) = bitmap_set_new ();
}
need_eh_cleanup = BITMAP_ALLOC (NULL);
need_ab_cleanup = BITMAP_ALLOC (NULL);
}
/* Deallocate data structures used by PRE. */
static void
fini_pre (bool do_fre)
fini_pre ()
{
bool do_eh_cleanup = !bitmap_empty_p (need_eh_cleanup);
bool do_ab_cleanup = !bitmap_empty_p (need_ab_cleanup);
free (postorder);
VEC_free (bitmap, heap, value_expressions);
BITMAP_FREE (inserted_exprs);
......@@ -4839,28 +4904,12 @@ fini_pre (bool do_fre)
free_aux_for_blocks ();
free_dominance_info (CDI_POST_DOMINATORS);
if (do_eh_cleanup)
gimple_purge_all_dead_eh_edges (need_eh_cleanup);
if (do_ab_cleanup)
gimple_purge_all_dead_abnormal_call_edges (need_ab_cleanup);
BITMAP_FREE (need_eh_cleanup);
BITMAP_FREE (need_ab_cleanup);
if (do_eh_cleanup || do_ab_cleanup)
cleanup_tree_cfg ();
if (!do_fre)
loop_optimizer_finalize ();
}
/* Main entry point to the SSA-PRE pass. DO_FRE is true if the caller
only wants to do full redundancy elimination. */
/* Gate and execute functions for PRE. */
static unsigned int
execute_pre (bool do_fre)
do_pre (void)
{
unsigned int todo = 0;
......@@ -4869,18 +4918,15 @@ execute_pre (bool do_fre)
/* This has to happen before SCCVN runs because
loop_optimizer_init may create new phis, etc. */
if (!do_fre)
loop_optimizer_init (LOOPS_NORMAL);
if (!run_scc_vn (do_fre ? VN_WALKREWRITE : VN_WALK))
if (!run_scc_vn (VN_WALK))
{
if (!do_fre)
loop_optimizer_finalize ();
return 0;
}
init_pre (do_fre);
init_pre ();
scev_initialize ();
/* Collect and value number expressions computed in each basic block. */
......@@ -4889,13 +4935,16 @@ execute_pre (bool do_fre)
if (dump_file && (dump_flags & TDF_DETAILS))
{
basic_block bb;
FOR_ALL_BB (bb)
{
print_bitmap_set (dump_file, EXP_GEN (bb), "exp_gen", bb->index);
print_bitmap_set (dump_file, PHI_GEN (bb), "phi_gen", bb->index);
print_bitmap_set (dump_file, TMP_GEN (bb), "tmp_gen", bb->index);
print_bitmap_set (dump_file, AVAIL_OUT (bb), "avail_out", bb->index);
print_bitmap_set (dump_file, EXP_GEN (bb),
"exp_gen", bb->index);
print_bitmap_set (dump_file, PHI_GEN (bb),
"phi_gen", bb->index);
print_bitmap_set (dump_file, TMP_GEN (bb),
"tmp_gen", bb->index);
print_bitmap_set (dump_file, AVAIL_OUT (bb),
"avail_out", bb->index);
}
}
......@@ -4904,7 +4953,7 @@ execute_pre (bool do_fre)
fixed, don't run it when he have an incredibly large number of
bb's. If we aren't going to run insert, there is no point in
computing ANTIC, either, even though it's plenty fast. */
if (!do_fre && n_basic_blocks < 4000)
if (n_basic_blocks < 4000)
{
compute_antic ();
insert ();
......@@ -4926,16 +4975,14 @@ execute_pre (bool do_fre)
statistics_counter_event (cfun, "Constified", pre_stats.constified);
clear_expression_ids ();
if (!do_fre)
{
remove_dead_inserted_code ();
todo |= TODO_verify_flow;
}
scev_finalize ();
fini_pre (do_fre);
fini_pre ();
fini_eliminate ();
loop_optimizer_finalize ();
if (!do_fre)
/* TODO: tail_merge_optimize may merge all predecessors of a block, in which
case we can merge the block with the remaining predecessor of the block.
It should either:
......@@ -4944,19 +4991,12 @@ execute_pre (bool do_fre)
- mark TODO_cleanup_cfg when necessary
- share the cfg cleanup with fini_pre. */
todo |= tail_merge_optimize (todo);
free_scc_vn ();
return todo;
}
/* Gate and execute functions for PRE. */
static unsigned int
do_pre (void)
{
return execute_pre (false);
}
static bool
gate_pre (void)
{
......@@ -4990,7 +5030,25 @@ struct gimple_opt_pass pass_pre =
static unsigned int
execute_fre (void)
{
return execute_pre (true);
unsigned int todo = 0;
if (!run_scc_vn (VN_WALKREWRITE))
return 0;
memset (&pre_stats, 0, sizeof (pre_stats));
/* Remove all the redundant expressions. */
todo |= eliminate ();
fini_eliminate ();
free_scc_vn ();
statistics_counter_event (cfun, "Insertions", pre_stats.insertions);
statistics_counter_event (cfun, "Eliminated", pre_stats.eliminations);
statistics_counter_event (cfun, "Constified", pre_stats.constified);
return todo;
}
static bool
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment