This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] More precise cfg for omp constructs


Hello,

this patch makes CFG for omp constructs match more precisely the CFG
after their expansion, in particular, back edges are added from
OMP_CONTINUE.  Also, OMP_SECTIONS_SWITCH tree (that corresponds to the
switch in sections expansion) is added, in order to create a basic block
to that the back-edge from the corresponding OMP_CONTINUE can lead.
The expanders are modified to reflect this.

The change is needed in order to make SSA form updating possible,
and thus make it possible to use omp expansion in the loop
parallelization pass.

OMP_CONTROL and OMP_SECTIONS are also added new operands (that reference
the control variables that are changed by them); this is also needed for
SSA form updating.  This change could go in a separate patch, but
including it here makes it somewhat simpler to merge the expander
changes.

Bootstrapped & regtested on i686.

Zdenek

	* 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.

Index: tree-pretty-print.c
===================================================================
*** tree-pretty-print.c	(revision 126547)
--- tree-pretty-print.c	(working copy)
*************** dump_generic_node (pretty_printer *buffe
*** 1852,1860 ****
--- 1852,1872 ----
  
      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;
*************** dump_generic_node (pretty_printer *buffe
*** 1902,1908 ****
        break;
  
      case OMP_CONTINUE:
!       pp_string (buffer, "OMP_CONTINUE");
        is_expr = false;
        break;
  
--- 1914,1924 ----
        break;
  
      case 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: tree.h
===================================================================
*** tree.h	(revision 126547)
--- tree.h	(working copy)
*************** extern const enum tree_code_class tree_c
*** 188,193 ****
--- 188,194 ----
      (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			\
*************** struct tree_constructor GTY(())
*** 1696,1701 ****
--- 1697,1703 ----
  
  #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)
  
Index: omp-low.c
===================================================================
*** omp-low.c	(revision 126547)
--- omp-low.c	(working copy)
*************** get_ws_args_for (tree ws_stmt)
*** 348,355 ****
      }
    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));
        t = tree_cons (NULL, t, NULL);
        return t;
      }
--- 348,358 ----
      }
    else if (TREE_CODE (ws_stmt) == OMP_SECTIONS)
      {
!       /* 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;
      }
*************** determine_parallel_type (struct omp_regi
*** 367,373 ****
    basic_block ws_entry_bb, ws_exit_bb;
  
    if (region == NULL || region->inner == NULL
!       || region->exit == NULL || region->inner->exit == NULL)
      return;
  
    /* We only support parallel+for and parallel+sections.  */
--- 370,377 ----
    basic_block ws_entry_bb, ws_exit_bb;
  
    if (region == NULL || region->inner == NULL
!       || region->exit == NULL || region->inner->exit == NULL
!       || region->inner->cont == NULL)
      return;
  
    /* We only support parallel+for and parallel+sections.  */
*************** expand_omp_parallel (struct omp_region *
*** 2567,2573 ****
      L3:
  
      If this is a combined omp parallel loop, instead of the call to
!     GOMP_loop_foo_start, we emit 'goto L3'.  */
  
  static void
  expand_omp_for_generic (struct omp_region *region,
--- 2571,2577 ----
      L3:
  
      If this is a combined omp parallel loop, instead of the call to
!     GOMP_loop_foo_start, we emit 'goto L2'.  */
  
  static void
  expand_omp_for_generic (struct omp_region *region,
*************** expand_omp_for_generic (struct omp_regio
*** 2581,2586 ****
--- 2585,2593 ----
    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);
  
*************** expand_omp_for_generic (struct omp_regio
*** 2590,2608 ****
    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)
      {
        l2_bb = create_empty_bb (cont_bb);
!       l3_bb = single_succ (cont_bb);
      }
  
    si = bsi_last (entry_bb);
    gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
--- 2597,2619 ----
    TREE_ADDRESSABLE (istart0) = 1;
    TREE_ADDRESSABLE (iend0) = 1;
  
    entry_bb = region->entry;
    cont_bb = region->cont;
!   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);
!       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);
*************** expand_omp_for_generic (struct omp_regio
*** 2627,2637 ****
  	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);
! 	}
        bsi_insert_after (&si, list, BSI_SAME_STMT);
      }
    bsi_remove (&si, true);
--- 2638,2645 ----
  	t = build_call_expr (built_in_decls[start_fn], 5,
  			     t0, t1, t2, t3, t4);
        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);
        bsi_insert_after (&si, list, BSI_SAME_STMT);
      }
    bsi_remove (&si, true);
*************** expand_omp_for_generic (struct omp_regio
*** 2649,2695 ****
    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)
      {
!       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 ();
  
!   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);
  
