aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-cfg.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2014-01-29 12:02:46 +0100
committerJakub Jelinek <jakub@gcc.gnu.org>2014-01-29 12:02:46 +0100
commit09b22f48d435d158761a02117facec4daa7395fb (patch)
tree4b721b57c74c1349afc462b869e17ae0bdb8fa90 /gcc/tree-cfg.c
parent42eb8bd17982621ad29ec491053851fd2d0d740e (diff)
downloadgcc-09b22f48d435d158761a02117facec4daa7395fb.zip
gcc-09b22f48d435d158761a02117facec4daa7395fb.tar.gz
gcc-09b22f48d435d158761a02117facec4daa7395fb.tar.bz2
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
Diffstat (limited to 'gcc/tree-cfg.c')
-rw-r--r--gcc/tree-cfg.c381
1 files changed, 234 insertions, 147 deletions
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 32110a7..dfc9b7b 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. */
-
-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. */
+/* Create edges for a goto statement at block BB. Returns true
+ if abnormal edges should be created. */
-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. */