From 09b22f48d435d158761a02117facec4daa7395fb Mon Sep 17 00:00:00 2001 From: Jakub Jelinek <jakub@redhat.com> Date: Wed, 29 Jan 2014 12:02:46 +0100 Subject: [PATCH] re PR middle-end/59917 (ICE in calc_dfs_tree, at dominance.c:401) PR middle-end/59917 PR tree-optimization/59920 * tree.c (build_common_builtin_nodes): Remove __builtin_setjmp_dispatcher initialization. * omp-low.h (make_gimple_omp_edges): Add a new int * argument. * profile.c (branch_prob): Use gsi_start_nondebug_after_labels_bb instead of gsi_after_labels + manually skipping debug stmts. Don't ignore bbs with BUILT_IN_SETJMP_DISPATCHER, instead ignore bbs with IFN_ABNORMAL_DISPATCHER. * tree-inline.c (copy_edges_for_bb): Remove can_make_abnormal_goto argument, instead add abnormal_goto_dest argument. Ignore computed_goto_p stmts. Don't call make_abnormal_goto_edges. If a call might need abnormal edges for non-local gotos, see if it already has an edge to IFN_ABNORMAL_DISPATCHER or if it is IFN_ABNORMAL_DISPATCHER with true argument, don't do anything then, otherwise add EDGE_ABNORMAL from the call's bb to abnormal_goto_dest. (copy_cfg_body): Compute abnormal_goto_dest, adjust copy_edges_for_bb caller. * gimple-low.c (struct lower_data): Remove calls_builtin_setjmp. (lower_function_body): Don't emit __builtin_setjmp_dispatcher. (lower_stmt): Don't set data->calls_builtin_setjmp. (lower_builtin_setjmp): Adjust comment. * builtins.def (BUILT_IN_SETJMP_DISPATCHER): Remove. * tree-cfg.c (found_computed_goto): Remove. (factor_computed_gotos): Remove. (make_goto_expr_edges): Return bool, true for computed gotos. Don't call make_abnormal_goto_edges. (build_gimple_cfg): Don't set found_computed_goto, don't call factor_computed_gotos. (computed_goto_p): No longer static. (make_blocks): Don't set found_computed_goto. (get_abnormal_succ_dispatcher, handle_abnormal_edges): New functions. (make_edges): If make_goto_expr_edges returns true, push bb into ab_edge_goto vector, for stmt_can_make_abnormal_goto calls instead of calling make_abnormal_goto_edges push bb into ab_edge_call vector. Record mapping between bbs and OpenMP regions if there are any, adjust make_gimple_omp_edges caller. Call handle_abnormal_edges. (make_abnormal_goto_edges): Remove. * tree-cfg.h (make_abnormal_goto_edges): Remove. (computed_goto_p, get_abnormal_succ_dispatcher): New prototypes. * internal-fn.c (expand_ABNORMAL_DISPATCHER): New function. * builtins.c (expand_builtin): Don't handle BUILT_IN_SETJMP_DISPATCHER. * internal-fn.def (ABNORMAL_DISPATCHER): New. * omp-low.c (make_gimple_omp_edges): Add region_idx argument, when filling *region also set *region_idx to (*region)->entry->index. * gcc.dg/pr59920-1.c: New test. * gcc.dg/pr59920-2.c: New test. * gcc.dg/pr59920-3.c: New test. * c-c++-common/gomp/pr59917-1.c: New test. * c-c++-common/gomp/pr59917-2.c: New test. From-SVN: r207231 --- gcc/ChangeLog | 49 +++ gcc/builtins.c | 14 - gcc/builtins.def | 1 - gcc/gimple-low.c | 51 +-- gcc/internal-fn.c | 5 + gcc/internal-fn.def | 1 + gcc/omp-low.c | 11 +- gcc/omp-low.h | 2 +- gcc/profile.c | 19 +- gcc/testsuite/ChangeLog | 8 + gcc/testsuite/c-c++-common/gomp/pr59917-1.c | 22 ++ gcc/testsuite/c-c++-common/gomp/pr59917-2.c | 22 ++ gcc/testsuite/gcc.dg/pr59920-1.c | 20 + gcc/testsuite/gcc.dg/pr59920-2.c | 30 ++ gcc/testsuite/gcc.dg/pr59920-3.c | 47 +++ gcc/tree-cfg.c | 381 ++++++++++++-------- gcc/tree-cfg.h | 3 +- gcc/tree-inline.c | 42 ++- gcc/tree.c | 6 - 19 files changed, 499 insertions(+), 235 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/gomp/pr59917-1.c create mode 100644 gcc/testsuite/c-c++-common/gomp/pr59917-2.c create mode 100644 gcc/testsuite/gcc.dg/pr59920-1.c create mode 100644 gcc/testsuite/gcc.dg/pr59920-2.c create mode 100644 gcc/testsuite/gcc.dg/pr59920-3.c diff --git a/gcc/ChangeLog b/gcc/ChangeLog index c8a165828ac..14f0cfb6e18 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,54 @@ 2014-01-29 Jakub Jelinek <jakub@redhat.com> + PR middle-end/59917 + PR tree-optimization/59920 + * tree.c (build_common_builtin_nodes): Remove + __builtin_setjmp_dispatcher initialization. + * omp-low.h (make_gimple_omp_edges): Add a new int * argument. + * profile.c (branch_prob): Use gsi_start_nondebug_after_labels_bb + instead of gsi_after_labels + manually skipping debug stmts. + Don't ignore bbs with BUILT_IN_SETJMP_DISPATCHER, instead + ignore bbs with IFN_ABNORMAL_DISPATCHER. + * tree-inline.c (copy_edges_for_bb): Remove + can_make_abnormal_goto argument, instead add abnormal_goto_dest + argument. Ignore computed_goto_p stmts. Don't call + make_abnormal_goto_edges. If a call might need abnormal edges + for non-local gotos, see if it already has an edge to + IFN_ABNORMAL_DISPATCHER or if it is IFN_ABNORMAL_DISPATCHER + with true argument, don't do anything then, otherwise add + EDGE_ABNORMAL from the call's bb to abnormal_goto_dest. + (copy_cfg_body): Compute abnormal_goto_dest, adjust copy_edges_for_bb + caller. + * gimple-low.c (struct lower_data): Remove calls_builtin_setjmp. + (lower_function_body): Don't emit __builtin_setjmp_dispatcher. + (lower_stmt): Don't set data->calls_builtin_setjmp. + (lower_builtin_setjmp): Adjust comment. + * builtins.def (BUILT_IN_SETJMP_DISPATCHER): Remove. + * tree-cfg.c (found_computed_goto): Remove. + (factor_computed_gotos): Remove. + (make_goto_expr_edges): Return bool, true for computed gotos. + Don't call make_abnormal_goto_edges. + (build_gimple_cfg): Don't set found_computed_goto, don't call + factor_computed_gotos. + (computed_goto_p): No longer static. + (make_blocks): Don't set found_computed_goto. + (get_abnormal_succ_dispatcher, handle_abnormal_edges): New functions. + (make_edges): If make_goto_expr_edges returns true, push bb + into ab_edge_goto vector, for stmt_can_make_abnormal_goto calls + instead of calling make_abnormal_goto_edges push bb into ab_edge_call + vector. Record mapping between bbs and OpenMP regions if there + are any, adjust make_gimple_omp_edges caller. Call + handle_abnormal_edges. + (make_abnormal_goto_edges): Remove. + * tree-cfg.h (make_abnormal_goto_edges): Remove. + (computed_goto_p, get_abnormal_succ_dispatcher): New prototypes. + * internal-fn.c (expand_ABNORMAL_DISPATCHER): New function. + * builtins.c (expand_builtin): Don't handle + BUILT_IN_SETJMP_DISPATCHER. + * internal-fn.def (ABNORMAL_DISPATCHER): New. + * omp-low.c (make_gimple_omp_edges): Add region_idx argument, when + filling *region also set *region_idx to (*region)->entry->index. + PR other/58712 * read-rtl.c (read_rtx_code): Clear all of RTX_CODE_SIZE (code). For REGs set ORIGINAL_REGNO. diff --git a/gcc/builtins.c b/gcc/builtins.c index 3e34c83858b..a45380ce877 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -6205,20 +6205,6 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode, } break; - case BUILT_IN_SETJMP_DISPATCHER: - /* __builtin_setjmp_dispatcher is passed the dispatcher label. */ - if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE)) - { - tree label = TREE_OPERAND (CALL_EXPR_ARG (exp, 0), 0); - rtx label_r = label_rtx (label); - - /* Remove the dispatcher label from the list of non-local labels - since the receiver labels have been added to it above. */ - remove_node_from_expr_list (label_r, &nonlocal_goto_handler_labels); - return const0_rtx; - } - break; - case BUILT_IN_SETJMP_RECEIVER: /* __builtin_setjmp_receiver is passed the receiver label. */ if (validate_arglist (exp, POINTER_TYPE, VOID_TYPE)) diff --git a/gcc/builtins.def b/gcc/builtins.def index 524153f22a5..2443a45751b 100644 --- a/gcc/builtins.def +++ b/gcc/builtins.def @@ -783,7 +783,6 @@ DEF_BUILTIN_STUB (BUILT_IN_NONLOCAL_GOTO, "__builtin_nonlocal_goto") /* Implementing __builtin_setjmp. */ DEF_BUILTIN_STUB (BUILT_IN_SETJMP_SETUP, "__builtin_setjmp_setup") -DEF_BUILTIN_STUB (BUILT_IN_SETJMP_DISPATCHER, "__builtin_setjmp_dispatcher") DEF_BUILTIN_STUB (BUILT_IN_SETJMP_RECEIVER, "__builtin_setjmp_receiver") /* Implementing variable sized local variables. */ diff --git a/gcc/gimple-low.c b/gcc/gimple-low.c index 8d2e71103a4..c60e8177d38 100644 --- a/gcc/gimple-low.c +++ b/gcc/gimple-low.c @@ -76,9 +76,6 @@ struct lower_data /* True if the current statement cannot fall through. */ bool cannot_fallthru; - - /* True if the function calls __builtin_setjmp. */ - bool calls_builtin_setjmp; }; static void lower_stmt (gimple_stmt_iterator *, struct lower_data *); @@ -99,7 +96,6 @@ lower_function_body (void) gimple_seq lowered_body; gimple_stmt_iterator i; gimple bind; - tree t; gimple x; /* The gimplifier should've left a body of exactly one statement, @@ -146,34 +142,6 @@ lower_function_body (void) gsi_insert_after (&i, t.stmt, GSI_CONTINUE_LINKING); } - /* If the function calls __builtin_setjmp, we need to emit the computed - goto that will serve as the unique dispatcher for all the receivers. */ - if (data.calls_builtin_setjmp) - { - tree disp_label, disp_var, arg; - - /* Build 'DISP_LABEL:' and insert. */ - disp_label = create_artificial_label (cfun->function_end_locus); - /* This mark will create forward edges from every call site. */ - DECL_NONLOCAL (disp_label) = 1; - cfun->has_nonlocal_label = 1; - x = gimple_build_label (disp_label); - gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); - - /* Build 'DISP_VAR = __builtin_setjmp_dispatcher (DISP_LABEL);' - and insert. */ - disp_var = create_tmp_var (ptr_type_node, "setjmpvar"); - arg = build_addr (disp_label, current_function_decl); - t = builtin_decl_implicit (BUILT_IN_SETJMP_DISPATCHER); - x = gimple_build_call (t, 1, arg); - gimple_call_set_lhs (x, disp_var); - - /* Build 'goto DISP_VAR;' and insert. */ - gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); - x = gimple_build_goto (disp_var); - gsi_insert_after (&i, x, GSI_CONTINUE_LINKING); - } - /* Once the old body has been lowered, replace it with the new lowered sequence. */ gimple_set_body (current_function_decl, lowered_body); @@ -364,7 +332,6 @@ lower_stmt (gimple_stmt_iterator *gsi, struct lower_data *data) { lower_builtin_setjmp (gsi); data->cannot_fallthru = false; - data->calls_builtin_setjmp = true; return; } @@ -689,15 +656,12 @@ lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data) all will be used on all machines). It operates similarly to the C library function of the same name, but is more efficient. - It is lowered into 3 other builtins, namely __builtin_setjmp_setup, - __builtin_setjmp_dispatcher and __builtin_setjmp_receiver, but with - __builtin_setjmp_dispatcher shared among all the instances; that's - why it is only emitted at the end by lower_function_body. + It is lowered into 2 other builtins, namely __builtin_setjmp_setup, + __builtin_setjmp_receiver. After full lowering, the body of the function should look like: { - void * setjmpvar.0; int D.1844; int D.2844; @@ -727,14 +691,13 @@ lower_gimple_return (gimple_stmt_iterator *gsi, struct lower_data *data) <D3850>:; return; - <D3853>: [non-local]; - setjmpvar.0 = __builtin_setjmp_dispatcher (&<D3853>); - goto setjmpvar.0; } - The dispatcher block will be both the unique destination of all the - abnormal call edges and the unique source of all the abnormal edges - to the receivers, thus keeping the complexity explosion localized. */ + During cfg creation an extra per-function (or per-OpenMP region) + block with ABNORMAL_DISPATCHER internal call will be added, unique + destination of all the abnormal call edges and the unique source of + all the abnormal edges to the receivers, thus keeping the complexity + explosion localized. */ static void lower_builtin_setjmp (gimple_stmt_iterator *gsi) diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c index 87a42e7e32c..43aaecba971 100644 --- a/gcc/internal-fn.c +++ b/gcc/internal-fn.c @@ -857,6 +857,11 @@ expand_MASK_STORE (gimple stmt) expand_insn (optab_handler (maskstore_optab, TYPE_MODE (type)), 3, ops); } +static void +expand_ABNORMAL_DISPATCHER (gimple) +{ +} + /* Routines to expand each internal function, indexed by function number. Each routine has the prototype: diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def index ca93a0354a2..379b35241b5 100644 --- a/gcc/internal-fn.def +++ b/gcc/internal-fn.def @@ -51,3 +51,4 @@ DEF_INTERNAL_FN (UBSAN_NULL, ECF_LEAF | ECF_NOTHROW) DEF_INTERNAL_FN (UBSAN_CHECK_ADD, ECF_CONST | ECF_LEAF | ECF_NOTHROW) DEF_INTERNAL_FN (UBSAN_CHECK_SUB, ECF_CONST | ECF_LEAF | ECF_NOTHROW) DEF_INTERNAL_FN (UBSAN_CHECK_MUL, ECF_CONST | ECF_LEAF | ECF_NOTHROW) +DEF_INTERNAL_FN (ABNORMAL_DISPATCHER, ECF_NORETURN) diff --git a/gcc/omp-low.c b/gcc/omp-low.c index eeba4ae8470..d7589aa9ec1 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -10449,7 +10449,8 @@ diagnose_sb_2 (gimple_stmt_iterator *gsi_p, bool *handled_ops_p, /* Called from tree-cfg.c::make_edges to create cfg edges for all GIMPLE_OMP codes. */ bool -make_gimple_omp_edges (basic_block bb, struct omp_region **region) +make_gimple_omp_edges (basic_block bb, struct omp_region **region, + int *region_idx) { gimple last = last_stmt (bb); enum gimple_code code = gimple_code (last); @@ -10556,7 +10557,13 @@ make_gimple_omp_edges (basic_block bb, struct omp_region **region) } if (*region != cur_region) - *region = cur_region; + { + *region = cur_region; + if (cur_region) + *region_idx = cur_region->entry->index; + else + *region_idx = 0; + } return fallthru; } diff --git a/gcc/omp-low.h b/gcc/omp-low.h index ce9cef9f5dd..d80c2d6f5c0 100644 --- a/gcc/omp-low.h +++ b/gcc/omp-low.h @@ -26,6 +26,6 @@ extern tree find_omp_clause (tree, enum omp_clause_code); extern void omp_expand_local (basic_block); extern void free_omp_regions (void); extern tree omp_reduction_init (tree, tree); -extern bool make_gimple_omp_edges (basic_block, struct omp_region **); +extern bool make_gimple_omp_edges (basic_block, struct omp_region **, int *); #endif /* GCC_OMP_LOW_H */ diff --git a/gcc/profile.c b/gcc/profile.c index e549453bfad..752d89fc3d8 100644 --- a/gcc/profile.c +++ b/gcc/profile.c @@ -1106,27 +1106,22 @@ branch_prob (void) gimple first; tree fndecl; - gsi = gsi_after_labels (bb); + gsi = gsi_start_nondebug_after_labels_bb (bb); gcc_checking_assert (!gsi_end_p (gsi)); first = gsi_stmt (gsi); - if (is_gimple_debug (first)) - { - gsi_next_nondebug (&gsi); - gcc_checking_assert (!gsi_end_p (gsi)); - first = gsi_stmt (gsi); - } /* Don't split the bbs containing __builtin_setjmp_receiver - or __builtin_setjmp_dispatcher calls. These are very + or ABNORMAL_DISPATCHER calls. These are very special and don't expect anything to be inserted before them. */ if (is_gimple_call (first) && (((fndecl = gimple_call_fndecl (first)) != NULL && DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_NORMAL && (DECL_FUNCTION_CODE (fndecl) - == BUILT_IN_SETJMP_RECEIVER - || (DECL_FUNCTION_CODE (fndecl) - == BUILT_IN_SETJMP_DISPATCHER))) - || gimple_call_flags (first) & ECF_RETURNS_TWICE)) + == BUILT_IN_SETJMP_RECEIVER)) + || (gimple_call_flags (first) & ECF_RETURNS_TWICE) + || (gimple_call_internal_p (first) + && (gimple_call_internal_fn (first) + == IFN_ABNORMAL_DISPATCHER)))) continue; if (dump_file) diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 191845a3b35..a4684473ab7 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,5 +1,13 @@ 2014-01-29 Jakub Jelinek <jakub@redhat.com> + PR middle-end/59917 + PR tree-optimization/59920 + * gcc.dg/pr59920-1.c: New test. + * gcc.dg/pr59920-2.c: New test. + * gcc.dg/pr59920-3.c: New test. + * c-c++-common/gomp/pr59917-1.c: New test. + * c-c++-common/gomp/pr59917-2.c: New test. + PR tree-optimization/59594 * gcc.dg/vect/no-vfa-vect-depend-2.c: New test. * gcc.dg/vect/no-vfa-vect-depend-3.c: New test. diff --git a/gcc/testsuite/c-c++-common/gomp/pr59917-1.c b/gcc/testsuite/c-c++-common/gomp/pr59917-1.c new file mode 100644 index 00000000000..cca3976ccb7 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/pr59917-1.c @@ -0,0 +1,22 @@ +/* PR middle-end/59917 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fopenmp" } */ + +struct J { long buf[8]; }; +extern int setjmp (struct J[1]); +extern struct J j[1]; +void foo (int); + +void +bar (void) +{ + if (setjmp (j) == 0) + { + int k; + foo (-1); +#pragma omp parallel + for (k = 0; k < 10; ++k) + foo (k); + foo (-2); + } +} diff --git a/gcc/testsuite/c-c++-common/gomp/pr59917-2.c b/gcc/testsuite/c-c++-common/gomp/pr59917-2.c new file mode 100644 index 00000000000..1d603422f66 --- /dev/null +++ b/gcc/testsuite/c-c++-common/gomp/pr59917-2.c @@ -0,0 +1,22 @@ +/* PR middle-end/59917 */ +/* { dg-do compile } */ +/* { dg-options "-O2 -fopenmp" } */ + +struct J { long buf[8]; }; +extern int setjmp (struct J[1]); +void foo (int); + +void +bar (void) +{ + int k; + foo (-1); +#pragma omp parallel + for (k = 0; k < 10; ++k) + { + struct J j[1]; + if (setjmp (j) == 0) + foo (k); + } + foo (-2); +} diff --git a/gcc/testsuite/gcc.dg/pr59920-1.c b/gcc/testsuite/gcc.dg/pr59920-1.c new file mode 100644 index 00000000000..3e60d37ae20 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr59920-1.c @@ -0,0 +1,20 @@ +/* PR tree-optimization/59920 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ + +#include <setjmp.h> + +int bar (void); +void baz (int); + +#define A { int x = bar (); if (setjmp (buf) == 0) baz (x); } +#define B A A A A A A A A A A +#define C B B B B B B B B B B + +extern jmp_buf buf; + +void +foo (void) +{ + C C +} diff --git a/gcc/testsuite/gcc.dg/pr59920-2.c b/gcc/testsuite/gcc.dg/pr59920-2.c new file mode 100644 index 00000000000..bee5542748b --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr59920-2.c @@ -0,0 +1,30 @@ +/* PR tree-optimization/59920 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ + +void *bar (void **); +void *baz (int, void **); + +#define A(n) \ + { __label__ l1_##n, l2_##n, l3_##n; \ + static void *a[] = { &&l1_##n, &&l2_##n, &&l3_##n };\ + void *b = bar (a); \ + goto *b; \ + l1_##n: \ + b = baz (1, a); \ + goto *b; \ + l2_##n: \ + b = baz (2, a); \ + goto *b; \ + l3_##n:; \ + } +#define B(n) A(n##0) A(n##1) A(n##2) A(n##3) A(n##4) \ + A(n##5) A(n##6) A(n##7) A(n##8) A(n##9) +#define C(n) B(n##0) B(n##1) B(n##2) B(n##3) B(n##4) \ + B(n##5) B(n##6) B(n##7) B(n##8) B(n##9) + +void +foo (void) +{ + C(1) +} diff --git a/gcc/testsuite/gcc.dg/pr59920-3.c b/gcc/testsuite/gcc.dg/pr59920-3.c new file mode 100644 index 00000000000..2159504e363 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr59920-3.c @@ -0,0 +1,47 @@ +/* PR tree-optimization/59920 */ +/* { dg-do compile } */ +/* { dg-options "-O0" } */ + +void *bar (void **); +void *baz (int, void **); + +#define A(n) __label__ l##n; +#define B(n) A(n##0) A(n##1) A(n##2) A(n##3) A(n##4) \ + A(n##5) A(n##6) A(n##7) A(n##8) A(n##9) +#define C(n) B(n##0) B(n##1) B(n##2) B(n##3) B(n##4) \ + B(n##5) B(n##6) B(n##7) B(n##8) B(n##9) +#define D C(1) + +int +foo (void) +{ + D + int bar (int i) + { + switch (i) + { +#undef A +#define A(n) \ + case n: goto l##n; + D + } + return i; + } + int w = 0; +#undef A +#define A(n) int w##n = 0; + D +#undef A +#define A(n) \ + { l##n:; \ + w##n += bar (10000 + n) - 10000; \ + w##n += bar (10001 + n) - 10000; \ + bar (n + 1); \ + return w##n; \ + } + D +#undef A +#define A(n) w += w##n; + D + return w; +} diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index 32110a7fafa..dfc9b7b4cef 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -106,9 +106,6 @@ struct cfg_stats_d static struct cfg_stats_d cfg_stats; -/* Nonzero if we found a computed goto while building basic blocks. */ -static bool found_computed_goto; - /* Hash table to store last discriminator assigned for each locus. */ struct locus_discrim_map { @@ -148,14 +145,13 @@ static hash_table <locus_discrim_hasher> discriminator_per_locus; /* Basic blocks and flowgraphs. */ static void make_blocks (gimple_seq); -static void factor_computed_gotos (void); /* Edges. */ static void make_edges (void); static void assign_discriminators (void); static void make_cond_expr_edges (basic_block); static void make_gimple_switch_edges (basic_block); -static void make_goto_expr_edges (basic_block); +static bool make_goto_expr_edges (basic_block); static void make_gimple_asm_edges (basic_block); static edge gimple_redirect_edge_and_branch (edge, basic_block); static edge gimple_try_redirect_by_replacing_jump (edge, basic_block); @@ -225,17 +221,8 @@ build_gimple_cfg (gimple_seq seq) init_empty_tree_cfg (); - found_computed_goto = 0; make_blocks (seq); - /* Computed gotos are hell to deal with, especially if there are - lots of them with a large number of destinations. So we factor - them to a common computed goto location before we build the - edge list. After we convert back to normal form, we will un-factor - the computed gotos since factoring introduces an unwanted jump. */ - if (found_computed_goto) - factor_computed_gotos (); - /* Make sure there is always at least one block, even if it's empty. */ if (n_basic_blocks_for_fn (cfun) == NUM_FIXED_BLOCKS) create_empty_bb (ENTRY_BLOCK_PTR_FOR_FN (cfun)); @@ -385,7 +372,7 @@ make_pass_build_cfg (gcc::context *ctxt) /* Return true if T is a computed goto. */ -static bool +bool computed_goto_p (gimple t) { return (gimple_code (t) == GIMPLE_GOTO @@ -437,82 +424,6 @@ assert_unreachable_fallthru_edge_p (edge e) } -/* Search the CFG for any computed gotos. If found, factor them to a - common computed goto site. Also record the location of that site so - that we can un-factor the gotos after we have converted back to - normal form. */ - -static void -factor_computed_gotos (void) -{ - basic_block bb; - tree factored_label_decl = NULL; - tree var = NULL; - gimple factored_computed_goto_label = NULL; - gimple factored_computed_goto = NULL; - - /* We know there are one or more computed gotos in this function. - Examine the last statement in each basic block to see if the block - ends with a computed goto. */ - - FOR_EACH_BB_FN (bb, cfun) - { - gimple_stmt_iterator gsi = gsi_last_bb (bb); - gimple last; - - if (gsi_end_p (gsi)) - continue; - - last = gsi_stmt (gsi); - - /* Ignore the computed goto we create when we factor the original - computed gotos. */ - if (last == factored_computed_goto) - continue; - - /* If the last statement is a computed goto, factor it. */ - if (computed_goto_p (last)) - { - gimple assignment; - - /* The first time we find a computed goto we need to create - the factored goto block and the variable each original - computed goto will use for their goto destination. */ - if (!factored_computed_goto) - { - basic_block new_bb = create_empty_bb (bb); - gimple_stmt_iterator new_gsi = gsi_start_bb (new_bb); - - /* Create the destination of the factored goto. Each original - computed goto will put its desired destination into this - variable and jump to the label we create immediately - below. */ - var = create_tmp_var (ptr_type_node, "gotovar"); - - /* Build a label for the new block which will contain the - factored computed goto. */ - factored_label_decl = create_artificial_label (UNKNOWN_LOCATION); - factored_computed_goto_label - = gimple_build_label (factored_label_decl); - gsi_insert_after (&new_gsi, factored_computed_goto_label, - GSI_NEW_STMT); - - /* Build our new computed goto. */ - factored_computed_goto = gimple_build_goto (var); - gsi_insert_after (&new_gsi, factored_computed_goto, GSI_NEW_STMT); - } - - /* Copy the original computed goto's destination into VAR. */ - assignment = gimple_build_assign (var, gimple_goto_dest (last)); - gsi_insert_before (&gsi, assignment, GSI_SAME_STMT); - - /* And re-vector the computed goto to the new destination. */ - gimple_goto_set_dest (last, factored_label_decl); - } - } -} - - /* Build a flowgraph for the sequence of stmts SEQ. */ static void @@ -546,9 +457,6 @@ make_blocks (gimple_seq seq) codes. */ gimple_set_bb (stmt, bb); - if (computed_goto_p (stmt)) - found_computed_goto = true; - /* If STMT is a basic block terminator, set START_NEW_BLOCK for the next iteration. */ if (stmt_ends_bb_p (stmt)) @@ -666,6 +574,144 @@ fold_cond_expr_cond (void) } } +/* If basic block BB has an abnormal edge to a basic block + containing IFN_ABNORMAL_DISPATCHER internal call, return + that the dispatcher's basic block, otherwise return NULL. */ + +basic_block +get_abnormal_succ_dispatcher (basic_block bb) +{ + edge e; + edge_iterator ei; + + FOR_EACH_EDGE (e, ei, bb->succs) + if ((e->flags & (EDGE_ABNORMAL | EDGE_EH)) == EDGE_ABNORMAL) + { + gimple_stmt_iterator gsi + = gsi_start_nondebug_after_labels_bb (e->dest); + gimple g = gsi_stmt (gsi); + if (g + && is_gimple_call (g) + && gimple_call_internal_p (g) + && gimple_call_internal_fn (g) == IFN_ABNORMAL_DISPATCHER) + return e->dest; + } + return NULL; +} + +/* Helper function for make_edges. Create a basic block with + with ABNORMAL_DISPATCHER internal call in it if needed, and + create abnormal edges from BBS to it and from it to FOR_BB + if COMPUTED_GOTO is false, otherwise factor the computed gotos. */ + +static void +handle_abnormal_edges (basic_block *dispatcher_bbs, + basic_block for_bb, int *bb_to_omp_idx, + auto_vec<basic_block> *bbs, bool computed_goto) +{ + basic_block *dispatcher = dispatcher_bbs + (computed_goto ? 1 : 0); + unsigned int idx = 0; + basic_block bb; + bool inner = false; + + if (bb_to_omp_idx) + { + dispatcher = dispatcher_bbs + 2 * bb_to_omp_idx[for_bb->index]; + if (bb_to_omp_idx[for_bb->index] != 0) + inner = true; + } + + /* If the dispatcher has been created already, then there are basic + blocks with abnormal edges to it, so just make a new edge to + for_bb. */ + if (*dispatcher == NULL) + { + /* Check if there are any basic blocks that need to have + abnormal edges to this dispatcher. If there are none, return + early. */ + if (bb_to_omp_idx == NULL) + { + if (bbs->is_empty ()) + return; + } + else + { + FOR_EACH_VEC_ELT (*bbs, idx, bb) + if (bb_to_omp_idx[bb->index] == bb_to_omp_idx[for_bb->index]) + break; + if (bb == NULL) + return; + } + + /* Create the dispatcher bb. */ + *dispatcher = create_basic_block (NULL, NULL, for_bb); + if (computed_goto) + { + /* Factor computed gotos into a common computed goto site. Also + record the location of that site so that we can un-factor the + gotos after we have converted back to normal form. */ + gimple_stmt_iterator gsi = gsi_start_bb (*dispatcher); + + /* Create the destination of the factored goto. Each original + computed goto will put its desired destination into this + variable and jump to the label we create immediately below. */ + tree var = create_tmp_var (ptr_type_node, "gotovar"); + + /* Build a label for the new block which will contain the + factored computed goto. */ + tree factored_label_decl + = create_artificial_label (UNKNOWN_LOCATION); + gimple factored_computed_goto_label + = gimple_build_label (factored_label_decl); + gsi_insert_after (&gsi, factored_computed_goto_label, GSI_NEW_STMT); + + /* Build our new computed goto. */ + gimple factored_computed_goto = gimple_build_goto (var); + gsi_insert_after (&gsi, factored_computed_goto, GSI_NEW_STMT); + + FOR_EACH_VEC_ELT (*bbs, idx, bb) + { + if (bb_to_omp_idx + && bb_to_omp_idx[bb->index] != bb_to_omp_idx[for_bb->index]) + continue; + + gsi = gsi_last_bb (bb); + gimple last = gsi_stmt (gsi); + + gcc_assert (computed_goto_p (last)); + + /* Copy the original computed goto's destination into VAR. */ + gimple assignment + = gimple_build_assign (var, gimple_goto_dest (last)); + gsi_insert_before (&gsi, assignment, GSI_SAME_STMT); + + edge e = make_edge (bb, *dispatcher, EDGE_FALLTHRU); + e->goto_locus = gimple_location (last); + gsi_remove (&gsi, true); + } + } + else + { + tree arg = inner ? boolean_true_node : boolean_false_node; + gimple g = gimple_build_call_internal (IFN_ABNORMAL_DISPATCHER, + 1, arg); + gimple_stmt_iterator gsi = gsi_after_labels (*dispatcher); + gsi_insert_after (&gsi, g, GSI_NEW_STMT); + + /* Create predecessor edges of the dispatcher. */ + FOR_EACH_VEC_ELT (*bbs, idx, bb) + { + if (bb_to_omp_idx + && bb_to_omp_idx[bb->index] != bb_to_omp_idx[for_bb->index]) + continue; + make_edge (bb, *dispatcher, EDGE_ABNORMAL); + } + } + } + + make_edge (*dispatcher, for_bb, EDGE_ABNORMAL); +} + /* Join all the blocks in the flowgraph. */ static void @@ -673,6 +719,10 @@ make_edges (void) { basic_block bb; struct omp_region *cur_region = NULL; + auto_vec<basic_block> ab_edge_goto; + auto_vec<basic_block> ab_edge_call; + int *bb_to_omp_idx = NULL; + int cur_omp_region_idx = 0; /* Create an edge from entry to the first block with executable statements in it. */ @@ -686,13 +736,17 @@ make_edges (void) gimple last = last_stmt (bb); bool fallthru; + if (bb_to_omp_idx) + bb_to_omp_idx[bb->index] = cur_omp_region_idx; + if (last) { enum gimple_code code = gimple_code (last); switch (code) { case GIMPLE_GOTO: - make_goto_expr_edges (bb); + if (make_goto_expr_edges (bb)) + ab_edge_goto.safe_push (bb); fallthru = false; break; case GIMPLE_RETURN: @@ -720,7 +774,7 @@ make_edges (void) make edges from this call site to all the nonlocal goto handlers. */ if (stmt_can_make_abnormal_goto (last)) - make_abnormal_goto_edges (bb, true); + ab_edge_call.safe_push (bb); /* If this statement has reachable exception handlers, then create abnormal edges to them. */ @@ -728,8 +782,10 @@ make_edges (void) /* BUILTIN_RETURN is really a return statement. */ if (gimple_call_builtin_p (last, BUILT_IN_RETURN)) - make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0), fallthru = - false; + { + make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0); + fallthru = false; + } /* Some calls are known not to return. */ else fallthru = !(gimple_call_flags (last) & ECF_NORETURN); @@ -749,7 +805,10 @@ make_edges (void) break; CASE_GIMPLE_OMP: - fallthru = make_gimple_omp_edges (bb, &cur_region); + fallthru = make_gimple_omp_edges (bb, &cur_region, + &cur_omp_region_idx); + if (cur_region && bb_to_omp_idx == NULL) + bb_to_omp_idx = XCNEWVEC (int, n_basic_blocks_for_fn (cfun)); break; case GIMPLE_TRANSACTION: @@ -773,6 +832,77 @@ make_edges (void) make_edge (bb, bb->next_bb, EDGE_FALLTHRU); } + /* Computed gotos are hell to deal with, especially if there are + lots of them with a large number of destinations. So we factor + them to a common computed goto location before we build the + edge list. After we convert back to normal form, we will un-factor + the computed gotos since factoring introduces an unwanted jump. + For non-local gotos and abnormal edges from calls to calls that return + twice or forced labels, factor the abnormal edges too, by having all + abnormal edges from the calls go to a common artificial basic block + with ABNORMAL_DISPATCHER internal call and abnormal edges from that + basic block to all forced labels and calls returning twice. + We do this per-OpenMP structured block, because those regions + are guaranteed to be single entry single exit by the standard, + so it is not allowed to enter or exit such regions abnormally this way, + thus all computed gotos, non-local gotos and setjmp/longjmp calls + must not transfer control across SESE region boundaries. */ + if (!ab_edge_goto.is_empty () || !ab_edge_call.is_empty ()) + { + gimple_stmt_iterator gsi; + basic_block dispatcher_bb_array[2] = { NULL, NULL }; + basic_block *dispatcher_bbs = dispatcher_bb_array; + int count = n_basic_blocks_for_fn (cfun); + + if (bb_to_omp_idx) + dispatcher_bbs = XCNEWVEC (basic_block, 2 * count); + + FOR_EACH_BB_FN (bb, cfun) + { + for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi)) + { + gimple label_stmt = gsi_stmt (gsi); + tree target; + + if (gimple_code (label_stmt) != GIMPLE_LABEL) + break; + + target = gimple_label_label (label_stmt); + + /* Make an edge to every label block that has been marked as a + potential target for a computed goto or a non-local goto. */ + if (FORCED_LABEL (target)) + handle_abnormal_edges (dispatcher_bbs, bb, bb_to_omp_idx, + &ab_edge_goto, true); + if (DECL_NONLOCAL (target)) + { + handle_abnormal_edges (dispatcher_bbs, bb, bb_to_omp_idx, + &ab_edge_call, false); + break; + } + } + + if (!gsi_end_p (gsi) && is_gimple_debug (gsi_stmt (gsi))) + gsi_next_nondebug (&gsi); + if (!gsi_end_p (gsi)) + { + /* Make an edge to every setjmp-like call. */ + gimple call_stmt = gsi_stmt (gsi); + if (is_gimple_call (call_stmt) + && ((gimple_call_flags (call_stmt) & ECF_RETURNS_TWICE) + || gimple_call_builtin_p (call_stmt, + BUILT_IN_SETJMP_RECEIVER))) + handle_abnormal_edges (dispatcher_bbs, bb, bb_to_omp_idx, + &ab_edge_call, false); + } + } + + if (bb_to_omp_idx) + XDELETE (dispatcher_bbs); + } + + XDELETE (bb_to_omp_idx); + free_omp_regions (); /* Fold COND_EXPR_COND of each COND_EXPR. */ @@ -1045,53 +1175,10 @@ label_to_block_fn (struct function *ifun, tree dest) return (*ifun->cfg->x_label_to_block_map)[uid]; } -/* Create edges for an abnormal goto statement at block BB. If FOR_CALL - is true, the source statement is a CALL_EXPR instead of a GOTO_EXPR. */ +/* Create edges for a goto statement at block BB. Returns true + if abnormal edges should be created. */ -void -make_abnormal_goto_edges (basic_block bb, bool for_call) -{ - basic_block target_bb; - gimple_stmt_iterator gsi; - - FOR_EACH_BB_FN (target_bb, cfun) - { - for (gsi = gsi_start_bb (target_bb); !gsi_end_p (gsi); gsi_next (&gsi)) - { - gimple label_stmt = gsi_stmt (gsi); - tree target; - - if (gimple_code (label_stmt) != GIMPLE_LABEL) - break; - - target = gimple_label_label (label_stmt); - - /* Make an edge to every label block that has been marked as a - potential target for a computed goto or a non-local goto. */ - if ((FORCED_LABEL (target) && !for_call) - || (DECL_NONLOCAL (target) && for_call)) - { - make_edge (bb, target_bb, EDGE_ABNORMAL); - break; - } - } - if (!gsi_end_p (gsi) - && is_gimple_debug (gsi_stmt (gsi))) - gsi_next_nondebug (&gsi); - if (!gsi_end_p (gsi)) - { - /* Make an edge to every setjmp-like call. */ - gimple call_stmt = gsi_stmt (gsi); - if (is_gimple_call (call_stmt) - && (gimple_call_flags (call_stmt) & ECF_RETURNS_TWICE)) - make_edge (bb, target_bb, EDGE_ABNORMAL); - } - } -} - -/* Create edges for a goto statement at block BB. */ - -static void +static bool make_goto_expr_edges (basic_block bb) { gimple_stmt_iterator last = gsi_last_bb (bb); @@ -1105,11 +1192,11 @@ make_goto_expr_edges (basic_block bb) edge e = make_edge (bb, label_bb, EDGE_FALLTHRU); e->goto_locus = gimple_location (goto_t); gsi_remove (&last, true); - return; + return false; } /* A computed GOTO creates abnormal edges. */ - make_abnormal_goto_edges (bb, false); + return true; } /* Create edges for an asm statement with labels at block BB. */ diff --git a/gcc/tree-cfg.h b/gcc/tree-cfg.h index babbd2db2ca..a115df58b9d 100644 --- a/gcc/tree-cfg.h +++ b/gcc/tree-cfg.h @@ -31,7 +31,6 @@ extern void start_recording_case_labels (void); extern void end_recording_case_labels (void); extern basic_block label_to_block_fn (struct function *, tree); #define label_to_block(t) (label_to_block_fn (cfun, t)) -extern void make_abnormal_goto_edges (basic_block, bool); extern void cleanup_dead_labels (void); extern void group_case_labels_stmt (gimple); extern void group_case_labels (void); @@ -46,7 +45,9 @@ extern void gimple_debug_cfg (int); extern void gimple_dump_cfg (FILE *, int); extern void dump_cfg_stats (FILE *); extern void debug_cfg_stats (void); +extern bool computed_goto_p (gimple); extern bool stmt_can_make_abnormal_goto (gimple); +extern basic_block get_abnormal_succ_dispatcher (basic_block); extern bool is_ctrl_stmt (gimple); extern bool is_ctrl_altering_stmt (gimple); extern bool simple_goto_p (gimple); diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index a3175b34484..79a39bca136 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -1967,7 +1967,7 @@ update_ssa_across_abnormal_edges (basic_block bb, basic_block ret_bb, static bool copy_edges_for_bb (basic_block bb, gcov_type count_scale, basic_block ret_bb, - bool can_make_abnormal_goto) + basic_block abnormal_goto_dest) { basic_block new_bb = (basic_block) bb->aux; edge_iterator ei; @@ -2021,7 +2021,9 @@ copy_edges_for_bb (basic_block bb, gcov_type count_scale, basic_block ret_bb, into a COMPONENT_REF which doesn't. If the copy can throw, the original could also throw. */ can_throw = stmt_can_throw_internal (copy_stmt); - nonlocal_goto = stmt_can_make_abnormal_goto (copy_stmt); + nonlocal_goto + = (stmt_can_make_abnormal_goto (copy_stmt) + && !computed_goto_p (copy_stmt)); if (can_throw || nonlocal_goto) { @@ -2052,9 +2054,26 @@ copy_edges_for_bb (basic_block bb, gcov_type count_scale, basic_block ret_bb, /* If the call we inline cannot make abnormal goto do not add additional abnormal edges but only retain those already present in the original function body. */ - nonlocal_goto &= can_make_abnormal_goto; + if (abnormal_goto_dest == NULL) + nonlocal_goto = false; if (nonlocal_goto) - make_abnormal_goto_edges (gimple_bb (copy_stmt), true); + { + basic_block copy_stmt_bb = gimple_bb (copy_stmt); + + if (get_abnormal_succ_dispatcher (copy_stmt_bb)) + nonlocal_goto = false; + /* ABNORMAL_DISPATCHER (1) is for longjmp/setjmp or nonlocal gotos + in OpenMP regions which aren't allowed to be left abnormally. + So, no need to add abnormal edge in that case. */ + else if (is_gimple_call (copy_stmt) + && gimple_call_internal_p (copy_stmt) + && (gimple_call_internal_fn (copy_stmt) + == IFN_ABNORMAL_DISPATCHER) + && gimple_call_arg (copy_stmt, 0) == boolean_true_node) + nonlocal_goto = false; + else + make_edge (copy_stmt_bb, abnormal_goto_dest, EDGE_ABNORMAL); + } if ((can_throw || nonlocal_goto) && gimple_in_ssa_p (cfun)) @@ -2493,13 +2512,22 @@ copy_cfg_body (copy_body_data * id, gcov_type count, int frequency_scale, last = last_basic_block_for_fn (cfun); /* Now that we've duplicated the blocks, duplicate their edges. */ - bool can_make_abormal_goto - = id->gimple_call && stmt_can_make_abnormal_goto (id->gimple_call); + basic_block abnormal_goto_dest = NULL; + if (id->gimple_call + && stmt_can_make_abnormal_goto (id->gimple_call)) + { + gimple_stmt_iterator gsi = gsi_for_stmt (id->gimple_call); + + bb = gimple_bb (id->gimple_call); + gsi_next (&gsi); + if (gsi_end_p (gsi)) + abnormal_goto_dest = get_abnormal_succ_dispatcher (bb); + } FOR_ALL_BB_FN (bb, cfun_to_copy) if (!id->blocks_to_copy || (bb->index > 0 && bitmap_bit_p (id->blocks_to_copy, bb->index))) need_debug_cleanup |= copy_edges_for_bb (bb, count_scale, exit_block_map, - can_make_abormal_goto); + abnormal_goto_dest); if (new_entry) { diff --git a/gcc/tree.c b/gcc/tree.c index 76e3efb4920..5fdd491a97d 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -9977,12 +9977,6 @@ build_common_builtin_nodes (void) BUILT_IN_SETJMP_SETUP, "__builtin_setjmp_setup", ECF_NOTHROW); - ftype = build_function_type_list (ptr_type_node, ptr_type_node, NULL_TREE); - local_define_builtin ("__builtin_setjmp_dispatcher", ftype, - BUILT_IN_SETJMP_DISPATCHER, - "__builtin_setjmp_dispatcher", - ECF_PURE | ECF_NOTHROW); - ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE); local_define_builtin ("__builtin_setjmp_receiver", ftype, BUILT_IN_SETJMP_RECEIVER,