Add gimple_find_sub_bbs
authorTom de Vries <tom@codesourcery.com>
Fri, 17 Apr 2015 09:26:33 +0000 (09:26 +0000)
committerTom de Vries <vries@gcc.gnu.org>
Fri, 17 Apr 2015 09:26:33 +0000 (09:26 +0000)
2015-04-17  Tom de Vries  <tom@codesourcery.com>
    Michael Matz  <matz@suse.de>

* tree-cfg.c (make_blocks_1): Factor out of ...
(make_blocks): ... here.
(make_edges_bb): Factor out of ...
(make_edges): ... here.
(gimple_find_sub_bbs): New function.
* tree-cfg.h (gimple_find_sub_bbs): Declare.

Co-Authored-By: Michael Matz <matz@suse.de>
From-SVN: r222170

gcc/ChangeLog
gcc/tree-cfg.c
gcc/tree-cfg.h

index a533ad4c4ebe0ad2b260a1eaa0fa0088dcc8f40f..36429850c236c6275ee33b5643bed2142c8c4149 100644 (file)
@@ -1,3 +1,13 @@
+2015-04-17  Tom de Vries  <tom@codesourcery.com>
+           Michael Matz  <matz@suse.de>
+
+       * tree-cfg.c (make_blocks_1): Factor out of ...
+       (make_blocks): ... here.
+       (make_edges_bb): Factor out of ...
+       (make_edges): ... here.
+       (gimple_find_sub_bbs): New function.
+       * tree-cfg.h (gimple_find_sub_bbs): Declare.
+
 2015-04-17  Tom de Vries  <tom@codesourcery.com>
 
        * tree.c (free_lang_data): Disable lang_hooks.gimplify_expr.
index 64bdc92e681026ea0d6e47208e35e3212c684722..1cfb67a4831bb95d650cf4fdcbe56b11cce56d95 100644 (file)
@@ -513,16 +513,15 @@ gimple_call_initialize_ctrl_altering (gimple stmt)
 }
 
 
-/* Build a flowgraph for the sequence of stmts SEQ.  */
+/* Insert SEQ after BB and build a flowgraph.  */
 
-static void
-make_blocks (gimple_seq seq)
+static basic_block
+make_blocks_1 (gimple_seq seq, basic_block bb)
 {
   gimple_stmt_iterator i = gsi_start (seq);
   gimple stmt = NULL;
   bool start_new_block = true;
   bool first_stmt_of_seq = true;
-  basic_block bb = ENTRY_BLOCK_PTR_FOR_FN (cfun);
 
   while (!gsi_end_p (i))
     {
@@ -579,8 +578,16 @@ make_blocks (gimple_seq seq)
       gsi_next (&i);
       first_stmt_of_seq = false;
     }
+  return bb;
 }
 
+/* Build a flowgraph for the sequence of stmts SEQ.  */
+
+static void
+make_blocks (gimple_seq seq)
+{
+  make_blocks_1 (seq, ENTRY_BLOCK_PTR_FOR_FN (cfun));
+}
 
 /* Create and return a new empty basic block after bb AFTER.  */
 
@@ -807,6 +814,112 @@ handle_abnormal_edges (basic_block *dispatcher_bbs,
   make_edge (*dispatcher, for_bb, EDGE_ABNORMAL);
 }
 
