tree-pretty-print.c (dump_generic_node): Dump OMP_SECTIONS_SWITCH.
authorZdenek Dvorak <ook@ucw.cz>
Wed, 1 Aug 2007 11:50:39 +0000 (13:50 +0200)
committerZdenek Dvorak <rakdver@gcc.gnu.org>
Wed, 1 Aug 2007 11:50:39 +0000 (11:50 +0000)
* tree-pretty-print.c (dump_generic_node): Dump OMP_SECTIONS_SWITCH.
Display new operands of OMP_SECTIONS and OMP_CONTINUE.
* tree.h (OMP_SECTIONS_CONTROL): New macro.
(OMP_DIRECTIVE_P): Add OMP_SECTIONS_SWITCH.
* omp-low.c (get_ws_args_for, determine_parallel_type,
expand_omp_for_generic, expand_omp_for_static_nochunk,
expand_omp_for_static_chunk, expand_omp_for, expand_omp_sections):
Work with more precise CFG.
(build_omp_regions_1): Handle OMP_SECTIONS_SWITCH.
(lower_omp_sections): Emit OMP_SECTIONS_SWITCH.  Add arguments to
OMP_CONTINUE.
* tree-gimple.c (is_gimple_stmt): Handle OMP_SECTIONS_SWITCH.
* gimple-low.c (lower_stmt): Ditto.
* tree-inline.c (estimate_num_insns_1): Ditto.
* tree.def (OMP_SECTIONS, OMP_CONTINUE): Added new operands.
(OMP_SECTIONS_SWITCH): New.
* tree-cfgcleanup.c (cleanup_omp_return): New.
(cleanup_tree_cfg_bb): Call cleanup_omp_return.
* tree-cfg.c (make_edges): Create back edges for OMP_CONTINUE
and exit edge for OMP_FOR.  Handle OMP_SECTIONS_SWITCH.
(tree_redirect_edge_and_branch): Handle omp constructs.

* fortran/trans-openmp.c (gfc_trans_omp_sections): Build OMP_SECTIONS
with three arguments.

From-SVN: r127121

gcc/ChangeLog
gcc/fortran/trans-openmp.c
gcc/gimple-low.c
gcc/omp-low.c
gcc/tree-cfg.c
gcc/tree-cfgcleanup.c
gcc/tree-gimple.c
gcc/tree-inline.c
gcc/tree-pretty-print.c
gcc/tree.def
gcc/tree.h

index 6736648ba0946a4fc0ff64b9329903341cc1e0c5..d7afe17fd9cdc9d04492f6f18740f44d4f4758d7 100644 (file)
@@ -1,3 +1,30 @@
+2007-08-01  Zdenek Dvorak  <ook@ucw.cz>
+
+       * tree-pretty-print.c (dump_generic_node): Dump OMP_SECTIONS_SWITCH.
+       Display new operands of OMP_SECTIONS and OMP_CONTINUE.
+       * tree.h (OMP_SECTIONS_CONTROL): New macro.
+       (OMP_DIRECTIVE_P): Add OMP_SECTIONS_SWITCH.
+       * omp-low.c (get_ws_args_for, determine_parallel_type,
+       expand_omp_for_generic, expand_omp_for_static_nochunk,
+       expand_omp_for_static_chunk, expand_omp_for, expand_omp_sections):
+       Work with more precise CFG.
+       (build_omp_regions_1): Handle OMP_SECTIONS_SWITCH.
+       (lower_omp_sections): Emit OMP_SECTIONS_SWITCH.  Add arguments to
+       OMP_CONTINUE.
+       * tree-gimple.c (is_gimple_stmt): Handle OMP_SECTIONS_SWITCH.
+       * gimple-low.c (lower_stmt): Ditto.
+       * tree-inline.c (estimate_num_insns_1): Ditto.
+       * tree.def (OMP_SECTIONS, OMP_CONTINUE): Added new operands.
+       (OMP_SECTIONS_SWITCH): New.
+       * tree-cfgcleanup.c (cleanup_omp_return): New.
+       (cleanup_tree_cfg_bb): Call cleanup_omp_return.
+       * tree-cfg.c (make_edges): Create back edges for OMP_CONTINUE
+       and exit edge for OMP_FOR.  Handle OMP_SECTIONS_SWITCH.
+       (tree_redirect_edge_and_branch): Handle omp constructs.
+
+       * fortran/trans-openmp.c (gfc_trans_omp_sections): Build OMP_SECTIONS
+       with three arguments.
+
 2007-08-01  Zdenek Dvorak  <ook@ucw.cz>
 
        * tree-cfg.c (tree_merge_blocks): Preserve loop exit phi nodes only
index b0683308f755dc12094b3345b4d92cf5b77046c5..99fd1d04ba6f6e8f5713c419d071ff1d0306a154 100644 (file)
@@ -1205,7 +1205,7 @@ gfc_trans_omp_sections (gfc_code *code, gfc_omp_clauses *clauses)
     }
   stmt = gfc_finish_block (&body);
 
