From patchwork Mon Jun 14 07:03:26 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: [gccgo] Fixes for tree-eh.c Date: Sun, 13 Jun 2010 21:03:26 -0000 From: Ian Taylor X-Patchwork-Id: 55480 Message-Id: To: gcc-patches@gcc.gnu.org This patch fixes a problem which arose when compiling some Go code with -O0. The code looked like this after ehcleanup2: # BLOCK 11 # PRED: 2 : resx 2 # SUCC: 12 (eh) # BLOCK 12 # PRED: 11 (eh) : finally_tmp.1007_15 = 1; goto ; # SUCC: 5 (fallthru) The resx pass turned it into this, via code with this comment: /* We can wind up with no source region when pass_cleanup_eh shows that there are no entries into an eh region and deletes it, but then the block that contains the resx isn't removed. This can happen without optimization when the switch statement created by lower_try_finally_switch isn't simplified to remove the eh case. Resolve this by expanding the resx node to an abort. */ # BLOCK 11 # PRED: 2 : __builtin_trap (); # SUCC: # BLOCK 12 # PRED: : finally_tmp.1007_15 = 1; goto ; # SUCC: 5 (fallthru) Now block 12 exists but has no predecessors. That causes the dominator pass to crash later. This patch avoids the problem by removing block 12 in this case. I haven't been able to find a C or C++ test case which replicates this. I think the problem is that I can't figure out how to generate a try/finally clause in which the finally clause does not make any function calls and hence can not throw an exception. This patch also brings in the trunk fix for PR 43365. I will try to do a merge from trunk to gccgo branch soon. This patch committed to gccgo branch. Ian Index: tree-eh.c =================================================================== --- tree-eh.c (revision 155628) +++ tree-eh.c (working copy) @@ -578,6 +578,7 @@ replace_goto_queue (struct leh_tf_state 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 @@ -658,7 +659,6 @@ record_in_goto_queue_label (struct leh_t 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 @@ -1545,6 +1545,7 @@ lower_try_finally (struct leh_state *sta struct leh_tf_state this_tf; struct leh_state this_state; int ndests; + gimple_seq old_eh_seq; /* Process the try block. */ @@ -1561,6 +1562,9 @@ lower_try_finally (struct leh_state *sta 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. */ @@ -1616,6 +1620,20 @@ lower_try_finally (struct leh_state *sta 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; } @@ -2844,7 +2862,8 @@ struct gimple_opt_pass pass_refactor_eh /* At the end of gimple optimization, we can lower RESX. */ static bool -lower_resx (basic_block bb, gimple stmt, struct pointer_map_t *mnt_map) +lower_resx (basic_block bb, gimple stmt, struct pointer_map_t *mnt_map, + bool *any_removed) { int lp_nr; eh_region src_r, dst_r; @@ -2877,7 +2896,31 @@ lower_resx (basic_block bb, gimple stmt, gsi_insert_before (&gsi, x, GSI_SAME_STMT); while (EDGE_COUNT (bb->succs) > 0) - remove_edge (EDGE_SUCC (bb, 0)); + { + edge e = EDGE_SUCC (bb, 0); + basic_block bbnext = e->dest; + + remove_edge (e); + + /* If we removed the last exception edge to the destination + block, remove the landing pad. */ + if (lp_nr >= 0) + { + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bbnext->preds) + if (e->flags & EDGE_EH) + break; + if (e == NULL) + { + eh_landing_pad lp = get_eh_landing_pad_from_number (lp_nr); + remove_eh_landing_pad (lp); + if (EDGE_COUNT (bbnext->preds) == 0) + *any_removed = true; + ret = true; + } + } + } } else if (dst_r) { @@ -2998,6 +3041,8 @@ execute_lower_resx (void) struct pointer_map_t *mnt_map; bool dominance_invalidated = false; bool any_rewritten = false; + bool any_removed = false; + unsigned int todo; mnt_map = pointer_map_create (); @@ -3006,7 +3051,8 @@ execute_lower_resx (void) gimple last = last_stmt (bb); if (last && is_gimple_resx (last)) { - dominance_invalidated |= lower_resx (bb, last, mnt_map); + dominance_invalidated |= lower_resx (bb, last, mnt_map, + &any_removed); any_rewritten = true; } } @@ -3019,7 +3065,12 @@ execute_lower_resx (void) free_dominance_info (CDI_POST_DOMINATORS); } - return any_rewritten ? TODO_update_ssa_only_virtuals : 0; + todo = 0; + if (any_removed) + todo |= TODO_cleanup_cfg; + if (any_rewritten) + todo |= TODO_update_ssa_only_virtuals; + return todo; } static bool