From: Jakub Jelinek Date: Wed, 27 Feb 2019 08:41:01 +0000 (+0100) Subject: re PR tree-optimization/89280 (ICE: Segmentation fault (in is_gimple_reg_type)) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f86624d85f937e03110eb044e438d8316d860501;p=gcc.git re PR tree-optimization/89280 (ICE: Segmentation fault (in is_gimple_reg_type)) PR tree-optimization/89280 * tree-cfgcleanup.c (maybe_dead_abnormal_edge_p, builtin_setjmp_setup_bb): New functions. (cleanup_control_flow_pre): Ignore maybe_dead_abnormal_edge_p edges. When visiting __builtin_setjmp_setup block, queue in special setjmp_vec vector edges from .ABNORMAL_DISPATCHER to corresponding __builtin_setjmp_receiver. Remove .ABNORMAL_DISPATCHER basic blocks from visited after the loop if they don't have any visited successor blocks. * gcc.c-torture/compile/pr89280.c: New test. * gcc.dg/torture/pr57147-2.c: Don't expect a setjmp after noreturn function. Skip the test for -O0. From-SVN: r269243 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index b46e08fca6c..961131bcf03 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2019-02-27 Jakub Jelinek + + PR tree-optimization/89280 + * tree-cfgcleanup.c (maybe_dead_abnormal_edge_p, + builtin_setjmp_setup_bb): New functions. + (cleanup_control_flow_pre): Ignore maybe_dead_abnormal_edge_p edges. + When visiting __builtin_setjmp_setup block, queue in special + setjmp_vec vector edges from .ABNORMAL_DISPATCHER to corresponding + __builtin_setjmp_receiver. Remove .ABNORMAL_DISPATCHER basic blocks + from visited after the loop if they don't have any visited successor + blocks. + 2018-02-26 Steve Ellcey * config/aarch64/aarch64.c (aarch64_get_multilib_abi_name): diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 807c04567f5..71ff3fa9aa9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2019-02-27 Jakub Jelinek + + PR tree-optimization/89280 + * gcc.c-torture/compile/pr89280.c: New test. + * gcc.dg/torture/pr57147-2.c: Don't expect a setjmp after noreturn + function. Skip the test for -O0. + 2018-02-26 Steve Ellcey * gfortran.dg/simd-builtins-1.f90: Update for aarch64*-*-*. diff --git a/gcc/testsuite/gcc.c-torture/compile/pr89280.c b/gcc/testsuite/gcc.c-torture/compile/pr89280.c new file mode 100644 index 00000000000..9db9965172f --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/pr89280.c @@ -0,0 +1,48 @@ +/* PR tree-optimization/89280 */ + +int a; +void foo (void); +__attribute__ ((returns_twice)) int bar (void); +void baz (int, int); +void *buf[5]; + +static inline void +inl (int x) +{ + while (x) + foo (); +} + +void +test1 (void) +{ + for (;;) + foo (); + baz (bar (), a); +} + +void +test2 (void) +{ + for (;;) + foo (); + baz (__builtin_setjmp (buf), a); + if (a) + __builtin_longjmp (buf, 1); +} + +void +test3 (void) +{ + inl (1); + baz (bar (), a); +} + +void +test4 (void) +{ + inl (2); + baz (__builtin_setjmp (buf), a); + if (a) + __builtin_longjmp (buf, 1); +} diff --git a/gcc/testsuite/gcc.dg/torture/pr57147-2.c b/gcc/testsuite/gcc.dg/torture/pr57147-2.c index fc5fb39eed5..bbfd13d2932 100644 --- a/gcc/testsuite/gcc.dg/torture/pr57147-2.c +++ b/gcc/testsuite/gcc.dg/torture/pr57147-2.c @@ -1,6 +1,7 @@ /* { dg-do compile } */ /* { dg-options "-fdump-tree-optimized" } */ /* { dg-skip-if "" { *-*-* } { "-fno-fat-lto-objects" } { "" } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" } { "" } } */ /* { dg-require-effective-target indirect_jumps } */ struct __jmp_buf_tag {}; @@ -19,4 +20,4 @@ void TestSyscall(void) _setjmp (g_return_jmp_buf); } -/* { dg-final { scan-tree-dump "setjmp" "optimized" } } */ +/* { dg-final { scan-tree-dump-not "setjmp" "optimized" } } */ diff --git a/gcc/tree-cfgcleanup.c b/gcc/tree-cfgcleanup.c index f2e8b96ee8e..63db3308344 100644 --- a/gcc/tree-cfgcleanup.c +++ b/gcc/tree-cfgcleanup.c @@ -723,6 +723,97 @@ cleanup_tree_cfg_bb (basic_block bb) return false; } +/* Return true if E is an EDGE_ABNORMAL edge for returns_twice calls, + i.e. one going from .ABNORMAL_DISPATCHER to basic block which doesn't + start with a forced or nonlocal label. Calls which return twice can return + the second time only if they are called normally the first time, so basic + blocks which can be only entered through these abnormal edges but not + 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. */ + +static bool +maybe_dead_abnormal_edge_p (edge e) +{ + if ((e->flags & (EDGE_ABNORMAL | EDGE_EH)) != EDGE_ABNORMAL) + return false; + + 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)) + return false; + + tree target = NULL_TREE; + for (gsi = gsi_start_bb (e->dest); !gsi_end_p (gsi); gsi_next (&gsi)) + if (glabel *label_stmt = dyn_cast (gsi_stmt (gsi))) + { + tree this_target = gimple_label_label (label_stmt); + if (DECL_NONLOCAL (this_target)) + return false; + if (FORCED_LABEL (this_target)) + { + if (target) + return false; + target = this_target; + } + } + else + break; + + if (target) + { + /* If there was a single FORCED_LABEL, check for + __builtin_setjmp_receiver with address of that label. */ + if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi))) + gsi_next_nondebug (&gsi); + if (gsi_end_p (gsi)) + return false; + if (!gimple_call_builtin_p (gsi_stmt (gsi), BUILT_IN_SETJMP_RECEIVER)) + return false; + + tree arg = gimple_call_arg (gsi_stmt (gsi), 0); + if (TREE_CODE (arg) != ADDR_EXPR || TREE_OPERAND (arg, 0) != target) + return false; + } + return true; +} + +/* If BB is a basic block ending with __builtin_setjmp_setup, return edge + from .ABNORMAL_DISPATCHER basic block to corresponding + __builtin_setjmp_receiver basic block, otherwise return NULL. */ +static edge +builtin_setjmp_setup_bb (basic_block bb) +{ + if (EDGE_COUNT (bb->succs) != 2 + || ((EDGE_SUCC (bb, 0)->flags + & (EDGE_ABNORMAL | EDGE_EH)) != EDGE_ABNORMAL + && (EDGE_SUCC (bb, 1)->flags + & (EDGE_ABNORMAL | EDGE_EH)) != EDGE_ABNORMAL)) + return NULL; + + gimple_stmt_iterator gsi = gsi_last_nondebug_bb (bb); + if (gsi_end_p (gsi) + || !gimple_call_builtin_p (gsi_stmt (gsi), BUILT_IN_SETJMP_SETUP)) + return NULL; + + tree arg = gimple_call_arg (gsi_stmt (gsi), 1); + if (TREE_CODE (arg) != ADDR_EXPR + || TREE_CODE (TREE_OPERAND (arg, 0)) != LABEL_DECL) + return NULL; + + basic_block recv_bb = label_to_block (cfun, TREE_OPERAND (arg, 0)); + if (EDGE_COUNT (recv_bb->preds) != 1 + || (EDGE_PRED (recv_bb, 0)->flags + & (EDGE_ABNORMAL | EDGE_EH)) != EDGE_ABNORMAL + || (EDGE_SUCC (bb, 0)->dest != EDGE_PRED (recv_bb, 0)->src + && EDGE_SUCC (bb, 1)->dest != EDGE_PRED (recv_bb, 0)->src)) + return NULL; + + /* EDGE_PRED (recv_bb, 0)->src should be the .ABNORMAL_DISPATCHER bb. */ + return EDGE_PRED (recv_bb, 0); +} + /* Do cleanup_control_flow_bb in PRE order. */ static bool @@ -736,10 +827,13 @@ cleanup_control_flow_pre () dom_state saved_state = dom_info_state (CDI_DOMINATORS); set_dom_info_availability (CDI_DOMINATORS, DOM_NONE); - auto_vec stack (n_basic_blocks_for_fn (cfun) + 1); + auto_vec stack (n_basic_blocks_for_fn (cfun) + 2); auto_sbitmap visited (last_basic_block_for_fn (cfun)); bitmap_clear (visited); + vec *setjmp_vec = NULL; + auto_vec abnormal_dispatchers; + stack.quick_push (ei_start (ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)); while (! stack.is_empty ()) @@ -749,12 +843,37 @@ cleanup_control_flow_pre () basic_block dest = ei_edge (ei)->dest; if (dest != EXIT_BLOCK_PTR_FOR_FN (cfun) - && ! bitmap_bit_p (visited, dest->index)) + && !bitmap_bit_p (visited, dest->index) + && (ei_container (ei) == setjmp_vec + || !maybe_dead_abnormal_edge_p (ei_edge (ei)))) { bitmap_set_bit (visited, dest->index); /* We only possibly remove edges from DEST here, leaving possibly unreachable code in the IL. */ retval |= cleanup_control_flow_bb (dest); + + /* Check for __builtin_setjmp_setup. Edges from .ABNORMAL_DISPATCH + to __builtin_setjmp_receiver will be normally ignored by + maybe_dead_abnormal_edge_p. If DEST is a visited + __builtin_setjmp_setup, queue edge from .ABNORMAL_DISPATCH + to __builtin_setjmp_receiver, so that it will be visited too. */ + if (edge e = builtin_setjmp_setup_bb (dest)) + { + vec_safe_push (setjmp_vec, e); + if (vec_safe_length (setjmp_vec) == 1) + 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)); } @@ -763,10 +882,32 @@ cleanup_control_flow_pre () if (!ei_one_before_end_p (ei)) ei_next (&stack.last ()); else - stack.pop (); + { + if (ei_container (ei) == setjmp_vec) + vec_safe_truncate (setjmp_vec, 0); + stack.pop (); + } } } + 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