/* Dead code elimination pass for the GNU compiler.
- Copyright (C) 2002-2013 Free Software Foundation, Inc.
+ Copyright (C) 2002-2015 Free Software Foundation, Inc.
Contributed by Ben Elliston <bje@redhat.com>
and Andrew MacLeod <amacleod@redhat.com>
Adapted to use control dependence by Steven Bosscher, SUSE Labs.
#include "system.h"
#include "coretypes.h"
#include "tm.h"
-
+#include "alias.h"
+#include "symtab.h"
#include "tree.h"
+#include "fold-const.h"
+#include "calls.h"
#include "gimple-pretty-print.h"
+#include "predict.h"
+#include "hard-reg-set.h"
+#include "function.h"
+#include "dominance.h"
+#include "cfg.h"
+#include "cfganal.h"
#include "basic-block.h"
-#include "tree-ssa.h"
+#include "tree-ssa-alias.h"
+#include "internal-fn.h"
+#include "tree-eh.h"
+#include "gimple-expr.h"
#include "gimple.h"
-#include "tree-pass.h"
+#include "gimplify.h"
+#include "gimple-iterator.h"
+#include "gimple-ssa.h"
+#include "tree-cfg.h"
+#include "tree-phinodes.h"
+#include "ssa-iterators.h"
+#include "stringpool.h"
+#include "tree-ssanames.h"
+#include "tree-ssa-loop-niter.h"
+#include "tree-into-ssa.h"
+#include "rtl.h"
#include "flags.h"
+#include "insn-config.h"
+#include "expmed.h"
+#include "dojump.h"
+#include "explow.h"
+#include "emit-rtl.h"
+#include "varasm.h"
+#include "stmt.h"
+#include "expr.h"
+#include "tree-dfa.h"
+#include "tree-pass.h"
#include "cfgloop.h"
#include "tree-scalar-evolution.h"
+#include "tree-chkp.h"
+#include "tree-ssa-propagate.h"
+#include "gimple-fold.h"
static struct stmt_stats
{
switch (DECL_FUNCTION_CODE (callee))
{
case BUILT_IN_MALLOC:
+ case BUILT_IN_ALIGNED_ALLOC:
case BUILT_IN_CALLOC:
case BUILT_IN_ALLOCA:
case BUILT_IN_ALLOCA_WITH_ALIGN:
break;
case GIMPLE_ASSIGN:
- if (TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME
- && TREE_CLOBBER_P (gimple_assign_rhs1 (stmt)))
+ if (gimple_clobber_p (stmt))
return;
break;
unsigned edge_number;
bool skipped = false;
- gcc_assert (bb != EXIT_BLOCK_PTR);
+ gcc_assert (bb != EXIT_BLOCK_PTR_FOR_FN (cfun));
- if (bb == ENTRY_BLOCK_PTR)
+ if (bb == ENTRY_BLOCK_PTR_FOR_FN (cfun))
return;
EXECUTE_IF_SET_IN_BITMAP (cd->get_edges_dependent_on (bb->index),
gimple phi, stmt;
int flags;
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
/* PHI nodes are never inherently necessary. */
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
/* Prevent the empty possibly infinite loops from being removed. */
if (aggressive)
{
- loop_iterator li;
struct loop *loop;
scev_initialize ();
if (mark_irreducible_loops ())
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
edge_iterator ei;
FOR_EACH_EDGE (e, ei, bb->succs)
}
}
- FOR_EACH_LOOP (li, loop, 0)
+ FOR_EACH_LOOP (loop, 0)
if (!finite_loop_p (loop))
{
if (dump_file)
switch (DECL_FUNCTION_CODE (callee))
{
case BUILT_IN_MALLOC:
+ case BUILT_IN_ALIGNED_ALLOC:
case BUILT_IN_CALLOC:
case BUILT_IN_ALLOCA:
case BUILT_IN_ALLOCA_WITH_ALIGN:
containing STMT is control dependent, but only if we haven't
already done so. */
basic_block bb = gimple_bb (stmt);
- if (bb != ENTRY_BLOCK_PTR
+ if (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun)
&& !bitmap_bit_p (visited_control_parents, bb->index))
mark_control_dependent_edges_necessary (bb, false);
}
we also consider the control dependent edges leading to the
predecessor block associated with each PHI alternative as
necessary. */
+ gphi *phi = as_a <gphi *> (stmt);
size_t k;
for (k = 0; k < gimple_phi_num_args (stmt); k++)
{
for (k = 0; k < gimple_phi_num_args (stmt); k++)
{
- basic_block arg_bb = gimple_phi_arg_edge (stmt, k)->src;
+ basic_block arg_bb = gimple_phi_arg_edge (phi, k)->src;
if (gimple_bb (stmt)
!= get_immediate_dominator (CDI_POST_DOMINATORS, arg_bb))
if (!bitmap_bit_p (last_stmt_necessary, arg_bb->index))
mark_last_stmt_necessary (arg_bb);
}
- else if (arg_bb != ENTRY_BLOCK_PTR
+ else if (arg_bb != ENTRY_BLOCK_PTR_FOR_FN (cfun)
&& !bitmap_bit_p (visited_control_parents,
arg_bb->index))
mark_control_dependent_edges_necessary (arg_bb, true);
&& is_gimple_call (def_stmt = SSA_NAME_DEF_STMT (ptr))
&& (def_callee = gimple_call_fndecl (def_stmt))
&& DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL
- && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
+ && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC
+ || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC
|| DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC))
- continue;
+ {
+ gimple bounds_def_stmt;
+ tree bounds;
+
+ /* For instrumented calls we should also check used
+ bounds are returned by the same allocation call. */
+ if (!gimple_call_with_bounds_p (stmt)
+ || ((bounds = gimple_call_arg (stmt, 1))
+ && TREE_CODE (bounds) == SSA_NAME
+ && (bounds_def_stmt = SSA_NAME_DEF_STMT (bounds))
+ && chkp_gimple_call_builtin_p (bounds_def_stmt,
+ BUILT_IN_CHKP_BNDRET)
+ && gimple_call_arg (bounds_def_stmt, 0) == ptr))
+ continue;
+ }
}
FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE)
&& (DECL_FUNCTION_CODE (callee) == BUILT_IN_MEMSET
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_MEMSET_CHK
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_MALLOC
+ || DECL_FUNCTION_CODE (callee) == BUILT_IN_ALIGNED_ALLOC
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_CALLOC
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_FREE
|| DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_END
mark_all_reaching_defs_necessary (stmt);
}
}
- else if (gimple_code (stmt) == GIMPLE_RETURN)
+ else if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
{
- tree rhs = gimple_return_retval (stmt);
+ tree rhs = gimple_return_retval (return_stmt);
/* A return statement may perform a load. */
if (rhs
&& TREE_CODE (rhs) != SSA_NAME
mark_all_reaching_defs_necessary (stmt);
}
}
- else if (gimple_code (stmt) == GIMPLE_ASM)
+ else if (gasm *asm_stmt = dyn_cast <gasm *> (stmt))
{
unsigned i;
mark_all_reaching_defs_necessary (stmt);
/* Inputs may perform loads. */
- for (i = 0; i < gimple_asm_ninputs (stmt); ++i)
+ for (i = 0; i < gimple_asm_ninputs (asm_stmt); ++i)
{
- tree op = TREE_VALUE (gimple_asm_input_op (stmt, i));
+ tree op = TREE_VALUE (gimple_asm_input_op (asm_stmt, i));
if (TREE_CODE (op) != SSA_NAME
&& !is_gimple_min_invariant (op)
&& TREE_CODE (op) != CONSTRUCTOR
}
}
-/* Replace all uses of NAME by underlying variable and mark it
- for renaming. This assumes the defining statement of NAME is
- going to be removed. */
-
-void
-mark_virtual_operand_for_renaming (tree name)
-{
- tree name_var = SSA_NAME_VAR (name);
- bool used = false;
- imm_use_iterator iter;
- use_operand_p use_p;
- gimple stmt;
-
- gcc_assert (VAR_DECL_IS_VIRTUAL_OPERAND (name_var));
- FOR_EACH_IMM_USE_STMT (stmt, iter, name)
- {
- FOR_EACH_IMM_USE_ON_STMT (use_p, iter)
- SET_USE (use_p, name_var);
- used = true;
- }
- if (used)
- mark_virtual_operands_for_renaming (cfun);
-}
-
-/* Replace all uses of the virtual PHI result by its underlying variable
- and mark it for renaming. This assumes the PHI node is going to be
- removed. */
-
-void
-mark_virtual_phi_result_for_renaming (gimple phi)
-{
- if (dump_file && (dump_flags & TDF_DETAILS))
- {
- fprintf (dump_file, "Marking result for renaming : ");
- print_gimple_stmt (dump_file, phi, 0, TDF_SLIM);
- fprintf (dump_file, "\n");
- }
-
- mark_virtual_operand_for_renaming (gimple_phi_result (phi));
-}
-
-
/* Remove dead PHI nodes from block BB. */
static bool
remove_dead_phis (basic_block bb)
{
bool something_changed = false;
- gimple phi;
- gimple_stmt_iterator gsi;
+ gphi *phi;
+ gphi_iterator gsi;
for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi);)
{
stats.total_phis++;
- phi = gsi_stmt (gsi);
+ phi = gsi.phi ();
/* We do not track necessity of virtual PHI nodes. Instead do
very simple dead PHI removal here. */
static edge
forward_edge_to_pdom (edge e, basic_block post_dom_bb)
{
- gimple_stmt_iterator gsi;
+ gphi_iterator gsi;
edge e2 = NULL;
edge_iterator ei;
break;
for (gsi = gsi_start_phis (post_dom_bb); !gsi_end_p (gsi);)
{
- gimple phi = gsi_stmt (gsi);
+ gphi *phi = gsi.phi ();
tree op;
source_location locus;
fake edges in the dominator tree. */
if (e)
;
- else if (! post_dom_bb || post_dom_bb == EXIT_BLOCK_PTR)
+ else if (! post_dom_bb || post_dom_bb == EXIT_BLOCK_PTR_FOR_FN (cfun))
e = EDGE_SUCC (bb, 0);
else
e = forward_edge_to_pdom (EDGE_SUCC (bb, 0), post_dom_bb);
if (e != e2)
{
cfg_altered = true;
- remove_edge (e2);
+ /* If we made a BB unconditionally exit a loop then this
+ transform alters the set of BBs in the loop. Schedule
+ a fixup. */
+ if (loop_exit_edge_p (bb->loop_father, e))
+ loops_state_set (LOOPS_NEED_FIXUP);
+ remove_edge (e2);
}
else
ei_next (&ei);
&& !DECL_HAS_VALUE_EXPR_P (lhs))
{
tree rhs = gimple_assign_rhs1 (stmt);
- gimple note
+ gdebug *note
= gimple_build_debug_bind (lhs, unshare_expr (rhs), stmt);
gsi_insert_after (i, note, GSI_SAME_STMT);
}
release_defs (stmt);
}
+/* Helper for maybe_optimize_arith_overflow. Find in *TP if there are any
+ uses of data (SSA_NAME) other than REALPART_EXPR referencing it. */
+
+static tree
+find_non_realpart_uses (tree *tp, int *walk_subtrees, void *data)
+{
+ if (TYPE_P (*tp) || TREE_CODE (*tp) == REALPART_EXPR)
+ *walk_subtrees = 0;
+ if (*tp == (tree) data)
+ return *tp;
+ return NULL_TREE;
+}
+
+/* If the IMAGPART_EXPR of the {ADD,SUB,MUL}_OVERFLOW result is never used,
+ but REALPART_EXPR is, optimize the {ADD,SUB,MUL}_OVERFLOW internal calls
+ into plain unsigned {PLUS,MINUS,MULT}_EXPR, and if needed reset debug
+ uses. */
+
+static void
+maybe_optimize_arith_overflow (gimple_stmt_iterator *gsi,
+ enum tree_code subcode)
+{
+ gimple stmt = gsi_stmt (*gsi);
+ tree lhs = gimple_call_lhs (stmt);
+
+ if (lhs == NULL || TREE_CODE (lhs) != SSA_NAME)
+ return;
+
+ imm_use_iterator imm_iter;
+ use_operand_p use_p;
+ bool has_debug_uses = false;
+ bool has_realpart_uses = false;
+ bool has_other_uses = false;
+ FOR_EACH_IMM_USE_FAST (use_p, imm_iter, lhs)
+ {
+ gimple use_stmt = USE_STMT (use_p);
+ if (is_gimple_debug (use_stmt))
+ has_debug_uses = true;
+ else if (is_gimple_assign (use_stmt)
+ && gimple_assign_rhs_code (use_stmt) == REALPART_EXPR
+ && TREE_OPERAND (gimple_assign_rhs1 (use_stmt), 0) == lhs)
+ has_realpart_uses = true;
+ else
+ {
+ has_other_uses = true;
+ break;
+ }
+ }
+
+ if (!has_realpart_uses || has_other_uses)
+ return;
+
+ tree arg0 = gimple_call_arg (stmt, 0);
+ tree arg1 = gimple_call_arg (stmt, 1);
+ location_t loc = gimple_location (stmt);
+ tree type = TREE_TYPE (TREE_TYPE (lhs));
+ tree utype = type;
+ if (!TYPE_UNSIGNED (type))
+ utype = build_nonstandard_integer_type (TYPE_PRECISION (type), 1);
+ tree result = fold_build2_loc (loc, subcode, utype,
+ fold_convert_loc (loc, utype, arg0),
+ fold_convert_loc (loc, utype, arg1));
+ result = fold_convert_loc (loc, type, result);
+
+ if (has_debug_uses)
+ {
+ gimple use_stmt;
+ FOR_EACH_IMM_USE_STMT (use_stmt, imm_iter, lhs)
+ {
+ if (!gimple_debug_bind_p (use_stmt))
+ continue;
+ tree v = gimple_debug_bind_get_value (use_stmt);
+ if (walk_tree (&v, find_non_realpart_uses, lhs, NULL))
+ {
+ gimple_debug_bind_reset_value (use_stmt);
+ update_stmt (use_stmt);
+ }
+ }
+ }
+
+ if (TREE_CODE (result) == INTEGER_CST && TREE_OVERFLOW (result))
+ result = drop_tree_overflow (result);
+ tree overflow = build_zero_cst (type);
+ tree ctype = build_complex_type (type);
+ if (TREE_CODE (result) == INTEGER_CST)
+ result = build_complex (ctype, result, overflow);
+ else
+ result = build2_loc (gimple_location (stmt), COMPLEX_EXPR,
+ ctype, result, overflow);
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Transforming call: ");
+ print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
+ fprintf (dump_file, "because the overflow result is never used into: ");
+ print_generic_stmt (dump_file, result, TDF_SLIM);
+ fprintf (dump_file, "\n");
+ }
+
+ if (!update_call_from_tree (gsi, result))
+ gimplify_and_update_call_from_tree (gsi, result);
+}
+
/* Eliminate unnecessary statements. Any instruction not marked as necessary
contributes nothing to the program, and can be deleted. */
as desired. */
gcc_assert (dom_info_available_p (CDI_DOMINATORS));
- h = get_all_dominated_blocks (CDI_DOMINATORS, single_succ (ENTRY_BLOCK_PTR));
+ h = get_all_dominated_blocks (CDI_DOMINATORS,
+ single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)));
while (h.length ())
{
stats.total++;
/* We can mark a call to free as not necessary if the
- defining statement of its argument is an allocation
- function and that is not necessary itself. */
- if (gimple_call_builtin_p (stmt, BUILT_IN_FREE))
+ defining statement of its argument is not necessary
+ (and thus is getting removed). */
+ if (gimple_plf (stmt, STMT_NECESSARY)
+ && gimple_call_builtin_p (stmt, BUILT_IN_FREE))
{
tree ptr = gimple_call_arg (stmt, 0);
- tree callee2;
- gimple def_stmt;
- if (TREE_CODE (ptr) != SSA_NAME)
- continue;
- def_stmt = SSA_NAME_DEF_STMT (ptr);
- if (!is_gimple_call (def_stmt)
- || gimple_plf (def_stmt, STMT_NECESSARY))
- continue;
- callee2 = gimple_call_fndecl (def_stmt);
- if (callee2 == NULL_TREE
- || DECL_BUILT_IN_CLASS (callee2) != BUILT_IN_NORMAL
- || (DECL_FUNCTION_CODE (callee2) != BUILT_IN_MALLOC
- && DECL_FUNCTION_CODE (callee2) != BUILT_IN_CALLOC))
- continue;
- gimple_set_plf (stmt, STMT_NECESSARY, false);
+ if (TREE_CODE (ptr) == SSA_NAME)
+ {
+ gimple def_stmt = SSA_NAME_DEF_STMT (ptr);
+ if (!gimple_nop_p (def_stmt)
+ && !gimple_plf (def_stmt, STMT_NECESSARY))
+ gimple_set_plf (stmt, STMT_NECESSARY, false);
+ }
+ /* We did not propagate necessity for free calls fed
+ by allocation function to allow unnecessary
+ alloc-free sequence elimination. For instrumented
+ calls it also means we did not mark bounds producer
+ as necessary and it is time to do it in case free
+ call is not removed. */
+ if (gimple_call_with_bounds_p (stmt))
+ {
+ gimple bounds_def_stmt;
+ tree bounds = gimple_call_arg (stmt, 1);
+ gcc_assert (TREE_CODE (bounds) == SSA_NAME);
+ bounds_def_stmt = SSA_NAME_DEF_STMT (bounds);
+ if (bounds_def_stmt
+ && !gimple_plf (bounds_def_stmt, STMT_NECESSARY))
+ gimple_set_plf (bounds_def_stmt, STMT_NECESSARY,
+ gimple_plf (stmt, STMT_NECESSARY));
+ }
}
/* If GSI is not necessary then remove it. */
if (!gimple_plf (stmt, STMT_NECESSARY))
{
+ /* Keep clobbers that we can keep live live. */
+ if (gimple_clobber_p (stmt))
+ {
+ ssa_op_iter iter;
+ use_operand_p use_p;
+ bool dead = false;
+ FOR_EACH_SSA_USE_OPERAND (use_p, stmt, iter, SSA_OP_USE)
+ {
+ tree name = USE_FROM_PTR (use_p);
+ if (!SSA_NAME_IS_DEFAULT_DEF (name)
+ && !bitmap_bit_p (processed, SSA_NAME_VERSION (name)))
+ {
+ dead = true;
+ break;
+ }
+ }
+ if (!dead)
+ continue;
+ }
if (!is_gimple_debug (stmt))
something_changed = true;
remove_dead_stmt (&gsi, bb);
{
tree name = gimple_call_lhs (stmt);
- notice_special_calls (stmt);
+ notice_special_calls (as_a <gcall *> (stmt));
/* When LHS of var = call (); is dead, simplify it into
call (); saving one operand. */
special logic we apply to malloc/free pair removal. */
&& (!(call = gimple_call_fndecl (stmt))
|| DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL
- || (DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC
+ || (DECL_FUNCTION_CODE (call) != BUILT_IN_ALIGNED_ALLOC
+ && DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC
&& DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC
&& DECL_FUNCTION_CODE (call) != BUILT_IN_ALLOCA
&& (DECL_FUNCTION_CODE (call)
- != BUILT_IN_ALLOCA_WITH_ALIGN))))
+ != BUILT_IN_ALLOCA_WITH_ALIGN)))
+ /* Avoid doing so for bndret calls for the same reason. */
+ && !chkp_gimple_call_builtin_p (stmt, BUILT_IN_CHKP_BNDRET))
{
something_changed = true;
if (dump_file && (dump_flags & TDF_DETAILS))
maybe_clean_or_replace_eh_stmt (stmt, stmt);
update_stmt (stmt);
release_ssa_name (name);
+
+ /* GOMP_SIMD_LANE without lhs is not needed. */
+ if (gimple_call_internal_p (stmt)
+ && gimple_call_internal_fn (stmt) == IFN_GOMP_SIMD_LANE)
+ remove_dead_stmt (&gsi, bb);
}
+ else if (gimple_call_internal_p (stmt))
+ switch (gimple_call_internal_fn (stmt))
+ {
+ case IFN_ADD_OVERFLOW:
+ maybe_optimize_arith_overflow (&gsi, PLUS_EXPR);
+ break;
+ case IFN_SUB_OVERFLOW:
+ maybe_optimize_arith_overflow (&gsi, MINUS_EXPR);
+ break;
+ case IFN_MUL_OVERFLOW:
+ maybe_optimize_arith_overflow (&gsi, MULT_EXPR);
+ break;
+ default:
+ break;
+ }
}
}
}
find_unreachable_blocks ();
/* Delete all unreachable basic blocks in reverse dominator order. */
- for (bb = EXIT_BLOCK_PTR->prev_bb; bb != ENTRY_BLOCK_PTR; bb = prev_bb)
+ for (bb = EXIT_BLOCK_PTR_FOR_FN (cfun)->prev_bb;
+ bb != ENTRY_BLOCK_PTR_FOR_FN (cfun); bb = prev_bb)
{
prev_bb = bb->prev_bb;
if (!bitmap_bit_p (bb_contains_live_stmts, bb->index)
|| !(bb->flags & BB_REACHABLE))
{
- for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- if (virtual_operand_p (gimple_phi_result (gsi_stmt (gsi))))
+ for (gphi_iterator gsi = gsi_start_phis (bb); !gsi_end_p (gsi);
+ gsi_next (&gsi))
+ if (virtual_operand_p (gimple_phi_result (gsi.phi ())))
{
bool found = false;
imm_use_iterator iter;
- FOR_EACH_IMM_USE_STMT (stmt, iter, gimple_phi_result (gsi_stmt (gsi)))
+ FOR_EACH_IMM_USE_STMT (stmt, iter,
+ gimple_phi_result (gsi.phi ()))
{
if (!(gimple_bb (stmt)->flags & BB_REACHABLE))
continue;
}
}
if (found)
- mark_virtual_phi_result_for_renaming (gsi_stmt (gsi));
+ mark_virtual_phi_result_for_renaming (gsi.phi ());
}
if (!(bb->flags & BB_REACHABLE))
}
}
}
- FOR_EACH_BB (bb)
+ FOR_EACH_BB_FN (bb, cfun)
{
/* Remove dead PHI nodes. */
something_changed |= remove_dead_phis (bb);
if (aggressive)
{
- last_stmt_necessary = sbitmap_alloc (last_basic_block);
+ last_stmt_necessary = sbitmap_alloc (last_basic_block_for_fn (cfun));
bitmap_clear (last_stmt_necessary);
- bb_contains_live_stmts = sbitmap_alloc (last_basic_block);
+ bb_contains_live_stmts = sbitmap_alloc (last_basic_block_for_fn (cfun));
bitmap_clear (bb_contains_live_stmts);
}
calculate_dominance_info (CDI_POST_DOMINATORS);
cd = new control_dependences (create_edge_list ());
- visited_control_parents = sbitmap_alloc (last_basic_block);
+ visited_control_parents =
+ sbitmap_alloc (last_basic_block_for_fn (cfun));
bitmap_clear (visited_control_parents);
mark_dfs_back_edges ();
tree_dce_done (aggressive);
if (something_changed)
- return TODO_update_ssa | TODO_cleanup_cfg;
+ {
+ free_numbers_of_iterations_estimates ();
+ if (scev_initialized_p ())
+ scev_reset ();
+ return TODO_update_ssa | TODO_cleanup_cfg;
+ }
return 0;
}
return perform_tree_ssa_dce (/*aggressive=*/false);
}
-static unsigned int
-tree_ssa_dce_loop (void)
-{
- unsigned int todo;
- todo = perform_tree_ssa_dce (/*aggressive=*/false);
- if (todo)
- {
- free_numbers_of_iterations_estimates ();
- scev_reset ();
- }
- return todo;
-}
-
static unsigned int
tree_ssa_cd_dce (void)
{
return perform_tree_ssa_dce (/*aggressive=*/optimize >= 2);
}
-static bool
-gate_dce (void)
-{
- return flag_tree_dce != 0;
-}
-
namespace {
const pass_data pass_data_dce =
GIMPLE_PASS, /* type */
"dce", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
TV_TREE_DCE, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- TODO_verify_ssa, /* todo_flags_finish */
+ 0, /* todo_flags_finish */
};
class pass_dce : public gimple_opt_pass
{
public:
- pass_dce(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_dce, ctxt)
+ pass_dce (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_dce, ctxt)
{}
/* opt_pass methods: */
- opt_pass * clone () { return new pass_dce (ctxt_); }
- bool gate () { return gate_dce (); }
- unsigned int execute () { return tree_ssa_dce (); }
+ opt_pass * clone () { return new pass_dce (m_ctxt); }
+ virtual bool gate (function *) { return flag_tree_dce != 0; }
+ virtual unsigned int execute (function *) { return tree_ssa_dce (); }
}; // class pass_dce
namespace {
-const pass_data pass_data_dce_loop =
-{
- GIMPLE_PASS, /* type */
- "dceloop", /* name */
- OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
- TV_TREE_DCE, /* tv_id */
- ( PROP_cfg | PROP_ssa ), /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_verify_ssa, /* todo_flags_finish */
-};
-
-class pass_dce_loop : public gimple_opt_pass
-{
-public:
- pass_dce_loop(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_dce_loop, ctxt)
- {}
-
- /* opt_pass methods: */
- opt_pass * clone () { return new pass_dce_loop (ctxt_); }
- bool gate () { return gate_dce (); }
- unsigned int execute () { return tree_ssa_dce_loop (); }
-
-}; // class pass_dce_loop
-
-} // anon namespace
-
-gimple_opt_pass *
-make_pass_dce_loop (gcc::context *ctxt)
-{
- return new pass_dce_loop (ctxt);
-}
-
-namespace {
-
const pass_data pass_data_cd_dce =
{
GIMPLE_PASS, /* type */
"cddce", /* name */
OPTGROUP_NONE, /* optinfo_flags */
- true, /* has_gate */
- true, /* has_execute */
TV_TREE_CD_DCE, /* tv_id */
( PROP_cfg | PROP_ssa ), /* properties_required */
0, /* properties_provided */
0, /* properties_destroyed */
0, /* todo_flags_start */
- ( TODO_verify_ssa | TODO_verify_flow ), /* todo_flags_finish */
+ 0, /* todo_flags_finish */
};
class pass_cd_dce : public gimple_opt_pass
{
public:
- pass_cd_dce(gcc::context *ctxt)
- : gimple_opt_pass(pass_data_cd_dce, ctxt)
+ pass_cd_dce (gcc::context *ctxt)
+ : gimple_opt_pass (pass_data_cd_dce, ctxt)
{}
/* opt_pass methods: */
- opt_pass * clone () { return new pass_cd_dce (ctxt_); }
- bool gate () { return gate_dce (); }
- unsigned int execute () { return tree_ssa_cd_dce (); }
+ opt_pass * clone () { return new pass_cd_dce (m_ctxt); }
+ virtual bool gate (function *) { return flag_tree_dce != 0; }
+ virtual unsigned int execute (function *) { return tree_ssa_cd_dce (); }
}; // class pass_cd_dce