!   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 ();
  
!   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);
  
    /* Add the loop cleanup function.  */
    si = bsi_last (exit_bb);
--- 2657,2695 ----
    si = bsi_start (l0_bb);
    bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
  
!   if (!broken_loop)
      {
!       /* 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 (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);
  
!       /* 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);
    
!       si = bsi_start (l2_bb);
!       bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
!     }
  
    /* Add the loop cleanup function.  */
    si = bsi_last (exit_bb);
*************** expand_omp_for_generic (struct omp_regio
*** 2702,2724 ****
    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);
    else
      {
!       make_edge (entry_bb, l0_bb, EDGE_TRUE_VALUE);
!       make_edge (entry_bb, l3_bb, 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);
  
!   make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
!   make_edge (l2_bb, l3_bb, EDGE_FALSE_VALUE);
  }
  
  
--- 2702,2727 ----
    bsi_remove (&si, true);
  
    /* Connect the new blocks.  */
    if (in_combined_parallel)
!     {
!       remove_edge (BRANCH_EDGE (entry_bb));
!       redirect_edge_and_branch (single_succ_edge (entry_bb), l2_bb);
!     }
    else
      {
!       find_edge (entry_bb, l0_bb)->flags = EDGE_TRUE_VALUE;
!       find_edge (entry_bb, l3_bb)->flags = 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);
!     }
  }
  
  
*************** expand_omp_for_static_nochunk (struct om
*** 2763,2772 ****
    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);
    exit_bb = region->exit;
  
    /* Iteration space partitioning goes in ENTRY_BB.  */
--- 2766,2779 ----
    type = TREE_TYPE (fd->v);
  
    entry_bb = region->entry;
    cont_bb = region->cont;
!   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.  */
*************** expand_omp_for_static_nochunk (struct om
*** 2872,2884 ****
    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 (cont_bb, fin_bb)->flags = EDGE_FALSE_VALUE;
  }
  
--- 2879,2888 ----
    bsi_remove (&si, true);
  
    /* Connect all the blocks.  */
!   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;
  }
  
*************** expand_omp_for_static_chunk (struct omp_
*** 2924,2939 ****
    basic_block trip_update_bb, cont_bb, fin_bb;
    tree list;
    block_stmt_iterator si;
  
    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);
    cont_bb = region->cont;
!   trip_update_bb = create_empty_bb (cont_bb);
!   fin_bb = single_succ (cont_bb);
    exit_bb = region->exit;
  
    /* Trip and adjustment setup goes in ENTRY_BB.  */
--- 2928,2951 ----
    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;
!   se = split_block (entry_bb, last_stmt (entry_bb));
!   entry_bb = se->src;
!   iter_part_bb = se->dest;
    cont_bb = region->cont;
!   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.  */
*************** expand_omp_for_static_chunk (struct omp_
*** 3058,3076 ****
    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);
  }
  
  
--- 3070,3082 ----
    bsi_remove (&si, true);
  
    /* Connect the new blocks.  */
!   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);
  }
  
  
*************** expand_omp_for (struct omp_region *regio
*** 3088,3095 ****
  
    if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
        && !fd.have_ordered
!       && region->cont
!       && region->exit)
      {
        if (fd.chunk_size == NULL)
  	expand_omp_for_static_nochunk (region, &fd);
--- 3094,3100 ----
  
    if (fd.sched_kind == OMP_CLAUSE_SCHEDULE_STATIC
        && !fd.have_ordered
!       && region->cont != NULL)
      {
        if (fd.chunk_size == NULL)
  	expand_omp_for_static_nochunk (region, &fd);
*************** expand_omp_for (struct omp_region *regio
*** 3138,3192 ****
  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;
    block_stmt_iterator si;
    struct omp_region *inner;
!   edge e;
  
    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));
    l1_bb = region->cont;
!   if (l1_bb)
      {
!       l2_bb = single_succ (l1_bb);
        default_bb = create_empty_bb (l1_bb->prev_bb);
- 
        l1 = tree_block_label (l1_bb);
      }
    else
      {
!       l2_bb = create_empty_bb (l0_bb);
!       default_bb = l2_bb;
! 
!       l1 = NULL;
      }
-   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);
  
    /* 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);
    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);
        u = built_in_decls[BUILT_IN_GOMP_SECTIONS_START];
        t = build_call_expr (u, 1, t);
        t = build_gimple_modify_stmt (v, t);
--- 3143,3192 ----
  static void
  expand_omp_sections (struct omp_region *region)
  {
!   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;
!   bool exit_reachable = region->cont != NULL;
  
+   gcc_assert (exit_reachable == (region->exit != NULL));
    entry_bb = region->entry;
!   l0_bb = single_succ (entry_bb);
    l1_bb = region->cont;
!   l2_bb = region->exit;
!   if (exit_reachable)
      {
!       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
      {
!       default_bb = create_empty_bb (l0_bb);
!       l1 = NULL_TREE;
!       l2 = tree_block_label (default_bb);
      }
  
    /* 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 (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,
! 			 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);
*************** expand_omp_sections (struct omp_region *
*** 3194,3212 ****
      }
    bsi_remove (&si, true);
  
!   /* The switch() statement replacing OMP_SECTIONS goes in L0_BB.  */
!   si = bsi_start (l0_bb);
  
    t = build3 (SWITCH_EXPR, void_type_node, v, NULL, label_vec);