-  stmt = build2_v (OMP_SECTIONS, stmt, omp_clauses);
+  stmt = build3_v (OMP_SECTIONS, stmt, omp_clauses, NULL_TREE);
   gfc_add_expr_to_block (&block, stmt);
 
   return gfc_finish_block (&block);
index 8cab8bd050b8bd5ccb5e22a08a5f31a1f6d95aef..93532b95626985ed7a60d505ce4abba859aeb4a9 100644 (file)
@@ -244,6 +244,7 @@ lower_stmt (tree_stmt_iterator *tsi, struct lower_data *data)
     case CHANGE_DYNAMIC_TYPE_EXPR:
     case OMP_FOR:
     case OMP_SECTIONS:
+    case OMP_SECTIONS_SWITCH:
     case OMP_SECTION:
     case OMP_SINGLE:
     case OMP_MASTER:
index feced73f5fed6e20ae5681c3e163f110c226a834..bc1c82193cbe16dfffb400a757d5aaef6ffc974d 100644 (file)
@@ -347,8 +347,11 @@ get_ws_args_for (tree ws_stmt)
     }
   else if (TREE_CODE (ws_stmt) == OMP_SECTIONS)
     {
-      basic_block bb = bb_for_stmt (ws_stmt);
-      t = build_int_cst (unsigned_type_node, EDGE_COUNT (bb->succs));
+      /* Number of sections is equal to the number of edges from the
+        OMP_SECTIONS_SWITCH statement, except for the one to the exit
+        of the sections region.  */
+      basic_block bb = single_succ (bb_for_stmt (ws_stmt));
+      t = build_int_cst (unsigned_type_node, EDGE_COUNT (bb->succs) - 1);
       t = tree_cons (NULL, t, NULL);
       return t;
     }
@@ -366,7 +369,8 @@ determine_parallel_type (struct omp_region *region)
   basic_block ws_entry_bb, ws_exit_bb;
 
   if (region == NULL || region->inner == NULL
-      || region->exit == NULL || region->inner->exit == NULL)
+      || region->exit == NULL || region->inner->exit == NULL
+      || region->inner->cont == NULL)
     return;
 
   /* We only support parallel+for and parallel+sections.  */
@@ -2566,7 +2570,7 @@ expand_omp_parallel (struct omp_region *region)
     L3:
 
     If this is a combined omp parallel loop, instead of the call to
