Mercurial > hg > CbC > CbC_gcc
diff gcc/tree-eh.c @ 63:b7f97abdc517 gcc-4.6-20100522
update gcc from gcc-4.5.0 to gcc-4.6
author | ryoma <e075725@ie.u-ryukyu.ac.jp> |
---|---|
date | Mon, 24 May 2010 12:47:05 +0900 |
parents | 77e2b8dfacca |
children | f6334be47118 |
line wrap: on
line diff
--- a/gcc/tree-eh.c Fri Feb 12 23:41:23 2010 +0900 +++ b/gcc/tree-eh.c Mon May 24 12:47:05 2010 +0900 @@ -1,5 +1,5 @@ /* Exception handling semantics and decomposition for trees. - Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 + Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. This file is part of GCC. @@ -23,11 +23,10 @@ #include "coretypes.h" #include "tm.h" #include "tree.h" -#include "rtl.h" -#include "tm_p.h" #include "flags.h" #include "function.h" #include "except.h" +#include "pointer-set.h" #include "tree-flow.h" #include "tree-dump.h" #include "tree-inline.h" @@ -563,6 +562,7 @@ 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); } /* Add a new record to the goto queue contained in TF. NEW_STMT is the @@ -643,7 +643,6 @@ labels. */ new_stmt = stmt; record_in_goto_queue (tf, new_stmt, index, true); - } /* For any GIMPLE_GOTO or GIMPLE_RETURN, decide whether it leaves a try_finally @@ -1518,6 +1517,20 @@ return f_estimate < 40 || f_estimate * 2 < sw_estimate * 3; } +/* REG is the enclosing region for a possible cleanup region, or the region + itself. Returns TRUE if such a region would be unreachable. + + Cleanup regions within a must-not-throw region aren't actually reachable + even if there are throwing stmts within them, because the personality + routine will call terminate before unwinding. */ + +static bool +cleanup_is_dead_in (eh_region reg) +{ + while (reg && reg->type == ERT_CLEANUP) + reg = reg->outer; + return (reg && reg->type == ERT_MUST_NOT_THROW); +} /* A subroutine of lower_eh_constructs_1. Lower a GIMPLE_TRY_FINALLY nodes to a sequence of labels and blocks, plus the exception region trees @@ -1530,6 +1543,7 @@ struct leh_tf_state this_tf; struct leh_state this_state; int ndests; + gimple_seq old_eh_seq; /* Process the try block. */ @@ -1537,22 +1551,30 @@ this_tf.try_finally_expr = tp; this_tf.top_p = tp; this_tf.outer = state; - if (using_eh_for_cleanups_p) - this_tf.region = gen_eh_region_cleanup (state->cur_region); + if (using_eh_for_cleanups_p && !cleanup_is_dead_in (state->cur_region)) + { + this_tf.region = gen_eh_region_cleanup (state->cur_region); + this_state.cur_region = this_tf.region; + } else - this_tf.region = NULL; - - this_state.cur_region = this_tf.region; + { + this_tf.region = NULL; + this_state.cur_region = state->cur_region; + } + this_state.ehp_region = state->ehp_region; this_state.tf = &this_tf; + old_eh_seq = eh_seq; + eh_seq = NULL; + lower_eh_constructs_1 (&this_state, gimple_try_eval(tp)); /* Determine if the try block is escaped through the bottom. */ this_tf.may_fallthru = gimple_seq_may_fallthru (gimple_try_eval (tp)); /* Determine if any exceptions are possible within the try block. */ - if (using_eh_for_cleanups_p) + if (this_tf.region) this_tf.may_throw = eh_region_may_contain_throw (this_tf.region); if (this_tf.may_throw) honor_protect_cleanup_actions (state, &this_state, &this_tf); @@ -1601,6 +1623,20 @@ if (this_tf.goto_queue_map) pointer_map_destroy (this_tf.goto_queue_map); + /* If there was an old (aka outer) eh_seq, append the current eh_seq. + If there was no old eh_seq, then the append is trivially already done. */ + if (old_eh_seq) + { + if (eh_seq == NULL) + eh_seq = old_eh_seq; + else + { + gimple_seq new_eh_seq = eh_seq; + eh_seq = old_eh_seq; + gimple_seq_add_seq(&eh_seq, new_eh_seq); + } + } + return this_tf.top_p_seq; } @@ -1762,8 +1798,9 @@ eh_region this_region = NULL; struct leh_tf_state fake_tf; gimple_seq result; - - if (flag_exceptions) + bool cleanup_dead = cleanup_is_dead_in (state->cur_region); + + if (flag_exceptions && !cleanup_dead) { this_region = gen_eh_region_cleanup (state->cur_region); this_state.cur_region = this_region; @@ -1771,7 +1808,7 @@ lower_eh_constructs_1 (&this_state, gimple_try_eval (tp)); - if (!eh_region_may_contain_throw (this_region)) + if (cleanup_dead || !eh_region_may_contain_throw (this_region)) return gimple_try_eval (tp); /* Build enough of a try-finally state so that we can reuse @@ -3038,9 +3075,10 @@ }; -/* At the end of inlining, we can lower EH_DISPATCH. */ - -static void +/* At the end of inlining, we can lower EH_DISPATCH. Return true when + we have found some duplicate labels and removed some edges. */ + +static bool lower_eh_dispatch (basic_block src, gimple stmt) { gimple_stmt_iterator gsi; @@ -3048,6 +3086,7 @@ eh_region r; tree filter, fn; gimple x; + bool redirected = false; region_nr = gimple_eh_dispatch_region (stmt); r = get_eh_region_from_number (region_nr); @@ -3063,6 +3102,7 @@ eh_catch c; edge_iterator ei; edge e; + struct pointer_set_t *seen_values = pointer_set_create (); /* Collect the labels for a switch. Zero the post_landing_pad field becase we'll no longer have anything keeping these labels @@ -3071,6 +3111,7 @@ for (c = r->u.eh_try.first_catch; c ; c = c->next_catch) { tree tp_node, flt_node, lab = c->label; + bool have_label = false; c->label = NULL; tp_node = c->type_list; @@ -3083,14 +3124,29 @@ } do { - tree t = build3 (CASE_LABEL_EXPR, void_type_node, - TREE_VALUE (flt_node), NULL, lab); - VEC_safe_push (tree, heap, labels, t); + /* Filter out duplicate labels that arise when this handler + is shadowed by an earlier one. When no labels are + attached to the handler anymore, we remove + the corresponding edge and then we delete unreachable + blocks at the end of this pass. */ + if (! pointer_set_contains (seen_values, TREE_VALUE (flt_node))) + { + tree t = build3 (CASE_LABEL_EXPR, void_type_node, + TREE_VALUE (flt_node), NULL, lab); + VEC_safe_push (tree, heap, labels, t); + pointer_set_insert (seen_values, TREE_VALUE (flt_node)); + have_label = true; + } tp_node = TREE_CHAIN (tp_node); flt_node = TREE_CHAIN (flt_node); } while (tp_node); + if (! have_label) + { + remove_edge (find_edge (src, label_to_block (lab))); + redirected = true; + } } /* Clean up the edge flags. */ @@ -3132,6 +3188,7 @@ VEC_free (tree, heap, labels); } + pointer_set_destroy (seen_values); } break; @@ -3165,6 +3222,7 @@ /* Replace the EH_DISPATCH with the SWITCH or COND generated above. */ gsi_remove (&gsi, true); + return redirected; } static unsigned @@ -3172,6 +3230,7 @@ { basic_block bb; bool any_rewritten = false; + bool redirected = false; assign_filter_values (); @@ -3180,11 +3239,13 @@ gimple last = last_stmt (bb); if (last && gimple_code (last) == GIMPLE_EH_DISPATCH) { - lower_eh_dispatch (bb, last); + redirected |= lower_eh_dispatch (bb, last); any_rewritten = true; } } + if (redirected) + delete_unreachable_blocks (); return any_rewritten ? TODO_update_ssa_only_virtuals : 0; } @@ -3350,8 +3411,11 @@ if ((e_in->flags & EDGE_EH) == 0 || (e_out->flags & EDGE_EH) != 0) return false; - /* The block must be empty except for the labels. */ - if (!gsi_end_p (gsi_after_labels (bb))) + /* The block must be empty except for the labels and debug insns. */ + gsi = gsi_after_labels (bb); + if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi))) + gsi_next_nondebug (&gsi); + if (!gsi_end_p (gsi)) return false; /* The destination block must not already have a landing pad