X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gcc%2Ftree-eh.c;h=973782ba5a86fd832db34156dbba5d21d01c8d67;hb=refs%2Fheads%2Fdevel;hp=2da170dded3afe876f445760b8692035fff88e9d;hpb=b209d8dc611f3cd793491b8490522bdaf819622b;p=platform%2Fupstream%2Fgcc48.git diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 2da170d..973782b 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -1,6 +1,5 @@ /* Exception handling semantics and decomposition for trees. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 - Free Software Foundation, Inc. + Copyright (C) 2003-2013 Free Software Foundation, Inc. This file is part of GCC. @@ -28,16 +27,14 @@ along with GCC; see the file COPYING3. If not see #include "except.h" #include "pointer-set.h" #include "tree-flow.h" -#include "tree-dump.h" #include "tree-inline.h" -#include "tree-iterator.h" #include "tree-pass.h" -#include "timevar.h" #include "langhooks.h" #include "ggc.h" #include "diagnostic-core.h" #include "gimple.h" #include "target.h" +#include "cfgloop.h" /* In some instances a tree and a gimple need to be stored in a same table, i.e. in hash tables. This is a structure to do this. */ @@ -323,6 +320,7 @@ static bitmap eh_region_may_contain_throw_map; struct goto_queue_node { treemple stmt; + location_t location; gimple_seq repl_stmt; gimple cont_stmt; int index; @@ -379,7 +377,7 @@ struct leh_tf_state struct pointer_map_t *goto_queue_map; /* The set of unique labels seen as entries in the goto queue. */ - VEC(tree,heap) *dest_array; + vec dest_array; /* A label to be added at the end of the completed transformed sequence. It will be set if may_fallthru was true *at one time*, @@ -405,7 +403,7 @@ static gimple_seq lower_eh_must_not_throw (struct leh_state *, gimple); #define LARGE_GOTO_QUEUE 20 -static void lower_eh_constructs_1 (struct leh_state *state, gimple_seq seq); +static void lower_eh_constructs_1 (struct leh_state *state, gimple_seq *seq); static gimple_seq find_goto_replacement (struct leh_tf_state *tf, treemple stmt) @@ -480,7 +478,7 @@ replace_goto_queue_cond_clause (tree *tp, struct leh_tf_state *tf, /* The real work of replace_goto_queue. Returns with TSI updated to point to the next statement. */ -static void replace_goto_queue_stmt_list (gimple_seq, struct leh_tf_state *); +static void replace_goto_queue_stmt_list (gimple_seq *, struct leh_tf_state *); static void replace_goto_queue_1 (gimple stmt, struct leh_tf_state *tf, @@ -510,18 +508,18 @@ replace_goto_queue_1 (gimple stmt, struct leh_tf_state *tf, break; case GIMPLE_TRY: - replace_goto_queue_stmt_list (gimple_try_eval (stmt), tf); - replace_goto_queue_stmt_list (gimple_try_cleanup (stmt), tf); + replace_goto_queue_stmt_list (gimple_try_eval_ptr (stmt), tf); + replace_goto_queue_stmt_list (gimple_try_cleanup_ptr (stmt), tf); break; case GIMPLE_CATCH: - replace_goto_queue_stmt_list (gimple_catch_handler (stmt), tf); + replace_goto_queue_stmt_list (gimple_catch_handler_ptr (stmt), tf); break; case GIMPLE_EH_FILTER: - replace_goto_queue_stmt_list (gimple_eh_filter_failure (stmt), tf); + replace_goto_queue_stmt_list (gimple_eh_filter_failure_ptr (stmt), tf); break; case GIMPLE_EH_ELSE: - replace_goto_queue_stmt_list (gimple_eh_else_n_body (stmt), tf); - replace_goto_queue_stmt_list (gimple_eh_else_e_body (stmt), tf); + replace_goto_queue_stmt_list (gimple_eh_else_n_body_ptr (stmt), tf); + replace_goto_queue_stmt_list (gimple_eh_else_e_body_ptr (stmt), tf); break; default: @@ -535,9 +533,9 @@ replace_goto_queue_1 (gimple stmt, struct leh_tf_state *tf, /* A subroutine of replace_goto_queue. Handles GIMPLE_SEQ. */ static void -replace_goto_queue_stmt_list (gimple_seq seq, struct leh_tf_state *tf) +replace_goto_queue_stmt_list (gimple_seq *seq, struct leh_tf_state *tf) { - gimple_stmt_iterator gsi = gsi_start (seq); + gimple_stmt_iterator gsi = gsi_start (*seq); while (!gsi_end_p (gsi)) replace_goto_queue_1 (gsi_stmt (gsi), tf, &gsi); @@ -550,8 +548,8 @@ replace_goto_queue (struct leh_tf_state *tf) { if (tf->goto_queue_active == 0) return; - replace_goto_queue_stmt_list (tf->top_p_seq, tf); - replace_goto_queue_stmt_list (eh_seq, tf); + replace_goto_queue_stmt_list (&tf->top_p_seq, tf); + replace_goto_queue_stmt_list (&eh_seq, tf); } /* Add a new record to the goto queue contained in TF. NEW_STMT is the @@ -562,7 +560,8 @@ static void record_in_goto_queue (struct leh_tf_state *tf, treemple new_stmt, int index, - bool is_label) + bool is_label, + location_t location) { size_t active, size; struct goto_queue_node *q; @@ -585,6 +584,7 @@ record_in_goto_queue (struct leh_tf_state *tf, memset (q, 0, sizeof (*q)); q->stmt = new_stmt; q->index = index; + q->location = location; q->is_label = is_label; } @@ -592,7 +592,8 @@ record_in_goto_queue (struct leh_tf_state *tf, TF is not null. */ static void -record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label) +record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label, + location_t location) { int index; treemple temp, new_stmt; @@ -611,27 +612,27 @@ record_in_goto_queue_label (struct leh_tf_state *tf, treemple stmt, tree label) if (!outside_finally_tree (temp, tf->try_finally_expr)) return; - if (! tf->dest_array) + if (! tf->dest_array.exists ()) { - tf->dest_array = VEC_alloc (tree, heap, 10); - VEC_quick_push (tree, tf->dest_array, label); + tf->dest_array.create (10); + tf->dest_array.quick_push (label); index = 0; } else { - int n = VEC_length (tree, tf->dest_array); + int n = tf->dest_array.length (); for (index = 0; index < n; ++index) - if (VEC_index (tree, tf->dest_array, index) == label) + if (tf->dest_array[index] == label) break; if (index == n) - VEC_safe_push (tree, heap, tf->dest_array, label); + tf->dest_array.safe_push (label); } /* In the case of a GOTO we want to record the destination label, since with a GIMPLE_COND we have an easy access to the then/else labels. */ new_stmt = stmt; - record_in_goto_queue (tf, new_stmt, index, true); + record_in_goto_queue (tf, new_stmt, index, true, location); } /* For any GIMPLE_GOTO or GIMPLE_RETURN, decide whether it leaves a try_finally @@ -651,19 +652,22 @@ maybe_record_in_goto_queue (struct leh_state *state, gimple stmt) { case GIMPLE_COND: new_stmt.tp = gimple_op_ptr (stmt, 2); - record_in_goto_queue_label (tf, new_stmt, gimple_cond_true_label (stmt)); + record_in_goto_queue_label (tf, new_stmt, gimple_cond_true_label (stmt), + EXPR_LOCATION (*new_stmt.tp)); new_stmt.tp = gimple_op_ptr (stmt, 3); - record_in_goto_queue_label (tf, new_stmt, gimple_cond_false_label (stmt)); + record_in_goto_queue_label (tf, new_stmt, gimple_cond_false_label (stmt), + EXPR_LOCATION (*new_stmt.tp)); break; case GIMPLE_GOTO: new_stmt.g = stmt; - record_in_goto_queue_label (tf, new_stmt, gimple_goto_dest (stmt)); + record_in_goto_queue_label (tf, new_stmt, gimple_goto_dest (stmt), + gimple_location (stmt)); break; case GIMPLE_RETURN: tf->may_return = true; new_stmt.g = stmt; - record_in_goto_queue (tf, new_stmt, -1, false); + record_in_goto_queue (tf, new_stmt, -1, false, gimple_location (stmt)); break; default: @@ -730,13 +734,11 @@ do_return_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod) q->cont_stmt = q->stmt.g; - if (!q->repl_stmt) - q->repl_stmt = gimple_seq_alloc (); - if (mod) gimple_seq_add_seq (&q->repl_stmt, mod); x = gimple_build_goto (finlab); + gimple_set_location (x, q->location); gimple_seq_add_stmt (&q->repl_stmt, x); } @@ -749,15 +751,14 @@ do_goto_redirection (struct goto_queue_node *q, tree finlab, gimple_seq mod, gimple x; gcc_assert (q->is_label); - if (!q->repl_stmt) - q->repl_stmt = gimple_seq_alloc (); - q->cont_stmt = gimple_build_goto (VEC_index (tree, tf->dest_array, q->index)); + q->cont_stmt = gimple_build_goto (tf->dest_array[q->index]); if (mod) gimple_seq_add_seq (&q->repl_stmt, mod); x = gimple_build_goto (finlab); + gimple_set_location (x, q->location); gimple_seq_add_stmt (&q->repl_stmt, x); } @@ -857,6 +858,7 @@ frob_into_branch_around (gimple tp, eh_region region, tree over) if (!over) over = create_artificial_label (loc); x = gimple_build_goto (over); + gimple_set_location (x, loc); gimple_seq_add_stmt (&cleanup, x); } gimple_seq_add_seq (&eh_seq, cleanup); @@ -873,13 +875,26 @@ frob_into_branch_around (gimple tp, eh_region region, tree over) Make sure to record all new labels found. */ static gimple_seq -lower_try_finally_dup_block (gimple_seq seq, struct leh_state *outer_state) +lower_try_finally_dup_block (gimple_seq seq, struct leh_state *outer_state, + location_t loc) { gimple region = NULL; gimple_seq new_seq; + gimple_stmt_iterator gsi; new_seq = copy_gimple_seq_and_replace_locals (seq); + for (gsi = gsi_start (new_seq); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION) + { + tree block = gimple_block (stmt); + gimple_set_location (stmt, loc); + gimple_set_block (stmt, block); + } + } + if (outer_state->tf) region = outer_state->tf->try_finally_expr; collect_finally_tree_1 (new_seq, region); @@ -974,7 +989,8 @@ honor_protect_cleanup_actions (struct leh_state *outer_state, gimple_try_set_cleanup (tf->top_p, gimple_eh_else_n_body (eh_else)); } else if (this_state) - finally = lower_try_finally_dup_block (finally, outer_state); + finally = lower_try_finally_dup_block (finally, outer_state, + gimple_location (tf->try_finally_expr)); finally_may_fallthru = gimple_seq_may_fallthru (finally); /* If this cleanup consists of a TRY_CATCH_EXPR with TRY_CATCH_IS_CLEANUP @@ -1049,13 +1065,13 @@ lower_try_finally_nofallthru (struct leh_state *state, if (eh_else) { finally = gimple_eh_else_n_body (eh_else); - lower_eh_constructs_1 (state, finally); + lower_eh_constructs_1 (state, &finally); gimple_seq_add_seq (&tf->top_p_seq, finally); if (tf->may_throw) { finally = gimple_eh_else_e_body (eh_else); - lower_eh_constructs_1 (state, finally); + lower_eh_constructs_1 (state, &finally); emit_post_landing_pad (&eh_seq, tf->region); gimple_seq_add_seq (&eh_seq, finally); @@ -1063,7 +1079,7 @@ lower_try_finally_nofallthru (struct leh_state *state, } else { - lower_eh_constructs_1 (state, finally); + lower_eh_constructs_1 (state, &finally); gimple_seq_add_seq (&tf->top_p_seq, finally); if (tf->may_throw) @@ -1071,6 +1087,7 @@ lower_try_finally_nofallthru (struct leh_state *state, emit_post_landing_pad (&eh_seq, tf->region); x = gimple_build_goto (lab); + gimple_set_location (x, gimple_location (tf->try_finally_expr)); gimple_seq_add_stmt (&eh_seq, x); } } @@ -1086,6 +1103,7 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf) struct goto_queue_node *q, *qe; gimple x; gimple_seq finally; + gimple_stmt_iterator gsi; tree finally_label; location_t loc = gimple_location (tf->try_finally_expr); @@ -1104,7 +1122,18 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf) finally = gimple_eh_else_n_body (x); } - lower_eh_constructs_1 (state, finally); + lower_eh_constructs_1 (state, &finally); + + for (gsi = gsi_start (finally); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple stmt = gsi_stmt (gsi); + if (LOCATION_LOCUS (gimple_location (stmt)) == UNKNOWN_LOCATION) + { + tree block = gimple_block (stmt); + gimple_set_location (stmt, gimple_location (tf->try_finally_expr)); + gimple_set_block (stmt, block); + } + } if (tf->may_throw) { @@ -1147,7 +1176,7 @@ lower_try_finally_onedest (struct leh_state *state, struct leh_tf_state *tf) do_goto_redirection (q, finally_label, NULL, tf); replace_goto_queue (tf); - if (VEC_index (tree, tf->dest_array, 0) == tf->fallthru_label) + if (tf->dest_array[0] == tf->fallthru_label) { /* Reachable by goto to fallthru label only. Redirect it to the new label (already created, sadly), and do not @@ -1191,12 +1220,13 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf) if (tf->may_fallthru) { - seq = lower_try_finally_dup_block (finally, state); - lower_eh_constructs_1 (state, seq); + seq = lower_try_finally_dup_block (finally, state, tf_loc); + lower_eh_constructs_1 (state, &seq); gimple_seq_add_seq (&new_stmt, seq); tmp = lower_try_finally_fallthru_label (tf); x = gimple_build_goto (tmp); + gimple_set_location (x, tf_loc); gimple_seq_add_stmt (&new_stmt, x); } @@ -1207,8 +1237,8 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf) if (eh_else) seq = gimple_eh_else_e_body (eh_else); else - seq = lower_try_finally_dup_block (finally, state); - lower_eh_constructs_1 (state, seq); + seq = lower_try_finally_dup_block (finally, state, tf_loc); + lower_eh_constructs_1 (state, &seq); emit_post_landing_pad (&eh_seq, tf->region); gimple_seq_add_seq (&eh_seq, seq); @@ -1225,7 +1255,7 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf) tree label; } *labels; - return_index = VEC_length (tree, tf->dest_array); + return_index = tf->dest_array.length (); labels = XCNEWVEC (struct labels_s, return_index + 1); q = tf->goto_queue; @@ -1257,8 +1287,8 @@ lower_try_finally_copy (struct leh_state *state, struct leh_tf_state *tf) x = gimple_build_label (lab); gimple_seq_add_stmt (&new_stmt, x); - seq = lower_try_finally_dup_block (finally, state); - lower_eh_constructs_1 (state, seq); + seq = lower_try_finally_dup_block (finally, state, q->location); + lower_eh_constructs_1 (state, &seq); gimple_seq_add_seq (&new_stmt, seq); gimple_seq_add_stmt (&new_stmt, q->cont_stmt); @@ -1304,8 +1334,8 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) int return_index, eh_index, fallthru_index; int nlabels, ndests, j, last_case_index; tree last_case; - VEC (tree,heap) *case_label_vec; - gimple_seq switch_body; + vec case_label_vec; + gimple_seq switch_body = NULL; gimple x, eh_else; tree tmp; gimple switch_stmt; @@ -1316,7 +1346,6 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) /* The location of the finally block. */ location_t finally_loc; - switch_body = gimple_seq_alloc (); finally = gimple_try_cleanup (tf->top_p); eh_else = get_eh_else (finally); @@ -1329,10 +1358,10 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) finally_loc = x ? gimple_location (x) : tf_loc; /* Lower the finally block itself. */ - lower_eh_constructs_1 (state, finally); + lower_eh_constructs_1 (state, &finally); /* Prepare for switch statement generation. */ - nlabels = VEC_length (tree, tf->dest_array); + nlabels = tf->dest_array.length (); return_index = nlabels; eh_index = return_index + tf->may_return; fallthru_index = eh_index + (tf->may_throw && !eh_else); @@ -1341,16 +1370,16 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) finally_tmp = create_tmp_var (integer_type_node, "finally_tmp"); finally_label = create_artificial_label (finally_loc); - /* We use VEC_quick_push on case_label_vec throughout this function, + /* We use vec::quick_push on case_label_vec throughout this function, since we know the size in advance and allocate precisely as muce space as needed. */ - case_label_vec = VEC_alloc (tree, heap, ndests); + case_label_vec.create (ndests); last_case = NULL; last_case_index = 0; /* Begin inserting code for getting to the finally block. Things are done in this order to correspond to the sequence the code is - layed out. */ + laid out. */ if (tf->may_fallthru) { @@ -1362,7 +1391,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) tmp = build_int_cst (integer_type_node, fallthru_index); last_case = build_case_label (tmp, NULL, create_artificial_label (tf_loc)); - VEC_quick_push (tree, case_label_vec, last_case); + case_label_vec.quick_push (last_case); last_case_index++; x = gimple_build_label (CASE_LABEL (last_case)); @@ -1370,6 +1399,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) tmp = lower_try_finally_fallthru_label (tf); x = gimple_build_goto (tmp); + gimple_set_location (x, tf_loc); gimple_seq_add_stmt (&switch_body, x); } @@ -1380,7 +1410,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) if (tf->may_throw) { finally = gimple_eh_else_e_body (eh_else); - lower_eh_constructs_1 (state, finally); + lower_eh_constructs_1 (state, &finally); emit_post_landing_pad (&eh_seq, tf->region); gimple_seq_add_seq (&eh_seq, finally); @@ -1398,12 +1428,13 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) gimple_seq_add_stmt (&eh_seq, x); x = gimple_build_goto (finally_label); + gimple_set_location (x, tf_loc); gimple_seq_add_stmt (&eh_seq, x); tmp = build_int_cst (integer_type_node, eh_index); last_case = build_case_label (tmp, NULL, create_artificial_label (tf_loc)); - VEC_quick_push (tree, case_label_vec, last_case); + case_label_vec.quick_push (last_case); last_case_index++; x = gimple_build_label (CASE_LABEL (last_case)); @@ -1424,12 +1455,10 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) entrance through a particular edge. */ for (; q < qe; ++q) { - gimple_seq mod; + gimple_seq mod = NULL; int switch_id; unsigned int case_index; - mod = gimple_seq_alloc (); - if (q->index < 0) { x = gimple_build_assign (finally_tmp, @@ -1449,8 +1478,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) } case_index = j + q->index; - if (VEC_length (tree, case_label_vec) <= case_index - || !VEC_index (tree, case_label_vec, case_index)) + if (case_label_vec.length () <= case_index || !case_label_vec[case_index]) { tree case_lab; void **slot; @@ -1463,7 +1491,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) cont_map = pointer_map_create (); slot = pointer_map_insert (cont_map, case_lab); *slot = q->cont_stmt; - VEC_quick_push (tree, case_label_vec, case_lab); + case_label_vec.quick_push (case_lab); } } for (j = last_case_index; j < last_case_index + nlabels; j++) @@ -1471,7 +1499,7 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) gimple cont_stmt; void **slot; - last_case = VEC_index (tree, case_label_vec, j); + last_case = case_label_vec[j]; gcc_assert (last_case); gcc_assert (cont_map); @@ -1497,8 +1525,8 @@ lower_try_finally_switch (struct leh_state *state, struct leh_tf_state *tf) /* Build the switch statement, setting last_case to be the default label. */ - switch_stmt = gimple_build_switch_vec (finally_tmp, last_case, - case_label_vec); + switch_stmt = gimple_build_switch (finally_tmp, last_case, + case_label_vec); gimple_set_location (switch_stmt, finally_loc); /* Need to link SWITCH_STMT after running replace_goto_queue @@ -1621,7 +1649,7 @@ lower_try_finally (struct leh_state *state, gimple tp) old_eh_seq = eh_seq; eh_seq = NULL; - lower_eh_constructs_1 (&this_state, gimple_try_eval(tp)); + lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp)); /* Determine if the try block is escaped through the bottom. */ this_tf.may_fallthru = gimple_seq_may_fallthru (gimple_try_eval (tp)); @@ -1636,7 +1664,7 @@ lower_try_finally (struct leh_state *state, gimple tp) how many destinations are reached by the finally block. Use this to determine how we process the finally block itself. */ - ndests = VEC_length (tree, this_tf.dest_array); + ndests = this_tf.dest_array.length (); ndests += this_tf.may_fallthru; ndests += this_tf.may_return; ndests += this_tf.may_throw; @@ -1671,7 +1699,7 @@ lower_try_finally (struct leh_state *state, gimple tp) gimple_seq_add_stmt (&this_tf.top_p_seq, x); } - VEC_free (tree, heap, this_tf.dest_array); + this_tf.dest_array.release (); free (this_tf.goto_queue); if (this_tf.goto_queue_map) pointer_map_destroy (this_tf.goto_queue_map); @@ -1704,7 +1732,7 @@ lower_catch (struct leh_state *state, gimple tp) struct leh_state this_state = *state; gimple_stmt_iterator gsi; tree out_label; - gimple_seq new_seq; + gimple_seq new_seq, cleanup; gimple x; location_t try_catch_loc = gimple_location (tp); @@ -1714,7 +1742,7 @@ lower_catch (struct leh_state *state, gimple tp) this_state.cur_region = try_region; } - lower_eh_constructs_1 (&this_state, gimple_try_eval (tp)); + lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp)); if (!eh_region_may_contain_throw (try_region)) return gimple_try_eval (tp); @@ -1727,7 +1755,8 @@ lower_catch (struct leh_state *state, gimple tp) this_state.ehp_region = try_region; out_label = NULL; - for (gsi = gsi_start (gimple_try_cleanup (tp)); + cleanup = gimple_try_cleanup (tp); + for (gsi = gsi_start (cleanup); !gsi_end_p (gsi); gsi_next (&gsi)) { @@ -1739,7 +1768,7 @@ lower_catch (struct leh_state *state, gimple tp) c = gen_eh_region_catch (try_region, gimple_catch_types (gcatch)); handler = gimple_catch_handler (gcatch); - lower_eh_constructs_1 (&this_state, handler); + lower_eh_constructs_1 (&this_state, &handler); c->label = create_artificial_label (UNKNOWN_LOCATION); x = gimple_build_label (c->label); @@ -1785,7 +1814,7 @@ lower_eh_filter (struct leh_state *state, gimple tp) this_state.cur_region = this_region; } - lower_eh_constructs_1 (&this_state, gimple_try_eval (tp)); + lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp)); if (!eh_region_may_contain_throw (this_region)) return gimple_try_eval (tp); @@ -1801,7 +1830,7 @@ lower_eh_filter (struct leh_state *state, gimple tp) x = gimple_build_label (this_region->u.allowed.label); gimple_seq_add_stmt (&new_seq, x); - lower_eh_constructs_1 (&this_state, gimple_eh_filter_failure (inner)); + lower_eh_constructs_1 (&this_state, gimple_eh_filter_failure_ptr (inner)); gimple_seq_add_seq (&new_seq, gimple_eh_filter_failure (inner)); gimple_try_set_cleanup (tp, new_seq); @@ -1826,7 +1855,8 @@ lower_eh_must_not_throw (struct leh_state *state, gimple tp) this_region = gen_eh_region_must_not_throw (state->cur_region); this_region->u.must_not_throw.failure_decl = gimple_eh_must_not_throw_fndecl (inner); - this_region->u.must_not_throw.failure_loc = gimple_location (tp); + this_region->u.must_not_throw.failure_loc + = LOCATION_LOCUS (gimple_location (tp)); /* In order to get mangling applied to this decl, we must mark it used now. Otherwise, pass_ipa_free_lang_data won't think it @@ -1836,7 +1866,7 @@ lower_eh_must_not_throw (struct leh_state *state, gimple tp) this_state.cur_region = this_region; } - lower_eh_constructs_1 (&this_state, gimple_try_eval (tp)); + lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp)); return gimple_try_eval (tp); } @@ -1859,7 +1889,7 @@ lower_cleanup (struct leh_state *state, gimple tp) this_state.cur_region = this_region; } - lower_eh_constructs_1 (&this_state, gimple_try_eval (tp)); + lower_eh_constructs_1 (&this_state, gimple_try_eval_ptr (tp)); if (cleanup_dead || !eh_region_may_contain_throw (this_region)) return gimple_try_eval (tp); @@ -1879,7 +1909,7 @@ lower_cleanup (struct leh_state *state, gimple tp) { /* In this case honor_protect_cleanup_actions had nothing to do, and we should process this normally. */ - lower_eh_constructs_1 (state, gimple_try_cleanup (tp)); + lower_eh_constructs_1 (state, gimple_try_cleanup_ptr (tp)); result = frob_into_branch_around (tp, this_region, fake_tf.fallthru_label); } @@ -1962,7 +1992,7 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi) /* If the stmt can throw use a new temporary for the assignment to a LHS. This makes sure the old value of the LHS is available on the EH edge. Only do so for statements that - potentially fall thru (no noreturn calls e.g.), otherwise + potentially fall through (no noreturn calls e.g.), otherwise this new assignment might create fake fallthru regions. */ if (stmt_could_throw_p (stmt) && gimple_has_lhs (stmt) @@ -2008,7 +2038,7 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi) if (!x) { replace = gimple_try_eval (stmt); - lower_eh_constructs_1 (state, replace); + lower_eh_constructs_1 (state, &replace); } else switch (gimple_code (x)) @@ -2055,10 +2085,10 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi) /* A helper to unwrap a gimple_seq and feed stmts to lower_eh_constructs_2. */ static void -lower_eh_constructs_1 (struct leh_state *state, gimple_seq seq) +lower_eh_constructs_1 (struct leh_state *state, gimple_seq *pseq) { gimple_stmt_iterator gsi; - for (gsi = gsi_start (seq); !gsi_end_p (gsi);) + for (gsi = gsi_start (*pseq); !gsi_end_p (gsi);) lower_eh_constructs_2 (state, &gsi); } @@ -2077,7 +2107,8 @@ lower_eh_constructs (void) memset (&null_state, 0, sizeof (null_state)); collect_finally_tree_1 (bodyp, NULL); - lower_eh_constructs_1 (&null_state, bodyp); + lower_eh_constructs_1 (&null_state, &bodyp); + gimple_set_body (current_function_decl, bodyp); /* We assume there's a return statement, or something, at the end of the function, and thus ploping the EH sequence afterward won't @@ -2108,6 +2139,7 @@ struct gimple_opt_pass pass_lower_eh = { GIMPLE_PASS, "eh", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ NULL, /* gate */ lower_eh_constructs, /* execute */ NULL, /* sub */ @@ -2531,7 +2563,7 @@ tree_could_trap_p (tree expr) if (!DECL_EXTERNAL (expr)) return false; node = cgraph_function_node (cgraph_get_node (expr), NULL); - if (node && node->in_other_partition) + if (node && node->symbol.in_other_partition) return false; return true; } @@ -2547,7 +2579,7 @@ tree_could_trap_p (tree expr) if (!DECL_EXTERNAL (expr)) return false; node = varpool_variable_node (varpool_get_node (expr), NULL); - if (node && node->in_other_partition) + if (node && node->symbol.in_other_partition) return false; return true; } @@ -2752,7 +2784,7 @@ maybe_clean_or_replace_eh_stmt (gimple old_stmt, gimple new_stmt) return false; } -/* Given a statement OLD_STMT in OLD_FUN and a duplicate statment NEW_STMT +/* Given a statement OLD_STMT in OLD_FUN and a duplicate statement NEW_STMT in NEW_FUN, copy the EH table data from OLD_STMT to NEW_STMT. The MAP operand is the return value of duplicate_eh_regions. */ @@ -2778,7 +2810,7 @@ maybe_duplicate_eh_stmt_fn (struct function *new_fun, gimple new_stmt, { eh_landing_pad old_lp, new_lp; - old_lp = VEC_index (eh_landing_pad, old_fun->eh->lp_array, old_lp_nr); + old_lp = (*old_fun->eh->lp_array)[old_lp_nr]; slot = pointer_map_contains (map, old_lp); new_lp = (eh_landing_pad) *slot; new_lp_nr = new_lp->index; @@ -2787,7 +2819,7 @@ maybe_duplicate_eh_stmt_fn (struct function *new_fun, gimple new_stmt, { eh_region old_r, new_r; - old_r = VEC_index (eh_region, old_fun->eh->region_array, -old_lp_nr); + old_r = (*old_fun->eh->region_array)[-old_lp_nr]; slot = pointer_map_contains (map, old_r); new_r = (eh_region) *slot; new_lp_nr = -new_r->index; @@ -2872,8 +2904,10 @@ optimize_double_finally (gimple one, gimple two) { gimple oneh; gimple_stmt_iterator gsi; + gimple_seq cleanup; - gsi = gsi_start (gimple_try_cleanup (one)); + cleanup = gimple_try_cleanup (one); + gsi = gsi_start (cleanup); if (!gsi_one_before_end_p (gsi)) return; @@ -2965,6 +2999,7 @@ struct gimple_opt_pass pass_refactor_eh = { GIMPLE_PASS, "ehopt", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ gate_refactor_eh, /* gate */ refactor_eh, /* execute */ NULL, /* sub */ @@ -3040,6 +3075,8 @@ lower_resx (basic_block bb, gimple stmt, struct pointer_map_t *mnt_map) gimple_stmt_iterator gsi2; new_bb = create_empty_bb (bb); + if (current_loops) + add_bb_to_loop (new_bb, bb->loop_father); lab = gimple_block_label (new_bb); gsi2 = gsi_start_bb (new_bb); @@ -3171,6 +3208,7 @@ struct gimple_opt_pass pass_lower_resx = { GIMPLE_PASS, "resx", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ gate_lower_resx, /* gate */ execute_lower_resx, /* execute */ NULL, /* sub */ @@ -3254,22 +3292,18 @@ sink_clobbers (basic_block bb) for (gsi_prev (&gsi); !gsi_end_p (gsi); gsi_prev (&gsi)) { gimple stmt = gsi_stmt (gsi); - tree vdef; if (is_gimple_debug (stmt)) continue; if (gimple_code (stmt) == GIMPLE_LABEL) break; unlink_stmt_vdef (stmt); gsi_remove (&gsi, false); - vdef = gimple_vdef (stmt); - if (vdef && TREE_CODE (vdef) == SSA_NAME) - { - vdef = SSA_NAME_VAR (vdef); - mark_sym_for_renaming (vdef); - gimple_set_vdef (stmt, vdef); - gimple_set_vuse (stmt, vdef); - } - release_defs (stmt); + /* Trigger the operand scanner to cause renaming for virtual + operands for this statement. + ??? Given the simple structure of this code manually + figuring out the reaching definition should not be too hard. */ + if (gimple_vuse (stmt)) + gimple_set_vuse (stmt, NULL_TREE); gsi_insert_before (&dgsi, stmt, GSI_SAME_STMT); } @@ -3298,7 +3332,7 @@ lower_eh_dispatch (basic_block src, gimple stmt) { case ERT_TRY: { - VEC (tree, heap) *labels = NULL; + vec labels = vNULL; tree default_label = NULL; eh_catch c; edge_iterator ei; @@ -3307,7 +3341,7 @@ lower_eh_dispatch (basic_block src, gimple stmt) /* Collect the labels for a switch. Zero the post_landing_pad field becase we'll no longer have anything keeping these labels - in existance and the optimizer will be free to merge these + in existence and the optimizer will be free to merge these blocks at will. */ for (c = r->u.eh_try.first_catch; c ; c = c->next_catch) { @@ -3334,7 +3368,7 @@ lower_eh_dispatch (basic_block src, gimple stmt) { tree t = build_case_label (TREE_VALUE (flt_node), NULL, lab); - VEC_safe_push (tree, heap, labels, t); + labels.safe_push (t); pointer_set_insert (seen_values, TREE_VALUE (flt_node)); have_label = true; } @@ -3365,7 +3399,7 @@ lower_eh_dispatch (basic_block src, gimple stmt) /* Don't generate a switch if there's only a default case. This is common in the form of try { A; } catch (...) { B; }. */ - if (labels == NULL) + if (!labels.exists ()) { e = single_succ_edge (src); e->flags |= EDGE_FALLTHRU; @@ -3384,10 +3418,10 @@ lower_eh_dispatch (basic_block src, gimple stmt) default_label = build_case_label (NULL, NULL, default_label); sort_case_labels (labels); - x = gimple_build_switch_vec (filter, default_label, labels); + x = gimple_build_switch (filter, default_label, labels); gsi_insert_before (&gsi, x, GSI_SAME_STMT); - VEC_free (tree, heap, labels); + labels.release (); } pointer_set_destroy (seen_values); } @@ -3471,6 +3505,7 @@ struct gimple_opt_pass pass_lower_eh_dispatch = { GIMPLE_PASS, "ehdisp", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ gate_lower_eh_dispatch, /* gate */ execute_lower_eh_dispatch, /* execute */ NULL, /* sub */ @@ -3485,23 +3520,37 @@ struct gimple_opt_pass pass_lower_eh_dispatch = } }; -/* Walk statements, see what regions are really referenced and remove - those that are unused. */ +/* Walk statements, see what regions and, optionally, landing pads + are really referenced. + + Returns in R_REACHABLEP an sbitmap with bits set for reachable regions, + and in LP_REACHABLE an sbitmap with bits set for reachable landing pads. + + Passing NULL for LP_REACHABLE is valid, in this case only reachable + regions are marked. + + The caller is responsible for freeing the returned sbitmaps. */ static void -remove_unreachable_handlers (void) +mark_reachable_handlers (sbitmap *r_reachablep, sbitmap *lp_reachablep) { sbitmap r_reachable, lp_reachable; - eh_region region; - eh_landing_pad lp; basic_block bb; - int lp_nr, r_nr; + bool mark_landing_pads = (lp_reachablep != NULL); + gcc_checking_assert (r_reachablep != NULL); - r_reachable = sbitmap_alloc (VEC_length (eh_region, cfun->eh->region_array)); - lp_reachable - = sbitmap_alloc (VEC_length (eh_landing_pad, cfun->eh->lp_array)); - sbitmap_zero (r_reachable); - sbitmap_zero (lp_reachable); + r_reachable = sbitmap_alloc (cfun->eh->region_array->length ()); + bitmap_clear (r_reachable); + *r_reachablep = r_reachable; + + if (mark_landing_pads) + { + lp_reachable = sbitmap_alloc (cfun->eh->lp_array->length ()); + bitmap_clear (lp_reachable); + *lp_reachablep = lp_reachable; + } + else + lp_reachable = NULL; FOR_EACH_BB (bb) { @@ -3510,62 +3559,82 @@ remove_unreachable_handlers (void) for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) { gimple stmt = gsi_stmt (gsi); - lp_nr = lookup_stmt_eh_lp (stmt); - - /* Negative LP numbers are MUST_NOT_THROW regions which - are not considered BB enders. */ - if (lp_nr < 0) - SET_BIT (r_reachable, -lp_nr); - /* Positive LP numbers are real landing pads, are are BB enders. */ - else if (lp_nr > 0) + if (mark_landing_pads) { - gcc_assert (gsi_one_before_end_p (gsi)); - region = get_eh_region_from_lp_number (lp_nr); - SET_BIT (r_reachable, region->index); - SET_BIT (lp_reachable, lp_nr); + int lp_nr = lookup_stmt_eh_lp (stmt); + + /* Negative LP numbers are MUST_NOT_THROW regions which + are not considered BB enders. */ + if (lp_nr < 0) + bitmap_set_bit (r_reachable, -lp_nr); + + /* Positive LP numbers are real landing pads, and BB enders. */ + else if (lp_nr > 0) + { + gcc_assert (gsi_one_before_end_p (gsi)); + eh_region region = get_eh_region_from_lp_number (lp_nr); + bitmap_set_bit (r_reachable, region->index); + bitmap_set_bit (lp_reachable, lp_nr); + } } /* Avoid removing regions referenced from RESX/EH_DISPATCH. */ switch (gimple_code (stmt)) { case GIMPLE_RESX: - SET_BIT (r_reachable, gimple_resx_region (stmt)); + bitmap_set_bit (r_reachable, gimple_resx_region (stmt)); break; case GIMPLE_EH_DISPATCH: - SET_BIT (r_reachable, gimple_eh_dispatch_region (stmt)); + bitmap_set_bit (r_reachable, gimple_eh_dispatch_region (stmt)); break; default: break; } } } +} + +/* Remove unreachable handlers and unreachable landing pads. */ + +static void +remove_unreachable_handlers (void) +{ + sbitmap r_reachable, lp_reachable; + eh_region region; + eh_landing_pad lp; + unsigned i; + + mark_reachable_handlers (&r_reachable, &lp_reachable); if (dump_file) { fprintf (dump_file, "Before removal of unreachable regions:\n"); dump_eh_tree (dump_file, cfun); fprintf (dump_file, "Reachable regions: "); - dump_sbitmap_file (dump_file, r_reachable); + dump_bitmap_file (dump_file, r_reachable); fprintf (dump_file, "Reachable landing pads: "); - dump_sbitmap_file (dump_file, lp_reachable); + dump_bitmap_file (dump_file, lp_reachable); } - for (r_nr = 1; - VEC_iterate (eh_region, cfun->eh->region_array, r_nr, region); ++r_nr) - if (region && !TEST_BIT (r_reachable, r_nr)) - { - if (dump_file) - fprintf (dump_file, "Removing unreachable region %d\n", r_nr); - remove_eh_handler (region); - } + if (dump_file) + { + FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region) + if (region && !bitmap_bit_p (r_reachable, region->index)) + fprintf (dump_file, + "Removing unreachable region %d\n", + region->index); + } + + remove_unreachable_eh_regions (r_reachable); - for (lp_nr = 1; - VEC_iterate (eh_landing_pad, cfun->eh->lp_array, lp_nr, lp); ++lp_nr) - if (lp && !TEST_BIT (lp_reachable, lp_nr)) + FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp) + if (lp && !bitmap_bit_p (lp_reachable, lp->index)) { if (dump_file) - fprintf (dump_file, "Removing unreachable landing pad %d\n", lp_nr); + fprintf (dump_file, + "Removing unreachable landing pad %d\n", + lp->index); remove_eh_landing_pad (lp); } @@ -3591,12 +3660,12 @@ void maybe_remove_unreachable_handlers (void) { eh_landing_pad lp; - int i; + unsigned i; if (cfun->eh == NULL) return; - - for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i) + + FOR_EACH_VEC_SAFE_ELT (cfun->eh->lp_array, i, lp) if (lp && lp->post_landing_pad) { if (label_to_block (lp->post_landing_pad) == NULL) @@ -3609,45 +3678,38 @@ maybe_remove_unreachable_handlers (void) /* Remove regions that do not have landing pads. This assumes that remove_unreachable_handlers has already been run, and - that we've just manipulated the landing pads since then. */ + that we've just manipulated the landing pads since then. + + Preserve regions with landing pads and regions that prevent + exceptions from propagating further, even if these regions + are not reachable. */ static void remove_unreachable_handlers_no_lp (void) { - eh_region r; - int i; + eh_region region; sbitmap r_reachable; - basic_block bb; + unsigned i; - r_reachable = sbitmap_alloc (VEC_length (eh_region, cfun->eh->region_array)); - sbitmap_zero (r_reachable); + mark_reachable_handlers (&r_reachable, /*lp_reachablep=*/NULL); - FOR_EACH_BB (bb) + FOR_EACH_VEC_SAFE_ELT (cfun->eh->region_array, i, region) { - gimple stmt = last_stmt (bb); - if (stmt) - /* Avoid removing regions referenced from RESX/EH_DISPATCH. */ - switch (gimple_code (stmt)) - { - case GIMPLE_RESX: - SET_BIT (r_reachable, gimple_resx_region (stmt)); - break; - case GIMPLE_EH_DISPATCH: - SET_BIT (r_reachable, gimple_eh_dispatch_region (stmt)); - break; - default: - break; - } + if (! region) + continue; + + if (region->landing_pads != NULL + || region->type == ERT_MUST_NOT_THROW) + bitmap_set_bit (r_reachable, region->index); + + if (dump_file + && !bitmap_bit_p (r_reachable, region->index)) + fprintf (dump_file, + "Removing unreachable region %d\n", + region->index); } - for (i = 1; VEC_iterate (eh_region, cfun->eh->region_array, i, r); ++i) - if (r && r->landing_pads == NULL && r->type != ERT_MUST_NOT_THROW - && !TEST_BIT (r_reachable, i)) - { - if (dump_file) - fprintf (dump_file, "Removing unreachable region %d\n", i); - remove_eh_handler (r); - } + remove_unreachable_eh_regions (r_reachable); sbitmap_free (r_reachable); } @@ -3766,7 +3828,7 @@ unsplit_all_eh (void) eh_landing_pad lp; int i; - for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i) + for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i) if (lp) changed |= unsplit_eh (lp); @@ -3865,7 +3927,7 @@ cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb, } /* If we didn't find the PHI, but it's a VOP, remember to rename it later, assuming all other tests succeed. */ - else if (!is_gimple_reg (nresult)) + else if (virtual_operand_p (nresult)) bitmap_set_bit (rename_virts, SSA_NAME_VERSION (nresult)); /* If we didn't find the PHI, and it's a real variable, we know from the fact that OLD_BB is tree_empty_eh_handler_p that the @@ -3912,6 +3974,21 @@ cleanup_empty_eh_merge_phis (basic_block new_bb, basic_block old_bb, for (ei = ei_start (old_bb->preds); (e = ei_safe_edge (ei)); ) if (e->flags & EDGE_EH) { + /* ??? CFG manipluation routines do not try to update loop + form on edge redirection. Do so manually here for now. */ + /* If we redirect a loop entry or latch edge that will either create + a multiple entry loop or rotate the loop. If the loops merge + we may have created a loop with multiple latches. + All of this isn't easily fixed thus cancel the affected loop + and mark the other loop as possibly having multiple latches. */ + if (current_loops + && e->dest == e->dest->loop_father->header) + { + e->dest->loop_father->header = NULL; + e->dest->loop_father->latch = NULL; + new_bb->loop_father->latch = NULL; + loops_state_set (LOOPS_NEED_FIXUP|LOOPS_MAY_HAVE_MULTIPLE_LATCHES); + } redirect_eh_edge_1 (e, new_bb, change_region); redirect_edge_succ (e, new_bb); flush_pending_stmts (e); @@ -3951,7 +4028,7 @@ cleanup_empty_eh_move_lp (basic_block bb, edge e_out, /* Delete the RESX that was matched within the empty handler block. */ gsi = gsi_last_bb (bb); - mark_virtual_ops_for_renaming (gsi_stmt (gsi)); + unlink_stmt_vdef (gsi_stmt (gsi)); gsi_remove (&gsi, true); /* Clean up E_OUT for the fallthru. */ @@ -4201,7 +4278,7 @@ cleanup_all_empty_eh (void) eh_landing_pad lp; int i; - for (i = 1; VEC_iterate (eh_landing_pad, cfun->eh->lp_array, i, lp); ++i) + for (i = 1; vec_safe_iterate (cfun->eh->lp_array, i, &lp); ++i) if (lp) changed |= cleanup_empty_eh (lp); @@ -4279,6 +4356,7 @@ struct gimple_opt_pass pass_cleanup_eh = { { GIMPLE_PASS, "ehcleanup", /* name */ + OPTGROUP_NONE, /* optinfo_flags */ gate_cleanup_eh, /* gate */ execute_cleanup_eh, /* execute */ NULL, /* sub */