!   bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
  
!   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);
  
    /* Convert each OMP_SECTION into a CASE_LABEL_EXPR.  */
!   for (inner = region->inner, i = 1; inner; inner = inner->next, ++i)
      {
        basic_block s_entry_bb, s_exit_bb;
  
--- 3194,3220 ----
      }
    bsi_remove (&si, true);
  
!   /* 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_SAME_STMT);
!   bsi_remove (&si, true);
  
!   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, casei = 1;
!        inner;
!        inner = inner->next, i++, casei++)
      {
        basic_block s_entry_bb, s_exit_bb;
  
*************** expand_omp_sections (struct omp_region *
*** 3214,3220 ****
        s_exit_bb = inner->exit;
  
        t = tree_block_label (s_entry_bb);
!       u = build_int_cst (unsigned_type_node, i);
        u = build3 (CASE_LABEL_EXPR, void_type_node, u, NULL, t);
        TREE_VEC_ELT (label_vec, i) = u;
  
--- 3222,3228 ----
        s_exit_bb = inner->exit;
  
        t = tree_block_label (s_entry_bb);
!       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;
  
*************** expand_omp_sections (struct omp_region *
*** 3222,3232 ****
        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)
--- 3230,3235 ----
*************** expand_omp_sections (struct omp_region *
*** 3242,3257 ****
    /* 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;
    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)
      {
        si = bsi_last (l1_bb);
        gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
  
--- 3245,3260 ----
    /* 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) = 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);
  
!   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);
  
*************** expand_omp_sections (struct omp_region *
*** 3259,3270 ****
        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);
        if (OMP_RETURN_NOWAIT (bsi_stmt (si)))
  	t = built_in_decls[BUILT_IN_GOMP_SECTIONS_END_NOWAIT];
        else
--- 3262,3272 ----
        t = build_gimple_modify_stmt (v, t);
        bsi_insert_after (&si, t, BSI_SAME_STMT);
        bsi_remove (&si, true);
  
!       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
*************** expand_omp_sections (struct omp_region *
*** 3280,3295 ****
        /* 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;
      }
  }
  
--- 3282,3289 ----
        /* 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.  */
!       gcc_assert (exit_reachable);
!       redirect_edge_and_branch (single_succ_edge (entry_bb), l1_bb);
      }
  }
  
