public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [patch] Make OMP expansion work on SSA form
@ 2007-08-20 15:13 Zdenek Dvorak
  2007-08-29 15:20 ` Diego Novillo
  0 siblings, 1 reply; 5+ messages in thread
From: Zdenek Dvorak @ 2007-08-20 15:13 UTC (permalink / raw)
  To: gcc-patches; +Cc: dnovillo

Hello,

this patch makes OMP expanders work on SSA form (and also maintain other
on-side structures present when the code is in SSA form, and dominance
information), so that they can be used from the autoparallelization.
Things are a bit complicated by need to write the code in such a way
that the expanders work both on and without SSA form (since we need to
expand OMP constructs even when we are not optimizing).

Although most of the code comes from parloop branch, some significant
changes were needed (the code on branch rewrites the split functions
out of SSA, but in mainline we now keep the functions in SSA form).
One other change is that on the branch, we do the expansion of OMP
constructs in SSA form when optimizing, so that the SSA form expansion
code is tested; this patch does the expansion always without SSA form
(unless you use newly introduced -fopenmp-ssa switch).  This is forced
by some pass ordering problems (early optimization passes would not be
run on the split functions if the expansion were done on SSA form).

Bootstrapped & regtested on i686.  The c-typeck.c piece is not part of
the patch, but it is necessary to make fortran runtime build on
mainline.

Zdenek

	* cgraphbuild.c (rebuild_cgraph_edges): Export.
	* cgraph.h (rebuild_cgraph_edges): Declare.
	* tree-pass.h (pass_expand_omp_ssa): New.
	* omp-low.c (find_omp_clause): Export.
	(copy_var_decl): Split from omp_copy_decl_2.
	(build_omp_barrier): Return the call to emit instead of emitting
	it directly.
	(lower_rec_input_clauses, expand_omp_single): Gimplify the result of
	build_omp_barrier.
	(extract_omp_for_data, expand_parallel_call, expand_omp_parallel,
	expand_omp_for_generic, expand_omp_for_static_nochunk,
	expand_omp_for_static_chunk, expand_omp_for, expand_omp_sections):
	Adapted to work on SSA form.
	(execute_expand_omp): Do not invalidate dominance information.
	(gate_expand_omp): Do not run with -fopenmp-ssa flag.
	(gate_expand_omp_ssa, pass_expand_omp_ssa): New.
	* gimplify.c (gimplify_omp_for): Ensure that the control variable is
	a gimple_reg.
	(force_gimple_operand): Allow gimplifying code expressions without
	value.
	* tree-predcom.c (mark_virtual_ops_for_renaming): Handle phi nodes.
	* common.opt (fopenmp-ssa): New.
	* tree-inline.c (push_cfun, pop_cfun): Set current_function_decl.
	* tree-flow.h (find_omp_clause, copy_var_decl): Declare.
	* Makefile.in (tree-cfg.o): Add TREE_INLINE_H dependency.
	* tree-cfg.c: Include tree-inline.h.
	(struct move_stmt_d): Replace vars_to_remove by vars_map field.
	(replace_by_duplicate_decl, replace_ssa_name,
	mark_virtual_ops_in_region): New functions.
	(move_stmt_r, move_block_to_fn, move_sese_region_to_fn): Adapted
	to work on SSA form.
	* passes.c (init_optimization_passes): Add pass_expand_omp_ssa pass.
	* tree-ssa-operands.c (get_expr_operands): Handle operands of OMP
	constructs.

Index: cgraphbuild.c
===================================================================
*** cgraphbuild.c	(revision 127626)
--- cgraphbuild.c	(working copy)
*************** record_references_in_initializer (tree d
*** 202,208 ****
  /* Rebuild cgraph edges for current function node.  This needs to be run after
     passes that don't update the cgraph.  */
  
! static unsigned int
  rebuild_cgraph_edges (void)
  {
    basic_block bb;
--- 202,208 ----
  /* Rebuild cgraph edges for current function node.  This needs to be run after
     passes that don't update the cgraph.  */
  
! unsigned int
  rebuild_cgraph_edges (void)
  {
    basic_block bb;
Index: cgraph.h
===================================================================
*** cgraph.h	(revision 127626)
--- cgraph.h	(working copy)
*************** struct cgraph_node *save_inline_function
*** 344,349 ****
--- 344,352 ----
  void record_references_in_initializer (tree);
  bool cgraph_process_new_functions (void);
  
+ /* In cgraphbuild.c  */
+ unsigned int rebuild_cgraph_edges (void);
+ 
  /* In ipa.c  */
  bool cgraph_remove_unreachable_nodes (bool, FILE *);
  int cgraph_postorder (struct cgraph_node **);
Index: tree-pass.h
===================================================================
*** tree-pass.h	(revision 127626)
--- tree-pass.h	(working copy)
*************** extern struct tree_opt_pass pass_lower_v
*** 289,294 ****
--- 289,295 ----
  extern struct tree_opt_pass pass_lower_vector_ssa;
  extern struct tree_opt_pass pass_lower_omp;
  extern struct tree_opt_pass pass_expand_omp;
+ extern struct tree_opt_pass pass_expand_omp_ssa;
  extern struct tree_opt_pass pass_object_sizes;
  extern struct tree_opt_pass pass_fold_builtins;
  extern struct tree_opt_pass pass_stdarg;
Index: omp-low.c
===================================================================
*** omp-low.c	(revision 127626)
--- omp-low.c	(working copy)
*************** static tree maybe_lookup_decl_in_outer_c
*** 117,123 ****
  
  /* Find an OpenMP clause of type KIND within CLAUSES.  */
  
! static tree
  find_omp_clause (tree clauses, enum tree_code kind)
  {
    for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses))
--- 117,123 ----
  
  /* Find an OpenMP clause of type KIND within CLAUSES.  */
  
! tree
  find_omp_clause (tree clauses, enum tree_code kind)
  {
    for (; clauses ; clauses = OMP_CLAUSE_CHAIN (clauses))
*************** is_combined_parallel (struct omp_region 
*** 151,157 ****
  static void
  extract_omp_for_data (tree for_stmt, struct omp_for_data *fd)
  {
!   tree t;
  
    fd->for_stmt = for_stmt;
    fd->pre = NULL;
--- 151,157 ----
  static void
  extract_omp_for_data (tree for_stmt, struct omp_for_data *fd)
  {
!   tree t, var;
  
    fd->for_stmt = for_stmt;
    fd->pre = NULL;
*************** extract_omp_for_data (tree for_stmt, str
*** 159,171 ****
    t = OMP_FOR_INIT (for_stmt);
    gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
    fd->v = GIMPLE_STMT_OPERAND (t, 0);
!   gcc_assert (DECL_P (fd->v));
    gcc_assert (TREE_CODE (TREE_TYPE (fd->v)) == INTEGER_TYPE);
    fd->n1 = GIMPLE_STMT_OPERAND (t, 1);
  
    t = OMP_FOR_COND (for_stmt);
    fd->cond_code = TREE_CODE (t);
!   gcc_assert (TREE_OPERAND (t, 0) == fd->v);
    fd->n2 = TREE_OPERAND (t, 1);
    switch (fd->cond_code)
      {
--- 159,172 ----
    t = OMP_FOR_INIT (for_stmt);
    gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
    fd->v = GIMPLE_STMT_OPERAND (t, 0);
!   gcc_assert (SSA_VAR_P (fd->v));
    gcc_assert (TREE_CODE (TREE_TYPE (fd->v)) == INTEGER_TYPE);
+   var = TREE_CODE (fd->v) == SSA_NAME ? SSA_NAME_VAR (fd->v) : fd->v;
    fd->n1 = GIMPLE_STMT_OPERAND (t, 1);
  
    t = OMP_FOR_COND (for_stmt);
    fd->cond_code = TREE_CODE (t);
!   gcc_assert (TREE_OPERAND (t, 0) == var);
    fd->n2 = TREE_OPERAND (t, 1);
    switch (fd->cond_code)
      {
*************** extract_omp_for_data (tree for_stmt, str
*** 188,196 ****
  
    t = OMP_FOR_INCR (fd->for_stmt);
    gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
!   gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == fd->v);
    t = GIMPLE_STMT_OPERAND (t, 1);
!   gcc_assert (TREE_OPERAND (t, 0) == fd->v);
    switch (TREE_CODE (t))
      {
      case PLUS_EXPR:
--- 189,197 ----
  
    t = OMP_FOR_INCR (fd->for_stmt);
    gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
!   gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == var);
    t = GIMPLE_STMT_OPERAND (t, 1);
!   gcc_assert (TREE_OPERAND (t, 0) == var);
    switch (TREE_CODE (t))
      {
      case PLUS_EXPR:
*************** use_pointer_for_field (const_tree decl, 
*** 513,534 ****
    return false;
  }
  
! /* Construct a new automatic decl similar to VAR.  */
  
! static tree
! omp_copy_decl_2 (tree var, tree name, tree type, omp_context *ctx)
  {
    tree copy = build_decl (VAR_DECL, name, type);
  
    TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var);
    DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var);
    DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (var);
    DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var);
    DECL_IGNORED_P (copy) = DECL_IGNORED_P (var);
    TREE_USED (copy) = 1;
-   DECL_CONTEXT (copy) = current_function_decl;
    DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
  
    TREE_CHAIN (copy) = ctx->block_vars;
    ctx->block_vars = copy;
  
--- 514,547 ----
    return false;
  }
  
! /* Create a new VAR_DECL and copy information from VAR to it.  */
  
! tree
! copy_var_decl (tree var, tree name, tree type)
  {
    tree copy = build_decl (VAR_DECL, name, type);
  
    TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (var);
+   TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (var);
    DECL_GIMPLE_REG_P (copy) = DECL_GIMPLE_REG_P (var);
    DECL_NO_TBAA_P (copy) = DECL_NO_TBAA_P (var);
    DECL_ARTIFICIAL (copy) = DECL_ARTIFICIAL (var);
    DECL_IGNORED_P (copy) = DECL_IGNORED_P (var);
+   DECL_CONTEXT (copy) = DECL_CONTEXT (var);
    TREE_USED (copy) = 1;
    DECL_SEEN_IN_BIND_EXPR_P (copy) = 1;
  
+   return copy;
+ }
+ 
+ /* Construct a new automatic decl similar to VAR.  */
+ 
+ static tree
+ omp_copy_decl_2 (tree var, tree name, tree type, omp_context *ctx)
+ {
+   tree copy = copy_var_decl (var, name, type);
+ 
+   DECL_CONTEXT (copy) = current_function_decl;
    TREE_CHAIN (copy) = ctx->block_vars;
    ctx->block_vars = copy;
  
*************** scan_omp (tree *stmt_p, omp_context *ctx
*** 1432,1442 ****
  
  /* Build a call to GOMP_barrier.  */
  
! static void
! build_omp_barrier (tree *stmt_list)
  {
!   tree t = build_call_expr (built_in_decls[BUILT_IN_GOMP_BARRIER], 0);
!   gimplify_and_add (t, stmt_list);
  }
  
  /* If a context was created for STMT when it was scanned, return it.  */
--- 1445,1454 ----
  
  /* Build a call to GOMP_barrier.  */
  
! static tree
! build_omp_barrier (void)
  {
!   return build_call_expr (built_in_decls[BUILT_IN_GOMP_BARRIER], 0);
  }
  
  /* If a context was created for STMT when it was scanned, return it.  */
*************** lower_rec_input_clauses (tree clauses, t
*** 1829,1835 ****
       lastprivate clauses we need to ensure the lastprivate copying
       happens after firstprivate copying in all threads.  */
    if (copyin_by_ref || lastprivate_firstprivate)
!     build_omp_barrier (ilist);
  }
  
  
--- 1841,1847 ----
       lastprivate clauses we need to ensure the lastprivate copying
       happens after firstprivate copying in all threads.  */
    if (copyin_by_ref || lastprivate_firstprivate)
!     gimplify_and_add (build_omp_barrier (), ilist);
  }
  
  
*************** static void
*** 2153,2164 ****
  expand_parallel_call (struct omp_region *region, basic_block bb,
  		      tree entry_stmt, tree ws_args)
  {
!   tree t, t1, t2, val, cond, c, list, clauses;
    block_stmt_iterator si;
    int start_ix;
  
    clauses = OMP_PARALLEL_CLAUSES (entry_stmt);
-   push_gimplify_context ();
  
    /* Determine what flavor of GOMP_parallel_start we will be
       emitting.  */
--- 2165,2175 ----
  expand_parallel_call (struct omp_region *region, basic_block bb,
  		      tree entry_stmt, tree ws_args)
  {
!   tree t, t1, t2, val, cond, c, clauses;
    block_stmt_iterator si;
    int start_ix;
  
    clauses = OMP_PARALLEL_CLAUSES (entry_stmt);
  
    /* Determine what flavor of GOMP_parallel_start we will be
       emitting.  */
*************** expand_parallel_call (struct omp_region 
*** 2204,2218 ****
        cond = gimple_boolify (cond);
  
        if (integer_zerop (val))
! 	val = build2 (EQ_EXPR, unsigned_type_node, cond,
! 		      build_int_cst (TREE_TYPE (cond), 0));
        else
  	{
  	  basic_block cond_bb, then_bb, else_bb;
! 	  edge e;
! 	  tree t, tmp;
  
- 	  tmp = create_tmp_var (TREE_TYPE (val), NULL);
  	  e = split_block (bb, NULL);
  	  cond_bb = e->src;
  	  bb = e->dest;
--- 2215,2242 ----
        cond = gimple_boolify (cond);
  
        if (integer_zerop (val))
! 	val = fold_build2 (EQ_EXPR, unsigned_type_node, cond,
! 			   build_int_cst (TREE_TYPE (cond), 0));
        else
  	{
  	  basic_block cond_bb, then_bb, else_bb;
! 	  edge e, e_then, e_else;
! 	  tree t, tmp_then, tmp_else, tmp_join, tmp_var;
! 
! 	  tmp_var = create_tmp_var (TREE_TYPE (val), NULL);
! 	  if (gimple_in_ssa_p (cfun))
! 	    {
! 	      tmp_then = make_ssa_name (tmp_var, NULL_TREE);
! 	      tmp_else = make_ssa_name (tmp_var, NULL_TREE);
! 	      tmp_join = make_ssa_name (tmp_var, NULL_TREE);
! 	    }
! 	  else
! 	    {
! 	      tmp_then = tmp_var;
! 	      tmp_else = tmp_var;
! 	      tmp_join = tmp_var;
! 	    }
  
  	  e = split_block (bb, NULL);
  	  cond_bb = e->src;
  	  bb = e->dest;
*************** expand_parallel_call (struct omp_region 
*** 2220,2225 ****
--- 2244,2251 ----
  
  	  then_bb = create_empty_bb (cond_bb);
  	  else_bb = create_empty_bb (then_bb);
+ 	  set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
+ 	  set_immediate_dominator (CDI_DOMINATORS, else_bb, cond_bb);
  
  	  t = build3 (COND_EXPR, void_type_node,
  		      cond, NULL_TREE, NULL_TREE);
*************** expand_parallel_call (struct omp_region 
*** 2228,2256 ****
  	  bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
  
  	  si = bsi_start (then_bb);
! 	  t = build_gimple_modify_stmt (tmp, val);
  	  bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
  
  	  si = bsi_start (else_bb);
! 	  t = build_gimple_modify_stmt (tmp, 
  					build_int_cst (unsigned_type_node, 1));
  	  bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
  
  	  make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
  	  make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE);
! 	  make_edge (then_bb, bb, EDGE_FALLTHRU);
! 	  make_edge (else_bb, bb, EDGE_FALLTHRU);
  
! 	  val = tmp;
  	}
  
-       list = NULL_TREE;
-       val = get_formal_tmp_var (val, &list);
        si = bsi_start (bb);
!       bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
      }
  
!   list = NULL_TREE;
    t = OMP_PARALLEL_DATA_ARG (entry_stmt);
    if (t == NULL)
      t1 = null_pointer_node;
--- 2254,2293 ----
  	  bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
  
  	  si = bsi_start (then_bb);
! 	  t = build_gimple_modify_stmt (tmp_then, val);
! 	  if (gimple_in_ssa_p (cfun))
! 	    SSA_NAME_DEF_STMT (tmp_then) = t;
  	  bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
  
  	  si = bsi_start (else_bb);
! 	  t = build_gimple_modify_stmt (tmp_else, 
  					build_int_cst (unsigned_type_node, 1));
+ 	  if (gimple_in_ssa_p (cfun))
+ 	    SSA_NAME_DEF_STMT (tmp_else) = t;
  	  bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
  
  	  make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
  	  make_edge (cond_bb, else_bb, EDGE_FALSE_VALUE);
! 	  e_then = make_edge (then_bb, bb, EDGE_FALLTHRU);
! 	  e_else = make_edge (else_bb, bb, EDGE_FALLTHRU);
! 
! 	  if (gimple_in_ssa_p (cfun))
! 	    {
! 	      tree phi = create_phi_node (tmp_join, bb);
! 	      SSA_NAME_DEF_STMT (tmp_join) = phi;
! 	      add_phi_arg (phi, tmp_then, e_then);
! 	      add_phi_arg (phi, tmp_else, e_else);
! 	    }
  
! 	  val = tmp_join;
  	}
  
        si = bsi_start (bb);
!       val = force_gimple_operand_bsi (&si, val, true, NULL_TREE,
! 				      false, BSI_CONTINUE_LINKING);
      }
  
!   si = bsi_last (bb);
    t = OMP_PARALLEL_DATA_ARG (entry_stmt);
    if (t == NULL)
      t1 = null_pointer_node;
*************** expand_parallel_call (struct omp_region 
*** 2268,2274 ****
    else
      t = build_call_expr (built_in_decls[start_ix], 3, t2, t1, val);
  
!   gimplify_and_add (t, &list);
  
    t = OMP_PARALLEL_DATA_ARG (entry_stmt);
    if (t == NULL)
--- 2305,2312 ----
    else
      t = build_call_expr (built_in_decls[start_ix], 3, t2, t1, val);
  
!   force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 			    false, BSI_CONTINUE_LINKING);
  
    t = OMP_PARALLEL_DATA_ARG (entry_stmt);
    if (t == NULL)
*************** expand_parallel_call (struct omp_region 
*** 2276,2290 ****
    else
      t = build_fold_addr_expr (t);
    t = build_call_expr (OMP_PARALLEL_FN (entry_stmt), 1, t);
!   gimplify_and_add (t, &list);
  
    t = build_call_expr (built_in_decls[BUILT_IN_GOMP_PARALLEL_END], 0);
!   gimplify_and_add (t, &list);
! 
!   si = bsi_last (bb);
!   bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
! 
!   pop_gimplify_context (NULL_TREE);
  }
  
  
--- 2314,2325 ----
    else
      t = build_fold_addr_expr (t);
    t = build_call_expr (OMP_PARALLEL_FN (entry_stmt), 1, t);
!   force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 			    false, BSI_CONTINUE_LINKING);
  
    t = build_call_expr (built_in_decls[BUILT_IN_GOMP_PARALLEL_END], 0);
!   force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 			    false, BSI_CONTINUE_LINKING);
  }
  
  
*************** static void
*** 2403,2419 ****
  expand_omp_parallel (struct omp_region *region)
  {
    basic_block entry_bb, exit_bb, new_bb;
!   struct function *child_cfun, *saved_cfun;
    tree child_fn, block, t, ws_args;
    block_stmt_iterator si;
    tree entry_stmt;
    edge e;
-   bool do_cleanup_cfg = false;
  
    entry_stmt = last_stmt (region->entry);
    child_fn = OMP_PARALLEL_FN (entry_stmt);
    child_cfun = DECL_STRUCT_FUNCTION (child_fn);
-   saved_cfun = cfun;
  
    entry_bb = region->entry;
    exit_bb = region->exit;
--- 2438,2452 ----
  expand_omp_parallel (struct omp_region *region)
  {
    basic_block entry_bb, exit_bb, new_bb;
!   struct function *child_cfun;
    tree child_fn, block, t, ws_args;
    block_stmt_iterator si;
    tree entry_stmt;
    edge e;
  
    entry_stmt = last_stmt (region->entry);
    child_fn = OMP_PARALLEL_FN (entry_stmt);
    child_cfun = DECL_STRUCT_FUNCTION (child_fn);
  
    entry_bb = region->entry;
    exit_bb = region->exit;
*************** expand_omp_parallel (struct omp_region *
*** 2438,2450 ****
        bsi_remove (&si, true);
  
        new_bb = entry_bb;
-       remove_edge (entry_succ_e);
        if (exit_bb)
  	{
  	  exit_succ_e = single_succ_edge (exit_bb);
  	  make_edge (new_bb, exit_succ_e->dest, EDGE_FALLTHRU);
  	}
!       do_cleanup_cfg = true;
      }
    else
      {
--- 2471,2482 ----
        bsi_remove (&si, true);
  
        new_bb = entry_bb;
        if (exit_bb)
  	{
  	  exit_succ_e = single_succ_edge (exit_bb);
  	  make_edge (new_bb, exit_succ_e->dest, EDGE_FALLTHRU);
  	}
!       remove_edge_and_dominated_blocks (entry_succ_e);
      }
    else
      {
*************** expand_omp_parallel (struct omp_region *
*** 2465,2470 ****
--- 2497,2503 ----
  	{
  	  basic_block entry_succ_bb = single_succ (entry_bb);
  	  block_stmt_iterator si;
+ 	  tree parcopy_stmt = NULL_TREE, arg, narg;
  
  	  for (si = bsi_start (entry_succ_bb); ; bsi_next (&si))
  	    {
*************** expand_omp_parallel (struct omp_region *
*** 2481,2494 ****
  		  && TREE_OPERAND (arg, 0)
  		     == OMP_PARALLEL_DATA_ARG (entry_stmt))
  		{
! 		  if (GIMPLE_STMT_OPERAND (stmt, 0)
! 		      == DECL_ARGUMENTS (child_fn))
! 		    bsi_remove (&si, true);
! 		  else
! 		    GIMPLE_STMT_OPERAND (stmt, 1) = DECL_ARGUMENTS (child_fn);
  		  break;
  		}
  	    }
  	}
  
        /* Declare local variables needed in CHILD_CFUN.  */
--- 2514,2545 ----
  		  && TREE_OPERAND (arg, 0)
  		     == OMP_PARALLEL_DATA_ARG (entry_stmt))
  		{
! 		  parcopy_stmt = stmt;
  		  break;
  		}
  	    }
+ 
+ 	  gcc_assert (parcopy_stmt != NULL_TREE);
+ 	  arg = DECL_ARGUMENTS (child_fn);
+ 
+ 	  if (!gimple_in_ssa_p (cfun))
+ 	    {
+ 	      if (GIMPLE_STMT_OPERAND (parcopy_stmt, 0) == arg)
+ 		bsi_remove (&si, true);
+ 	      else
+ 		GIMPLE_STMT_OPERAND (parcopy_stmt, 1) = arg;
+ 	    }
+ 	  else
+ 	    {
+ 	      /* If we are in ssa form, we must load the value from the default
+ 		 definition of the argument.  That should not be defined now,
+ 		 since the argument is not used uninitialized.  */
+ 	      gcc_assert (gimple_default_def (cfun, arg) == NULL);
+ 	      narg = make_ssa_name (arg, build_empty_stmt ());
+ 	      set_default_def (arg, narg);
+ 	      GIMPLE_STMT_OPERAND (parcopy_stmt, 1) = narg;
+ 	      update_stmt (parcopy_stmt);
+ 	    }
  	}
  
        /* Declare local variables needed in CHILD_CFUN.  */
*************** expand_omp_parallel (struct omp_region *
*** 2496,2505 ****
        BLOCK_VARS (block) = list2chain (child_cfun->unexpanded_var_list);
        DECL_SAVED_TREE (child_fn) = bb_stmt_list (single_succ (entry_bb));
  
!       /* Reset DECL_CONTEXT on locals and function arguments.  */
!       for (t = BLOCK_VARS (block); t; t = TREE_CHAIN (t))
! 	DECL_CONTEXT (t) = child_fn;
! 
        for (t = DECL_ARGUMENTS (child_fn); t; t = TREE_CHAIN (t))
  	DECL_CONTEXT (t) = child_fn;
  
--- 2547,2553 ----
        BLOCK_VARS (block) = list2chain (child_cfun->unexpanded_var_list);
        DECL_SAVED_TREE (child_fn) = bb_stmt_list (single_succ (entry_bb));
  
!       /* Reset DECL_CONTEXT on function arguments.  */
        for (t = DECL_ARGUMENTS (child_fn); t; t = TREE_CHAIN (t))
  	DECL_CONTEXT (t) = child_fn;
  
*************** expand_omp_parallel (struct omp_region *
*** 2513,2529 ****
        entry_bb = e->dest;
        single_succ_edge (entry_bb)->flags = EDGE_FALLTHRU;
  
-       /* Move the parallel region into CHILD_CFUN.  We need to reset
- 	 dominance information because the expansion of the inner
- 	 regions has invalidated it.  */
-       free_dominance_info (CDI_DOMINATORS);
-       new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb);
-       if (exit_bb)
- 	single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
-       DECL_STRUCT_FUNCTION (child_fn)->curr_properties
- 	= cfun->curr_properties;
-       cgraph_add_new_function (child_fn, true);
- 
        /* Convert OMP_RETURN into a RETURN_EXPR.  */
        if (exit_bb)
  	{
--- 2561,2566 ----
*************** expand_omp_parallel (struct omp_region *
*** 2534,2551 ****
  	  bsi_insert_after (&si, t, BSI_SAME_STMT);
  	  bsi_remove (&si, true);
  	}
      }
  
    /* Emit a library call to launch the children threads.  */
    expand_parallel_call (region, new_bb, entry_stmt, ws_args);
- 
-   if (do_cleanup_cfg)
-     {
-       /* Clean up the unreachable sub-graph we created above.  */
-       free_dominance_info (CDI_DOMINATORS);
-       free_dominance_info (CDI_POST_DOMINATORS);
-       cleanup_tree_cfg ();
-     }
  }
  
  
--- 2571,2605 ----
  	  bsi_insert_after (&si, t, BSI_SAME_STMT);
  	  bsi_remove (&si, true);
  	}
+ 
+       /* Move the parallel region into CHILD_CFUN.  */
+  
+       if (gimple_in_ssa_p (cfun))
+ 	{
+ 	  push_cfun (child_cfun);
+ 	  init_tree_ssa ();
+ 	  init_ssa_operands ();
+ 	  cfun->gimple_df->in_ssa_p = true;
+ 	  pop_cfun ();
+ 	}
+       new_bb = move_sese_region_to_fn (child_cfun, entry_bb, exit_bb);
+       if (exit_bb)
+ 	single_succ_edge (new_bb)->flags = EDGE_FALLTHRU;
+ 
+       /* Inform the callgraph about the new function.  */
+       DECL_STRUCT_FUNCTION (child_fn)->curr_properties
+ 	= cfun->curr_properties;
+       cgraph_add_new_function (child_fn, true);
+ 
+       /* Fix the callgraph edges for child_cfun.  Those for cfun will be
+ 	 fixed in a following pass.  */
+       push_cfun (child_cfun);
+       rebuild_cgraph_edges ();
+       pop_cfun ();
      }
  
    /* Emit a library call to launch the children threads.  */
    expand_parallel_call (region, new_bb, entry_stmt, ws_args);
  }
  
  
*************** expand_omp_parallel (struct omp_region *
*** 2570,2576 ****
      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,
--- 2624,2630 ----
      L3:
  
      If this is a combined omp parallel loop, instead of the call to
!     GOMP_loop_foo_start, we call GOMP_loop_foo_next.  */
  
  static void
  expand_omp_for_generic (struct omp_region *region,
*************** expand_omp_for_generic (struct omp_regio
*** 2578,2590 ****
  			enum built_in_function start_fn,
  			enum built_in_function next_fn)
  {
!   tree type, istart0, iend0, iend;
!   tree t, list;
    basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb;
    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);
  
--- 2632,2645 ----
  			enum built_in_function start_fn,
  			enum built_in_function next_fn)
  {
!   tree type, istart0, iend0, iend, phi;
!   tree t, vmain, vback;
    basic_block entry_bb, cont_bb, exit_bb, l0_bb, l1_bb;
    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;
+   edge e, ne;
  
    gcc_assert (!broken_loop || !in_combined_parallel);
  
*************** expand_omp_for_generic (struct omp_regio
*** 2592,2600 ****
  
    istart0 = create_tmp_var (long_integer_type_node, ".istart0");
    iend0 = create_tmp_var (long_integer_type_node, ".iend0");
-   iend = create_tmp_var (type, NULL);
    TREE_ADDRESSABLE (istart0) = 1;
    TREE_ADDRESSABLE (iend0) = 1;
  
    entry_bb = region->entry;
    cont_bb = region->cont;
--- 2647,2659 ----
  
    istart0 = create_tmp_var (long_integer_type_node, ".istart0");
    iend0 = create_tmp_var (long_integer_type_node, ".iend0");
    TREE_ADDRESSABLE (istart0) = 1;
    TREE_ADDRESSABLE (iend0) = 1;
+   if (gimple_in_ssa_p (cfun))
+     {
+       add_referenced_var (istart0);
+       add_referenced_var (iend0);
+     }
  
    entry_bb = region->entry;
    cont_bb = region->cont;
*************** expand_omp_for_generic (struct omp_regio
*** 2616,2627 ****
  
    si = bsi_last (entry_bb);
    gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
!   if (!in_combined_parallel)
      {
        tree t0, t1, t2, t3, t4;
        /* If this is not a combined parallel loop, emit a call to
  	 GOMP_loop_foo_start in ENTRY_BB.  */
-       list = alloc_stmt_list ();
        t4 = build_fold_addr_expr (iend0);
        t3 = build_fold_addr_expr (istart0);
        t2 = fold_convert (long_integer_type_node, fd->step);
--- 2675,2693 ----
  
    si = bsi_last (entry_bb);
    gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
!   if (in_combined_parallel)
!     {
!       /* In a combined parallel loop, emit a call to
! 	 GOMP_loop_foo_next.  */
!       t = build_call_expr (built_in_decls[next_fn], 2,
! 			   build_fold_addr_expr (istart0),
! 			   build_fold_addr_expr (iend0));
!     }
!   else
      {
        tree t0, t1, t2, t3, t4;
        /* If this is not a combined parallel loop, emit a call to
  	 GOMP_loop_foo_start in ENTRY_BB.  */
        t4 = build_fold_addr_expr (iend0);
        t3 = build_fold_addr_expr (istart0);
        t2 = fold_convert (long_integer_type_node, fd->step);
*************** expand_omp_for_generic (struct omp_regio
*** 2636,2693 ****
        else
  	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);
  
    /* Iteration setup for sequential loop goes in L0_BB.  */
!   list = alloc_stmt_list ();
    t = fold_convert (type, istart0);
    t = build_gimple_modify_stmt (fd->v, t);
!   gimplify_and_add (t, &list);
  
    t = fold_convert (type, iend0);
!   t = build_gimple_modify_stmt (iend, t);
!   gimplify_and_add (t, &list);
! 
!   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.  */
--- 2702,2781 ----
        else
  	t = build_call_expr (built_in_decls[start_fn], 5,
  			     t0, t1, t2, t3, t4);
      }
+   t = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
+ 			       	true, BSI_SAME_STMT);
+   t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
+   bsi_insert_after (&si, t, BSI_SAME_STMT);
+ 
+   /* V may be used outside of the loop (e.g., to handle lastprivate clause).
+      If this is the case, its value is undefined if the loop is not entered
+      at all.  To handle this case, set its initial value to N1.  */
+   if (gimple_in_ssa_p (cfun))
+     {
+       e = find_edge (entry_bb, l3_bb);
+       for (phi = phi_nodes (l3_bb); phi; phi = PHI_CHAIN (phi))
+ 	if (PHI_ARG_DEF_FROM_EDGE (phi, e) == fd->v)
+ 	  SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, e), fd->n1);
+     }
+   else
+     {
+       t = build_gimple_modify_stmt (fd->v, fd->n1);
+       bsi_insert_before (&si, t, BSI_SAME_STMT);
+     }
+ 
+   /* Remove the OMP_FOR statement.  */
    bsi_remove (&si, true);
  
    /* Iteration setup for sequential loop goes in L0_BB.  */
!   si = bsi_start (l0_bb);
    t = fold_convert (type, istart0);
+   t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
+ 				false, BSI_CONTINUE_LINKING);
    t = build_gimple_modify_stmt (fd->v, t);
!   bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
!   if (gimple_in_ssa_p (cfun))
!     SSA_NAME_DEF_STMT (fd->v) = t;
  
    t = fold_convert (type, iend0);
!   iend = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				   false, BSI_CONTINUE_LINKING);
  
    if (!broken_loop)
      {
        /* Code to control the increment and predicate for the sequential
  	 loop goes in the CONT_BB.  */
!       si = bsi_last (cont_bb);
!       t = bsi_stmt (si);
!       gcc_assert (TREE_CODE (t) == OMP_CONTINUE);
!       vmain = TREE_OPERAND (t, 1);
!       vback = TREE_OPERAND (t, 0);
! 
!       t = fold_build2 (PLUS_EXPR, type, vmain, fd->step);
!       t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
! 				    true, BSI_SAME_STMT);
!       t = build_gimple_modify_stmt (vback, t);
!       bsi_insert_before (&si, t, BSI_SAME_STMT);
!       if (gimple_in_ssa_p (cfun))
! 	SSA_NAME_DEF_STMT (vback) = t;
    
!       t = build2 (fd->cond_code, boolean_type_node, vback, iend);
        t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
!       bsi_insert_before (&si, t, BSI_SAME_STMT);
  
!       /* Remove OMP_CONTINUE.  */
        bsi_remove (&si, true);
  
        /* Emit code to get the next parallel iteration in L2_BB.  */
!       si = bsi_start (l2_bb);
  
        t = build_call_expr (built_in_decls[next_fn], 2,
  			   build_fold_addr_expr (istart0),
  			   build_fold_addr_expr (iend0));
!       t = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				    false, BSI_CONTINUE_LINKING);
        t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
!       bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
      }
  
    /* Add the loop cleanup function.  */
*************** expand_omp_for_generic (struct omp_regio
*** 2701,2725 ****
    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);
      }
  }
  
--- 2789,2819 ----
    bsi_remove (&si, true);
  
    /* Connect the new blocks.  */
!   find_edge (entry_bb, l0_bb)->flags = EDGE_TRUE_VALUE;
!   find_edge (entry_bb, l3_bb)->flags = EDGE_FALSE_VALUE;
  
    if (!broken_loop)
      {
+       e = find_edge (cont_bb, l3_bb);
+       ne = make_edge (l2_bb, l3_bb, EDGE_FALSE_VALUE);
+ 
+       for (phi = phi_nodes (l3_bb); phi; phi = PHI_CHAIN (phi))
+ 	SET_USE (PHI_ARG_DEF_PTR_FROM_EDGE (phi, ne),
+ 		 PHI_ARG_DEF_FROM_EDGE (phi, e));
+       remove_edge (e);
+ 
        find_edge (cont_bb, l1_bb)->flags = EDGE_TRUE_VALUE;
        make_edge (cont_bb, l2_bb, EDGE_FALSE_VALUE);
        make_edge (l2_bb, l0_bb, EDGE_TRUE_VALUE);
! 
!       set_immediate_dominator (CDI_DOMINATORS, l2_bb,
! 			       recompute_dominator (CDI_DOMINATORS, l2_bb));
!       set_immediate_dominator (CDI_DOMINATORS, l3_bb,
! 			       recompute_dominator (CDI_DOMINATORS, l3_bb));
!       set_immediate_dominator (CDI_DOMINATORS, l0_bb,
! 			       recompute_dominator (CDI_DOMINATORS, l0_bb));
!       set_immediate_dominator (CDI_DOMINATORS, l1_bb,
! 			       recompute_dominator (CDI_DOMINATORS, l1_bb));
      }
  }
  
*************** expand_omp_for_generic (struct omp_regio
*** 2741,2749 ****
  	q += (q * nthreads != n);
  	s0 = q * threadid;
  	e0 = min(s0 + q, n);
  	if (s0 >= e0) goto L2; else goto L0;
      L0:
- 	V = s0 * STEP + N1;
  	e = e0 * STEP + N1;
      L1:
  	BODY;
--- 2835,2843 ----
  	q += (q * nthreads != n);
  	s0 = q * threadid;
  	e0 = min(s0 + q, n);
+ 	V = s0 * STEP + N1;
  	if (s0 >= e0) goto L2; else goto L0;
      L0:
  	e = e0 * STEP + N1;
      L1:
  	BODY;
*************** expand_omp_for_static_nochunk (struct om
*** 2757,2763 ****
  			       struct omp_for_data *fd)
  {
    tree n, q, s0, e0, e, t, nthreads, threadid;
!   tree type, list;
    basic_block entry_bb, exit_bb, seq_start_bb, body_bb, cont_bb;
    basic_block fin_bb;
    block_stmt_iterator si;
--- 2851,2857 ----
  			       struct omp_for_data *fd)
  {
    tree n, q, s0, e0, e, t, nthreads, threadid;
!   tree type, vmain, vback;
    basic_block entry_bb, exit_bb, seq_start_bb, body_bb, cont_bb;
    basic_block fin_bb;
    block_stmt_iterator si;
*************** expand_omp_for_static_nochunk (struct om
*** 2776,2802 ****
    exit_bb = region->exit;
  
    /* Iteration space partitioning goes in ENTRY_BB.  */
!   list = alloc_stmt_list ();
  
    t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0);
    t = fold_convert (type, t);
!   nthreads = get_formal_tmp_var (t, &list);
    
    t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0);
    t = fold_convert (type, t);
!   threadid = get_formal_tmp_var (t, &list);
  
!   fd->n1 = fold_convert (type, fd->n1);
!   if (!is_gimple_val (fd->n1))
!     fd->n1 = get_formal_tmp_var (fd->n1, &list);
! 
!   fd->n2 = fold_convert (type, fd->n2);
!   if (!is_gimple_val (fd->n2))
!     fd->n2 = get_formal_tmp_var (fd->n2, &list);
! 
!   fd->step = fold_convert (type, fd->step);
!   if (!is_gimple_val (fd->step))
!     fd->step = get_formal_tmp_var (fd->step, &list);
  
    t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1));
    t = fold_build2 (PLUS_EXPR, type, fd->step, t);
--- 2870,2902 ----
    exit_bb = region->exit;
  
    /* Iteration space partitioning goes in ENTRY_BB.  */
!   si = bsi_last (entry_bb);
!   gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
  
    t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0);
    t = fold_convert (type, t);
!   nthreads = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				       true, BSI_SAME_STMT);
    
    t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0);
    t = fold_convert (type, t);
!   threadid = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				       true, BSI_SAME_STMT);
  
!   fd->n1 = force_gimple_operand_bsi (&si,
! 				     fold_convert (type, fd->n1),
! 				     true, NULL_TREE,
! 				     true, BSI_SAME_STMT);
! 
!   fd->n2 = force_gimple_operand_bsi (&si,
! 				    fold_convert (type, fd->n2),
! 				    true, NULL_TREE,
! 				    true, BSI_SAME_STMT);
! 
!   fd->step = force_gimple_operand_bsi (&si,
! 				       fold_convert (type, fd->step),
! 				       true, NULL_TREE,
! 				       true, BSI_SAME_STMT);
  
    t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1));
    t = fold_build2 (PLUS_EXPR, type, fd->step, t);
*************** expand_omp_for_static_nochunk (struct om
*** 2804,2888 ****
    t = fold_build2 (MINUS_EXPR, type, t, fd->n1);
    t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step);
    t = fold_convert (type, t);
!   if (is_gimple_val (t))
!     n = t;
!   else
!     n = get_formal_tmp_var (t, &list);
  
!   t = build2 (TRUNC_DIV_EXPR, type, n, nthreads);
!   q = get_formal_tmp_var (t, &list);
  
!   t = build2 (MULT_EXPR, type, q, nthreads);
!   t = build2 (NE_EXPR, type, t, n);
!   t = build2 (PLUS_EXPR, type, q, t);
!   q = get_formal_tmp_var (t, &list);
  
    t = build2 (MULT_EXPR, type, q, threadid);
!   s0 = get_formal_tmp_var (t, &list);
  
!   t = build2 (PLUS_EXPR, type, s0, q);
!   t = build2 (MIN_EXPR, type, t, n);
!   e0 = get_formal_tmp_var (t, &list);
  
    t = build2 (GE_EXPR, boolean_type_node, s0, e0);
    t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
!   append_to_statement_list (t, &list);
  
!   si = bsi_last (entry_bb);
!   gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
!   bsi_insert_after (&si, list, BSI_SAME_STMT);
    bsi_remove (&si, true);
  
    /* Setup code for sequential iteration goes in SEQ_START_BB.  */
!   list = alloc_stmt_list ();
! 
!   t = fold_convert (type, s0);
!   t = build2 (MULT_EXPR, type, t, fd->step);
!   t = build2 (PLUS_EXPR, type, t, fd->n1);
!   t = build_gimple_modify_stmt (fd->v, t);
!   gimplify_and_add (t, &list);
  
    t = fold_convert (type, e0);
!   t = build2 (MULT_EXPR, type, t, fd->step);
!   t = build2 (PLUS_EXPR, type, t, fd->n1);
!   e = get_formal_tmp_var (t, &list);
! 
!   si = bsi_start (seq_start_bb);
!   bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
  
    /* The code controlling the sequential loop replaces the OMP_CONTINUE.  */
!   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, e);
!   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);
!   gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
!   bsi_insert_after (&si, list, BSI_SAME_STMT);
    bsi_remove (&si, true);
  
    /* Replace the OMP_RETURN with a barrier, or nothing.  */
    si = bsi_last (exit_bb);
    if (!OMP_RETURN_NOWAIT (bsi_stmt (si)))
!     {
!       list = alloc_stmt_list ();
!       build_omp_barrier (&list);
!       bsi_insert_after (&si, list, BSI_SAME_STMT);
!     }
    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;
  }
  
  
--- 2904,2993 ----
    t = fold_build2 (MINUS_EXPR, type, t, fd->n1);
    t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step);
    t = fold_convert (type, t);
!   n = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
  
!   t = fold_build2 (TRUNC_DIV_EXPR, type, n, nthreads);
!   q = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
  
!   t = fold_build2 (MULT_EXPR, type, q, nthreads);
!   t = fold_build2 (NE_EXPR, type, t, n);
!   t = fold_build2 (PLUS_EXPR, type, q, t);
!   q = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
  
    t = build2 (MULT_EXPR, type, q, threadid);
!   s0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
! 
!   t = fold_build2 (PLUS_EXPR, type, s0, q);
!   t = fold_build2 (MIN_EXPR, type, t, n);
!   e0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE, true, BSI_SAME_STMT);
  
!   t = fold_convert (type, s0);
!   t = fold_build2 (MULT_EXPR, type, t, fd->step);
!   t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
!   t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
! 				true, BSI_SAME_STMT);
!   t = build_gimple_modify_stmt (fd->v, t);
!   bsi_insert_before (&si, t, BSI_SAME_STMT);
!   if (gimple_in_ssa_p (cfun))
!     SSA_NAME_DEF_STMT (fd->v) = t;
  
    t = build2 (GE_EXPR, boolean_type_node, s0, e0);
    t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
!   bsi_insert_before (&si, t, BSI_SAME_STMT);
  
!   /* Remove the OMP_FOR statement.  */
    bsi_remove (&si, true);
  
    /* Setup code for sequential iteration goes in SEQ_START_BB.  */
!   si = bsi_start (seq_start_bb);
  
    t = fold_convert (type, e0);
!   t = fold_build2 (MULT_EXPR, type, t, fd->step);
!   t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
!   e = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				false, BSI_CONTINUE_LINKING);
  
    /* The code controlling the sequential loop replaces the OMP_CONTINUE.  */
!   si = bsi_last (cont_bb);
!   t = bsi_stmt (si);
!   gcc_assert (TREE_CODE (t) == OMP_CONTINUE);
!   vmain = TREE_OPERAND (t, 1);
!   vback = TREE_OPERAND (t, 0);
! 
!   t = fold_build2 (PLUS_EXPR, type, vmain, fd->step);
!   t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
! 				true, BSI_SAME_STMT);
!   t = build_gimple_modify_stmt (vback, t);
!   bsi_insert_before (&si, t, BSI_SAME_STMT);
!   if (gimple_in_ssa_p (cfun))
!     SSA_NAME_DEF_STMT (vback) = t;
  
!   t = build2 (fd->cond_code, boolean_type_node, vback, e);
    t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
!   bsi_insert_before (&si, t, BSI_SAME_STMT);
  
!   /* Remove the OMP_CONTINUE statement.  */
    bsi_remove (&si, true);
  
    /* Replace the OMP_RETURN with a barrier, or nothing.  */
    si = bsi_last (exit_bb);
    if (!OMP_RETURN_NOWAIT (bsi_stmt (si)))
!     force_gimple_operand_bsi (&si, build_omp_barrier (), false, NULL_TREE,
! 			      false, BSI_SAME_STMT);
    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;
+  
+   set_immediate_dominator (CDI_DOMINATORS, seq_start_bb, entry_bb);
+   set_immediate_dominator (CDI_DOMINATORS, body_bb,
+ 			   recompute_dominator (CDI_DOMINATORS, body_bb));
+   set_immediate_dominator (CDI_DOMINATORS, fin_bb,
+ 			   recompute_dominator (CDI_DOMINATORS, fin_bb));
  }
  
  
*************** expand_omp_for_static_nochunk (struct om
*** 2900,2905 ****
--- 3005,3013 ----
  	  adj = STEP + 1;
  	n = (adj + N2 - N1) / STEP;
  	trip = 0;
+ 	V = threadid * CHUNK * STEP + N1;  -- this extra definition of V is
+ 					      here so that V is defined
+ 					      if the loop is not entered
      L0:
  	s0 = (trip * nthreads + threadid) * CHUNK;
  	e0 = min(s0 + CHUNK, n);
*************** expand_omp_for_static_nochunk (struct om
*** 2920,2933 ****
  static void
  expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
  {
!   tree n, s0, e0, e, t;
!   tree trip, nthreads, threadid;
!   tree type;
    basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb;
    basic_block trip_update_bb, cont_bb, fin_bb;
-   tree list;
    block_stmt_iterator si;
!   edge se;
  
    type = TREE_TYPE (fd->v);
  
--- 3028,3040 ----
  static void
  expand_omp_for_static_chunk (struct omp_region *region, struct omp_for_data *fd)
  {
!   tree n, s0, e0, e, t, phi, nphi, args;
!   tree trip_var, trip_init, trip_main, trip_back, nthreads, threadid;
!   tree type, cont, v_main, v_back, v_extra;
    basic_block entry_bb, exit_bb, body_bb, seq_start_bb, iter_part_bb;
    basic_block trip_update_bb, cont_bb, fin_bb;
    block_stmt_iterator si;
!   edge se, re, ene;
  
    type = TREE_TYPE (fd->v);
  
*************** expand_omp_for_static_chunk (struct omp_
*** 2948,2978 ****
    exit_bb = region->exit;
  
    /* Trip and adjustment setup goes in ENTRY_BB.  */
!   list = alloc_stmt_list ();
  
    t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0);
    t = fold_convert (type, t);
!   nthreads = get_formal_tmp_var (t, &list);
    
    t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0);
    t = fold_convert (type, t);
!   threadid = get_formal_tmp_var (t, &list);
  
!   fd->n1 = fold_convert (type, fd->n1);
!   if (!is_gimple_val (fd->n1))
!     fd->n1 = get_formal_tmp_var (fd->n1, &list);
! 
!   fd->n2 = fold_convert (type, fd->n2);
!   if (!is_gimple_val (fd->n2))
!     fd->n2 = get_formal_tmp_var (fd->n2, &list);
! 
!   fd->step = fold_convert (type, fd->step);
!   if (!is_gimple_val (fd->step))
!     fd->step = get_formal_tmp_var (fd->step, &list);
! 
!   fd->chunk_size = fold_convert (type, fd->chunk_size);
!   if (!is_gimple_val (fd->chunk_size))
!     fd->chunk_size = get_formal_tmp_var (fd->chunk_size, &list);
  
    t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1));
    t = fold_build2 (PLUS_EXPR, type, fd->step, t);
--- 3055,3087 ----
    exit_bb = region->exit;
  
    /* Trip and adjustment setup goes in ENTRY_BB.  */
!   si = bsi_last (entry_bb);
!   gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
  
    t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_NUM_THREADS], 0);
    t = fold_convert (type, t);
!   nthreads = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				       true, BSI_SAME_STMT);
    
    t = build_call_expr (built_in_decls[BUILT_IN_OMP_GET_THREAD_NUM], 0);
    t = fold_convert (type, t);
!   threadid = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				       true, BSI_SAME_STMT);
  
!   fd->n1 = force_gimple_operand_bsi (&si, fold_convert (type, fd->n1),
! 				     true, NULL_TREE,
! 				     true, BSI_SAME_STMT);
!   fd->n2 = force_gimple_operand_bsi (&si, fold_convert (type, fd->n2),
! 				     true, NULL_TREE,
! 				     true, BSI_SAME_STMT);
!   fd->step = force_gimple_operand_bsi (&si, fold_convert (type, fd->step),
! 				       true, NULL_TREE,
! 				       true, BSI_SAME_STMT);
!   fd->chunk_size
! 	  = force_gimple_operand_bsi (&si, fold_convert (type,
! 							 fd->chunk_size),
! 				      true, NULL_TREE,
! 				      true, BSI_SAME_STMT);
  
    t = build_int_cst (type, (fd->cond_code == LT_EXPR ? -1 : 1));
    t = fold_build2 (PLUS_EXPR, type, fd->step, t);
*************** expand_omp_for_static_chunk (struct omp_
*** 2980,3081 ****
    t = fold_build2 (MINUS_EXPR, type, t, fd->n1);
    t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step);
    t = fold_convert (type, t);
!   if (is_gimple_val (t))
!     n = t;
!   else
!     n = get_formal_tmp_var (t, &list);
  
!   t = build_int_cst (type, 0);
!   trip = get_initialized_tmp_var (t, &list, NULL);
  
!   si = bsi_last (entry_bb);
!   gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_FOR);
!   bsi_insert_after (&si, list, BSI_SAME_STMT);
    bsi_remove (&si, true);
  
    /* Iteration space partitioning goes in ITER_PART_BB.  */
!   list = alloc_stmt_list ();
  
!   t = build2 (MULT_EXPR, type, trip, nthreads);
!   t = build2 (PLUS_EXPR, type, t, threadid);
!   t = build2 (MULT_EXPR, type, t, fd->chunk_size);
!   s0 = get_formal_tmp_var (t, &list);
! 
!   t = build2 (PLUS_EXPR, type, s0, fd->chunk_size);
!   t = build2 (MIN_EXPR, type, t, n);
!   e0 = get_formal_tmp_var (t, &list);
  
    t = build2 (LT_EXPR, boolean_type_node, s0, n);
    t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
!   append_to_statement_list (t, &list);
! 
!   si = bsi_start (iter_part_bb);
!   bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
  
    /* Setup code for sequential iteration goes in SEQ_START_BB.  */
!   list = alloc_stmt_list ();
  
    t = fold_convert (type, s0);
!   t = build2 (MULT_EXPR, type, t, fd->step);
!   t = build2 (PLUS_EXPR, type, t, fd->n1);
    t = build_gimple_modify_stmt (fd->v, t);
!   gimplify_and_add (t, &list);
  
    t = fold_convert (type, e0);
!   t = build2 (MULT_EXPR, type, t, fd->step);
!   t = build2 (PLUS_EXPR, type, t, fd->n1);
!   e = get_formal_tmp_var (t, &list);
! 
!   si = bsi_start (seq_start_bb);
!   bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
  
    /* The code controlling the sequential loop goes in CONT_BB,
       replacing the OMP_CONTINUE.  */
!   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, e);
!   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);
!   gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
!   bsi_insert_after (&si, list, BSI_SAME_STMT);
    bsi_remove (&si, true);
  
    /* Trip update code goes into TRIP_UPDATE_BB.  */
!   list = alloc_stmt_list ();
  
    t = build_int_cst (type, 1);
!   t = build2 (PLUS_EXPR, type, trip, t);
!   t = build_gimple_modify_stmt (trip, t);
!   gimplify_and_add (t, &list);
! 
!   si = bsi_start (trip_update_bb);
!   bsi_insert_after (&si, list, BSI_CONTINUE_LINKING);
  
    /* Replace the OMP_RETURN with a barrier, or nothing.  */
    si = bsi_last (exit_bb);
    if (!OMP_RETURN_NOWAIT (bsi_stmt (si)))
!     {
!       list = alloc_stmt_list ();
!       build_omp_barrier (&list);
!       bsi_insert_after (&si, list, BSI_SAME_STMT);
!     }
    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);
  }
  
  
--- 3089,3258 ----
    t = fold_build2 (MINUS_EXPR, type, t, fd->n1);
    t = fold_build2 (TRUNC_DIV_EXPR, type, t, fd->step);
    t = fold_convert (type, t);
!   n = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				true, BSI_SAME_STMT);
  
!   trip_var = create_tmp_var (type, ".trip");
!   if (gimple_in_ssa_p (cfun))
!     {
!       add_referenced_var (trip_var);
!       trip_init = make_ssa_name (trip_var, NULL_TREE);
!       trip_main = make_ssa_name (trip_var, NULL_TREE);
!       trip_back = make_ssa_name (trip_var, NULL_TREE);
!     }
!   else
!     {
!       trip_init = trip_var;
!       trip_main = trip_var;
!       trip_back = trip_var;
!     }
! 
!   t = build_gimple_modify_stmt (trip_init, build_int_cst (type, 0));
!   bsi_insert_before (&si, t, BSI_SAME_STMT);
!   if (gimple_in_ssa_p (cfun))
!     SSA_NAME_DEF_STMT (trip_init) = t;
! 
!   t = fold_build2 (MULT_EXPR, type, threadid, fd->chunk_size);
!   t = fold_build2 (MULT_EXPR, type, t, fd->step);
!   t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
!   v_extra = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				      true, BSI_SAME_STMT);
  
!   /* Remove the OMP_FOR.  */
    bsi_remove (&si, true);
  
    /* Iteration space partitioning goes in ITER_PART_BB.  */
!   si = bsi_last (iter_part_bb);
  
!   t = fold_build2 (MULT_EXPR, type, trip_main, nthreads);
!   t = fold_build2 (PLUS_EXPR, type, t, threadid);
!   t = fold_build2 (MULT_EXPR, type, t, fd->chunk_size);
!   s0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				 false, BSI_CONTINUE_LINKING);
! 
!   t = fold_build2 (PLUS_EXPR, type, s0, fd->chunk_size);
!   t = fold_build2 (MIN_EXPR, type, t, n);
!   e0 = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				 false, BSI_CONTINUE_LINKING);
  
    t = build2 (LT_EXPR, boolean_type_node, s0, n);
    t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
!   bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
  
    /* Setup code for sequential iteration goes in SEQ_START_BB.  */
!   si = bsi_start (seq_start_bb);
  
    t = fold_convert (type, s0);
!   t = fold_build2 (MULT_EXPR, type, t, fd->step);
!   t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
!   t = force_gimple_operand_bsi (&si, t, false, NULL_TREE,
! 				false, BSI_CONTINUE_LINKING);
    t = build_gimple_modify_stmt (fd->v, t);
!   bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
!   if (gimple_in_ssa_p (cfun))
!     SSA_NAME_DEF_STMT (fd->v) = t;
  
    t = fold_convert (type, e0);
!   t = fold_build2 (MULT_EXPR, type, t, fd->step);
!   t = fold_build2 (PLUS_EXPR, type, t, fd->n1);
!   e = force_gimple_operand_bsi (&si, t, true, NULL_TREE,
! 				false, BSI_CONTINUE_LINKING);
  
    /* The code controlling the sequential loop goes in CONT_BB,
       replacing the OMP_CONTINUE.  */
!   si = bsi_last (cont_bb);
!   cont = bsi_stmt (si);
!   gcc_assert (TREE_CODE (cont) == OMP_CONTINUE);
!   v_main = TREE_OPERAND (cont, 1);
!   v_back = TREE_OPERAND (cont, 0);
! 
!   t = build2 (PLUS_EXPR, type, v_main, fd->step);
!   t = build_gimple_modify_stmt (v_back, t);
!   bsi_insert_before (&si, t, BSI_SAME_STMT);
!   if (gimple_in_ssa_p (cfun))
!     SSA_NAME_DEF_STMT (v_back) = t;
  
!   t = build2 (fd->cond_code, boolean_type_node, v_back, e);
    t = build3 (COND_EXPR, void_type_node, t, NULL_TREE, NULL_TREE);
!   bsi_insert_before (&si, t, BSI_SAME_STMT);
    
!   /* Remove OMP_CONTINUE.  */
    bsi_remove (&si, true);
  
    /* Trip update code goes into TRIP_UPDATE_BB.  */
!   si = bsi_start (trip_update_bb);
  
    t = build_int_cst (type, 1);
!   t = build2 (PLUS_EXPR, type, trip_main, t);
!   t = build_gimple_modify_stmt (trip_back, t);
!   bsi_insert_after (&si, t, BSI_CONTINUE_LINKING);
!   if (gimple_in_ssa_p (cfun))
!     SSA_NAME_DEF_STMT (trip_back) = t;
  
    /* Replace the OMP_RETURN with a barrier, or nothing.  */
    si = bsi_last (exit_bb);
    if (!OMP_RETURN_NOWAIT (bsi_stmt (si)))
!     force_gimple_operand_bsi (&si, build_omp_barrier (), false, NULL_TREE,
! 			      false, BSI_SAME_STMT);
    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);
+ 
+   if (gimple_in_ssa_p (cfun))
+     {
+       /* When we redirect the edge from trip_update_bb to iter_part_bb, we
+ 	 remove arguments of the phi nodes in fin_bb.  We need to create
+ 	 appropriate phi nodes in iter_part_bb instead.  */
+       se = single_pred_edge (fin_bb);
+       re = single_succ_edge (trip_update_bb);
+       ene = single_succ_edge (entry_bb);
+ 
+       args = PENDING_STMT (re);
+       PENDING_STMT (re) = NULL_TREE;
+       for (phi = phi_nodes (fin_bb);
+ 	   phi && args;
+ 	   phi = PHI_CHAIN (phi), args = TREE_CHAIN (args))
+ 	{
+ 	  t = PHI_RESULT (phi);
+ 	  gcc_assert (t == TREE_PURPOSE (args));
+ 	  nphi = create_phi_node (t, iter_part_bb);
+ 	  SSA_NAME_DEF_STMT (t) = nphi;
+ 
+ 	  t = PHI_ARG_DEF_FROM_EDGE (phi, se);
+ 	  /* A special case -- fd->v is not yet computed in iter_part_bb, we
+ 	     need to use v_extra instead.  */
+ 	  if (t == fd->v)
+ 	    t = v_extra;
+ 	  add_phi_arg (nphi, t, ene);
+ 	  add_phi_arg (nphi, TREE_VALUE (args), re);
+ 	}
+       gcc_assert (!phi && !args);
+       while ((phi = phi_nodes (fin_bb)) != NULL_TREE)
+ 	remove_phi_node (phi, NULL_TREE, false);
+ 
+       /* Make phi node for trip.  */
+       phi = create_phi_node (trip_main, iter_part_bb);
+       SSA_NAME_DEF_STMT (trip_main) = phi;
+       add_phi_arg (phi, trip_back, single_succ_edge (trip_update_bb));
+       add_phi_arg (phi, trip_init, single_succ_edge (entry_bb));
+     }
+ 
+   set_immediate_dominator (CDI_DOMINATORS, trip_update_bb, cont_bb);
+   set_immediate_dominator (CDI_DOMINATORS, iter_part_bb,
+ 			   recompute_dominator (CDI_DOMINATORS, iter_part_bb));
+   set_immediate_dominator (CDI_DOMINATORS, fin_bb,
+ 			   recompute_dominator (CDI_DOMINATORS, fin_bb));
+   set_immediate_dominator (CDI_DOMINATORS, seq_start_bb,
+ 			   recompute_dominator (CDI_DOMINATORS, seq_start_bb));
+   set_immediate_dominator (CDI_DOMINATORS, body_bb,
+ 			   recompute_dominator (CDI_DOMINATORS, body_bb));
  }
  
  
*************** expand_omp_for (struct omp_region *regio
*** 3086,3093 ****
  {
    struct omp_for_data fd;
  
-   push_gimplify_context ();
- 
    extract_omp_for_data (last_stmt (region->entry), &fd);
    region->sched_kind = fd.sched_kind;
  
--- 3263,3268 ----
*************** expand_omp_for (struct omp_region *regio
*** 3107,3114 ****
        int next_ix = BUILT_IN_GOMP_LOOP_STATIC_NEXT + fn_index;
        expand_omp_for_generic (region, &fd, start_ix, next_ix);
      }
- 
-   pop_gimplify_context (NULL);
  }
  
  
--- 3282,3287 ----
*************** expand_omp_for (struct omp_region *regio
*** 3137,3148 ****
  	reduction;
  
      If this is a combined parallel sections, replace the call to
!     GOMP_sections_start with 'goto L1'.  */
  
  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;
--- 3310,3321 ----
  	reduction;
  
      If this is a combined parallel sections, replace the call to
!     GOMP_sections_start with call to GOMP_sections_next.  */
  
  static void
  expand_omp_sections (struct omp_region *region)
  {
!   tree label_vec, l1, l2, t, u, sections_stmt, vin, vmain, vnext, cont;
    unsigned i, casei, len;
    basic_block entry_bb, l0_bb, l1_bb, l2_bb, default_bb;
    block_stmt_iterator si;
*************** expand_omp_sections (struct omp_region *
*** 3179,3185 ****
    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,
--- 3352,3358 ----
    si = bsi_last (entry_bb);
    sections_stmt = bsi_stmt (si);
    gcc_assert (TREE_CODE (sections_stmt) == OMP_SECTIONS);
!   vin = OMP_SECTIONS_CONTROL (sections_stmt);
    if (!is_combined_parallel (region))
      {
        /* If we are not inside a combined parallel+sections region,
*************** expand_omp_sections (struct omp_region *
*** 3188,3203 ****
  			 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);
-       bsi_insert_after (&si, t, BSI_SAME_STMT);
      }
    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);
  
--- 3361,3396 ----
  			 exit_reachable ? len - 1 : len);
        u = built_in_decls[BUILT_IN_GOMP_SECTIONS_START];
        t = build_call_expr (u, 1, t);
      }
+   else
+     {
+       /* Otherwise, call GOMP_sections_next.  */
+       u = built_in_decls[BUILT_IN_GOMP_SECTIONS_NEXT];
+       t = build_call_expr (u, 0);
+     }
+   t = build_gimple_modify_stmt (vin, t);
+   bsi_insert_after (&si, t, BSI_SAME_STMT);
+   if (gimple_in_ssa_p (cfun))
+     SSA_NAME_DEF_STMT (vin) = t;
    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);
+   if (exit_reachable)
+     {
+       cont = last_stmt (l1_bb);
+       gcc_assert (TREE_CODE (cont) == OMP_CONTINUE);
+       vmain = TREE_OPERAND (cont, 1);
+       vnext = TREE_OPERAND (cont, 0);
+     }
+   else
+     {
+       vmain = vin;
+       vnext = NULL_TREE;
+     }
  
!   t = build3 (SWITCH_EXPR, void_type_node, vmain, NULL, label_vec);
    bsi_insert_after (&si, t, BSI_SAME_STMT);
    bsi_remove (&si, true);
  
*************** expand_omp_sections (struct omp_region *
*** 3258,3265 ****
        gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
  
        t = build_call_expr (built_in_decls[BUILT_IN_GOMP_SECTIONS_NEXT], 0);
!       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;
--- 3451,3460 ----
        gcc_assert (TREE_CODE (bsi_stmt (si)) == OMP_CONTINUE);
  
        t = build_call_expr (built_in_decls[BUILT_IN_GOMP_SECTIONS_NEXT], 0);
!       t = build_gimple_modify_stmt (vnext, t);
        bsi_insert_after (&si, t, BSI_SAME_STMT);
+       if (gimple_in_ssa_p (cfun))
+ 	SSA_NAME_DEF_STMT (vnext) = t;
        bsi_remove (&si, true);
  
        single_succ_edge (l1_bb)->flags = EDGE_FALLTHRU;
*************** expand_omp_sections (struct omp_region *
*** 3275,3289 ****
        bsi_remove (&si, true);
      }
  
!   /* Connect the new blocks.  */
!   if (is_combined_parallel (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.  */
!       gcc_assert (exit_reachable);
!       redirect_edge_and_branch (single_succ_edge (entry_bb), l1_bb);
!     }
  }
  
  
--- 3470,3476 ----
        bsi_remove (&si, true);
      }
  
!   set_immediate_dominator (CDI_DOMINATORS, default_bb, l0_bb);
  }
  
  
*************** expand_omp_single (struct omp_region *re
*** 3313,3323 ****
  
    si = bsi_last (exit_bb);
    if (!OMP_RETURN_NOWAIT (bsi_stmt (si)) || need_barrier)
!     {
!       tree t = alloc_stmt_list ();
!       build_omp_barrier (&t);
!       bsi_insert_after (&si, t, BSI_SAME_STMT);
!     }
    bsi_remove (&si, true);
    single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU;
  }
--- 3500,3507 ----
  
    si = bsi_last (exit_bb);
    if (!OMP_RETURN_NOWAIT (bsi_stmt (si)) || need_barrier)
!     force_gimple_operand_bsi (&si, build_omp_barrier (), false, NULL_TREE,
! 			      false, BSI_SAME_STMT);
    bsi_remove (&si, true);
    single_succ_edge (exit_bb)->flags = EDGE_FALLTHRU;
  }
*************** execute_expand_omp (void)
*** 3499,3506 ****
  
    expand_omp (root_omp_region);
  
-   free_dominance_info (CDI_DOMINATORS);
-   free_dominance_info (CDI_POST_DOMINATORS);
    cleanup_tree_cfg ();
  
    free_omp_regions ();
--- 3683,3688 ----
*************** execute_expand_omp (void)
*** 3508,3517 ****
    return 0;
  }
  
  static bool
  gate_expand_omp (void)
  {
!   return flag_openmp != 0 && errorcount == 0;
  }
  
  struct tree_opt_pass pass_expand_omp = 
--- 3690,3726 ----
    return 0;
  }
  
+ /* OMP expansion in SSA form.  For testing purposes only.  */
+ 
+ static bool
+ gate_expand_omp_ssa (void)
+ {
+   return flag_openmp_ssa && flag_openmp != 0 && errorcount == 0;
+ }
+ 
+ struct tree_opt_pass pass_expand_omp_ssa = 
+ {
+   "ompexpssa",				/* name */
+   gate_expand_omp_ssa,			/* gate */
+   execute_expand_omp,			/* execute */
+   NULL,					/* sub */
+   NULL,					/* next */
+   0,					/* static_pass_number */
+   0,					/* tv_id */
+   PROP_gimple_any,			/* properties_required */
+   PROP_gimple_lomp,			/* properties_provided */
+   0,					/* properties_destroyed */
+   0,					/* todo_flags_start */
+   TODO_dump_func,			/* todo_flags_finish */
+   0					/* letter */
+ };
+ 
+ /* OMP expansion -- the default pass, run before creation of SSA form.  */
+ 
  static bool
  gate_expand_omp (void)
  {
!   return !flag_openmp_ssa && flag_openmp != 0 && errorcount == 0;
  }
  
  struct tree_opt_pass pass_expand_omp = 
Index: c-typeck.c
===================================================================
*** c-typeck.c	(revision 127626)
--- c-typeck.c	(working copy)
*************** convert_for_assignment (tree type, tree 
*** 4039,4045 ****
  	  if (pedantic && (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl)))
  	    pedwarn ("ISO C prohibits argument conversion to union type");
  
! 	  return build_constructor_single (type, memb, rhs);
  	}
      }
  
--- 4039,4047 ----
  	  if (pedantic && (!fundecl || !DECL_IN_SYSTEM_HEADER (fundecl)))
  	    pedwarn ("ISO C prohibits argument conversion to union type");
  
! 	  return build_constructor_single (type, memb,
! 					   fold_convert (TREE_TYPE (memb),
! 							 rhs));
  	}
      }
  
Index: gimplify.c
===================================================================
*** gimplify.c	(revision 127626)
--- gimplify.c	(working copy)
*************** gimplify_omp_parallel (tree *expr_p, tre
*** 5074,5081 ****
  static enum gimplify_status
  gimplify_omp_for (tree *expr_p, tree *pre_p)
  {
!   tree for_stmt, decl, t;
    enum gimplify_status ret = GS_OK;
  
    for_stmt = *expr_p;
  
--- 5074,5082 ----
  static enum gimplify_status
  gimplify_omp_for (tree *expr_p, tree *pre_p)
  {
!   tree for_stmt, decl, var, t;
    enum gimplify_status ret = GS_OK;
+   tree body, init_decl = NULL_TREE;
  
    for_stmt = *expr_p;
  
*************** gimplify_omp_for (tree *expr_p, tree *pr
*** 5094,5099 ****
--- 5095,5114 ----
    else
      omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
  
+   /* If DECL is not a gimple register, create a temporary variable to act as an
+      iteration counter.  This is valid, since DECL cannot be modified in the
+      body of the loop.  */
+   if (!is_gimple_reg (decl))
+     {
+       var = create_tmp_var (TREE_TYPE (decl), get_name (decl));
+       GENERIC_TREE_OPERAND (t, 0) = var;
+ 
+       init_decl = build_gimple_modify_stmt (decl, var);
+       omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
+     }
+   else
+     var = decl;
+ 
    ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
  			&OMP_FOR_PRE_BODY (for_stmt),
  			NULL, is_gimple_val, fb_rvalue);
*************** gimplify_omp_for (tree *expr_p, tree *pr
*** 5103,5108 ****
--- 5118,5124 ----
    t = OMP_FOR_COND (for_stmt);
    gcc_assert (COMPARISON_CLASS_P (t));
    gcc_assert (GENERIC_TREE_OPERAND (t, 0) == decl);
+   TREE_OPERAND (t, 0) = var;
  
    ret |= gimplify_expr (&GENERIC_TREE_OPERAND (t, 1),
  			&OMP_FOR_PRE_BODY (for_stmt),
*************** gimplify_omp_for (tree *expr_p, tree *pr
*** 5115,5135 ****
      case PREINCREMENT_EXPR:
      case POSTINCREMENT_EXPR:
        t = build_int_cst (TREE_TYPE (decl), 1);
!       t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
!       t = build_gimple_modify_stmt (decl, t);
        OMP_FOR_INCR (for_stmt) = t;
        break;
  
      case PREDECREMENT_EXPR:
      case POSTDECREMENT_EXPR:
        t = build_int_cst (TREE_TYPE (decl), -1);
!       t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
!       t = build_gimple_modify_stmt (decl, t);
        OMP_FOR_INCR (for_stmt) = t;
        break;
        
      case GIMPLE_MODIFY_STMT:
        gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == decl);
        t = GIMPLE_STMT_OPERAND (t, 1);
        switch (TREE_CODE (t))
  	{
--- 5131,5153 ----
      case PREINCREMENT_EXPR:
      case POSTINCREMENT_EXPR:
        t = build_int_cst (TREE_TYPE (decl), 1);
!       t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
!       t = build_gimple_modify_stmt (var, t);
        OMP_FOR_INCR (for_stmt) = t;
        break;
  
      case PREDECREMENT_EXPR:
      case POSTDECREMENT_EXPR:
        t = build_int_cst (TREE_TYPE (decl), -1);
!       t = build2 (PLUS_EXPR, TREE_TYPE (decl), var, t);
!       t = build_gimple_modify_stmt (var, t);
        OMP_FOR_INCR (for_stmt) = t;
        break;
        
      case GIMPLE_MODIFY_STMT:
        gcc_assert (GIMPLE_STMT_OPERAND (t, 0) == decl);
+       GIMPLE_STMT_OPERAND (t, 0) = var;
+ 
        t = GIMPLE_STMT_OPERAND (t, 1);
        switch (TREE_CODE (t))
  	{
*************** gimplify_omp_for (tree *expr_p, tree *pr
*** 5137,5147 ****
  	  if (TREE_OPERAND (t, 1) == decl)
  	    {
  	      TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0);
! 	      TREE_OPERAND (t, 0) = decl;
  	      break;
  	    }
  	case MINUS_EXPR:
  	  gcc_assert (TREE_OPERAND (t, 0) == decl);
  	  break;
  	default:
  	  gcc_unreachable ();
--- 5155,5168 ----
  	  if (TREE_OPERAND (t, 1) == decl)
  	    {
  	      TREE_OPERAND (t, 1) = TREE_OPERAND (t, 0);
! 	      TREE_OPERAND (t, 0) = var;
  	      break;
  	    }
+ 
+ 	  /* Fallthru.  */
  	case MINUS_EXPR:
  	  gcc_assert (TREE_OPERAND (t, 0) == decl);
+ 	  TREE_OPERAND (t, 0) = var;
  	  break;
  	default:
  	  gcc_unreachable ();
*************** gimplify_omp_for (tree *expr_p, tree *pr
*** 5155,5161 ****
        gcc_unreachable ();
      }
  
!   gimplify_to_stmt_list (&OMP_FOR_BODY (for_stmt));
    gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt));
  
    return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR;
--- 5176,5188 ----
        gcc_unreachable ();
      }
  
!   body = OMP_FOR_BODY (for_stmt);
!   gimplify_to_stmt_list (&body);
!   t = alloc_stmt_list ();
!   if (init_decl)
!     append_to_statement_list (init_decl, &t);
!   append_to_statement_list (body, &t);
!   OMP_FOR_BODY (for_stmt) = t;
    gimplify_adjust_omp_clauses (&OMP_FOR_CLAUSES (for_stmt));
  
    return ret == GS_ALL_DONE ? GS_ALL_DONE : GS_ERROR;
*************** force_gimple_operand (tree expr, tree *s
*** 6550,6558 ****
    if (var)
      expr = build_gimple_modify_stmt (var, expr);
  
!   ret = gimplify_expr (&expr, stmts, NULL,
! 		       gimple_test_f, fb_rvalue);
!   gcc_assert (ret != GS_ERROR);
  
    if (gimple_referenced_vars (cfun))
      {
--- 6577,6594 ----
    if (var)
      expr = build_gimple_modify_stmt (var, expr);
  
!   if (TREE_CODE (expr) != GIMPLE_MODIFY_STMT
!       && TREE_TYPE (expr) == void_type_node)
!     {
!       gimplify_and_add (expr, stmts);
!       expr = NULL_TREE;
!     }
!   else
!     {
!       ret = gimplify_expr (&expr, stmts, NULL,
! 			   gimple_test_f, fb_rvalue);
!       gcc_assert (ret != GS_ERROR);
!     }
  
    if (gimple_referenced_vars (cfun))
      {
Index: tree-predcom.c
===================================================================
*** tree-predcom.c	(revision 127626)
--- tree-predcom.c	(working copy)
*************** mark_virtual_ops_for_renaming (tree stmt
*** 1393,1399 ****
    tree var;
  
    if (TREE_CODE (stmt) == PHI_NODE)
!     return;
  
    update_stmt (stmt);
  
--- 1393,1408 ----
    tree var;
  
    if (TREE_CODE (stmt) == PHI_NODE)
!     {
!       var = PHI_RESULT (stmt);
!       if (is_gimple_reg (var))
! 	return;
! 
!       if (TREE_CODE (var) == SSA_NAME)
! 	var = SSA_NAME_VAR (var);
!       mark_sym_for_renaming (var);
!       return;
!     }
  
    update_stmt (stmt);
  
Index: common.opt
===================================================================
*** common.opt	(revision 127626)
--- common.opt	(working copy)
*************** fomit-frame-pointer
*** 703,708 ****
--- 703,712 ----
  Common Report Var(flag_omit_frame_pointer) Optimization
  When possible do not generate stack frames
  
+ fopenmp-ssa
+ Common Report Var(flag_openmp_ssa)
+ Expand OpenMP operations on SSA form
+ 
  foptimize-register-move
  Common Report Var(flag_regmove) Optimization
  Do the full register move optimization pass
Index: tree-inline.c
===================================================================
*** tree-inline.c	(revision 127626)
--- tree-inline.c	(working copy)
*************** push_cfun (struct function *new_cfun)
*** 2325,2336 ****
--- 2325,2341 ----
  {
    VEC_safe_push (function_p, heap, cfun_stack, cfun);
    cfun = new_cfun;
+   current_function_decl = new_cfun->decl;
  }
  
  void
  pop_cfun (void)
  {
    cfun = VEC_pop (function_p, cfun_stack);
+   if (cfun)
+     current_function_decl = cfun->decl;
+   else
+     current_function_decl = NULL_TREE;
  }
  
  /* Install new lexical TREE_BLOCK underneath 'current_block'.  */
Index: tree-flow.h
===================================================================
*** tree-flow.h	(revision 127626)
--- tree-flow.h	(working copy)
*************** extern struct omp_region *root_omp_regio
*** 715,720 ****
--- 715,722 ----
  extern struct omp_region *new_omp_region (basic_block, enum tree_code,
  					  struct omp_region *);
  extern void free_omp_regions (void);
+ extern tree find_omp_clause (tree, enum tree_code);
+ tree copy_var_decl (tree, tree, tree);
  
  /*---------------------------------------------------------------------------
  			      Function prototypes
Index: Makefile.in
===================================================================
*** Makefile.in	(revision 127626)
--- Makefile.in	(working copy)
*************** tree-cfg.o : tree-cfg.c $(TREE_FLOW_H) $
*** 2074,2080 ****
     $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
     $(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \
     $(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h toplev.h \
!    tree-ssa-propagate.h
  tree-cfgcleanup.o : tree-cfgcleanup.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
     $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
     $(DIAGNOSTIC_H) toplev.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
--- 2074,2080 ----
     $(DIAGNOSTIC_H) $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
     $(TREE_DUMP_H) except.h langhooks.h $(CFGLOOP_H) tree-pass.h \
     $(CFGLAYOUT_H) $(BASIC_BLOCK_H) hard-reg-set.h toplev.h \
!    tree-ssa-propagate.h $(TREE_INLINE_H)
  tree-cfgcleanup.o : tree-cfgcleanup.c $(TREE_FLOW_H) $(CONFIG_H) $(SYSTEM_H) \
     $(RTL_H) $(TREE_H) $(TM_P_H) $(EXPR_H) $(GGC_H) $(FLAGS_H) output.h \
     $(DIAGNOSTIC_H) toplev.h $(FUNCTION_H) $(TIMEVAR_H) $(TM_H) coretypes.h \
Index: tree-cfg.c
===================================================================
*** tree-cfg.c	(revision 127626)
--- tree-cfg.c	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 46,51 ****
--- 46,52 ----
  #include "tree-ssa-propagate.h"
  #include "value-prof.h"
  #include "pointer-set.h"
+ #include "tree-inline.h"
  
  /* This file contains functions for building the Control Flow Graph (CFG)
     for a function tree.  */
*************** gather_blocks_in_sese_region (basic_bloc
*** 5258,5270 ****
      }
  }
  
  
  struct move_stmt_d
  {
    tree block;
    tree from_context;
    tree to_context;
!   bitmap vars_to_remove;
    htab_t new_label_map;
    bool remap_decls_p;
  };
--- 5259,5347 ----
      }
  }
  
+ /* Replaces *TP with a duplicate (belonging to function TO_CONTEXT).
+    The duplicates are recorded in VARS_MAP.  */
+ 
+ static void
+ replace_by_duplicate_decl (tree *tp, struct pointer_map_t *vars_map,
+ 			   tree to_context)
+ {
+   tree t = *tp, new_t;
+   struct function *f = DECL_STRUCT_FUNCTION (to_context);
+   void **loc;
+ 
+   if (DECL_CONTEXT (t) == to_context)
+     return;
+ 
+   loc = pointer_map_contains (vars_map, t);
+ 
+   if (!loc)
+     {
+       loc = pointer_map_insert (vars_map, t);
+ 
+       if (SSA_VAR_P (t))
+ 	{
+ 	  new_t = copy_var_decl (t, DECL_NAME (t), TREE_TYPE (t));
+ 	  f->unexpanded_var_list
+ 		  = tree_cons (NULL_TREE, new_t, f->unexpanded_var_list);
+ 	}
+       else
+ 	{
+ 	  gcc_assert (TREE_CODE (t) == CONST_DECL);
+ 	  new_t = copy_node (t);
+ 	}
+       DECL_CONTEXT (new_t) = to_context;
+ 
+       *loc = new_t;
+     }
+   else
+     new_t = *loc;
+ 
+   *tp = new_t;
+ }
+ 
+ /* Creates an ssa name in TO_CONTEXT equivalent to NAME.
+    VARS_MAP maps old ssa names and var_decls to the new ones.  */
+ 
+ static tree
+ replace_ssa_name (tree name, struct pointer_map_t *vars_map,
+ 		  tree to_context)
+ {
+   void **loc;
+   tree new_name, decl = SSA_NAME_VAR (name);
+ 
+   gcc_assert (is_gimple_reg (name));
+ 
+   loc = pointer_map_contains (vars_map, name);
+ 
+   if (!loc)
+     {
+       replace_by_duplicate_decl (&decl, vars_map, to_context);
+ 
+       push_cfun (DECL_STRUCT_FUNCTION (to_context));
+       if (gimple_in_ssa_p (cfun))
+ 	add_referenced_var (decl);
+ 
+       new_name = make_ssa_name (decl, SSA_NAME_DEF_STMT (name));
+       if (SSA_NAME_IS_DEFAULT_DEF (name))
+ 	set_default_def (decl, new_name);
+       pop_cfun ();
+ 
+       loc = pointer_map_insert (vars_map, name);
+       *loc = new_name;
+     }
+   else
+     new_name = *loc;
+ 
+   return new_name;
+ }
  
  struct move_stmt_d
  {
    tree block;
    tree from_context;
    tree to_context;
!   struct pointer_map_t *vars_map;
    htab_t new_label_map;
    bool remap_decls_p;
  };
*************** move_stmt_r (tree *tp, int *walk_subtree
*** 5299,5307 ****
  
        p->remap_decls_p = save_remap_decls_p;
      }
!   else if (DECL_P (t) && DECL_CONTEXT (t) == p->from_context)
      {
!       if (TREE_CODE (t) == LABEL_DECL)
  	{
  	  if (p->new_label_map)
  	    {
--- 5376,5386 ----
  
        p->remap_decls_p = save_remap_decls_p;
      }
!   else if (DECL_P (t) || TREE_CODE (t) == SSA_NAME)
      {
!       if (TREE_CODE (t) == SSA_NAME)
! 	*tp = replace_ssa_name (t, p->vars_map, p->to_context);
!       else if (TREE_CODE (t) == LABEL_DECL)
  	{
  	  if (p->new_label_map)
  	    {
*************** move_stmt_r (tree *tp, int *walk_subtree
*** 5316,5335 ****
  	}
        else if (p->remap_decls_p)
  	{
! 	  DECL_CONTEXT (t) = p->to_context;
! 
! 	  if (TREE_CODE (t) == VAR_DECL)
  	    {
! 	      struct function *f = DECL_STRUCT_FUNCTION (p->to_context);
! 	      f->unexpanded_var_list
! 		= tree_cons (0, t, f->unexpanded_var_list);
! 
! 	      /* Mark T to be removed from the original function,
! 	         otherwise it will be given a DECL_RTL when the
! 		 original function is expanded.  */
! 	      bitmap_set_bit (p->vars_to_remove, DECL_UID (t));
  	    }
  	}
      }
    else if (TYPE_P (t))
      *walk_subtrees = 0;
--- 5395,5420 ----
  	}
        else if (p->remap_decls_p)
  	{
! 	  /* Replace T with its duplicate.  T should no longer appear in the
! 	     parent function, so this looks wasteful; however, it may appear
! 	     in referenced_vars, and more importantly, as virtual operands of
! 	     statements, and in alias lists of other variables.  It would be
! 	     quite difficult to expunge it from all those places.  ??? It might
! 	     suffice to do this for addressable variables.  */
! 	  if ((TREE_CODE (t) == VAR_DECL
! 	       && !is_global_var (t))
! 	      || TREE_CODE (t) == CONST_DECL)
! 	    replace_by_duplicate_decl (tp, p->vars_map, p->to_context);
! 	  
! 	  if (SSA_VAR_P (t)
! 	      && gimple_in_ssa_p (cfun))
  	    {
! 	      push_cfun (DECL_STRUCT_FUNCTION (p->to_context));
! 	      add_referenced_var (*tp);
! 	      pop_cfun ();
  	    }
  	}
+       *walk_subtrees = 0;
      }
    else if (TYPE_P (t))
      *walk_subtrees = 0;
*************** move_stmt_r (tree *tp, int *walk_subtree
*** 5337,5342 ****
--- 5422,5447 ----
    return NULL_TREE;
  }
  
+ /* Marks virtual operands of all statements in basic blocks BBS for
+    renaming.  */
+ 
+ static void
+ mark_virtual_ops_in_region (VEC (basic_block,heap) *bbs)
+ {
+   tree phi;
+   block_stmt_iterator bsi;
+   basic_block bb;
+   unsigned i;
+ 
+   for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
+     {
+       for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+ 	mark_virtual_ops_for_renaming (phi);
+ 
+       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
+ 	mark_virtual_ops_for_renaming (bsi_stmt (bsi));
+     }
+ }
  
  /* Move basic block BB from function CFUN to function DEST_FN.  The
     block is moved out of the original linked list and placed after
*************** move_stmt_r (tree *tp, int *walk_subtree
*** 5345,5357 ****
     If UPDATE_EDGE_COUNT_P is true, the edge counts on both CFGs is
     updated to reflect the moved edges.
  
!    On exit, local variables that need to be removed from
!    CFUN->UNEXPANDED_VAR_LIST will have been added to VARS_TO_REMOVE.  */
  
  static void
  move_block_to_fn (struct function *dest_cfun, basic_block bb,
  		  basic_block after, bool update_edge_count_p,
! 		  bitmap vars_to_remove, htab_t new_label_map, int eh_offset)
  {
    struct control_flow_graph *cfg;
    edge_iterator ei;
--- 5450,5463 ----
     If UPDATE_EDGE_COUNT_P is true, the edge counts on both CFGs is
     updated to reflect the moved edges.
  
!    The local variables are remapped to new instances, VARS_MAP is used
!    to record the mapping.  */
  
  static void
  move_block_to_fn (struct function *dest_cfun, basic_block bb,
  		  basic_block after, bool update_edge_count_p,
! 		  struct pointer_map_t *vars_map, htab_t new_label_map,
! 		  int eh_offset)
  {
    struct control_flow_graph *cfg;
    edge_iterator ei;
*************** move_block_to_fn (struct function *dest_
*** 5359,5364 ****
--- 5465,5471 ----
    block_stmt_iterator si;
    struct move_stmt_d d;
    unsigned old_len, new_len;
+   tree phi;
  
    /* Remove BB from dominance structures.  */
    delete_from_dominance_info (CDI_DOMINATORS, bb);
*************** move_block_to_fn (struct function *dest_
*** 5395,5414 ****
    VEC_replace (basic_block, cfg->x_basic_block_info,
                 bb->index, bb);
  
    /* The statements in BB need to be associated with a new TREE_BLOCK.
       Labels need to be associated with a new label-to-block map.  */
    memset (&d, 0, sizeof (d));
!   d.vars_to_remove = vars_to_remove;
  
    for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
      {
        tree stmt = bsi_stmt (si);
        int region;
  
-       d.from_context = cfun->decl;
-       d.to_context = dest_cfun->decl;
        d.remap_decls_p = true;
-       d.new_label_map = new_label_map;
        if (TREE_BLOCK (stmt))
  	d.block = DECL_INITIAL (dest_cfun->decl);
  
--- 5502,5540 ----
    VEC_replace (basic_block, cfg->x_basic_block_info,
                 bb->index, bb);
  
+   /* Remap the variables in phi nodes.  */
+   for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
+     {
+       use_operand_p use;
+       tree op = PHI_RESULT (phi);
+       ssa_op_iter oi;
+ 
+       if (!is_gimple_reg (op))
+ 	continue;
+ 
+       SET_PHI_RESULT (phi, replace_ssa_name (op, vars_map, dest_cfun->decl));
+       FOR_EACH_PHI_ARG (use, phi, oi, SSA_OP_USE)
+ 	{
+ 	  op = USE_FROM_PTR (use);
+ 	  if (TREE_CODE (op) == SSA_NAME)
+ 	    SET_USE (use, replace_ssa_name (op, vars_map, dest_cfun->decl));
+ 	}
+     }
+ 
    /* The statements in BB need to be associated with a new TREE_BLOCK.
       Labels need to be associated with a new label-to-block map.  */
    memset (&d, 0, sizeof (d));
!   d.vars_map = vars_map;
!   d.from_context = cfun->decl;
!   d.to_context = dest_cfun->decl;
!   d.new_label_map = new_label_map;
  
    for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
      {
        tree stmt = bsi_stmt (si);
        int region;
  
        d.remap_decls_p = true;
        if (TREE_BLOCK (stmt))
  	d.block = DECL_INITIAL (dest_cfun->decl);
  
*************** move_block_to_fn (struct function *dest_
*** 5451,5456 ****
--- 5577,5584 ----
  	  gimple_duplicate_stmt_histograms (dest_cfun, stmt, cfun, stmt);
            gimple_remove_stmt_histograms (cfun, stmt);
  	}
+ 
+       update_stmt (stmt);
      }
  }
  
*************** basic_block
*** 5528,5548 ****
  move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
  		        basic_block exit_bb)
  {
!   VEC(basic_block,heap) *bbs;
!   basic_block after, bb, *entry_pred, *exit_succ;
!   struct function *saved_cfun;
    int *entry_flag, *exit_flag, eh_offset;
    unsigned i, num_entry_edges, num_exit_edges;
    edge e;
    edge_iterator ei;
-   bitmap vars_to_remove;
    htab_t new_label_map;
! 
!   saved_cfun = cfun;
! 
!   /* Collect all the blocks in the region.  Manually add ENTRY_BB
!      because it won't be added by dfs_enumerate_from.  */
!   calculate_dominance_info (CDI_DOMINATORS);
  
    /* If ENTRY does not strictly dominate EXIT, this cannot be an SESE
       region.  */
--- 5656,5672 ----
  move_sese_region_to_fn (struct function *dest_cfun, basic_block entry_bb,
  		        basic_block exit_bb)
  {
!   VEC(basic_block,heap) *bbs, *dom_bbs;
!   basic_block dom_entry = get_immediate_dominator (CDI_DOMINATORS, entry_bb);
!   basic_block after, bb, *entry_pred, *exit_succ, abb;
!   struct function *saved_cfun = cfun;
    int *entry_flag, *exit_flag, eh_offset;
+   unsigned *entry_prob, *exit_prob;
    unsigned i, num_entry_edges, num_exit_edges;
    edge e;
    edge_iterator ei;
    htab_t new_label_map;
!   struct pointer_map_t *vars_map;
  
    /* If ENTRY does not strictly dominate EXIT, this cannot be an SESE
       region.  */
*************** move_sese_region_to_fn (struct function 
*** 5550,5559 ****
--- 5674,5691 ----
                && (!exit_bb
  		  || dominated_by_p (CDI_DOMINATORS, exit_bb, entry_bb)));
  
+   /* Collect all the blocks in the region.  Manually add ENTRY_BB
+      because it won't be added by dfs_enumerate_from.  */
    bbs = NULL;
    VEC_safe_push (basic_block, heap, bbs, entry_bb);
    gather_blocks_in_sese_region (entry_bb, exit_bb, &bbs);
  
+   /* The blocks that used to be dominated by something in BBS will now be
+      dominated by the new block.  */
+   dom_bbs = get_dominated_by_region (CDI_DOMINATORS,
+ 				     VEC_address (basic_block, bbs),
+ 				     VEC_length (basic_block, bbs));
+ 
    /* Detach ENTRY_BB and EXIT_BB from CFUN->CFG.  We need to remember
       the predecessor edges to ENTRY_BB and the successor edges to
       EXIT_BB so that we can re-attach them to the new basic block that
*************** move_sese_region_to_fn (struct function 
*** 5561,5569 ****
--- 5693,5703 ----
    num_entry_edges = EDGE_COUNT (entry_bb->preds);
    entry_pred = (basic_block *) xcalloc (num_entry_edges, sizeof (basic_block));
    entry_flag = (int *) xcalloc (num_entry_edges, sizeof (int));
+   entry_prob = XNEWVEC (unsigned, num_entry_edges);
    i = 0;
    for (ei = ei_start (entry_bb->preds); (e = ei_safe_edge (ei)) != NULL;)
      {
+       entry_prob[i] = e->probability;
        entry_flag[i] = e->flags;
        entry_pred[i++] = e->src;
        remove_edge (e);
*************** move_sese_region_to_fn (struct function 
*** 5575,5583 ****
--- 5709,5719 ----
        exit_succ = (basic_block *) xcalloc (num_exit_edges,
  					   sizeof (basic_block));
        exit_flag = (int *) xcalloc (num_exit_edges, sizeof (int));
+       exit_prob = XNEWVEC (unsigned, num_exit_edges);
        i = 0;
        for (ei = ei_start (exit_bb->succs); (e = ei_safe_edge (ei)) != NULL;)
  	{
+ 	  exit_prob[i] = e->probability;
  	  exit_flag[i] = e->flags;
  	  exit_succ[i++] = e->dest;
  	  remove_edge (e);
*************** move_sese_region_to_fn (struct function 
*** 5588,5598 ****
        num_exit_edges = 0;
        exit_succ = NULL;
        exit_flag = NULL;
      }
  
    /* Switch context to the child function to initialize DEST_FN's CFG.  */
    gcc_assert (dest_cfun->cfg == NULL);
!   cfun = dest_cfun;
  
    init_empty_tree_cfg ();
  
--- 5724,5735 ----
        num_exit_edges = 0;
        exit_succ = NULL;
        exit_flag = NULL;
+       exit_prob = NULL;
      }
  
    /* Switch context to the child function to initialize DEST_FN's CFG.  */
    gcc_assert (dest_cfun->cfg == NULL);
!   push_cfun (dest_cfun);
  
    init_empty_tree_cfg ();
  
*************** move_sese_region_to_fn (struct function 
*** 5615,5660 ****
  	}
      }
  
!   cfun = saved_cfun;
  
    /* Move blocks from BBS into DEST_CFUN.  */
    gcc_assert (VEC_length (basic_block, bbs) >= 2);
    after = dest_cfun->cfg->x_entry_block_ptr;
!   vars_to_remove = BITMAP_ALLOC (NULL);
    for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
      {
        /* No need to update edge counts on the last block.  It has
  	 already been updated earlier when we detached the region from
  	 the original CFG.  */
!       move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, vars_to_remove,
  	                new_label_map, eh_offset);
        after = bb;
      }
  
    if (new_label_map)
      htab_delete (new_label_map);
! 
!   /* Remove the variables marked in VARS_TO_REMOVE from
!      CFUN->UNEXPANDED_VAR_LIST.  Otherwise, they will be given a
!      DECL_RTL in the context of CFUN.  */
!   if (!bitmap_empty_p (vars_to_remove))
!     {
!       tree *p;
! 
!       for (p = &cfun->unexpanded_var_list; *p; )
! 	{
! 	  tree var = TREE_VALUE (*p);
! 	  if (bitmap_bit_p (vars_to_remove, DECL_UID (var)))
! 	    {
! 	      *p = TREE_CHAIN (*p);
! 	      continue;
! 	    }
! 
! 	  p = &TREE_CHAIN (*p);
! 	}
!     }
! 
!   BITMAP_FREE (vars_to_remove);
  
    /* Rewire the entry and exit blocks.  The successor to the entry
       block turns into the successor of DEST_FN's ENTRY_BLOCK_PTR in
--- 5752,5781 ----
  	}
      }
  
!   pop_cfun ();
! 
!   /* The ssa form for virtual operands in the source function will have to
!      be repaired.  We do not care for the real operands -- the sese region
!      must be closed with respect to those.  */
!   mark_virtual_ops_in_region (bbs);
  
    /* Move blocks from BBS into DEST_CFUN.  */
    gcc_assert (VEC_length (basic_block, bbs) >= 2);
    after = dest_cfun->cfg->x_entry_block_ptr;
!   vars_map = pointer_map_create ();
    for (i = 0; VEC_iterate (basic_block, bbs, i, bb); i++)
      {
        /* No need to update edge counts on the last block.  It has
  	 already been updated earlier when we detached the region from
  	 the original CFG.  */
!       move_block_to_fn (dest_cfun, bb, after, bb != exit_bb, vars_map,
  	                new_label_map, eh_offset);
        after = bb;
      }
  
    if (new_label_map)
      htab_delete (new_label_map);
!   pointer_map_destroy (vars_map);
  
    /* Rewire the entry and exit blocks.  The successor to the entry
       block turns into the successor of DEST_FN's ENTRY_BLOCK_PTR in
*************** move_sese_region_to_fn (struct function 
*** 5665,5694 ****
  
       FIXME, this is silly.  The CFG ought to become a parameter to
       these helpers.  */
!   cfun = dest_cfun;
    make_edge (ENTRY_BLOCK_PTR, entry_bb, EDGE_FALLTHRU);
    if (exit_bb)
      make_edge (exit_bb,  EXIT_BLOCK_PTR, 0);
!   cfun = saved_cfun;
  
    /* Back in the original function, the SESE region has disappeared,
       create a new basic block in its place.  */
    bb = create_empty_bb (entry_pred[0]);
    for (i = 0; i < num_entry_edges; i++)
!     make_edge (entry_pred[i], bb, entry_flag[i]);
  
    for (i = 0; i < num_exit_edges; i++)
!     make_edge (bb, exit_succ[i], exit_flag[i]);
  
    if (exit_bb)
      {
        free (exit_flag);
        free (exit_succ);
      }
    free (entry_flag);
    free (entry_pred);
-   free_dominance_info (CDI_DOMINATORS);
-   free_dominance_info (CDI_POST_DOMINATORS);
    VEC_free (basic_block, heap, bbs);
  
    return bb;
--- 5786,5826 ----
  
       FIXME, this is silly.  The CFG ought to become a parameter to
       these helpers.  */
!   push_cfun (dest_cfun);
    make_edge (ENTRY_BLOCK_PTR, entry_bb, EDGE_FALLTHRU);
    if (exit_bb)
      make_edge (exit_bb,  EXIT_BLOCK_PTR, 0);
!   pop_cfun ();
  
    /* Back in the original function, the SESE region has disappeared,
       create a new basic block in its place.  */
    bb = create_empty_bb (entry_pred[0]);
    for (i = 0; i < num_entry_edges; i++)
!     {
!       e = make_edge (entry_pred[i], bb, entry_flag[i]);
!       e->probability = entry_prob[i];
!     }
  
    for (i = 0; i < num_exit_edges; i++)
!     {
!       e = make_edge (bb, exit_succ[i], exit_flag[i]);
!       e->probability = exit_prob[i];
!     }
! 
!   set_immediate_dominator (CDI_DOMINATORS, bb, dom_entry);
!   for (i = 0; VEC_iterate (basic_block, dom_bbs, i, abb); i++)
!     set_immediate_dominator (CDI_DOMINATORS, abb, bb);
!   VEC_free (basic_block, heap, dom_bbs);
  
    if (exit_bb)
      {
+       free (exit_prob);
        free (exit_flag);
        free (exit_succ);
      }
+   free (entry_prob);
    free (entry_flag);
    free (entry_pred);
    VEC_free (basic_block, heap, bbs);
  
    return bb;
Index: passes.c
===================================================================
*** passes.c	(revision 127626)
--- passes.c	(working copy)
*************** init_optimization_passes (void)
*** 515,520 ****
--- 515,521 ----
  	  NEXT_PASS (pass_referenced_vars);
  	  NEXT_PASS (pass_reset_cc_flags);
  	  NEXT_PASS (pass_build_ssa);
+ 	  NEXT_PASS (pass_expand_omp_ssa);
  	  NEXT_PASS (pass_early_warn_uninitialized);
  	  NEXT_PASS (pass_rebuild_cgraph_edges);
  	  NEXT_PASS (pass_early_inline);
Index: tree-ssa-operands.c
===================================================================
*** tree-ssa-operands.c	(revision 127626)
--- tree-ssa-operands.c	(working copy)
*************** get_expr_operands (tree stmt, tree *expr
*** 2177,2197 ****
        get_expr_operands (stmt, &CHANGE_DYNAMIC_TYPE_LOCATION (expr), opf_use);
        return;
  
      case BLOCK:
      case FUNCTION_DECL:
      case EXC_PTR_EXPR:
      case FILTER_EXPR:
      case LABEL_DECL:
      case CONST_DECL:
-     case OMP_PARALLEL:
-     case OMP_SECTIONS:
-     case OMP_FOR:
      case OMP_SINGLE:
      case OMP_MASTER:
      case OMP_ORDERED:
      case OMP_CRITICAL:
      case OMP_RETURN:
!     case OMP_CONTINUE:
        /* Expressions that make no memory references.  */
        return;
  
--- 2177,2248 ----
        get_expr_operands (stmt, &CHANGE_DYNAMIC_TYPE_LOCATION (expr), opf_use);
        return;
  
+     case OMP_FOR:
+       {
+ 	tree init = OMP_FOR_INIT (expr);
+ 	tree cond = OMP_FOR_COND (expr);
+ 	tree incr = OMP_FOR_INCR (expr);
+ 	tree c, clauses = OMP_FOR_CLAUSES (stmt);
+ 
+ 	get_expr_operands (stmt, &GIMPLE_STMT_OPERAND (init, 0), opf_def);
+ 	get_expr_operands (stmt, &GIMPLE_STMT_OPERAND (init, 1), opf_use);
+ 	get_expr_operands (stmt, &TREE_OPERAND (cond, 1), opf_use);
+ 	get_expr_operands (stmt, &TREE_OPERAND (GIMPLE_STMT_OPERAND (incr, 1), 1),
+ 			   opf_use);
+ 
+ 	c = find_omp_clause (clauses, OMP_CLAUSE_SCHEDULE);
+ 	if (c)
+ 	  get_expr_operands (stmt, &OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c),
+ 			     opf_use);
+ 	return;
+       }
+ 
+     case OMP_CONTINUE:
+       {
+ 	get_expr_operands (stmt, &TREE_OPERAND (expr, 0), opf_def);
+ 	get_expr_operands (stmt, &TREE_OPERAND (expr, 1), opf_use);
+ 	return;
+       }
+ 
+     case OMP_PARALLEL:
+       {
+ 	tree c, clauses = OMP_PARALLEL_CLAUSES (stmt);
+ 
+ 	if (OMP_PARALLEL_DATA_ARG (stmt))
+ 	  {
+ 	    get_expr_operands (stmt, &OMP_PARALLEL_DATA_ARG (stmt), opf_use);
+ 	    add_to_addressable_set (OMP_PARALLEL_DATA_ARG (stmt),
+ 				    &s_ann->addresses_taken);
+ 	  }
+ 
+ 	c = find_omp_clause (clauses, OMP_CLAUSE_IF);
+ 	if (c)
+ 	  get_expr_operands (stmt, &OMP_CLAUSE_IF_EXPR (c), opf_use);
+ 	c = find_omp_clause (clauses, OMP_CLAUSE_NUM_THREADS);
+ 	if (c)
+ 	  get_expr_operands (stmt, &OMP_CLAUSE_NUM_THREADS_EXPR (c), opf_use);
+ 	return;
+       }
+ 
+     case OMP_SECTIONS:
+       {
+ 	get_expr_operands (stmt, &OMP_SECTIONS_CONTROL (expr), opf_def);
+ 	return;
+       }
+ 
      case BLOCK:
      case FUNCTION_DECL:
      case EXC_PTR_EXPR:
      case FILTER_EXPR:
      case LABEL_DECL:
      case CONST_DECL:
      case OMP_SINGLE:
      case OMP_MASTER:
      case OMP_ORDERED:
      case OMP_CRITICAL:
      case OMP_RETURN:
!     case OMP_SECTION:
!     case OMP_SECTIONS_SWITCH:
        /* Expressions that make no memory references.  */
        return;
  

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [patch] Make OMP expansion work on SSA form
  2007-08-20 15:13 [patch] Make OMP expansion work on SSA form Zdenek Dvorak
@ 2007-08-29 15:20 ` Diego Novillo
  2007-08-30 17:46   ` Zdenek Dvorak
  0 siblings, 1 reply; 5+ messages in thread
From: Diego Novillo @ 2007-08-29 15:20 UTC (permalink / raw)
  To: Zdenek Dvorak; +Cc: gcc-patches

On 8/20/07 11:02 AM, Zdenek Dvorak wrote:

> One other change is that on the branch, we do the expansion of OMP
> constructs in SSA form when optimizing, so that the SSA form expansion
> code is tested; this patch does the expansion always without SSA form
> (unless you use newly introduced -fopenmp-ssa switch).  This is forced
> by some pass ordering problems (early optimization passes would not be
> run on the split functions if the expansion were done on SSA form).

I don't like this.  A new switch for doing OpenMP expansion in SSA form?
 Too confusing.  I realize that we need to expand OpenMP constructs in
SSA form and without SSA form (for -O0), but we should do this
automatically, not with a switch.

I'm reviewing the rest of the patch.  More feedback soon.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [patch] Make OMP expansion work on SSA form
  2007-08-29 15:20 ` Diego Novillo