+/* Creates outgoing edges for BB.  Returns 1 when it ends with an
+   computed goto, returns 2 when it ends with a statement that
+   might return to this function via an nonlocal goto, otherwise
+   return 0.  Updates *PCUR_REGION with the OMP region this BB is in.  */
+
+static int
+make_edges_bb (basic_block bb, struct omp_region **pcur_region, int *pomp_index)
+{
+  gimple last = last_stmt (bb);
+  bool fallthru = false;
+  int ret = 0;
+
+  if (!last)
+    return ret;
+
+  switch (gimple_code (last))
+    {
+    case GIMPLE_GOTO:
+      if (make_goto_expr_edges (bb))
+       ret = 1;
+      fallthru = false;
+      break;
+    case GIMPLE_RETURN:
+      {
+       edge e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
+       e->goto_locus = gimple_location (last);
+       fallthru = false;
+      }
+      break;
+    case GIMPLE_COND:
+      make_cond_expr_edges (bb);
+      fallthru = false;
+      break;
+    case GIMPLE_SWITCH:
+      make_gimple_switch_edges (as_a <gswitch *> (last), bb);
+      fallthru = false;
+      break;
+    case GIMPLE_RESX:
+      make_eh_edges (last);
+      fallthru = false;
+      break;
+    case GIMPLE_EH_DISPATCH:
+      fallthru = make_eh_dispatch_edges (as_a <geh_dispatch *> (last));
+      break;
+
+    case GIMPLE_CALL:
+      /* If this function receives a nonlocal goto, then we need to
+        make edges from this call site to all the nonlocal goto
+        handlers.  */
+      if (stmt_can_make_abnormal_goto (last))
+       ret = 2;
+
+      /* If this statement has reachable exception handlers, then
+        create abnormal edges to them.  */
+      make_eh_edges (last);
+
+      /* 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;
+       }
+      /* Some calls are known not to return.  */
+      else
+       fallthru = !(gimple_call_flags (last) & ECF_NORETURN);
+      break;
+
+    case GIMPLE_ASSIGN:
+      /* A GIMPLE_ASSIGN may throw internally and thus be considered
+        control-altering.  */
+      if (is_ctrl_altering_stmt (last))
+       make_eh_edges (last);
+      fallthru = true;
+      break;
+
+    case GIMPLE_ASM:
+      make_gimple_asm_edges (bb);
+      fallthru = true;
+      break;
+
+    CASE_GIMPLE_OMP:
+      fallthru = make_gimple_omp_edges (bb, pcur_region, pomp_index);
+      break;
+
+    case GIMPLE_TRANSACTION:
+      {
+       tree abort_label
+         = gimple_transaction_label (as_a <gtransaction *> (last));
+       if (abort_label)
+         make_edge (bb, label_to_block (abort_label), EDGE_TM_ABORT);
+       fallthru = true;
+      }
+      break;
+
+    default:
+      gcc_assert (!stmt_ends_bb_p (last));
+      fallthru = true;
+      break;
+    }
+
+  if (fallthru)
+    make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+
+  return ret;
+}
+
 /* Join all the blocks in the flowgraph.  */
 
 static void
