of space by only allocating memory for those that can throw. */
static void
-record_stmt_eh_region (struct eh_region *region, gimple t)
+record_stmt_eh_region (struct eh_region_d *region, gimple t)
{
if (!region)
return;
The eh region creation is straight-forward, but frobbing all the gotos
and such into shape isn't. */
+/* The GOTO_QUEUE is is an array of GIMPLE_GOTO and GIMPLE_RETURN
+ statements that are seen to escape this GIMPLE_TRY_FINALLY node.
+ The idea is to record a gimple statement for everything except for
+ the conditionals, which get their labels recorded. Since labels are
+ of type 'tree', we need this node to store both gimple and tree
+ objects. REPL_STMT is the sequence used to replace the goto/return
+ statement. CONT_STMT is used to store the statement that allows
+ the return/goto to jump to the original destination. */
+
+struct goto_queue_node
+{
+ treemple stmt;
+ gimple_seq repl_stmt;
+ gimple cont_stmt;
+ int index;
+ /* This is used when index >= 0 to indicate that stmt is a label (as
+ opposed to a goto stmt). */
+ int is_label;
+};
+
/* State of the world while lowering. */
struct leh_state
/* What's "current" while constructing the eh region tree. These
correspond to variables of the same name in cfun->eh, which we
don't have easy access to. */
- struct eh_region *cur_region;
- struct eh_region *prev_try;
+ struct eh_region_d *cur_region;
/* Processing of TRY_FINALLY requires a bit more state. This is
split out into a separate structure so that we don't have to
struct leh_state *outer;
/* The exception region created for it. */
- struct eh_region *region;
-
- /* The GOTO_QUEUE is is an array of GIMPLE_GOTO and GIMPLE_RETURN statements
- that are seen to escape this GIMPLE_TRY_FINALLY node.
- The idea is to record a gimple statement for everything except for
- the conditionals, which get their labels recorded. Since labels are of
- type 'tree', we need this node to store both gimple and tree objects.
- REPL_STMT is the sequence used to replace the goto/return statement.
- CONT_STMT is used to store the statement that allows the return/goto to
- jump to the original destination. */
- struct goto_queue_node {
- treemple stmt;
- gimple_seq repl_stmt;
- gimple cont_stmt;
- int index;
- /* this is used when index >= 0 to indicate that stmt is a label(as
- opposed to a goto stmt) */
- int is_label;
- } *goto_queue;
+ struct eh_region_d *region;
+
+ /* The goto queue. */
+ struct goto_queue_node *goto_queue;
size_t goto_queue_size;
size_t goto_queue_active;
this_tf.outer = state;
if (using_eh_for_cleanups_p)
this_tf.region
- = gen_eh_region_cleanup (state->cur_region, state->prev_try);
+ = gen_eh_region_cleanup (state->cur_region);
else
this_tf.region = NULL;
this_state.cur_region = this_tf.region;
- this_state.prev_try = state->prev_try;
this_state.tf = &this_tf;
lower_eh_constructs_1 (&this_state, gimple_try_eval(tp));
static gimple_seq
lower_catch (struct leh_state *state, gimple tp)
{
- struct eh_region *try_region;
+ struct eh_region_d *try_region;
struct leh_state this_state;
gimple_stmt_iterator gsi;
tree out_label;
try_region = gen_eh_region_try (state->cur_region);
this_state.cur_region = try_region;
- this_state.prev_try = try_region;
this_state.tf = state->tf;
lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
out_label = NULL;
for (gsi = gsi_start (gimple_try_cleanup (tp)); !gsi_end_p (gsi); )
{
- struct eh_region *catch_region;
+ struct eh_region_d *catch_region;
tree eh_label;
gimple x, gcatch;
gimple_catch_types (gcatch));
this_state.cur_region = catch_region;
- this_state.prev_try = state->prev_try;
lower_eh_constructs_1 (&this_state, gimple_catch_handler (gcatch));
eh_label = create_artificial_label ();
lower_eh_filter (struct leh_state *state, gimple tp)
{
struct leh_state this_state;
- struct eh_region *this_region;
+ struct eh_region_d *this_region;
gimple inner;
tree eh_label;
gimple_eh_filter_types (inner));
this_state = *state;
this_state.cur_region = this_region;
- /* For must not throw regions any cleanup regions inside it
- can't reach outer catch regions. */
- if (gimple_eh_filter_must_not_throw (inner))
- this_state.prev_try = NULL;
lower_eh_constructs_1 (&this_state, gimple_try_eval (tp));
lower_cleanup (struct leh_state *state, gimple tp)
{
struct leh_state this_state;
- struct eh_region *this_region;
+ struct eh_region_d *this_region;
struct leh_tf_state fake_tf;
gimple_seq result;
return result;
}
- this_region = gen_eh_region_cleanup (state->cur_region, state->prev_try);
+ this_region = gen_eh_region_cleanup (state->cur_region);
this_state = *state;
this_state.cur_region = this_region;
/* Construct EH edges for STMT. */
static void
-make_eh_edge (struct eh_region *region, void *data)
+make_eh_edge (struct eh_region_d *region, void *data)
{
gimple stmt;
tree lab;
src = gimple_bb (stmt);
dst = label_to_block (lab);
- make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH);
+ make_edge (src, dst, EDGE_EH);
}
/* See if STMT is call that might be inlined. */
EDGE_SUCC (bb, 0)->probability = REG_BR_PROB_BASE;
}
+/* Redirect EH edge E to NEW_BB. */
+
+edge
+redirect_eh_edge (edge e, basic_block new_bb)
+{
+ gimple stmt = gsi_stmt (gsi_last_bb (e->src));
+ int region_nr, new_region_nr;
+ bool is_resx;
+ bool inlinable = false;
+ tree label = gimple_block_label (new_bb);
+ struct eh_region_d *r;
+
+ if (gimple_code (stmt) == GIMPLE_RESX)
+ {
+ region_nr = gimple_resx_region (stmt);
+ is_resx = true;
+ }
+ else
+ {
+ region_nr = lookup_stmt_eh_region (stmt);
+ gcc_assert (region_nr >= 0);
+ is_resx = false;
+ inlinable = inlinable_call_p (stmt);
+ }
+
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Redirecting EH edge %i->%i to %i, region %i, resx %i\n",
+ e->src->index, e->dest->index, new_bb->index, region_nr, is_resx);
+ r = redirect_eh_edge_to_label (e, label, is_resx, inlinable, region_nr);
+ new_region_nr = get_eh_region_number (r);
+ if (new_region_nr != region_nr)
+ {
+ if (is_resx)
+ gimple_resx_set_region (stmt, new_region_nr);
+ else
+ {
+ remove_stmt_from_eh_region (stmt);
+ add_stmt_to_eh_region (stmt, new_region_nr);
+ }
+ }
+ e = ssa_redirect_edge (e, new_bb);
+ return e;
+}
+
static bool mark_eh_edge_found_error;
/* Mark edge make_eh_edge would create for given region by setting it aux
field, output error if something goes wrong. */
static void
-mark_eh_edge (struct eh_region *region, void *data)
+mark_eh_edge (struct eh_region_d *region, void *data)
{
gimple stmt;
tree lab;
SET_BIT (reachable, region);
}
if (gimple_code (stmt) == GIMPLE_RESX)
- SET_BIT (reachable, gimple_resx_region (stmt));
+ SET_BIT (reachable,
+ VEC_index (eh_region, cfun->eh->region_array,
+ gimple_resx_region (stmt))->region_number);
if ((region = lookup_stmt_eh_region (stmt)) >= 0)
SET_BIT (contains_stmt, region);
}
operands from DATA->bb_to_remove. */
static void
-make_eh_edge_and_update_phi (struct eh_region *region, void *data)
+make_eh_edge_and_update_phi (struct eh_region_d *region, void *data)
{
struct update_info *info = (struct update_info *) data;
edge e, e2;
}
dominance_info_invalidated = true;
e2 = find_edge (info->bb_to_remove, dst);
- e = make_edge (src, dst, EDGE_ABNORMAL | EDGE_EH);
+ e = make_edge (src, dst, EDGE_EH);
e->aux = e;
gcc_assert (e2);
for (si = gsi_start_phis (dst); !gsi_end_p (si); gsi_next (&si))
is really dead. */
if (found && !has_non_eh_preds)
- remove_eh_region (region);
+ {
+ if (dump_file && (dump_flags & TDF_DETAILS))
+ fprintf (dump_file, "Empty EH handler %i removed.\n", region);
+ remove_eh_region (region);
+ }
else if (!removed_some)
return false;