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> 2012-09-12 Diego Novillo <dnovillo@google.com>
* vec.h: Remove compatibility notes for previous distinction * 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) \ ...@@ -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 \ $(TM_H) coretypes.h $(TREE_PASS_H) $(FLAGS_H) langhooks.h \
$(CFGLOOP_H) alloc-pool.h $(BASIC_BLOCK_H) $(BITMAP_H) $(HASH_TABLE_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) \ $(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) \ tree-ssa-sccvn.o : tree-ssa-sccvn.c $(TREE_FLOW_H) $(CONFIG_H) \
$(SYSTEM_H) $(TREE_H) $(DIAGNOSTIC_H) \ $(SYSTEM_H) $(TREE_H) $(DIAGNOSTIC_H) \
$(TM_H) coretypes.h dumpfile.h $(FLAGS_H) $(CFGLOOP_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 ...@@ -43,6 +43,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-scalar-evolution.h" #include "tree-scalar-evolution.h"
#include "params.h" #include "params.h"
#include "dbgcnt.h" #include "dbgcnt.h"
#include "domwalk.h"
/* TODO: /* TODO:
...@@ -351,8 +352,6 @@ get_or_alloc_expr_for_name (tree name) ...@@ -351,8 +352,6 @@ get_or_alloc_expr_for_name (tree name)
return result; return result;
} }
static bool in_fre = false;
/* An unordered bitmap set. One bitmap tracks values, the other, /* An unordered bitmap set. One bitmap tracks values, the other,
expressions. */ expressions. */
typedef struct bitmap_set typedef struct bitmap_set
...@@ -637,6 +636,25 @@ get_expr_value_id (pre_expr expr) ...@@ -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. */ /* Remove an expression EXPR from a bitmapped set. */
static void static void
...@@ -1022,16 +1040,13 @@ DEBUG_FUNCTION void ...@@ -1022,16 +1040,13 @@ DEBUG_FUNCTION void
debug_bitmap_sets_for (basic_block bb) debug_bitmap_sets_for (basic_block bb)
{ {
print_bitmap_set (stderr, AVAIL_OUT (bb), "avail_out", bb->index); 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, EXP_GEN (bb), "exp_gen", bb->index); print_bitmap_set (stderr, TMP_GEN (bb), "tmp_gen", bb->index);
print_bitmap_set (stderr, PHI_GEN (bb), "phi_gen", bb->index); print_bitmap_set (stderr, ANTIC_IN (bb), "antic_in", bb->index);
print_bitmap_set (stderr, TMP_GEN (bb), "tmp_gen", bb->index); if (do_partial_partial)
print_bitmap_set (stderr, ANTIC_IN (bb), "antic_in", bb->index); print_bitmap_set (stderr, PA_IN (bb), "pa_in", bb->index);
if (do_partial_partial) print_bitmap_set (stderr, NEW_SETS (bb), "new_sets", bb->index);
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. */ /* Print out the expressions that have VAL to OUTFILE. */
...@@ -1402,11 +1417,9 @@ get_representative_for (const pre_expr e) ...@@ -1402,11 +1417,9 @@ get_representative_for (const pre_expr e)
that we will return. */ that we will return. */
name = make_temp_ssa_name (get_expr_type (e), gimple_build_nop (), "pretmp"); name = make_temp_ssa_name (get_expr_type (e), gimple_build_nop (), "pretmp");
VN_INFO_GET (name)->value_id = value_id; VN_INFO_GET (name)->value_id = value_id;
if (e->kind == CONSTANT) VN_INFO (name)->valnum = sccvn_valnum_from_value_id (value_id);
VN_INFO (name)->valnum = PRE_EXPR_CONSTANT (e); if (VN_INFO (name)->valnum == NULL_TREE)
else
VN_INFO (name)->valnum = name; VN_INFO (name)->valnum = name;
add_to_value (value_id, get_or_alloc_expr_for_name (name)); add_to_value (value_id, get_or_alloc_expr_for_name (name));
if (dump_file) if (dump_file)
{ {
...@@ -2563,23 +2576,6 @@ compute_antic (void) ...@@ -2563,23 +2576,6 @@ compute_antic (void)
sbitmap_free (changed_blocks); 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 /* Inserted expressions are placed onto this worklist, which is used
for performing quick dead code elimination of insertions we made for performing quick dead code elimination of insertions we made
...@@ -3072,8 +3068,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr, ...@@ -3072,8 +3068,7 @@ create_expression_by_pieces (basic_block block, pre_expr expr,
VN_INFO (forcedname)->value_id = get_next_value_id (); VN_INFO (forcedname)->value_id = get_next_value_id ();
nameexpr = get_or_alloc_expr_for_name (forcedname); nameexpr = get_or_alloc_expr_for_name (forcedname);
add_to_value (VN_INFO (forcedname)->value_id, nameexpr); 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 (NEW_SETS (block), nameexpr);
bitmap_value_replace_in_set (AVAIL_OUT (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, ...@@ -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 we are creating the expression by pieces, and this particular piece of
the expression may have been represented. There is no harm in replacing the expression may have been represented. There is no harm in replacing
here. */ here. */
VN_INFO_GET (name)->valnum = name;
value_id = get_expr_value_id (expr); 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); nameexpr = get_or_alloc_expr_for_name (name);
add_to_value (value_id, nameexpr); add_to_value (value_id, nameexpr);
if (NEW_SETS (block)) if (NEW_SETS (block))
...@@ -3339,9 +3337,11 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum, ...@@ -3339,9 +3337,11 @@ insert_into_preds_of_block (basic_block block, unsigned int exprnum,
phi = create_phi_node (temp, block); phi = create_phi_node (temp, block);
gimple_set_plf (phi, NECESSARY, false); gimple_set_plf (phi, NECESSARY, false);
VN_INFO_GET (gimple_phi_result (phi))->valnum = gimple_phi_result (phi); VN_INFO_GET (temp)->value_id = val;
VN_INFO (gimple_phi_result (phi))->value_id = val; VN_INFO (temp)->valnum = sccvn_valnum_from_value_id (val);
bitmap_set_bit (inserted_exprs, SSA_NAME_VERSION (gimple_phi_result (phi))); 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) FOR_EACH_EDGE (pred, ei, block->preds)
{ {
pre_expr ae = VEC_index (pre_expr, avail, pred->dest_idx); 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, ...@@ -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); 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); add_to_value (val, newphi);
/* The value should *not* exist in PHI_GEN, or else we wouldn't be doing /* 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) ...@@ -3782,8 +3782,6 @@ add_to_exp_gen (basic_block block, tree op)
{ {
pre_expr result; pre_expr result;
gcc_checking_assert (!in_fre);
if (TREE_CODE (op) == SSA_NAME && ssa_undefined_value_p (op)) if (TREE_CODE (op) == SSA_NAME && ssa_undefined_value_p (op))
return; return;
...@@ -3797,6 +3795,7 @@ static void ...@@ -3797,6 +3795,7 @@ static void
make_values_for_phi (gimple phi, basic_block block) make_values_for_phi (gimple phi, basic_block block)
{ {
tree result = gimple_phi_result (phi); tree result = gimple_phi_result (phi);
unsigned i;
/* We have no need for virtual phis, as they don't represent /* We have no need for virtual phis, as they don't represent
actual computations. */ actual computations. */
...@@ -3806,18 +3805,14 @@ make_values_for_phi (gimple phi, basic_block block) ...@@ -3806,18 +3805,14 @@ make_values_for_phi (gimple phi, basic_block block)
pre_expr e = get_or_alloc_expr_for_name (result); pre_expr e = get_or_alloc_expr_for_name (result);
add_to_value (get_expr_value_id (e), e); add_to_value (get_expr_value_id (e), e);
bitmap_value_insert_into_set (AVAIL_OUT (block), e); bitmap_value_insert_into_set (AVAIL_OUT (block), e);
if (!in_fre) bitmap_insert_into_set (PHI_GEN (block), e);
for (i = 0; i < gimple_phi_num_args (phi); ++i)
{ {
unsigned i; tree arg = gimple_phi_arg_def (phi, i);
bitmap_insert_into_set (PHI_GEN (block), e); if (TREE_CODE (arg) == SSA_NAME)
for (i = 0; i < gimple_phi_num_args (phi); ++i)
{ {
tree arg = gimple_phi_arg_def (phi, i); e = get_or_alloc_expr_for_name (arg);
if (TREE_CODE (arg) == SSA_NAME) add_to_value (get_expr_value_id (e), e);
{
e = get_or_alloc_expr_for_name (arg);
add_to_value (get_expr_value_id (e), e);
}
} }
} }
} }
...@@ -3855,8 +3850,7 @@ compute_avail (void) ...@@ -3855,8 +3850,7 @@ compute_avail (void)
e = get_or_alloc_expr_for_name (name); e = get_or_alloc_expr_for_name (name);
add_to_value (get_expr_value_id (e), e); add_to_value (get_expr_value_id (e), e);
if (!in_fre) bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), e);
bitmap_insert_into_set (TMP_GEN (ENTRY_BLOCK_PTR), e);
bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), e); bitmap_value_insert_into_set (AVAIL_OUT (ENTRY_BLOCK_PTR), e);
} }
...@@ -3924,15 +3918,10 @@ compute_avail (void) ...@@ -3924,15 +3918,10 @@ compute_avail (void)
pre_expr e = get_or_alloc_expr_for_name (op); pre_expr e = get_or_alloc_expr_for_name (op);
add_to_value (get_expr_value_id (e), e); add_to_value (get_expr_value_id (e), e);
if (!in_fre) bitmap_insert_into_set (TMP_GEN (block), e);
bitmap_insert_into_set (TMP_GEN (block), e);
bitmap_value_insert_into_set (AVAIL_OUT (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)) if (gimple_has_side_effects (stmt) || stmt_could_throw_p (stmt))
continue; continue;
...@@ -4123,407 +4112,471 @@ compute_avail (void) ...@@ -4123,407 +4112,471 @@ compute_avail (void)
free (worklist); free (worklist);
} }
/* Insert the expression for SSA_VN that SCCVN thought would be simpler
than the available expressions for it. The insertion point is /* Local state for the eliminate domwalk. */
right before the first use in STMT. Returns the SSA_NAME that should static VEC (gimple, heap) *el_to_remove;
be used for replacement. */ 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 static tree
do_SCCVN_insertion (gimple stmt, tree ssa_vn) eliminate_avail (tree op)
{ {
basic_block bb = gimple_bb (stmt); tree valnum = VN_INFO (op)->valnum;
gimple_stmt_iterator gsi; if (TREE_CODE (valnum) == SSA_NAME)
gimple_seq stmts = NULL; {
tree expr; if (SSA_NAME_IS_DEFAULT_DEF (valnum))
pre_expr e; 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 static void
to insert and associate it with the value handle for SSA_VN. */ eliminate_push_avail (tree op)
e = get_or_alloc_expr_for (vn_get_expr_for (ssa_vn)); {
if (e == NULL) 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; return NULL_TREE;
/* Then use create_expression_by_pieces to generate a valid tree op = TREE_OPERAND (expr, 0);
expression to insert at this point of the IL stream. */ tree leader = TREE_CODE (op) == SSA_NAME ? eliminate_avail (op) : op;
expr = create_expression_by_pieces (bb, e, &stmts, stmt, NULL); if (!leader)
if (expr == NULL_TREE)
return NULL_TREE; 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 static void
eliminate (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_iterator gsi;
gimple stmt; 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);)
{ {
for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&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))
{ {
tree lhs = NULL_TREE; gsi_next (&gsi);
tree rhs = NULL_TREE; continue;
}
stmt = gsi_stmt (gsi);
if (gimple_has_lhs (stmt))
lhs = gimple_get_lhs (stmt);
if (gimple_assign_single_p (stmt))
rhs = gimple_assign_rhs1 (stmt);
/* Lookup the RHS of the expression, see if we have an
available computation for it. If so, replace the RHS with
the available computation.
See PR43491.
We don't replace global register variable when it is a the RHS of
a single assign. We do replace local register variable since gcc
does not guarantee local variable will be allocated in register. */
if (gimple_has_lhs (stmt)
&& TREE_CODE (lhs) == SSA_NAME
&& !gimple_assign_ssa_name_copy_p (stmt)
&& (!gimple_assign_single_p (stmt)
|| (!is_gimple_min_invariant (rhs)
&& (gimple_assign_rhs_code (stmt) != VAR_DECL
|| !is_global_var (rhs)
|| !DECL_HARD_REGISTER (rhs))))
&& !gimple_has_volatile_ops (stmt)
&& !has_zero_uses (lhs))
{
tree sprime = NULL;
pre_expr lhsexpr = get_or_alloc_expr_for_name (lhs);
pre_expr sprimeexpr;
gimple orig_stmt = stmt;
sprimeexpr = bitmap_find_leader (AVAIL_OUT (b), sprime = eliminate_avail (res);
get_expr_value_id (lhsexpr), if (!sprime
NULL); || 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 (sprimeexpr) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
if (sprimeexpr->kind == CONSTANT) fprintf (dump_file, "Replaced redundant PHI node defining ");
sprime = PRE_EXPR_CONSTANT (sprimeexpr); print_generic_expr (dump_file, res, 0);
else if (sprimeexpr->kind == NAME) fprintf (dump_file, " with ");
sprime = PRE_EXPR_NAME (sprimeexpr); print_generic_expr (dump_file, sprime, 0);
else fprintf (dump_file, "\n");
gcc_unreachable (); }
}
/* If there is no existing leader but SCCVN knows this remove_phi_node (&gsi, false);
value is constant, use that constant. */
if (!sprime && is_gimple_min_invariant (VN_INFO (lhs)->valnum)) if (inserted_exprs
{ && !bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))
sprime = VN_INFO (lhs)->valnum; && TREE_CODE (sprime) == SSA_NAME)
if (!useless_type_conversion_p (TREE_TYPE (lhs), gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
TREE_TYPE (sprime)))
sprime = fold_convert (TREE_TYPE (lhs), sprime); 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++;
}
if (dump_file && (dump_flags & TDF_DETAILS)) for (gsi = gsi_start_bb (b); !gsi_end_p (gsi); gsi_next (&gsi))
{ {
fprintf (dump_file, "Replaced "); tree lhs = NULL_TREE;
print_gimple_expr (dump_file, stmt, 0, 0); tree rhs = NULL_TREE;
fprintf (dump_file, " with ");
print_generic_expr (dump_file, sprime, 0); stmt = gsi_stmt (gsi);
fprintf (dump_file, " in ");
print_gimple_stmt (dump_file, stmt, 0, 0); if (gimple_has_lhs (stmt))
} lhs = gimple_get_lhs (stmt);
pre_stats.eliminations++;
propagate_tree_value_into_stmt (&gsi, sprime); if (gimple_assign_single_p (stmt))
stmt = gsi_stmt (gsi); rhs = gimple_assign_rhs1 (stmt);
update_stmt (stmt);
/* Lookup the RHS of the expression, see if we have an
/* If we removed EH side-effects from the statement, clean available computation for it. If so, replace the RHS with
its EH information. */ the available computation.
if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
{ See PR43491.
bitmap_set_bit (need_eh_cleanup, We don't replace global register variable when it is a the RHS of
gimple_bb (stmt)->index); a single assign. We do replace local register variable since gcc
if (dump_file && (dump_flags & TDF_DETAILS)) does not guarantee local variable will be allocated in register. */
fprintf (dump_file, " Removed EH side-effects.\n"); if (gimple_has_lhs (stmt)
} && TREE_CODE (lhs) == SSA_NAME
continue; && !gimple_assign_ssa_name_copy_p (stmt)
} && (!gimple_assign_single_p (stmt)
|| (!is_gimple_min_invariant (rhs)
&& (gimple_assign_rhs_code (stmt) != VAR_DECL
|| !is_global_var (rhs)
|| !DECL_HARD_REGISTER (rhs))))
&& !gimple_has_volatile_ops (stmt))
{
tree sprime;
gimple orig_stmt = stmt;
sprime = eliminate_avail (lhs);
if (!sprime)
{
/* If there is no existing usable leader but SCCVN thinks /* If there is no existing usable leader but SCCVN thinks
it has an expression it wants to use as replacement, it has an expression it wants to use as replacement,
insert that. */ 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
&& (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 (!useless_type_conversion_p (TREE_TYPE (lhs),
TREE_TYPE (sprime)))
sprime = fold_convert (TREE_TYPE (lhs), sprime);
if (dump_file && (dump_flags & TDF_DETAILS))
{ {
tree val = VN_INFO (lhs)->valnum; fprintf (dump_file, "Replaced ");
if (val != VN_TOP print_gimple_expr (dump_file, stmt, 0, 0);
&& TREE_CODE (val) == SSA_NAME fprintf (dump_file, " with ");
&& VN_INFO (val)->needs_insertion print_generic_expr (dump_file, sprime, 0);
&& can_PRE_operation (vn_get_expr_for (val))) fprintf (dump_file, " in ");
sprime = do_SCCVN_insertion (stmt, val); print_gimple_stmt (dump_file, stmt, 0, 0);
} }
if (sprime pre_stats.eliminations++;
&& sprime != lhs propagate_tree_value_into_stmt (&gsi, sprime);
&& (rhs == NULL_TREE stmt = gsi_stmt (gsi);
|| TREE_CODE (rhs) != SSA_NAME update_stmt (stmt);
|| may_propagate_copy (rhs, sprime)))
/* If we removed EH side-effects from the statement, clean
its EH information. */
if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
{ {
bool can_make_abnormal_goto bitmap_set_bit (need_eh_cleanup,
= is_gimple_call (stmt) gimple_bb (stmt)->index);
&& stmt_can_make_abnormal_goto (stmt); if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed EH side-effects.\n");
}
continue;
}
gcc_assert (sprime != rhs); /* If there is no usable leader mark lhs as leader for its value. */
if (!sprime)
eliminate_push_avail (lhs);
if (dump_file && (dump_flags & TDF_DETAILS)) if (sprime
{ && sprime != lhs
fprintf (dump_file, "Replaced "); && (rhs == NULL_TREE
print_gimple_expr (dump_file, stmt, 0, 0); || TREE_CODE (rhs) != SSA_NAME
fprintf (dump_file, " with "); || may_propagate_copy (rhs, sprime)))
print_generic_expr (dump_file, sprime, 0); {
fprintf (dump_file, " in "); bool can_make_abnormal_goto
print_gimple_stmt (dump_file, stmt, 0, 0); = is_gimple_call (stmt)
} && stmt_can_make_abnormal_goto (stmt);
if (TREE_CODE (sprime) == SSA_NAME) gcc_assert (sprime != rhs);
gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
NECESSARY, true);
/* We need to make sure the new and old types actually match,
which may require adding a simple cast, which fold_convert
will do for us. */
if ((!rhs || TREE_CODE (rhs) != SSA_NAME)
&& !useless_type_conversion_p (gimple_expr_type (stmt),
TREE_TYPE (sprime)))
sprime = fold_convert (gimple_expr_type (stmt), sprime);
pre_stats.eliminations++;
propagate_tree_value_into_stmt (&gsi, sprime);
stmt = gsi_stmt (gsi);
update_stmt (stmt);
/* If we removed EH side-effects from the statement, clean
its EH information. */
if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
{
bitmap_set_bit (need_eh_cleanup,
gimple_bb (stmt)->index);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed EH side-effects.\n");
}
/* Likewise for AB side-effects. */ if (dump_file && (dump_flags & TDF_DETAILS))
if (can_make_abnormal_goto {
&& !stmt_can_make_abnormal_goto (stmt)) fprintf (dump_file, "Replaced ");
{ print_gimple_expr (dump_file, stmt, 0, 0);
bitmap_set_bit (need_ab_cleanup, fprintf (dump_file, " with ");
gimple_bb (stmt)->index); print_generic_expr (dump_file, sprime, 0);
if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, " in ");
fprintf (dump_file, " Removed AB side-effects.\n"); print_gimple_stmt (dump_file, stmt, 0, 0);
}
} }
}
/* If the statement is a scalar store, see if the expression if (TREE_CODE (sprime) == SSA_NAME)
has the same value number as its rhs. If so, the store is gimple_set_plf (SSA_NAME_DEF_STMT (sprime),
dead. */ NECESSARY, true);
else if (gimple_assign_single_p (stmt) /* We need to make sure the new and old types actually match,
&& !gimple_has_volatile_ops (stmt) which may require adding a simple cast, which fold_convert
&& !is_gimple_reg (gimple_assign_lhs (stmt)) will do for us. */
&& (TREE_CODE (rhs) == SSA_NAME if ((!rhs || TREE_CODE (rhs) != SSA_NAME)
|| is_gimple_min_invariant (rhs))) && !useless_type_conversion_p (gimple_expr_type (stmt),
{ TREE_TYPE (sprime)))
tree val; sprime = fold_convert (gimple_expr_type (stmt), sprime);
val = vn_reference_lookup (gimple_assign_lhs (stmt),
gimple_vuse (stmt), VN_WALK, NULL); pre_stats.eliminations++;
if (TREE_CODE (rhs) == SSA_NAME) propagate_tree_value_into_stmt (&gsi, sprime);
rhs = VN_INFO (rhs)->valnum; stmt = gsi_stmt (gsi);
if (val update_stmt (stmt);
&& operand_equal_p (val, rhs, 0))
/* If we removed EH side-effects from the statement, clean
its EH information. */
if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
{ {
bitmap_set_bit (need_eh_cleanup,
gimple_bb (stmt)->index);
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ fprintf (dump_file, " Removed EH side-effects.\n");
fprintf (dump_file, "Deleted redundant store "); }
print_gimple_stmt (dump_file, stmt, 0, 0);
}
/* Queue stmt for removal. */ /* Likewise for AB side-effects. */
VEC_safe_push (gimple, heap, to_remove, stmt); if (can_make_abnormal_goto
&& !stmt_can_make_abnormal_goto (stmt))
{
bitmap_set_bit (need_ab_cleanup,
gimple_bb (stmt)->index);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed AB side-effects.\n");
} }
} }
/* Visit COND_EXPRs and fold the comparison with the }
available value-numbers. */ /* If the statement is a scalar store, see if the expression
else if (gimple_code (stmt) == GIMPLE_COND) has the same value number as its rhs. If so, the store is
dead. */
else if (gimple_assign_single_p (stmt)
&& !gimple_has_volatile_ops (stmt)
&& !is_gimple_reg (gimple_assign_lhs (stmt))
&& (TREE_CODE (rhs) == SSA_NAME
|| is_gimple_min_invariant (rhs)))
{
tree val;
val = vn_reference_lookup (gimple_assign_lhs (stmt),
gimple_vuse (stmt), VN_WALK, NULL);
if (TREE_CODE (rhs) == SSA_NAME)
rhs = VN_INFO (rhs)->valnum;
if (val
&& operand_equal_p (val, rhs, 0))
{ {
tree op0 = gimple_cond_lhs (stmt); if (dump_file && (dump_flags & TDF_DETAILS))
tree op1 = gimple_cond_rhs (stmt);
tree result;
if (TREE_CODE (op0) == SSA_NAME)
op0 = VN_INFO (op0)->valnum;
if (TREE_CODE (op1) == SSA_NAME)
op1 = VN_INFO (op1)->valnum;
result = fold_binary (gimple_cond_code (stmt), boolean_type_node,
op0, op1);
if (result && TREE_CODE (result) == INTEGER_CST)
{ {
if (integer_zerop (result)) fprintf (dump_file, "Deleted redundant store ");
gimple_cond_make_false (stmt); print_gimple_stmt (dump_file, stmt, 0, 0);
else
gimple_cond_make_true (stmt);
update_stmt (stmt);
todo = TODO_cleanup_cfg;
} }
/* Queue stmt for removal. */
VEC_safe_push (gimple, heap, el_to_remove, stmt);
} }
/* Visit indirect calls and turn them into direct calls if }
possible. */ /* Visit COND_EXPRs and fold the comparison with the
if (is_gimple_call (stmt)) available value-numbers. */
else if (gimple_code (stmt) == GIMPLE_COND)
{
tree op0 = gimple_cond_lhs (stmt);
tree op1 = gimple_cond_rhs (stmt);
tree result;
if (TREE_CODE (op0) == SSA_NAME)
op0 = VN_INFO (op0)->valnum;
if (TREE_CODE (op1) == SSA_NAME)
op1 = VN_INFO (op1)->valnum;
result = fold_binary (gimple_cond_code (stmt), boolean_type_node,
op0, op1);
if (result && TREE_CODE (result) == INTEGER_CST)
{ {
tree orig_fn = gimple_call_fn (stmt); if (integer_zerop (result))
tree fn; gimple_cond_make_false (stmt);
if (!orig_fn)
continue;
if (TREE_CODE (orig_fn) == SSA_NAME)
fn = VN_INFO (orig_fn)->valnum;
else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF
&& TREE_CODE (OBJ_TYPE_REF_EXPR (orig_fn)) == SSA_NAME)
fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
else else
continue; gimple_cond_make_true (stmt);
if (gimple_call_addr_fndecl (fn) != NULL_TREE update_stmt (stmt);
&& useless_type_conversion_p (TREE_TYPE (orig_fn), el_todo = TODO_cleanup_cfg;
TREE_TYPE (fn))) }
{ }
bool can_make_abnormal_goto /* Visit indirect calls and turn them into direct calls if
= stmt_can_make_abnormal_goto (stmt); possible. */
bool was_noreturn = gimple_call_noreturn_p (stmt); if (is_gimple_call (stmt))
{
if (dump_file && (dump_flags & TDF_DETAILS)) tree orig_fn = gimple_call_fn (stmt);
{ tree fn;
fprintf (dump_file, "Replacing call target with "); if (!orig_fn)
print_generic_expr (dump_file, fn, 0); continue;
fprintf (dump_file, " in "); if (TREE_CODE (orig_fn) == SSA_NAME)
print_gimple_stmt (dump_file, stmt, 0, 0); fn = VN_INFO (orig_fn)->valnum;
} else if (TREE_CODE (orig_fn) == OBJ_TYPE_REF
&& TREE_CODE (OBJ_TYPE_REF_EXPR (orig_fn)) == SSA_NAME)
fn = VN_INFO (OBJ_TYPE_REF_EXPR (orig_fn))->valnum;
else
continue;
if (gimple_call_addr_fndecl (fn) != NULL_TREE
&& useless_type_conversion_p (TREE_TYPE (orig_fn),
TREE_TYPE (fn)))
{
bool can_make_abnormal_goto
= stmt_can_make_abnormal_goto (stmt);
bool was_noreturn = gimple_call_noreturn_p (stmt);
gimple_call_set_fn (stmt, fn); if (dump_file && (dump_flags & TDF_DETAILS))
VEC_safe_push (gimple, heap, to_update, stmt); {
fprintf (dump_file, "Replacing call target with ");
print_generic_expr (dump_file, fn, 0);
fprintf (dump_file, " in ");
print_gimple_stmt (dump_file, stmt, 0, 0);
}
/* When changing a call into a noreturn call, cfg cleanup gimple_call_set_fn (stmt, fn);
is needed to fix up the noreturn call. */ VEC_safe_push (gimple, heap, el_to_update, stmt);
if (!was_noreturn && gimple_call_noreturn_p (stmt))
todo |= TODO_cleanup_cfg;
/* If we removed EH side-effects from the statement, clean /* When changing a call into a noreturn call, cfg cleanup
its EH information. */ is needed to fix up the noreturn call. */
if (maybe_clean_or_replace_eh_stmt (stmt, stmt)) if (!was_noreturn && gimple_call_noreturn_p (stmt))
{ el_todo |= TODO_cleanup_cfg;
bitmap_set_bit (need_eh_cleanup,
gimple_bb (stmt)->index);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed EH side-effects.\n");
}
/* Likewise for AB side-effects. */ /* If we removed EH side-effects from the statement, clean
if (can_make_abnormal_goto its EH information. */
&& !stmt_can_make_abnormal_goto (stmt)) if (maybe_clean_or_replace_eh_stmt (stmt, stmt))
{ {
bitmap_set_bit (need_ab_cleanup, bitmap_set_bit (need_eh_cleanup,
gimple_bb (stmt)->index); gimple_bb (stmt)->index);
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed AB side-effects.\n"); fprintf (dump_file, " Removed EH side-effects.\n");
} }
/* Changing an indirect call to a direct call may /* Likewise for AB side-effects. */
have exposed different semantics. This may if (can_make_abnormal_goto
require an SSA update. */ && !stmt_can_make_abnormal_goto (stmt))
todo |= TODO_update_ssa_only_virtuals; {
bitmap_set_bit (need_ab_cleanup,
gimple_bb (stmt)->index);
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Removed AB side-effects.\n");
} }
/* Changing an indirect call to a direct call may
have exposed different semantics. This may
require an SSA update. */
el_todo |= TODO_update_ssa_only_virtuals;
} }
} }
}
}
for (gsi = gsi_start_phis (b); !gsi_end_p (gsi);) /* Make no longer available leaders no longer available. */
{
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); static void
sprimeexpr = bitmap_find_leader (AVAIL_OUT (b), eliminate_leave_block (dom_walk_data *, basic_block)
get_expr_value_id (resexpr), NULL); {
if (sprimeexpr) tree entry;
{ while ((entry = VEC_pop (tree, el_avail_stack)) != NULL_TREE)
if (sprimeexpr->kind == CONSTANT) VEC_replace (tree, el_avail,
sprime = PRE_EXPR_CONSTANT (sprimeexpr); SSA_NAME_VERSION (VN_INFO (entry)->valnum), NULL_TREE);
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;
}
if (dump_file && (dump_flags & TDF_DETAILS)) /* Eliminate fully redundant computations. */
{
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); static unsigned int
eliminate (void)
{
struct dom_walk_data walk_data;
gimple_stmt_iterator gsi;
gimple stmt;
unsigned i;
if (!bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res)) need_eh_cleanup = BITMAP_ALLOC (NULL);
&& TREE_CODE (sprime) == SSA_NAME) need_ab_cleanup = BITMAP_ALLOC (NULL);
gimple_set_plf (SSA_NAME_DEF_STMT (sprime), NECESSARY, true);
if (!useless_type_conversion_p (TREE_TYPE (res), TREE_TYPE (sprime))) el_to_remove = NULL;
sprime = fold_convert (TREE_TYPE (res), sprime); el_to_update = NULL;
stmt = gimple_build_assign (res, sprime); el_todo = 0;
SSA_NAME_DEF_STMT (res) = stmt; el_avail = NULL;
gimple_set_plf (stmt, NECESSARY, gimple_plf (phi, NECESSARY)); el_avail_stack = NULL;
gsi2 = gsi_after_labels (b); walk_data.dom_direction = CDI_DOMINATORS;
gsi_insert_before (&gsi2, stmt, GSI_NEW_STMT); walk_data.initialize_block_local_data = NULL;
/* Queue the copy for eventual removal. */ walk_data.before_dom_children = eliminate_bb;
VEC_safe_push (gimple, heap, to_remove, stmt); walk_data.after_dom_children = eliminate_leave_block;
/* If we inserted this PHI node ourself, it's not an elimination. */ walk_data.global_data = NULL;
if (bitmap_bit_p (inserted_exprs, SSA_NAME_VERSION (res))) walk_data.block_local_data_size = 0;
pre_stats.phis--; init_walk_dominator_tree (&walk_data);
else walk_dominator_tree (&walk_data, ENTRY_BLOCK_PTR);
pre_stats.eliminations++; 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 /* We cannot remove stmts during BB walk, especially not release SSA
names there as this confuses the VN machinery. The stmts ending names there as this confuses the VN machinery. The stmts ending
up in to_remove are either stores or simple copies. */ up in el_to_remove are either stores or simple copies. */
FOR_EACH_VEC_ELT (gimple, to_remove, i, stmt) FOR_EACH_VEC_ELT (gimple, el_to_remove, i, stmt)
{ {
tree lhs = gimple_assign_lhs (stmt); tree lhs = gimple_assign_lhs (stmt);
tree rhs = gimple_assign_rhs1 (stmt); tree rhs = gimple_assign_rhs1 (stmt);
...@@ -4539,7 +4592,8 @@ eliminate (void) ...@@ -4539,7 +4592,8 @@ eliminate (void)
{ {
SET_USE (use_p, rhs); SET_USE (use_p, rhs);
update_stmt (use_stmt); 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) && TREE_CODE (rhs) == SSA_NAME)
gimple_set_plf (SSA_NAME_DEF_STMT (rhs), NECESSARY, true); gimple_set_plf (SSA_NAME_DEF_STMT (rhs), NECESSARY, true);
} }
...@@ -4553,21 +4607,43 @@ eliminate (void) ...@@ -4553,21 +4607,43 @@ eliminate (void)
unlink_stmt_vdef (stmt); unlink_stmt_vdef (stmt);
if (gsi_remove (&gsi, true)) if (gsi_remove (&gsi, true))
bitmap_set_bit (need_eh_cleanup, bb->index); 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)); bitmap_clear_bit (inserted_exprs, SSA_NAME_VERSION (lhs));
release_defs (stmt); 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 /* We cannot update call statements with virtual operands during
SSA walk. This might remove them which in turn makes our SSA walk. This might remove them which in turn makes our
VN lattice invalid. */ 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); 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. /* 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) ...@@ -4767,7 +4843,7 @@ my_rev_post_order_compute (int *post_order, bool include_entry_exit)
/* Initialize data structures used by PRE. */ /* Initialize data structures used by PRE. */
static void static void
init_pre (bool do_fre) init_pre (void)
{ {
basic_block bb; basic_block bb;
...@@ -4779,8 +4855,6 @@ init_pre (bool do_fre) ...@@ -4779,8 +4855,6 @@ init_pre (bool do_fre)
get_max_value_id() + 1); get_max_value_id() + 1);
name_to_id = NULL; name_to_id = NULL;
in_fre = do_fre;
inserted_exprs = BITMAP_ALLOC (NULL); inserted_exprs = BITMAP_ALLOC (NULL);
connect_infinite_loops_to_exit (); connect_infinite_loops_to_exit ();
...@@ -4804,28 +4878,19 @@ init_pre (bool do_fre) ...@@ -4804,28 +4878,19 @@ init_pre (bool do_fre)
sizeof (struct pre_expr_d), 30); sizeof (struct pre_expr_d), 30);
FOR_ALL_BB (bb) FOR_ALL_BB (bb)
{ {
if (!do_fre) EXP_GEN (bb) = bitmap_set_new ();
{ PHI_GEN (bb) = bitmap_set_new ();
EXP_GEN (bb) = bitmap_set_new (); TMP_GEN (bb) = bitmap_set_new ();
PHI_GEN (bb) = bitmap_set_new ();
TMP_GEN (bb) = bitmap_set_new ();
}
AVAIL_OUT (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. */ /* Deallocate data structures used by PRE. */
static void 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); free (postorder);
VEC_free (bitmap, heap, value_expressions); VEC_free (bitmap, heap, value_expressions);
BITMAP_FREE (inserted_exprs); BITMAP_FREE (inserted_exprs);
...@@ -4839,28 +4904,12 @@ fini_pre (bool do_fre) ...@@ -4839,28 +4904,12 @@ fini_pre (bool do_fre)
free_aux_for_blocks (); free_aux_for_blocks ();
free_dominance_info (CDI_POST_DOMINATORS); 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 /* Gate and execute functions for PRE. */
only wants to do full redundancy elimination. */
static unsigned int static unsigned int
execute_pre (bool do_fre) do_pre (void)
{ {
unsigned int todo = 0; unsigned int todo = 0;
...@@ -4869,18 +4918,15 @@ execute_pre (bool do_fre) ...@@ -4869,18 +4918,15 @@ execute_pre (bool do_fre)
/* This has to happen before SCCVN runs because /* This has to happen before SCCVN runs because
loop_optimizer_init may create new phis, etc. */ loop_optimizer_init may create new phis, etc. */
if (!do_fre) loop_optimizer_init (LOOPS_NORMAL);
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 ();
loop_optimizer_finalize ();
return 0; return 0;
} }
init_pre (do_fre); init_pre ();
scev_initialize (); scev_initialize ();
/* Collect and value number expressions computed in each basic block. */ /* Collect and value number expressions computed in each basic block. */
...@@ -4889,13 +4935,16 @@ execute_pre (bool do_fre) ...@@ -4889,13 +4935,16 @@ execute_pre (bool do_fre)
if (dump_file && (dump_flags & TDF_DETAILS)) if (dump_file && (dump_flags & TDF_DETAILS))
{ {
basic_block bb; basic_block bb;
FOR_ALL_BB (bb) FOR_ALL_BB (bb)
{ {
print_bitmap_set (dump_file, EXP_GEN (bb), "exp_gen", bb->index); print_bitmap_set (dump_file, EXP_GEN (bb),
print_bitmap_set (dump_file, PHI_GEN (bb), "phi_gen", bb->index); "exp_gen", bb->index);
print_bitmap_set (dump_file, TMP_GEN (bb), "tmp_gen", bb->index); print_bitmap_set (dump_file, PHI_GEN (bb),
print_bitmap_set (dump_file, AVAIL_OUT (bb), "avail_out", bb->index); "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) ...@@ -4904,7 +4953,7 @@ execute_pre (bool do_fre)
fixed, don't run it when he have an incredibly large number of 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 bb's. If we aren't going to run insert, there is no point in
computing ANTIC, either, even though it's plenty fast. */ computing ANTIC, either, even though it's plenty fast. */
if (!do_fre && n_basic_blocks < 4000) if (n_basic_blocks < 4000)
{ {
compute_antic (); compute_antic ();
insert (); insert ();
...@@ -4926,37 +4975,28 @@ execute_pre (bool do_fre) ...@@ -4926,37 +4975,28 @@ execute_pre (bool do_fre)
statistics_counter_event (cfun, "Constified", pre_stats.constified); statistics_counter_event (cfun, "Constified", pre_stats.constified);
clear_expression_ids (); clear_expression_ids ();
if (!do_fre) remove_dead_inserted_code ();
{ todo |= TODO_verify_flow;
remove_dead_inserted_code ();
todo |= TODO_verify_flow;
}
scev_finalize (); scev_finalize ();
fini_pre (do_fre); fini_pre ();
fini_eliminate ();
if (!do_fre) loop_optimizer_finalize ();
/* 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. /* TODO: tail_merge_optimize may merge all predecessors of a block, in which
It should either: case we can merge the block with the remaining predecessor of the block.
- call merge_blocks after each tail merge iteration It should either:
- call merge_blocks after all tail merge iterations - call merge_blocks after each tail merge iteration
- mark TODO_cleanup_cfg when necessary - call merge_blocks after all tail merge iterations
- share the cfg cleanup with fini_pre. */ - mark TODO_cleanup_cfg when necessary
todo |= tail_merge_optimize (todo); - share the cfg cleanup with fini_pre. */
todo |= tail_merge_optimize (todo);
free_scc_vn (); free_scc_vn ();
return todo; return todo;
} }
/* Gate and execute functions for PRE. */
static unsigned int
do_pre (void)
{
return execute_pre (false);
}
static bool static bool
gate_pre (void) gate_pre (void)
{ {
...@@ -4990,7 +5030,25 @@ struct gimple_opt_pass pass_pre = ...@@ -4990,7 +5030,25 @@ struct gimple_opt_pass pass_pre =
static unsigned int static unsigned int
execute_fre (void) 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 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