+2015-03-13 Richard Biener <rguenther@suse.de>
+
+ PR middle-end/44563
+ * tree-cfgcleanup.c (split_bb_on_noreturn_calls): Remove.
+ (cleanup_tree_cfg_1): Do not call it.
+ (execute_cleanup_cfg_post_optimizing): Fixup the CFG here.
+ (fixup_noreturn_call): Mark the stmt as control altering.
+ * tree-cfg.c (execute_fixup_cfg): Do not dump the function
+ here.
+ (pass_data_fixup_cfg): Produce a dump file.
+ * tree-ssa-dom.c: Include tree-cfgcleanup.h.
+ (need_noreturn_fixup): New global.
+ (pass_dominator::execute): Fixup queued noreturn calls.
+ (optimize_stmt): Queue calls that became noreturn for fixup.
+ * tree-ssa-forwprop.c (pass_forwprop::execute): Likewise.
+ * tree-ssa-pre.c: Include tree-cfgcleanup.h.
+ (el_to_fixup): New global.
+ (eliminate_dom_walker::before_dom_childre): Queue calls that
+ became noreturn for fixup.
+ (eliminate): Fixup queued noreturn calls.
+ * tree-ssa-propagate.c: Include tree-cfgcleanup.h.
+ (substitute_and_fold_dom_walker): New member stmts_to_fixup.
+ (substitute_and_fold_dom_walker::before_dom_children): Queue
+ alls that became noreturn for fixup.
+ (substitute_and_fold): Fixup queued noreturn calls.
+
2015-03-12 Jan Hubicka <hubicka@ucw.cz>
* ipa-icf.c (sem_function::equals_wpa): Match CXX_CONSTRUCTOR_P
if (count_scale != REG_BR_PROB_BASE)
compute_function_frequency ();
- /* Dump a textual representation of the flowgraph. */
- if (dump_file)
- gimple_dump_cfg (dump_file, dump_flags);
-
if (current_loops
&& (todo & TODO_cleanup_cfg))
loops_state_set (LOOPS_NEED_FIXUP);
const pass_data pass_data_fixup_cfg =
{
GIMPLE_PASS, /* type */
- "*free_cfg_annotations", /* name */
+ "fixup_cfg", /* name */
OPTGROUP_NONE, /* optinfo_flags */
TV_NONE, /* tv_id */
PROP_cfg, /* properties_required */
update_stmt (stmt);
}
+ /* Mark the call as altering control flow. */
+ gimple_call_set_ctrl_altering (stmt, true);
+
return remove_fallthru_edge (bb->succs);
}
-/* Split basic blocks on calls in the middle of a basic block that are now
- known not to return, and remove the unreachable code. */
-
-static bool
-split_bb_on_noreturn_calls (basic_block bb)
-{
- bool changed = false;
- gimple_stmt_iterator gsi;
-
- for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gimple stmt = gsi_stmt (gsi);
-
- if (!is_gimple_call (stmt))
- continue;
-
- if (gimple_call_noreturn_p (stmt))
- changed |= fixup_noreturn_call (stmt);
- }
-
- if (changed)
- bitmap_set_bit (cfgcleanup_altered_bbs, bb->index);
- return changed;
-}
-
/* Tries to cleanup cfg in basic block BB. Returns true if anything
changes. */
{
bb = BASIC_BLOCK_FOR_FN (cfun, i);
if (bb)
- {
- retval |= cleanup_tree_cfg_bb (bb);
- retval |= split_bb_on_noreturn_calls (bb);
- }
+ retval |= cleanup_tree_cfg_bb (bb);
}
/* Now process the altered blocks, as long as any are available. */
continue;
retval |= cleanup_tree_cfg_bb (bb);
-
- /* Rerun split_bb_on_noreturn_calls, in case we have altered any noreturn
- calls. */
- retval |= split_bb_on_noreturn_calls (bb);
}
end_recording_case_labels ();
static unsigned int
execute_cleanup_cfg_post_optimizing (void)
{
- unsigned int todo = 0;
+ unsigned int todo = execute_fixup_cfg ();
if (cleanup_tree_cfg ())
- todo |= TODO_update_ssa;
+ {
+ todo &= ~TODO_cleanup_cfg;
+ todo |= TODO_update_ssa;
+ }
maybe_remove_unreachable_handlers ();
cleanup_dead_labels ();
group_case_labels ();
#include "tree-ssa-dom.h"
#include "inchash.h"
#include "gimplify.h"
+#include "tree-cfgcleanup.h"
/* This file implements optimizations on the dominator tree. */
/* Bitmap of blocks that have had EH statements cleaned. We should
remove their dead edges eventually. */
static bitmap need_eh_cleanup;
+static vec<gimple> need_noreturn_fixup;
/* Statistics for dominator optimizations. */
struct opt_stats_d
avail_exprs_stack.create (20);
const_and_copies_stack.create (20);
need_eh_cleanup = BITMAP_ALLOC (NULL);
+ need_noreturn_fixup.create (0);
calculate_dominance_info (CDI_DOMINATORS);
cfg_altered = false;
bitmap_clear (need_eh_cleanup);
}
+ /* Fixup stmts that became noreturn calls. This may require splitting
+ blocks and thus isn't possible during the dominator walk or before
+ jump threading finished. Do this in reverse order so we don't
+ inadvertedly remove a stmt we want to fixup by visiting a dominating
+ now noreturn call first. */
+ while (!need_noreturn_fixup.is_empty ())
+ {
+ gimple stmt = need_noreturn_fixup.pop ();
+ if (dump_file && dump_flags & TDF_DETAILS)
+ {
+ fprintf (dump_file, "Fixing up noreturn call ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ fprintf (dump_file, "\n");
+ }
+ fixup_noreturn_call (stmt);
+ }
+
statistics_counter_event (fun, "Redundant expressions eliminated",
opt_stats.num_re);
statistics_counter_event (fun, "Constants propagated",
/* Free asserted bitmaps and stacks. */
BITMAP_FREE (need_eh_cleanup);
-
+ need_noreturn_fixup.release ();
avail_exprs_stack.release ();
const_and_copies_stack.release ();
gimple stmt, old_stmt;
bool may_optimize_p;
bool modified_p = false;
+ bool was_noreturn;
old_stmt = stmt = gsi_stmt (si);
+ was_noreturn = is_gimple_call (stmt) && gimple_call_noreturn_p (stmt);
if (dump_file && (dump_flags & TDF_DETAILS))
{
if (dump_file && (dump_flags & TDF_DETAILS))
fprintf (dump_file, " Flagged to clear EH edges.\n");
}
+
+ if (!was_noreturn
+ && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt))
+ need_noreturn_fixup.safe_push (stmt);
}
}
lattice.quick_grow_cleared (num_ssa_names);
int *postorder = XNEWVEC (int, n_basic_blocks_for_fn (fun));
int postorder_num = inverted_post_order_compute (postorder);
+ auto_vec<gimple, 4> to_fixup;
to_purge = BITMAP_ALLOC (NULL);
for (int i = 0; i < postorder_num; ++i)
{
gimple stmt = gsi_stmt (gsi);
gimple orig_stmt = stmt;
bool changed = false;
+ bool was_noreturn = (is_gimple_call (stmt)
+ && gimple_call_noreturn_p (stmt));
/* Mark stmt as potentially needing revisiting. */
gimple_set_plf (stmt, GF_PLF_1, false);
stmt = gsi_stmt (gsi);
if (maybe_clean_or_replace_eh_stmt (orig_stmt, stmt))
bitmap_set_bit (to_purge, bb->index);
+ if (!was_noreturn
+ && is_gimple_call (stmt) && gimple_call_noreturn_p (stmt))
+ to_fixup.safe_push (stmt);
/* Cleanup the CFG if we simplified a condition to
true or false. */
if (gcond *cond = dyn_cast <gcond *> (stmt))
free (postorder);
lattice.release ();
+ /* Fixup stmts that became noreturn calls. This may require splitting
+ blocks and thus isn't possible during the walk. Do this
+ in reverse order so we don't inadvertedly remove a stmt we want to
+ fixup by visiting a dominating now noreturn call first. */
+ while (!to_fixup.is_empty ())
+ {
+ gimple stmt = to_fixup.pop ();
+ if (dump_file && dump_flags & TDF_DETAILS)
+ {
+ fprintf (dump_file, "Fixing up noreturn call ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ fprintf (dump_file, "\n");
+ }
+ cfg_changed |= fixup_noreturn_call (stmt);
+ }
+
cfg_changed |= gimple_purge_all_dead_eh_edges (to_purge);
BITMAP_FREE (to_purge);
#include "ipa-prop.h"
#include "tree-ssa-propagate.h"
#include "ipa-utils.h"
+#include "tree-cfgcleanup.h"
/* TODO:
/* Local state for the eliminate domwalk. */
static vec<gimple> el_to_remove;
+static vec<gimple> el_to_fixup;
static unsigned int el_todo;
static vec<tree> el_avail;
static vec<tree> el_avail_stack;
/* 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))
- el_todo |= TODO_cleanup_cfg;
+ el_to_fixup.safe_push (stmt);
}
else
{
need_ab_cleanup = BITMAP_ALLOC (NULL);
el_to_remove.create (0);
+ el_to_fixup.create (0);
el_todo = 0;
el_avail.create (num_ssa_names);
el_avail_stack.create (0);
}
el_to_remove.release ();
+ /* Fixup stmts that became noreturn calls. This may require splitting
+ blocks and thus isn't possible during the dominator walk. Do this
+ in reverse order so we don't inadvertedly remove a stmt we want to
+ fixup by visiting a dominating now noreturn call first. */
+ while (!el_to_fixup.is_empty ())
+ {
+ stmt = el_to_fixup.pop ();
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ {
+ fprintf (dump_file, "Fixing up noreturn call ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ }
+
+ if (fixup_noreturn_call (stmt))
+ el_todo |= TODO_cleanup_cfg;
+ }
+ el_to_fixup.release ();
+
return el_todo;
}
#include "value-prof.h"
#include "domwalk.h"
#include "cfgloop.h"
+#include "tree-cfgcleanup.h"
/* This file implements a generic value propagation engine based on
the same propagation used by the SSA-CCP algorithm [1].
fold_fn (fold_fn_), do_dce (do_dce_), something_changed (false)
{
stmts_to_remove.create (0);
+ stmts_to_fixup.create (0);
need_eh_cleanup = BITMAP_ALLOC (NULL);
}
~substitute_and_fold_dom_walker ()
{
stmts_to_remove.release ();
+ stmts_to_fixup.release ();
BITMAP_FREE (need_eh_cleanup);
}
bool do_dce;
bool something_changed;
vec<gimple> stmts_to_remove;
+ vec<gimple> stmts_to_fixup;
bitmap need_eh_cleanup;
};
{
bool did_replace;
gimple stmt = gsi_stmt (i);
- gimple old_stmt;
enum gimple_code code = gimple_code (stmt);
/* Ignore ASSERT_EXPRs. They are used by VRP to generate
print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM);
}
- old_stmt = stmt;
+ gimple old_stmt = stmt;
+ bool was_noreturn = (is_gimple_call (stmt)
+ && gimple_call_noreturn_p (stmt));
/* Some statements may be simplified using propagator
specific information. Do this before propagating
if (maybe_clean_or_replace_eh_stmt (old_stmt, stmt))
bitmap_set_bit (need_eh_cleanup, bb->index);
+ /* If we turned a not noreturn call into a noreturn one
+ schedule it for fixup. */
+ if (!was_noreturn
+ && is_gimple_call (stmt)
+ && gimple_call_noreturn_p (stmt))
+ stmts_to_fixup.safe_push (stmt);
+
if (is_gimple_assign (stmt)
&& (get_gimple_rhs_class (gimple_assign_rhs_code (stmt))
== GIMPLE_SINGLE_RHS))
if (!bitmap_empty_p (walker.need_eh_cleanup))
gimple_purge_all_dead_eh_edges (walker.need_eh_cleanup);
+ /* Fixup stmts that became noreturn calls. This may require splitting
+ blocks and thus isn't possible during the dominator walk. Do this
+ in reverse order so we don't inadvertedly remove a stmt we want to
+ fixup by visiting a dominating now noreturn call first. */
+ while (!walker.stmts_to_fixup.is_empty ())
+ {
+ gimple stmt = walker.stmts_to_fixup.pop ();
+ if (dump_file && dump_flags & TDF_DETAILS)
+ {
+ fprintf (dump_file, "Fixing up noreturn call ");
+ print_gimple_stmt (dump_file, stmt, 0, 0);
+ fprintf (dump_file, "\n");
+ }
+ fixup_noreturn_call (stmt);
+ }
+
statistics_counter_event (cfun, "Constants propagated",
prop_stats.num_const_prop);
statistics_counter_event (cfun, "Copies propagated",