@ 2007-08-30 17:46   ` Zdenek Dvorak
  2007-09-06 21:35     ` Diego Novillo
  0 siblings, 1 reply; 5+ messages in thread
From: Zdenek Dvorak @ 2007-08-30 17:46 UTC (permalink / raw)
  To: Diego Novillo; +Cc: gcc-patches

Hello,

> On 8/20/07 11:02 AM, Zdenek Dvorak wrote:
> 
> > One other change is that on the branch, we do the expansion of OMP
> > constructs in SSA form when optimizing, so that the SSA form expansion
> > code is tested; this patch does the expansion always without SSA form
> > (unless you use newly introduced -fopenmp-ssa switch).  This is forced
> > by some pass ordering problems (early optimization passes would not be
> > run on the split functions if the expansion were done on SSA form).
> 
> I don't like this.  A new switch for doing OpenMP expansion in SSA form?
>  Too confusing.  I realize that we need to expand OpenMP constructs in
> SSA form and without SSA form (for -O0), but we should do this
> automatically, not with a switch.

by default, the expansion is always done without ssa form, for the reasons I
explained.  I kept the possibility to force the expansion on ssa form
for testing purposes; I guess I can remove the switch, but I would
prefer to keep it at least for some time.

Zdenek

> I'm reviewing the rest of the patch.  More feedback soon.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [patch] Make OMP expansion work on SSA form
  2007-08-30 17:46   ` Zdenek Dvorak
@ 2007-09-06 21:35     ` Diego Novillo
  2007-09-06 22:56       ` Zdenek Dvorak
  0 siblings, 1 reply; 5+ messages in thread
From: Diego Novillo @ 2007-09-06 21:35 UTC (permalink / raw)
  To: Zdenek Dvorak; +Cc: gcc-patches

On 8/30/07, Zdenek Dvorak <rakdver@kam.mff.cuni.cz> wrote:

> for testing purposes; I guess I can remove the switch, but I would
> prefer to keep it at least for some time.

"Some time" meaning until you figure out the expansion problems you
mentioned in your original mail?

The code is not too much, so I guess it won't hurt.  But unless you
figure this problem out shortly, I'm afraid that it will just rot
away.  Isn't the whole purpose of the patch to expand OMP while in SSA
form?

I suppose that the main autoparallelization patch will require this, right?

The rest of the patch looks fine.  Thanks.

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [patch] Make OMP expansion work on SSA form
  2007-09-06 21:35     ` Diego Novillo