*************** build_omp_regions_1 (basic_block bb, str
*** 3452,3457 ****
--- 3446,3456 ----
  	  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
*************** struct tree_opt_pass pass_expand_omp = 
*** 3540,3546 ****
  static void
  lower_omp_sections (tree *stmt_p, omp_context *ctx)
  {
!   tree new_stmt, stmt, body, bind, block, ilist, olist, new_body;
    tree t, dlist;
    tree_stmt_iterator tsi;
    unsigned i, len;
--- 3539,3545 ----
  static void
  lower_omp_sections (tree *stmt_p, omp_context *ctx)
  {
!   tree new_stmt, stmt, body, bind, block, ilist, olist, new_body, control;
    tree t, dlist;
    tree_stmt_iterator tsi;
    unsigned i, len;
*************** lower_omp_sections (tree *stmt_p, omp_co
*** 3602,3610 ****
    new_body = alloc_stmt_list ();
    append_to_statement_list (ilist, &new_body);
    append_to_statement_list (stmt, &new_body);
    append_to_statement_list (bind, &new_body);
  
!   t = make_node (OMP_CONTINUE);
    append_to_statement_list (t, &new_body);
  
    append_to_statement_list (olist, &new_body);
--- 3601,3612 ----
    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);
  
!   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);
*************** lower_omp_for (tree *stmt_p, omp_context
*** 4041,4047 ****
  
    append_to_statement_list (OMP_FOR_BODY (stmt), body_p);
  
!   t = make_node (OMP_CONTINUE);
    append_to_statement_list (t, body_p);
  
    /* After the loop, add exit clauses.  */
--- 4043,4049 ----
  
    append_to_statement_list (OMP_FOR_BODY (stmt), body_p);
  
!   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: tree-gimple.c
===================================================================
*** tree-gimple.c	(revision 126547)
--- tree-gimple.c	(working copy)
*************** is_gimple_stmt (tree t)
*** 231,236 ****
--- 231,237 ----
      case OMP_PARALLEL:
      case OMP_FOR:
      case OMP_SECTIONS:
+     case OMP_SECTIONS_SWITCH:
      case OMP_SECTION:
      case OMP_SINGLE:
      case OMP_MASTER:
Index: gimple-low.c
===================================================================
*** gimple-low.c	(revision 126547)
--- gimple-low.c	(working copy)
*************** lower_stmt (tree_stmt_iterator *tsi, str
*** 245,250 ****
--- 245,251 ----
      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: fortran/trans-openmp.c
===================================================================
*** fortran/trans-openmp.c	(revision 126547)
--- fortran/trans-openmp.c	(working copy)
*************** gfc_trans_omp_sections (gfc_code *code, 
*** 1202,1208 ****
      }
    stmt = gfc_finish_block (&body);
  
!   stmt = build2_v (OMP_SECTIONS, stmt, omp_clauses);
    gfc_add_expr_to_block (&block, stmt);
  
    return gfc_finish_block (&block);
--- 1202,1208 ----
      }
    stmt = gfc_finish_block (&body);
  
!   stmt = build3_v (OMP_SECTIONS, stmt, omp_clauses, NULL_TREE);
    gfc_add_expr_to_block (&block, stmt);
  
    return gfc_finish_block (&block);
Index: tree.def
===================================================================
*** tree.def	(revision 126547)
--- tree.def	(working copy)
*************** DEFTREECODE (OMP_FOR, "omp_for", tcc_sta
*** 999,1006 ****
  
  /* 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)
  
  /* OpenMP - #pragma omp single
     Operand 0: OMP_SINGLE_BODY: Single section body.
--- 999,1012 ----
  
  /* OpenMP - #pragma omp sections [clause1 ... clauseN]
     Operand 0: OMP_SECTIONS_BODY: Sections body.
!    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.
*************** DEFTREECODE (OMP_CRITICAL, "omp_critical
*** 1028,1035 ****
  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)
  
  /* OpenMP - #pragma omp atomic
     Operand 0: The address at which the atomic operation is to be performed.
--- 1034,1042 ----
  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.
!    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: tree-cfgcleanup.c
===================================================================
*** tree-cfgcleanup.c	(revision 126547)
--- tree-cfgcleanup.c	(working copy)
*************** split_bbs_on_noreturn_calls (void)
*** 508,513 ****
--- 508,543 ----
    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.  */
  
*************** cleanup_tree_cfg_bb (basic_block bb)
*** 516,523 ****
  {
    bool retval = false;
  
!   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.  */
--- 546,556 ----
  {
    bool retval = false;
  
!   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: tree-inline.c
===================================================================
*** tree-inline.c	(revision 126547)
--- tree-inline.c	(working copy)
*************** estimate_num_insns_1 (tree *tp, int *wal
*** 2011,2016 ****
--- 2011,2017 ----
      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: tree-cfg.c
===================================================================
*** tree-cfg.c	(revision 126547)
--- tree-cfg.c	(working copy)
*************** make_edges (void)
*** 518,523 ****
--- 518,527 ----
  
  	    case OMP_SECTIONS:
  	      cur_region = new_omp_region (bb, code, cur_region);
+ 	      fallthru = true;
+ 	      break;
+ 
+ 	    case OMP_SECTIONS_SWITCH:
  	      fallthru = false;
  	      break;
  
*************** make_edges (void)
*** 534,564 ****
  	      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.  */
  		  break;
  
  		case OMP_SECTIONS:
  		  /* Wire up the edges into and out of the nested sections.  */
- 		  /* ??? Similarly wrt loopback.  */
  		  {
  		    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 (i->exit, bb, EDGE_FALLTHRU);
  		      }
  		  }
  		  break;
  
  		default:
  		  gcc_unreachable ();
  		}
- 	      fallthru = true;
  	      break;
  
  	    default:
--- 538,579 ----
  	      switch (cur_region->type)
  		{
  		case OMP_FOR:
! 		  /* 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.  */
  		  {
+ 		    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 (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 ();
  		}
  	      break;
  
  	    default:
*************** tree_redirect_edge_and_branch (edge e, b
*** 4103,4108 ****
--- 4118,4130 ----
        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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]