On Tue, Feb 26, 2019 at 04:08:21PM +0100, Richard Biener wrote: > I think we can have multiple .ABNORMAL_DISPATCHERs - at least in theory > via inlining, though I see code in the inliner avoiding multiple ones > at least for nonlocal goto, not sure if that covers all cases.
Ok. > > Shall I modify the patch for that? > > Might it even simplify the patch? If not the only comment on the > original patch is that it would be nice to test it on a SJLJ EH > target ... 1 file changed, 29 insertions(+), 16 deletions(-) so not really simplify it, but not terrible either. Here is the incremental (untested) diff of what handles that. I don't have access to any standard SJLJ EH targets, but will try --enable-sjlj-exceptions on x86_64-linux to see how far I get with that. --- gcc/tree-cfgcleanup.c.jj 2019-02-26 16:52:33.828719803 +0100 +++ gcc/tree-cfgcleanup.c 2019-02-26 17:11:07.735576027 +0100 @@ -731,12 +731,7 @@ cleanup_tree_cfg_bb (basic_block bb) normally are effectively unreachable as well. Additionally ignore __builtin_setjmp_receiver starting blocks, which have one FORCED_LABEL and which are always only reachable through EDGE_ABNORMAL edge. They are - handled in cleanup_control_flow_pre. - Similarly, return true for EDGE_ABNORMAL edge from any basic block to - .ABNORMAL_DISPATCHER basic block if the latter block has no successors. - .ABNORMAL_DISPATCHER basic blocks that don't dispatch to anything are dead, - don't really need any EDGE_ABNORMAL edges to them and can be safely - removed. */ + handled in cleanup_control_flow_pre. */ static bool maybe_dead_abnormal_edge_p (edge e) @@ -747,16 +742,7 @@ maybe_dead_abnormal_edge_p (edge e) gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (e->src); gimple *g = gsi_stmt (gsi); if (!g || !gimple_call_internal_p (g, IFN_ABNORMAL_DISPATCHER)) - { - if (EDGE_COUNT (e->dest->succs) == 0) - { - gsi = gsi_start_nondebug_after_labels_bb (e->dest); - g = gsi_stmt (gsi); - if (g && gimple_call_internal_p (g, IFN_ABNORMAL_DISPATCHER)) - return true; - } - return false; - } + return false; tree target = NULL_TREE; for (gsi = gsi_start_bb (e->dest); !gsi_end_p (gsi); gsi_next (&gsi)) @@ -846,6 +832,7 @@ cleanup_control_flow_pre () bitmap_clear (visited); vec<edge, va_gc> *setjmp_vec = NULL; + auto_vec<basic_block, 4> abnormal_dispatchers; stack.quick_push (ei_start (ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)); @@ -877,6 +864,16 @@ cleanup_control_flow_pre () stack.quick_push (ei_start (setjmp_vec)); } + if ((ei_edge (ei)->flags + & (EDGE_ABNORMAL | EDGE_EH)) == EDGE_ABNORMAL) + { + gimple_stmt_iterator gsi + = gsi_start_nondebug_after_labels_bb (dest); + gimple *g = gsi_stmt (gsi); + if (g && gimple_call_internal_p (g, IFN_ABNORMAL_DISPATCHER)) + abnormal_dispatchers.safe_push (dest); + } + if (EDGE_COUNT (dest->succs) > 0) stack.quick_push (ei_start (dest->succs)); } @@ -895,6 +892,22 @@ cleanup_control_flow_pre () vec_free (setjmp_vec); + /* If we've marked .ABNORMAL_DISPATCHER basic block(s) as visited + above, but haven't marked any of their successors as visited, + unmark them now, so that they can be removed as useless. */ + basic_block dispatcher_bb; + unsigned int k; + FOR_EACH_VEC_ELT (abnormal_dispatchers, k, dispatcher_bb) + { + edge e; + edge_iterator ei; + FOR_EACH_EDGE (e, ei, dispatcher_bb->succs) + if (bitmap_bit_p (visited, e->dest->index)) + break; + if (e == NULL) + bitmap_clear_bit (visited, dispatcher_bb->index); + } + set_dom_info_availability (CDI_DOMINATORS, saved_state); /* We are deleting BBs in non-reverse dominator order, make sure Jakub