@@ -828,107 +941,19 @@ make_edges (void)
   /* Traverse the basic block array placing edges.  */
   FOR_EACH_BB_FN (bb, cfun)
     {
-      gimple last = last_stmt (bb);
-      bool fallthru;
+      int mer;
 
       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:
-             if (make_goto_expr_edges (bb))
-               ab_edge_goto.safe_push (bb);
-             fallthru = false;
-             break;
-           case GIMPLE_RETURN:
-             {
-               edge e = make_edge (bb, EXIT_BLOCK_PTR_FOR_FN (cfun), 0);
-               e->goto_locus = gimple_location (last);
-               fallthru = false;
-             }
-             break;
-           case GIMPLE_COND:
-             make_cond_expr_edges (bb);
-             fallthru = false;
-             break;
-           case GIMPLE_SWITCH:
-             make_gimple_switch_edges (as_a <gswitch *> (last), bb);
-             fallthru = false;
-             break;
-           case GIMPLE_RESX:
-             make_eh_edges (last);
-             fallthru = false;
-             break;
-           case GIMPLE_EH_DISPATCH:
-             fallthru = make_eh_dispatch_edges (as_a <geh_dispatch *> (last));
-             break;
-
-           case GIMPLE_CALL:
-             /* If this function receives a nonlocal goto, then we need to
-                make edges from this call site to all the nonlocal goto
-                handlers.  */
-             if (stmt_can_make_abnormal_goto (last))
-               ab_edge_call.safe_push (bb);
-
-             /* If this statement has reachable exception handlers, then
-                create abnormal edges to them.  */
-             make_eh_edges (last);
-
-             /* 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;
-               }
-             /* Some calls are known not to return.  */
-             else
-               fallthru = !(gimple_call_flags (last) & ECF_NORETURN);
-             break;
+      mer = make_edges_bb (bb, &cur_region, &cur_omp_region_idx);
+      if (mer == 1)
+       ab_edge_goto.safe_push (bb);
+      else if (mer == 2)
+       ab_edge_call.safe_push (bb);
 
-           case GIMPLE_ASSIGN:
-              /* A GIMPLE_ASSIGN may throw internally and thus be considered
-                 control-altering. */
-             if (is_ctrl_altering_stmt (last))
-               make_eh_edges (last);
-             fallthru = true;
-             break;
-
-           case GIMPLE_ASM:
-             make_gimple_asm_edges (bb);
-             fallthru = true;
-             break;
-
-           CASE_GIMPLE_OMP:
-             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:
-             {
-               tree abort_label
-                 = gimple_transaction_label (as_a <gtransaction *> (last));
-               if (abort_label)
-                 make_edge (bb, label_to_block (abort_label), EDGE_TM_ABORT);
-               fallthru = true;
-             }
-             break;
-
-           default:
-             gcc_assert (!stmt_ends_bb_p (last));
-             fallthru = true;
-           }
-       }
-      else
-       fallthru = true;
-
-      if (fallthru)
-       make_edge (bb, bb->next_bb, EDGE_FALLTHRU);
+      if (cur_region && bb_to_omp_idx == NULL)
+       bb_to_omp_idx = XCNEWVEC (int, n_basic_blocks_for_fn (cfun));
     }
 
   /* Computed gotos are hell to deal with, especially if there are
@@ -1008,6 +1033,43 @@ make_edges (void)
   fold_cond_expr_cond ();
 }
 
+/* Add SEQ after GSI.  Start new bb after GSI, and created further bbs as
+   needed.  Returns true if new bbs were created.
+   Note: This is transitional code, and should not be used for new code.  We
+   should be able to get rid of this by rewriting all target va-arg
+   gimplification hooks to use an interface gimple_build_cond_value as described
+   in https://gcc.gnu.org/ml/gcc-patches/2015-02/msg01194.html.  */
+
+bool
+gimple_find_sub_bbs (gimple_seq seq, gimple_stmt_iterator *gsi)
+{
+  gimple stmt = gsi_stmt (*gsi);
+  basic_block bb = gimple_bb (stmt);
+  basic_block lastbb, afterbb;
+  int old_num_bbs = n_basic_blocks_for_fn (cfun);
+  edge e;
+  lastbb = make_blocks_1 (seq, bb);
+  if (old_num_bbs == n_basic_blocks_for_fn (cfun))
+    return false;
+  e = split_block (bb, stmt);
+  /* Move e->dest to come after the new basic blocks.  */
+  afterbb = e->dest;
+  unlink_block (afterbb);
+  link_block (afterbb, lastbb);
+  redirect_edge_succ (e, bb->next_bb);
+  bb = bb->next_bb;
+  while (bb != afterbb)
+    {
+      struct omp_region *cur_region = NULL;
+      int cur_omp_region_idx = 0;
+      int mer = make_edges_bb (bb, &cur_region, &cur_omp_region_idx);
+      gcc_assert (!mer && !cur_region);
+      add_bb_to_loop (bb, afterbb->loop_father);
+      bb = bb->next_bb;
+    }
+  return true;
+}
+
 /* Find the next available discriminator value for LOCUS.  The
    discriminator distinguishes among several basic blocks that
    share a common locus, allowing for more accurate sample-based
index cd28a80c7f62942fca27827839fd177c79bf42a5..2fc1e886ff0d5bf194c1300c33c4fec7d6522db6 100644 (file)
@@ -103,5 +103,6 @@ extern void extract_true_false_edges_from_block (basic_block, edge *, edge *);
 extern unsigned int execute_fixup_cfg (void);
 extern unsigned int split_critical_edges (void);
 extern basic_block insert_cond_bb (basic_block, gimple, gimple);
+extern bool gimple_find_sub_bbs (gimple_seq, gimple_stmt_iterator *);
 
 #endif /* _TREE_CFG_H  */