@ 2007-09-06 22:56       ` Zdenek Dvorak
  0 siblings, 0 replies; 5+ messages in thread
From: Zdenek Dvorak @ 2007-09-06 22:56 UTC (permalink / raw)
  To: Diego Novillo; +Cc: gcc-patches

Hello,

> The code is not too much, so I guess it won't hurt.  But unless you
> figure this problem out shortly, I'm afraid that it will just rot
> away.  Isn't the whole purpose of the patch to expand OMP while in SSA
> form?
> 
> I suppose that the main autoparallelization patch will require this, right?

yes, the reason is that in autoparallelization, we need to be able to
expand the omp trees while in SSA form.

I do not really have any strong preference regarding whether the main
omp expansion pass (pass_expand_omp) should run on SSA form or not.  As
we need to expand omp at -O0, at least in this case it has to be run out
of SSA.  With optimizations, we have choice between running the
expansion on SSA form or without (neither of them has any particular
advantages or disadvantages).

> > for testing purposes; I guess I can remove the switch, but I would
> > prefer to keep it at least for some time.
> 
> "Some time" meaning until you figure out the expansion problems you
> mentioned in your original mail?

I perhaps was not clear; I do not know about any expansion problems.
However, there are some pass ordering problems (early optimizations are
not run for the extracted functions).

I ment the flag mostly for the case someone fixes/changes something in
omp expansion code; we then need to test the change both for SSA
expansion and out of SSA expansion.

One way would of course be not to have this special flag and to do the
expansion on SSA with optimizations enabled.  This needs some hacks
in pass manager, though.

Thanks for review, I will send followup patches ASAP.

Zdenek

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2007-09-06 21:59 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-08-20 15:13 [patch] Make OMP expansion work on SSA form Zdenek Dvorak
2007-08-29 15:20 ` Diego Novillo
2007-08-30 17:46   ` Zdenek Dvorak
2007-09-06 21:35     ` Diego Novillo
2007-09-06 22:56       ` Zdenek Dvorak

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).