-    GOMP_loop_foo_start, we emit 'goto L3'.  */
+    GOMP_loop_foo_start, we emit 'goto L2'.  */
 
 static void
 expand_omp_for_generic (struct omp_region *region,
@@ -2580,6 +2584,9 @@ expand_omp_for_generic (struct omp_region *region,
   basic_block l2_bb = NULL, l3_bb = NULL;
   block_stmt_iterator si;
   bool in_combined_parallel = is_combined_parallel (region);
+  bool broken_loop = region->cont == NULL;
+
+  gcc_assert (!broken_loop || !in_combined_parallel);
 
   type = TREE_TYPE (fd->v);
 
@@ -2589,19 +2596,23 @@ expand_omp_for_generic (struct omp_region *region,
   TREE_ADDRESSABLE (istart0) = 1;
   TREE_ADDRESSABLE (iend0) = 1;
 
-  gcc_assert ((region->cont != NULL) ^ (region->exit == NULL));
-
   entry_bb = region->entry;
-  l0_bb = create_empty_bb (entry_bb);
-  l1_bb = single_succ (entry_bb);
-
   cont_bb = region->cont;
-  exit_bb = region->exit;
-  if (cont_bb)
+  gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
+  gcc_assert (broken_loop
+             || BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
+  l0_bb = split_edge (FALLTHRU_EDGE (entry_bb));
+  l1_bb = single_succ (l0_bb);
+  if (!broken_loop)
     {
       l2_bb = create_empty_bb (cont_bb);
-      l3_bb = single_succ (cont_bb);
+      gcc_assert (BRANCH_EDGE (cont_bb)->dest == l1_bb);
+      gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
     }
+  else
+    l2_bb = NULL;
+  l3_bb = BRANCH_EDGE (entry_bb)->dest;
+  exit_bb = region->exit;
 
   si = bsi_last (entry_bb);
   gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
@@ -2626,11 +2637,8 @@ expand_omp_for_generic (struct omp_region *region,
        t = build_call_expr (built_in_decls[start_fn], 5,
                             t0, t1, t2, t3, t4);
       t = get_formal_tmp_var (t, &list);
-      if (cont_bb)
-       {
-         t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
-         append_to_statement_list (t, &list);
-       }
+      t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
+      append_to_statement_list (t, &list);
       bsi_insert_after (&si, list, BSI_SAME_STMT);
     }
   bsi_remove (&si, true);
@@ -2648,47 +2656,39 @@ expand_omp_for_generic (struct omp_region *region,
   si = bsi_start (l0_bb);
   bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
 
-  /* Handle the rare case where BODY doesn't ever return.  */
-  if (cont_bb == NULL)
+  if (!broken_loop)
     {
-      remove_edge (single_succ_edge (entry_bb));
-      make_edge (entry_bb, l0_bb, EDGE_FALLTHRU);
-      make_edge (l0_bb, l1_bb, EDGE_FALLTHRU);
-      return;
-    }
-
-  /* Code to control the increment and predicate for the sequential
-     loop goes in the first half of EXIT_BB (we split EXIT_BB so
-     that we can inherit all the edges going out of the loop
-     body).  */
-  list = alloc_stmt_list ();
+      /* Code to control the increment and predicate for the sequential
+        loop goes in the CONT_BB.  */
+      list = alloc_stmt_list ();
 
-  t = build2 (PLUS_EXPR, type, fd->v, fd->step);
-  t = build_gimple_modify_stmt (fd->v, t);
-  gimplify_and_add (t, &list);
+      t = build2 (PLUS_EXPR, type, fd->v, fd->step);
+      t = build_gimple_modify_stmt (fd->v, t);
+      gimplify_and_add (t, &list);
   
-  t = build2 (fd->cond_code, boolean_type_node, fd->v, iend);
-  t = get_formal_tmp_var (t, &list);
-  t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
-  append_to_statement_list (t, &list);
+      t = build2 (fd->cond_code, boolean_type_node, fd->v, iend);
+      t = get_formal_tmp_var (t, &list);
+      t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
+      append_to_statement_list (t, &list);
 
-  si = bsi_last (cont_bb);
-  bsi_insert_after (&si, list, BSI_SAME_STMT);
-  gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
-  bsi_remove (&si, true);
+      si = bsi_last (cont_bb);
+      bsi_insert_after (&si, list, BSI_SAME_STMT);
+      gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
+      bsi_remove (&si, true);
 
-  /* Emit code to get the next parallel iteration in L2_BB.  */
-  list = alloc_stmt_list ();
+      /* Emit code to get the next parallel iteration in L2_BB.  */
+      list = alloc_stmt_list ();
 
-  t = build_call_expr (built_in_decls[next_fn], 2,
-                      build_fold_addr_expr (istart0),
-                      build_fold_addr_expr (iend0));
-  t = get_formal_tmp_var (t, &list);
-  t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
-  append_to_statement_list (t, &list);
+      t = build_call_expr (built_in_decls[next_fn], 2,
+                          build_fold_addr_expr (istart0),
+                          build_fold_addr_expr (iend0));
+      t = get_formal_tmp_var (t, &list);
+      t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
+      append_to_statement_list (t, &list);
   
-  si = bsi_start (l2_bb);
-  bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
+      si = bsi_start (l2_bb);
+      bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
+    }
 
   /* Add the loop cleanup function.  */
   si = bsi_last (exit_bb);
@@ -2701,23 +2701,26 @@ expand_omp_for_generic (struct omp_region *region,
   bsi_remove (&si, true);
 
   /* Connect the new blocks.  */
-  remove_edge (single_succ_edge (entry_bb));
   if (in_combined_parallel)
-    make_edge (entry_bb, l2_bb, EDGE_FALLTHRU);
+    {
+      remove_edge (BRANCH_EDGE (entry_bb));
+      redirect_edge_and_branch (single_succ_edge (entry_bb), l2_bb);
+    }
   else
     {
-      make_edge (entry_bb, l0_bb, EDGE_TRUE_VALUE);
-      make_edge (entry_bb, l3_bb, EDGE_FALSE_VALUE);
+      find_edge (entry_bb, l0_bb)->flags = EDGE_TRUE_VALUE;
+      find_edge (entry_bb, l3_bb)->flags = EDGE_FALSE_VALUE;
     }
 
-  make_edge (l0_bb, l1_bb, EDGE_FALLTHRU);
-
-  remove_edge (single_succ_edge (cont_bb));
-  make_edge (cont_bb, l1_bb, EDGE_TRUE_VALUE);
-  make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE);
+  if (!broken_loop)
+    {
+      find_edge (cont_bb, l1_bb)->flags = EDGE_TRUE_VALUE;
+      remove_edge (find_edge (cont_bb, l3_bb));
+      make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE);
 
-  make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
-  make_edge (l2_bb, l3_bb, EDGE_FALSE_VALUE);
+      make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
+      make_edge (l2_bb, l3_bb, EDGE_FALSE_VALUE);
+    }
 }
 
 
@@ -2762,10 +2765,14 @@ expand_omp_for_static_nochunk (struct omp_region *region,
   type = TREE_TYPE (fd->v);
 
   entry_bb = region->entry;
-  seq_start_bb = create_empty_bb (entry_bb);
-  body_bb = single_succ (entry_bb);
   cont_bb = region->cont;
-  fin_bb = single_succ (cont_bb);
+  gcc_assert (EDGE_COUNT (entry_bb->succs) == 2);
+  gcc_assert (BRANCH_EDGE (entry_bb)->dest == FALLTHRU_EDGE (cont_bb)->dest);
+  seq_start_bb = split_edge (FALLTHRU_EDGE (entry_bb));
+  body_bb = single_succ (seq_start_bb);
+  gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
+  gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
+  fin_bb = FALLTHRU_EDGE (cont_bb)->dest;
   exit_bb = region->exit;
 
   /* Iteration space partitioning goes in ENTRY_BB.  */
@@ -2871,13 +2878,10 @@ expand_omp_for_static_nochunk (struct omp_region *region,
   bsi_remove (&si, true);
 
   /* Connect all the blocks.  */
-  make_edge (seq_start_bb, body_bb, EDGE_FALLTHRU);
-
-  remove_edge (single_succ_edge (entry_bb));
-  make_edge (entry_bb, fin_bb, EDGE_TRUE_VALUE);
-  make_edge (entry_bb, seq_start_bb, EDGE_FALSE_VALUE);
-
-  make_edge (cont_bb, body_bb, EDGE_TRUE_VALUE);
+  find_edge (entry_bb, seq_start_bb)->flags = EDGE_FALSE_VALUE;
+  find_edge (entry_bb, fin_bb)->flags = EDGE_TRUE_VALUE;
+  
+  find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE;
   find_edge (cont_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
 }
 
@@ -2923,16 +2927,24 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
   basic_block trip_update_bb, cont_bb, fin_bb;
   tree list;
   block_stmt_iterator si;
+  edge se;
 
   type = TREE_TYPE (fd->v);
 
   entry_bb = region->entry;
-  iter_part_bb = create_empty_bb (entry_bb);
-  seq_start_bb = create_empty_bb (iter_part_bb);
-  body_bb = single_succ (entry_bb);
+  se = split_block (entry_bb, last_stmt (entry_bb));
+  entry_bb = se->src;
+  iter_part_bb = se->dest;
   cont_bb = region->cont;
-  trip_update_bb = create_empty_bb (cont_bb);
-  fin_bb = single_succ (cont_bb);
+  gcc_assert (EDGE_COUNT (iter_part_bb->succs) == 2);
+  gcc_assert (BRANCH_EDGE (iter_part_bb)->dest
+             == FALLTHRU_EDGE (cont_bb)->dest);
+  seq_start_bb = split_edge (FALLTHRU_EDGE (iter_part_bb));
+  body_bb = single_succ (seq_start_bb);
+  gcc_assert (BRANCH_EDGE (cont_bb)->dest == body_bb);
+  gcc_assert (EDGE_COUNT (cont_bb->succs) == 2);
+  fin_bb = FALLTHRU_EDGE (cont_bb)->dest;
+  trip_update_bb = split_edge (FALLTHRU_EDGE (cont_bb));
   exit_bb = region->exit;
 
   /* Trip and adjustment setup goes in ENTRY_BB.  */
@@ -3057,19 +3069,13 @@ expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
   bsi_remove (&si, true);
 
   /* Connect the new blocks.  */
-  remove_edge (single_succ_edge (entry_bb));
-  make_edge (entry_bb, iter_part_bb, EDGE_FALLTHRU);
-
-  make_edge (iter_part_bb, seq_start_bb, EDGE_TRUE_VALUE);
-  make_edge (iter_part_bb, fin_bb, EDGE_FALSE_VALUE);
-
-  make_edge (seq_start_bb, body_bb, EDGE_FALLTHRU);
-
-  remove_edge (single_succ_edge (cont_bb));
-  make_edge (cont_bb, body_bb, EDGE_TRUE_VALUE);
-  make_edge (cont_bb, trip_update_bb, EDGE_FALSE_VALUE);
-
-  make_edge (trip_update_bb, iter_part_bb, EDGE_FALLTHRU);
+  find_edge (iter_part_bb, seq_start_bb)->flags = EDGE_TRUE_VALUE;
+  find_edge (iter_part_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
+  
+  find_edge (cont_bb, body_bb)->flags = EDGE_TRUE_VALUE;
+  find_edge (cont_bb, trip_update_bb)->flags = EDGE_FALSE_VALUE;
+  
+  redirect_edge_and_branch (single_succ_edge (trip_update_bb), iter_part_bb);
 }
 
 
@@ -3087,8 +3093,7 @@ expand_omp_for (struct omp_region *region)
 
   if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
       && !fd.have_ordered
-      && region->cont
-      && region->exit)
+      && region->cont != NULL)
     {
       if (fd.chunk_size == NULL)
        expand_omp_for_static_nochunk (region, &fd);
@@ -3137,55 +3142,50 @@ expand_omp_for (struct omp_region *region)
 static void
 expand_omp_sections (struct omp_region *region)
 {
-  tree label_vec, l0, l1, l2, t, u, v, sections_stmt;
-  unsigned i, len;
-  basic_block entry_bb, exit_bb, l0_bb, l1_bb, l2_bb, default_bb;
+  tree label_vec, l1, l2, t, u, v, sections_stmt;
+  unsigned i, casei, len;
+  basic_block entry_bb, l0_bb, l1_bb, l2_bb, default_bb;
   block_stmt_iterator si;
   struct omp_region *inner;
-  edge e;
+  bool exit_reachable = region->cont != NULL;
 
+  gcc_assert (exit_reachable == (region->exit != NULL));
   entry_bb = region->entry;
-  l0_bb = create_empty_bb (entry_bb);
-  l0 = tree_block_label (l0_bb);
-
-  gcc_assert ((region->cont != NULL) ^ (region->exit == NULL));
+  l0_bb = single_succ (entry_bb);
   l1_bb = region->cont;
-  if (l1_bb)
+  l2_bb = region->exit;
+  if (exit_reachable)
     {
-      l2_bb = single_succ (l1_bb);
+      gcc_assert (single_pred (l2_bb) == l0_bb);
       default_bb = create_empty_bb (l1_bb->prev_bb);
-
       l1 = tree_block_label (l1_bb);
+      l2 = tree_block_label (l2_bb);
     }
   else
     {
-      l2_bb = create_empty_bb (l0_bb);
-      default_bb = l2_bb;
-
-      l1 = NULL;
+      default_bb = create_empty_bb (l0_bb);
+      l1 = NULL_TREE;
+      l2 = tree_block_label (default_bb);
     }
-  l2 = tree_block_label (l2_bb);
-
-  exit_bb = region->exit;
-
-  v = create_tmp_var (unsigned_type_node, ".section");
 
   /* We will build a switch() with enough cases for all the
      OMP_SECTION regions, a '0' case to handle the end of more work
      and a default case to abort if something goes wrong.  */
-  len = EDGE_COUNT (entry_bb->succs);
-  label_vec = make_tree_vec (len + 2);
+  len = EDGE_COUNT (l0_bb->succs);
+  label_vec = make_tree_vec (len + 1);
 
   /* The call to GOMP_sections_start goes in ENTRY_BB, replacing the
      OMP_SECTIONS statement.  */
   si = bsi_last (entry_bb);
   sections_stmt = bsi_stmt (si);
   gcc_assert (TREE_CODE (sections_stmt) == OMP_SECTIONS);
+  v = OMP_SECTIONS_CONTROL (sections_stmt);
   if (!is_combined_parallel (region))
     {
       /* If we are not inside a combined parallel+sections region,
         call GOMP_sections_start.  */
-      t = build_int_cst (unsigned_type_node, len);
+      t = build_int_cst (unsigned_type_node,
+                        exit_reachable ? len - 1 : len);
       u = built_in_decls[BUILT_IN_GOMP_SECTIONS_START];
       t = build_call_expr (u, 1, t);
       t = build_gimple_modify_stmt (v, t);
@@ -3193,19 +3193,27 @@ expand_omp_sections (struct omp_region *region)
     }
   bsi_remove (&si, true);
 
-  /* The switch() statement replacing OMP_SECTIONS goes in L0_BB.  */
-  si = bsi_start (l0_bb);
+  /* The switch() statement replacing OMP_SECTIONS_SWITCH goes in L0_BB.  */
+  si = bsi_last (l0_bb);
+  gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_SECTIONS_SWITCH);
 
   t = build3 (SWITCH_EXPR, void_type_node, v, NULL, label_vec);
-  bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
+  bsi_insert_after (&si, t, BSI_SAME_STMT);
+  bsi_remove (&si, true);
 
-  t = build3 (CASE_LABEL_EXPR, void_type_node,
-             build_int_cst (unsigned_type_node, 0), NULL, l2);
-  TREE_VEC_ELT (label_vec, 0) = t;
-  make_edge (l0_bb, l2_bb, 0);
+  i = 0;
+  if (exit_reachable)
+    {
+      t = build3 (CASE_LABEL_EXPR, void_type_node,
+                 build_int_cst (unsigned_type_node, 0), NULL, l2);
+      TREE_VEC_ELT (label_vec, 0) = t;
+      i++;
+    }
 
   /* Convert each OMP_SECTION into a CASE_LABEL_EXPR.  */
-  for (inner = region->inner, i = 1; inner; inner = inner->next, ++i)
+  for (inner = region->inner, casei = 1;
+       inner;
+       inner = inner->next, i++, casei++)
     {
       basic_block s_entry_bb, s_exit_bb;
 
@@ -3213,7 +3221,7 @@ expand_omp_sections (struct omp_region *region)
       s_exit_bb = inner->exit;
 
       t = tree_block_label (s_entry_bb);
-      u = build_int_cst (unsigned_type_node, i);
+      u = build_int_cst (unsigned_type_node, casei);
       u = build3 (CASE_LABEL_EXPR, void_type_node, u, NULL, t);
       TREE_VEC_ELT (label_vec, i) = u;
 
@@ -3221,11 +3229,6 @@ expand_omp_sections (struct omp_region *region)
       gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_SECTION);
       gcc_assert (i < len || OMP_SECTION_LAST (bsi_stmt (si)));
       bsi_remove (&si, true);
-
-      e = single_pred_edge (s_entry_bb);
-      e->flags = 0;
-      redirect_edge_pred (e, l0_bb);
-
       single_succ_edge (s_entry_bb)->flags = EDGE_FALLTHRU;
 
       if (s_exit_bb == NULL)
@@ -3241,16 +3244,16 @@ expand_omp_sections (struct omp_region *region)
   /* Error handling code goes in DEFAULT_BB.  */
   t = tree_block_label (default_bb);
   u = build3 (CASE_LABEL_EXPR, void_type_node, NULL, NULL, t);
-  TREE_VEC_ELT (label_vec, len + 1) = u;
+  TREE_VEC_ELT (label_vec, len) = u;
   make_edge (l0_bb, default_bb, 0);
 
   si = bsi_start (default_bb);
   t = build_call_expr (built_in_decls[BUILT_IN_TRAP], 0);
   bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
 
-  /* Code to get the next section goes in L1_BB.  */
-  if (l1_bb)
+  if (exit_reachable)
     {
+      /* Code to get the next section goes in L1_BB.  */
       si = bsi_last (l1_bb);
       gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
 
@@ -3258,12 +3261,11 @@ expand_omp_sections (struct omp_region *region)
       t = build_gimple_modify_stmt (v, t);
       bsi_insert_after (&si, t, BSI_SAME_STMT);
       bsi_remove (&si, true);
-    }
 
-  /* Cleanup function replaces OMP_RETURN in EXIT_BB.  */
-  if (exit_bb)
-    {
-      si = bsi_last (exit_bb);
+      single_succ_edge (l1_bb)->flags = EDGE_FALLTHRU;
+
+      /* Cleanup function replaces OMP_RETURN in EXIT_BB.  */
+      si = bsi_last (l2_bb);
       if (OMP_RETURN_NOWAIT (bsi_stmt (si)))
        t = built_in_decls[BUILT_IN_GOMP_SECTIONS_END_NOWAIT];
       else
@@ -3279,16 +3281,8 @@ expand_omp_sections (struct omp_region *region)
       /* If this was a combined parallel+sections region, we did not
         emit a GOMP_sections_start in the entry block, so we just
         need to jump to L1_BB to get the next section.  */
-      make_edge (entry_bb, l1_bb, EDGE_FALLTHRU);
-    }
-  else
-    make_edge (entry_bb, l0_bb, EDGE_FALLTHRU);
-
-  if (l1_bb)
-    {
-      e = single_succ_edge (l1_bb);
-      redirect_edge_succ (e, l0_bb);
-      e->flags = EDGE_FALLTHRU;
+      gcc_assert (exit_reachable);
+      redirect_edge_and_branch (single_succ_edge (entry_bb), l1_bb);
     }
 }
 
@@ -3451,6 +3445,11 @@ build_omp_regions_1 (basic_block bb, struct omp_region *parent)
          gcc_assert (parent);
          parent->cont = bb;
        }
+      else if (code == OMP_SECTIONS_SWITCH)
+       {
+         /* OMP_SECTIONS_SWITCH is part of OMP_SECTIONS, and we do nothing for
+            it.  */
+       }
       else
        {
          /* Otherwise, this directive becomes the parent for a new
@@ -3539,7 +3538,7 @@ struct tree_opt_pass pass_expand_omp =
 static void
 lower_omp_sections (tree *stmt_p, omp_context *ctx)
 {
-  tree new_stmt, stmt, body, bind, block, ilist, olist, new_body;
+  tree new_stmt, stmt, body, bind, block, ilist, olist, new_body, control;
   tree t, dlist;
   tree_stmt_iterator tsi;
   unsigned i, len;
@@ -3601,9 +3600,12 @@ lower_omp_sections (tree *stmt_p, omp_context *ctx)
   new_body = alloc_stmt_list ();
   append_to_statement_list (ilist, &new_body);
   append_to_statement_list (stmt, &new_body);
+  append_to_statement_list (make_node (OMP_SECTIONS_SWITCH), &new_body);
   append_to_statement_list (bind, &new_body);
 
-  t = make_node (OMP_CONTINUE);
+  control = create_tmp_var (unsigned_type_node, ".section");
+  t = build2 (OMP_CONTINUE, void_type_node, control, control);
+  OMP_SECTIONS_CONTROL (stmt) = control;
   append_to_statement_list (t, &new_body);
 
   append_to_statement_list (olist, &new_body);
@@ -4040,7 +4042,7 @@ lower_omp_for (tree *stmt_p, omp_context *ctx)
 
   append_to_statement_list (OMP_FOR_BODY (stmt), body_p);
 
-  t = make_node (OMP_CONTINUE);
+  t = build2 (OMP_CONTINUE, void_type_node, fd.v, fd.v);
   append_to_statement_list (t, body_p);
 
   /* After the loop, add exit clauses.  */
index c24b1c69524fbc7c8575f0bf8d42b9ad58bdc086..f124c9a436fd05e7acf27bfd615b2c69a847f608 100644 (file)
@@ -517,6 +517,10 @@ make_edges (void)
 
            case OMP_SECTIONS:
              cur_region = new_omp_region (bb, code, cur_region);
+             fallthru = true;
+             break;
+
+           case OMP_SECTIONS_SWITCH:
              fallthru = false;
              break;
 
@@ -533,31 +537,42 @@ make_edges (void)
              switch (cur_region->type)
                {
                case OMP_FOR:
-                 /* ??? Technically there should be a some sort of loopback
-                    edge here, but it goes to a block that doesn't exist yet,
-                    and without it, updating the ssa form would be a real
-                    bear.  Fortunately, we don't yet do ssa before expanding
-                    these nodes.  */
+                 /* Make the loopback edge.  */
+                 make_edge (bb, single_succ (cur_region->entry), 0);
+             
+                 /* Create an edge from OMP_FOR to exit, which corresponds to
+                    the case that the body of the loop is not executed at
+                    all.  */
+                 make_edge (cur_region->entry, bb->next_bb, 0);
+                 fallthru = true;
                  break;
 
                case OMP_SECTIONS:
                  /* Wire up the edges into and out of the nested sections.  */
-                 /* ??? Similarly wrt loopback.  */
                  {
+                   basic_block switch_bb = single_succ (cur_region->entry);
+
                    struct omp_region *i;
                    for (i = cur_region->inner; i ; i = i->next)
                      {
                        gcc_assert (i->type == OMP_SECTION);
-                       make_edge (cur_region->entry, i->entry, 0);
+                       make_edge (switch_bb, i->entry, 0);
                        make_edge (i->exit, bb, EDGE_FALLTHRU);
                      }
+
+                   /* Make the loopback edge to the block with
+                      OMP_SECTIONS_SWITCH.  */
+                   make_edge (bb, switch_bb, 0);
+
+                   /* Make the edge from the switch to exit.  */
+                   make_edge (switch_bb, bb->next_bb, 0);
+                   fallthru = false;
                  }
                  break;
 
                default:
                  gcc_unreachable ();
                }
-             fallthru = true;
              break;
 
            default:
@@ -4807,6 +4822,13 @@ tree_redirect_edge_and_branch (edge e, basic_block dest)
       e->flags |= EDGE_FALLTHRU;
       break;
 
+    case OMP_RETURN:
+    case OMP_CONTINUE:
+    case OMP_SECTIONS_SWITCH:
+    case OMP_FOR:
+      /* The edges from OMP constructs can be simply redirected.  */
+      break;
+
     default:
       /* Otherwise it must be a fallthru edge, and we don't need to
         do anything besides redirecting it.  */
index c35001c33e7c2978e5a3c0a95e01df74d146d3a3..bd2523bf7e6b72e069cce225d358bd1dd73088f6 100644 (file)
@@ -507,6 +507,36 @@ split_bbs_on_noreturn_calls (void)
   return changed;
 }
 
+/* If OMP_RETURN in basic block BB is unreachable, remove it.  */
+
+static bool
+cleanup_omp_return (basic_block bb)
+{
+  tree stmt = last_stmt (bb);
+  basic_block control_bb;
+
+  if (stmt == NULL_TREE
+      || TREE_CODE (stmt) != OMP_RETURN
+      || !single_pred_p (bb))
+    return false;
+
+  control_bb = single_pred (bb);
+  stmt = last_stmt (control_bb);
+
+  if (TREE_CODE (stmt) != OMP_SECTIONS_SWITCH)
+    return false;
+
+  /* The block with the control statement normally has two entry edges -- one
+     from entry, one from continue.  If continue is removed, return is
+     unreachable, so we remove it here as well.  */
+  if (EDGE_COUNT (control_bb->preds) == 2)
+    return false;
+
+  gcc_assert (EDGE_COUNT (control_bb->preds) == 1);
+  remove_edge_and_dominated_blocks (single_pred_edge (bb));
+  return true;
+}
+
 /* Tries to cleanup cfg in basic block BB.  Returns true if anything
    changes.  */
 
@@ -515,8 +545,11 @@ cleanup_tree_cfg_bb (basic_block bb)
 {
   bool retval = false;
 
-  retval = cleanup_control_flow_bb (bb);
+  if (cleanup_omp_return (bb))
+    return true;
 
+  retval = cleanup_control_flow_bb (bb);
+  
   /* Forwarder blocks can carry line number information which is
      useful when debugging, so we only clean them up when
      optimizing.  */
index 181b16f58de89149f9ed7e10d190d309146c0587..e9753ebeecbd58685c10c35ce87fb5c8a0f040d5 100644 (file)
@@ -230,6 +230,7 @@ is_gimple_stmt (tree t)
     case OMP_PARALLEL:
     case OMP_FOR:
     case OMP_SECTIONS:
+    case OMP_SECTIONS_SWITCH:
     case OMP_SECTION:
     case OMP_SINGLE:
     case OMP_MASTER:
index 33b369dfe4c71b763486de44f140c8097d6c1bb7..af0c7d40667366364ee9c313691c959fdf836b30 100644 (file)
@@ -2010,6 +2010,7 @@ estimate_num_insns_1 (tree *tp, int *walk_subtrees, void *data)
     case OMP_CLAUSE:
     case OMP_RETURN:
     case OMP_CONTINUE:
+    case OMP_SECTIONS_SWITCH:
       break;
 
     /* We don't account constants for now.  Assume that the cost is amortized
index 77ecb95385dcb4ab88251535c5a6f7b58d067fe8..bd71a7df0e9b33b5d9b3beabafbc4a4947f9ef8b 100644 (file)
@@ -1851,9 +1851,21 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
 
     case OMP_SECTIONS:
       pp_string (buffer, "#pragma omp sections");
+      if (OMP_SECTIONS_CONTROL (node))
+       {
+         pp_string (buffer, " <");
+         dump_generic_node (buffer, OMP_SECTIONS_CONTROL (node), spc,
+                            flags, false);
+         pp_string (buffer, ">");
+       }
       dump_omp_clauses (buffer, OMP_SECTIONS_CLAUSES (node), spc, flags);
       goto dump_omp_body;
 
+    case OMP_SECTIONS_SWITCH:
+      pp_string (buffer, "OMP_SECTIONS_SWITCH");
+      is_expr = false;
+      break;
     case OMP_SECTION:
       pp_string (buffer, "#pragma omp section");
       goto dump_omp_body;
@@ -1901,7 +1913,11 @@ dump_generic_node (pretty_printer *buffer, tree node, int spc, int flags,
       break;
 
     case OMP_CONTINUE:
-      pp_string (buffer, "OMP_CONTINUE");
+      pp_string (buffer, "OMP_CONTINUE <");
+      dump_generic_node (buffer, TREE_OPERAND (node, 0), spc, flags, false);
+      pp_string (buffer, " <- ");
+      dump_generic_node (buffer, TREE_OPERAND (node, 1), spc, flags, false);
+      pp_string (buffer, ">");
       is_expr = false;
       break;
 
index aa95cb1db316c705546a7efa0d64148c02ec7d5c..72c6d246b4f3959d228f60a2ac862ddf19626b8e 100644 (file)
@@ -999,8 +999,14 @@ DEFTREECODE (OMP_FOR, "omp_for", tcc_statement, 6)
 
 /* OpenMP - #pragma omp sections [clause1 ... clauseN]
    Operand 0: OMP_SECTIONS_BODY: Sections body.
-   Operand 1: OMP_SECTIONS_CLAUSES: List of clauses.  */
-DEFTREECODE (OMP_SECTIONS, "omp_sections", tcc_statement, 2)
+   Operand 1: OMP_SECTIONS_CLAUSES: List of clauses.
+   Operand 2: OMP_SECTIONS_CONTROL: The control variable used for deciding
+             which of the sections to execute.  */
+DEFTREECODE (OMP_SECTIONS, "omp_sections", tcc_statement, 3)
+
+/* This tree immediatelly follows OMP_SECTIONS, and represents the switch
+   used to decide which branch is taken.  */
+DEFTREECODE (OMP_SECTIONS_SWITCH, "omp_sections_switch", tcc_statement, 0)
 
 /* OpenMP - #pragma omp single
    Operand 0: OMP_SINGLE_BODY: Single section body.
@@ -1028,8 +1034,9 @@ DEFTREECODE (OMP_CRITICAL, "omp_critical", tcc_statement, 2)
 DEFTREECODE (OMP_RETURN, "omp_return", tcc_statement, 0)
 
 /* OpenMP - An intermediate tree code to mark the location of the
-   loop or sections iteration in the partially lowered code.  */
-DEFTREECODE (OMP_CONTINUE, "omp_continue", tcc_statement, 0)
+   loop or sections iteration in the partially lowered code.
+   The arguments are definition and use of the control variable.  */
+DEFTREECODE (OMP_CONTINUE, "omp_continue", tcc_statement, 2)
 
 /* OpenMP - #pragma omp atomic
    Operand 0: The address at which the atomic operation is to be performed.
index 946898232343dfbf8fb65b7208f947f01b1d3d70..f955b87629bbe7359e85ab26f5f271e74f6a8dae 100644 (file)
@@ -187,6 +187,7 @@ extern const enum tree_code_class tree_code_type[];
     (TREE_CODE (NODE) == OMP_PARALLEL                  \
      || TREE_CODE (NODE) == OMP_FOR                    \
      || TREE_CODE (NODE) == OMP_SECTIONS               \
+     || TREE_CODE (NODE) == OMP_SECTIONS_SWITCH                \
      || TREE_CODE (NODE) == OMP_SINGLE                 \
      || TREE_CODE (NODE) == OMP_SECTION                        \
      || TREE_CODE (NODE) == OMP_MASTER                 \
@@ -1695,6 +1696,7 @@ struct tree_constructor GTY(())
 
 #define OMP_SECTIONS_BODY(NODE)    TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 0)
 #define OMP_SECTIONS_CLAUSES(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 1)
+#define OMP_SECTIONS_CONTROL(NODE) TREE_OPERAND (OMP_SECTIONS_CHECK (NODE), 2)
 
 #define OMP_SECTION_BODY(NODE)    TREE_OPERAND (OMP_SECTION_CHECK (NODE), 0)