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


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

[gomp3] lastprivate fixes


Hi!

The following patch fixes lastprivate iteration variables which, if they
weren't the actual iteration vars used in the loop, but computed at the
start of loop body, weren't incremented for the last time before copying.
I had to move lastprivate clauses for the iterator from OMP_PARALLEL to OMP_FOR
for combined parallels, as the new lastprivate statements need to be
gimplified/walked in the context of the OMP_FOR, but given that the iterator
must not be firstprivate, that isn't a problem.  In addition to this it
fixes e.g. walking of OMP_CLAUSE_REDUCTION_* in tree-nested.c.
lastprivate now works properly even with C++ random access iterators,
Fortran iterators for complex do loops (non-1/-1 step), or when the iterator
isn't a gimple var and the gimplifier replaces them.

Most of this might be backportable to 4.3 eventually (except of course the
bits that deal with random access iterators), as it fixes several bugs that
even trunk exhibits on OpenMP 2.5ish code.

Regtested on x86_64-linux, committed to gomp-3_0-branch.

2008-02-15  Jakub Jelinek  <jakub@redhat.com>

	* tree.h (OMP_CLAUSE_LASTPRIVATE_STMT): Define.
	* tree.c (omp_clause_num_ops): Increase OMP_CLAUSE_LASTPRIVATE num_ops
	to 2.
	(walk_tree_1): Walk OMP_CLAUSE_LASTPRIVATE_STMT.
	* omp-low.c (scan_sharing_clauses): Scan
	OMP_CLAUSE_LASTPRIVATE_STMT.
	(lower_lastprivate_clauses): Even if some lastprivate is found on a
	work-sharing construct, continue looking for them on parent parallel
	construct.
	* gimplify.c (gimplify_scan_omp_clauses): Handle
	OMP_CLAUSE_LASTPRIVATE_STMT.
	(gimplify_omp_for): If loop counter has been replaced and original
	iterator is present in lastprivate clause, set
	OMP_CLAUSE_LASTPRIVATE_STMT.
	* tree-nested.c (convert_nonlocal_omp_clauses,
	convert_local_omp_clauses): Handle OMP_CLAUSE_LASTPRIVATE_STMT,
	OMP_CLAUSE_REDUCTION_INIT and OMP_CLAUSE_REDUCTION_MERGE.
	Don't do about TREE_STATIC or DECL_EXTERNAL VAR_DECLs in
	OMP_CLAUSE_DECL.
	* c-parser.c (c_parser_omp_clause_collapse): Don't clear
	OMP_CLAUSE_COLLAPSE_ITERVAR and OMP_CLAUSE_COLLAPSE_COUNT.
	(c_parser_omp_for_loop): Add par_clauses argument.  If decl is
	present in parallel's lastprivate clause, change it to shared
	and add lastprivate clause for decl to OMP_FOR_CLAUSES.
	(c_parser_omp_for, c_parser_omp_parallel): Adjust
	c_parser_omp_for_loop callers.

	* cp-tree.h (finish_omp_for): Add new clauses argument.
	* cp-gimplify.c (cp_genericize_r): Walk OMP_CLAUSE_LASTPRIVATE_STMT.
	* pt.c (tsubst_omp_clauses): Handle OMP_CLAUSE_LASTPRIVATE_STMT.
	(tsubst_expr) <case OMP_FOR>: Fix wording of error messages.  Call
	finish_omp_clauses on the newly added OMP_CLAUSE_PRIVATE.  Adjust
	finish_omp_for caller, don't set OMP_FOR_CLAUSES here.
	* semantics.c (finish_omp_for): Add new clauses argument.  Fix check
	for type dependent cond or incr.  Set OMP_FOR_CLAUSES to clauses.
	Use cp_convert instead of fold_convert to convert incr amount to
	difference_type.  Only fold if not in template.  If decl is
	mentioned in lastprivate clause, set OMP_CLAUSE_LASTPRIVATE_STMT.
	* parser.c (cp_parser_omp_clause_collapse): Don't clear
	OMP_CLAUSE_COLLAPSE_ITERVAR and OMP_CLAUSE_COLLAPSE_COUNT.
	(cp_parser_omp_for_loop): Add par_clauses argument.  If decl is
	present in parallel's lastprivate clause, change that clause to
	shared and add a lastprivate clause for decl to OMP_FOR_CLAUSES.
	Fix wording of error messages.  Adjust finish_omp_for caller, don't
	set OMP_FOR_CLAUSES here.
	(cp_parser_omp_for, cp_parser_omp_parallel): Adjust
	cp_parser_omp_for_loop callers.

	* trans-openmp.c (gfc_trans_omp_clauses): Don't clear
	OMP_CLAUSE_COLLAPSE_ITERVAR and OMP_CLAUSE_COLLAPSE_COUNT.
	(gfc_trans_omp_do): Add par_clauses argument.  If dovar is
	present in lastprivate clause and do loop isn't simple,
	set OMP_CLAUSE_LASTPRIVATE_STMT.  If dovar is present in
	parallel's lastprivate clause, change it to shared and add
	lastprivate clause to OMP_FOR_CLAUSES.
	(gfc_trans_omp_parallel_do, gfc_trans_omp_directive): Adjust
	gfc_trans_omp_do callers.

	* testsuite/libgomp.c/nestedfn-6.c: New test.
	* testsuite/libgomp.c++/for-5.C: New test.
	* testsuite/libgomp.fortran/nestedfn4.f90: New test.
	* testsuite/libgomp.fortran/collapse3.f90: Uncomment tests for
	lastprivate values, make sure all iterators are in lastprivate
	clauses.
	* testsuite/libgomp.fortran/lastprivate1.f90: New test.
	* testsuite/libgomp.fortran/lastprivate2.f90: New test.

--- gcc/tree.c	(revision 132090)
+++ gcc/tree.c	(working copy)
@@ -177,7 +177,7 @@ unsigned const char omp_clause_num_ops[]
   1, /* OMP_CLAUSE_PRIVATE  */
   1, /* OMP_CLAUSE_SHARED  */
   1, /* OMP_CLAUSE_FIRSTPRIVATE  */
-  1, /* OMP_CLAUSE_LASTPRIVATE  */
+  2, /* OMP_CLAUSE_LASTPRIVATE  */
   4, /* OMP_CLAUSE_REDUCTION  */
   1, /* OMP_CLAUSE_COPYIN  */
   1, /* OMP_CLAUSE_COPYPRIVATE  */
@@ -8507,7 +8507,6 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 	case OMP_CLAUSE_PRIVATE:
 	case OMP_CLAUSE_SHARED:
 	case OMP_CLAUSE_FIRSTPRIVATE:
-	case OMP_CLAUSE_LASTPRIVATE:
 	case OMP_CLAUSE_COPYIN:
 	case OMP_CLAUSE_COPYPRIVATE:
 	case OMP_CLAUSE_IF:
@@ -8522,6 +8521,11 @@ walk_tree_1 (tree *tp, walk_tree_fn func
 	case OMP_CLAUSE_UNTIED:
 	  WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
 
+	case OMP_CLAUSE_LASTPRIVATE:
+	  WALK_SUBTREE (OMP_CLAUSE_DECL (*tp));
+	  WALK_SUBTREE (OMP_CLAUSE_LASTPRIVATE_STMT (*tp));
+	  WALK_SUBTREE_TAIL (OMP_CLAUSE_CHAIN (*tp));
+
 	case OMP_CLAUSE_COLLAPSE:
 	  {
 	    int i;
--- gcc/tree.h	(revision 132090)
+++ gcc/tree.h	(working copy)
@@ -1817,6 +1817,10 @@ struct tree_constructor GTY(())
    decl is present in the chain.  */
 #define OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE(NODE) \
   TREE_PUBLIC (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LASTPRIVATE))
+#define OMP_CLAUSE_LASTPRIVATE_STMT(NODE) \
+  OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE,			\
+						OMP_CLAUSE_LASTPRIVATE),\
+		      1)
 
 #define OMP_CLAUSE_IF_EXPR(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_IF), 0)
--- gcc/omp-low.c	(revision 132255)
+++ gcc/omp-low.c	(working copy)
@@ -1150,6 +1150,8 @@ scan_sharing_clauses (tree clauses, omp_
 	case OMP_CLAUSE_LASTPRIVATE:
 	  /* Let the corresponding firstprivate clause create
 	     the variable.  */
+	  if (OMP_CLAUSE_LASTPRIVATE_STMT (c))
+	    scan_array_reductions = true;
 	  if (OMP_CLAUSE_LASTPRIVATE_FIRSTPRIVATE (c))
 	    break;
 	  /* FALLTHRU */
@@ -1199,6 +1201,9 @@ scan_sharing_clauses (tree clauses, omp_
 	  scan_omp (&OMP_CLAUSE_REDUCTION_INIT (c), ctx);
 	  scan_omp (&OMP_CLAUSE_REDUCTION_MERGE (c), ctx);
 	}
+      else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+	       && OMP_CLAUSE_LASTPRIVATE_STMT (c))
+	scan_omp (&OMP_CLAUSE_LASTPRIVATE_STMT (c), ctx);
 }
 
 /* Create a new name for omp child function.  Returns an identifier.  */
@@ -2007,9 +2012,10 @@ lower_rec_input_clauses (tree clauses, t
 
 static void
 lower_lastprivate_clauses (tree clauses, tree predicate, tree *stmt_list,
-			    omp_context *ctx)
+			   omp_context *ctx)
 {
   tree sub_list, x, c;
+  bool par_clauses = false;
 
   /* Early exit if there are no lastprivate clauses.  */
   clauses = find_omp_clause (clauses, OMP_CLAUSE_LASTPRIVATE);
@@ -2029,25 +2035,47 @@ lower_lastprivate_clauses (tree clauses,
 				 OMP_CLAUSE_LASTPRIVATE);
       if (clauses == NULL)
 	return;
+      par_clauses = true;
     }
 
   sub_list = alloc_stmt_list ();
 
-  for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+  for (c = clauses; c ;)
     {
       tree var, new_var;
 
-      if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_LASTPRIVATE)
-	continue;
+      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
+	{
+	  var = OMP_CLAUSE_DECL (c);
+	  new_var = lookup_decl (var, ctx);
 
-      var = OMP_CLAUSE_DECL (c);
-      new_var = lookup_decl (var, ctx);
+	  if (OMP_CLAUSE_LASTPRIVATE_STMT (c))
+	    gimplify_and_add (OMP_CLAUSE_LASTPRIVATE_STMT (c), &sub_list);
+	  OMP_CLAUSE_LASTPRIVATE_STMT (c) = NULL;
 
-      x = build_outer_var_ref (var, ctx);
-      if (is_reference (var))
-	new_var = build_fold_indirect_ref (new_var);
-      x = lang_hooks.decls.omp_clause_assign_op (c, x, new_var);
-      append_to_statement_list (x, &sub_list);
+	  x = build_outer_var_ref (var, ctx);
+	  if (is_reference (var))
+	    new_var = build_fold_indirect_ref (new_var);
+	  x = lang_hooks.decls.omp_clause_assign_op (c, x, new_var);
+	  append_to_statement_list (x, &sub_list);
+	}
+      c = OMP_CLAUSE_CHAIN (c);
+      if (c == NULL && !par_clauses)
+	{
+	  /* If this was a workshare clause, see if it had been combined
+	     with its parallel.  In that case, continue looking for the
+	     clauses also on the parallel statement itself.  */
+	  if (is_parallel_ctx (ctx))
+	    break;
+
+	  ctx = ctx->outer;
+	  if (ctx == NULL || !is_parallel_ctx (ctx))
+	    break;
+
+	  c = find_omp_clause (OMP_PARALLEL_CLAUSES (ctx->stmt),
+			       OMP_CLAUSE_LASTPRIVATE);
+	  par_clauses = true;
+	}
     }
 
   if (predicate)
--- gcc/cp/cp-tree.h	(revision 132166)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -4663,7 +4663,7 @@ extern tree finish_omp_parallel			(tree,
 extern tree begin_omp_task			(void);
 extern tree finish_omp_task			(tree, tree);
 extern tree finish_omp_for			(location_t, tree, tree,
-						 tree, tree, tree, tree);
+						 tree, tree, tree, tree, tree);
 extern void finish_omp_atomic			(enum tree_code, tree, tree);
 extern void finish_omp_barrier			(void);
 extern void finish_omp_flush			(void);
--- gcc/cp/cp-gimplify.c	(revision 132166)
+++ gcc/cp/cp-gimplify.c	(working copy)
@@ -673,10 +673,19 @@ cp_genericize_r (tree *stmt_p, int *walk
   else if (TREE_CODE (stmt) == OMP_CLAUSE)
     switch (OMP_CLAUSE_CODE (stmt))
       {
+      case OMP_CLAUSE_LASTPRIVATE:
+	/* Don't dereference an invisiref in OpenMP clauses.  */
+	if (is_invisiref_parm (OMP_CLAUSE_DECL (stmt)))
+	  {
+	    *walk_subtrees = 0;
+	    if (OMP_CLAUSE_LASTPRIVATE_STMT (stmt))
+	      cp_walk_tree (&OMP_CLAUSE_LASTPRIVATE_STMT (stmt),
+			    cp_genericize_r, p_set, NULL);
+	  }
+	break;
       case OMP_CLAUSE_PRIVATE:
       case OMP_CLAUSE_SHARED:
       case OMP_CLAUSE_FIRSTPRIVATE:
-      case OMP_CLAUSE_LASTPRIVATE:
       case OMP_CLAUSE_COPYIN:
       case OMP_CLAUSE_COPYPRIVATE:
 	/* Don't dereference an invisiref in OpenMP clauses.  */
--- gcc/cp/pt.c	(revision 132255)
+++ gcc/cp/pt.c	(working copy)
@@ -10136,10 +10136,19 @@ tsubst_omp_clauses (tree clauses, tree a
 
       switch (OMP_CLAUSE_CODE (nc))
 	{
+	case OMP_CLAUSE_LASTPRIVATE:
+	  if (OMP_CLAUSE_LASTPRIVATE_STMT (oc))
+	    {
+	      OMP_CLAUSE_LASTPRIVATE_STMT (nc) = push_stmt_list ();
+	      tsubst_expr (OMP_CLAUSE_LASTPRIVATE_STMT (oc), args, complain,
+			   in_decl, /*integral_constant_expression_p=*/false);
+	      OMP_CLAUSE_LASTPRIVATE_STMT (nc)
+		= pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (nc));
+	    }
+	  /* FALLTHRU */
 	case OMP_CLAUSE_PRIVATE:
 	case OMP_CLAUSE_SHARED:
 	case OMP_CLAUSE_FIRSTPRIVATE:
-	case OMP_CLAUSE_LASTPRIVATE:
 	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_COPYIN:
 	case OMP_CLAUSE_COPYPRIVATE:
@@ -10554,19 +10563,23 @@ tsubst_expr (tree t, tree args, tsubst_f
 		      break;
 		    else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
 			     && OMP_CLAUSE_DECL (c) == decl)
-		      error ("iteration variable %qD should be firstprivate",
+		      error ("iteration variable %qD should not be firstprivate",
 			     decl);
 		    else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
 			     && OMP_CLAUSE_DECL (c) == decl)
-		      error ("iteration variable %qD should be reduction",
+		      error ("iteration variable %qD should not be reduction",
 			     decl);
 		  }
 		if (c == NULL)
 		  {
 		    c = build_omp_clause (OMP_CLAUSE_PRIVATE);
 		    OMP_CLAUSE_DECL (c) = decl;
-		    OMP_CLAUSE_CHAIN (c) = clauses;
-		    clauses = c;
+		    c = finish_omp_clauses (c);
+		    if (c)
+		      {
+			OMP_CLAUSE_CHAIN (c) = clauses;
+			clauses = c;
+		      }
 		  }
 	      }
 	    cond = TREE_VEC_ELT (OMP_FOR_COND (t), 0);
@@ -10664,9 +10677,7 @@ tsubst_expr (tree t, tree args, tsubst_f
 	body = pop_stmt_list (body);
 
 	t = finish_omp_for (EXPR_LOCATION (t), decl, init, cond, incr, body,
-			    pre_body);
-	if (t)
-	  OMP_FOR_CLAUSES (t) = clauses;
+			    pre_body, clauses);
 
 	add_stmt (finish_omp_structured_block (stmt));
       }
--- gcc/cp/semantics.c	(revision 132255)
+++ gcc/cp/semantics.c	(working copy)
@@ -3849,9 +3849,10 @@ finish_omp_task (tree clauses, tree body
 
 tree
 finish_omp_for (location_t locus, tree decl, tree init, tree cond,
-		tree incr, tree body, tree pre_body)
+		tree incr, tree body, tree pre_body, tree clauses)
 {
   tree omp_for = NULL, orig_incr = incr;
+  bool type_dep = false;
 
   if (decl == NULL)
     {
@@ -3880,16 +3881,42 @@ finish_omp_for (location_t locus, tree d
 	}
     }
 
-  if (type_dependent_expression_p (decl)
-      || (init && type_dependent_expression_p (init))
-      || (cond && type_dependent_expression_p (cond))
-      || (incr
-	  && ((TREE_CODE (incr) != MODOP_EXPR
-	       && type_dependent_expression_p (incr))
-	      || (TREE_CODE (incr) == MODOP_EXPR
-		  && (type_dependent_expression_p (TREE_OPERAND (incr, 0))
-		      || type_dependent_expression_p (TREE_OPERAND (incr,
-								    2)))))))
+  if (!processing_template_decl)
+    ;
+  else if (type_dependent_expression_p (decl))
+    type_dep = true;
+  else if (init && type_dependent_expression_p (init))
+    type_dep = true;
+  else if (cond)
+    {
+      if (type_dependent_expression_p (cond))
+	type_dep = true;
+      else if (COMPARISON_CLASS_P (cond))
+	type_dep = (type_dependent_expression_p (TREE_OPERAND (cond, 0))
+		    || type_dependent_expression_p (TREE_OPERAND (cond, 1)));
+    }
+  if (!type_dep && incr && processing_template_decl)
+    {
+      if (TREE_CODE (incr) == MODOP_EXPR)
+	type_dep = (type_dependent_expression_p (TREE_OPERAND (incr, 0))
+		    || type_dependent_expression_p (TREE_OPERAND (incr, 2)));
+      else if (type_dependent_expression_p (incr))
+	type_dep = true;
+      else if (TREE_CODE (incr) == MODIFY_EXPR)
+	{
+	  if (type_dependent_expression_p (TREE_OPERAND (incr, 0)))
+	    type_dep = true;
+	  else if (BINARY_CLASS_P (TREE_OPERAND (incr, 1)))
+	    {
+	      tree t = TREE_OPERAND (incr, 1);
+	      type_dep = (type_dependent_expression_p (TREE_OPERAND (t, 0))
+			  || type_dependent_expression_p (TREE_OPERAND (t,
+									1)));
+	    }
+	}
+    }
+
+  if (type_dep)
     {
       tree stmt;
 
@@ -3921,6 +3948,7 @@ finish_omp_for (location_t locus, tree d
       TREE_VEC_ELT (OMP_FOR_INCR (stmt), 0) = incr;
       OMP_FOR_BODY (stmt) = body;
       OMP_FOR_PRE_BODY (stmt) = pre_body;
+      OMP_FOR_CLAUSES (stmt) = clauses;
 
       SET_EXPR_LOCATION (stmt, locus);
       return add_stmt (stmt);
@@ -3942,8 +3970,8 @@ finish_omp_for (location_t locus, tree d
 
   if (CLASS_TYPE_P (TREE_TYPE (decl)))
     {
-      tree diff, iter = decl, iter_init, last;
-      tree orig_pre_body, orig_body;
+      tree diff, iter = decl, iter_init, iter_incr = NULL, last;
+      tree incr_var = NULL, orig_pre_body, orig_body, c;
 
       if (cond == NULL)
 	{
@@ -3999,8 +4027,12 @@ finish_omp_for (location_t locus, tree d
 	case POSTINCREMENT_EXPR:
 	case POSTDECREMENT_EXPR:
 	  if (TREE_OPERAND (incr, 0) != iter)
-	    incr = error_mark_node;
-	  else if (error_operand_p (build_x_unary_op (TREE_CODE (incr), iter)))
+	    {
+	      incr = error_mark_node;
+	      break;
+	    }
+	  iter_incr = build_x_unary_op (TREE_CODE (incr), iter);
+	  if (error_operand_p (iter_incr))
 	    return NULL;
 	  else if (TREE_CODE (incr) == PREINCREMENT_EXPR
 		   || TREE_CODE (incr) == POSTINCREMENT_EXPR)
@@ -4022,17 +4054,22 @@ finish_omp_for (location_t locus, tree d
 		    incr = error_mark_node;
 		  else
 		    {
-		      tree tem = build_x_modify_expr (iter, TREE_CODE (rhs),
-						      TREE_OPERAND (rhs, 1));
-		      if (error_operand_p (tem))
+		      iter_incr = build_x_modify_expr (iter, TREE_CODE (rhs),
+						       TREE_OPERAND (rhs, 1));
+		      if (error_operand_p (iter_incr))
 			return NULL;
+		      incr = TREE_OPERAND (rhs, 1);
+		      incr = cp_convert (TREE_TYPE (diff), incr);
 		      if (TREE_CODE (rhs) == MINUS_EXPR)
-			incr = fold_build1 (NEGATE_EXPR, TREE_TYPE (diff),
-					    fold_convert (TREE_TYPE (diff),
-							  TREE_OPERAND (rhs,
-									1)));
-		      else
-			incr = TREE_OPERAND (rhs, 1);
+			{
+			  incr = build1 (NEGATE_EXPR, TREE_TYPE (diff), incr);
+			  incr = fold_if_not_in_template (incr);
+			}
+		      if (TREE_CODE (incr) != INTEGER_CST
+			  && (TREE_CODE (incr) != NOP_EXPR
+			      || (TREE_CODE (TREE_OPERAND (incr, 0))
+				  != INTEGER_CST)))
+			iter_incr = NULL;
 		    }
 		}
 	      else if (TREE_OPERAND (rhs, 1) == iter)
@@ -4043,16 +4080,18 @@ finish_omp_for (location_t locus, tree d
 		    incr = error_mark_node;
 		  else
 		    {
-		      tree tem
+		      iter_incr
 			= build_x_binary_op (PLUS_EXPR, TREE_OPERAND (rhs, 0),
 					     ERROR_MARK, iter, ERROR_MARK,
 					     NULL);
-		      if (error_operand_p (tem))
+		      if (error_operand_p (iter_incr))
 			return NULL;
-		      tem = build_x_modify_expr (iter, NOP_EXPR, tem);
-		      if (error_operand_p (tem))
+		      iter_incr = build_x_modify_expr (iter, NOP_EXPR,
+						       iter_incr);
+		      if (error_operand_p (iter_incr))
 			return NULL;
 		      incr = TREE_OPERAND (rhs, 0);
+		      iter_incr = NULL;
 		    }
 		}
 	      else
@@ -4072,17 +4111,24 @@ finish_omp_for (location_t locus, tree d
 	  return NULL;
 	}
 
+      incr = cp_convert (TREE_TYPE (diff), incr);
+      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+	if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+	    && OMP_CLAUSE_DECL (c) == iter)
+	  break;
+
       decl = create_temporary_var (TREE_TYPE (diff));
       pushdecl (decl);
       add_decl_expr (decl);
       last = create_temporary_var (TREE_TYPE (diff));
       pushdecl (last);
       add_decl_expr (last);
-      cond = cp_build_binary_op (TREE_CODE (cond), decl, diff);
-      incr = build_modify_expr (decl, PLUS_EXPR,
-				fold_convert (TREE_TYPE (diff), incr));
-      orig_incr = incr;
-
+      if (c && iter_incr == NULL)
+	{
+	  incr_var = create_temporary_var (TREE_TYPE (diff));
+	  pushdecl (incr_var);
+	  add_decl_expr (incr_var);
+	}
       gcc_assert (stmts_are_full_exprs_p ());
 
       orig_pre_body = pre_body;
@@ -4092,18 +4138,36 @@ finish_omp_for (location_t locus, tree d
       if (init != NULL)
 	finish_expr_stmt (build_x_modify_expr (iter, NOP_EXPR, init));
       init = build_int_cst (TREE_TYPE (diff), 0);
+      if (c && iter_incr == NULL)
+	{
+	  finish_expr_stmt (build_x_modify_expr (incr_var, NOP_EXPR, incr));
+	  incr = incr_var;
+	  iter_incr = build_x_modify_expr (iter, PLUS_EXPR, incr);
+	}
       finish_expr_stmt (build_x_modify_expr (last, NOP_EXPR, init));
       pre_body = pop_stmt_list (pre_body);
 
+      cond = cp_build_binary_op (TREE_CODE (cond), decl, diff);
+      incr = build_modify_expr (decl, PLUS_EXPR, incr);
+      orig_incr = incr;
+
       orig_body = body;
       body = push_stmt_list ();
-      iter_init = fold_build2 (MINUS_EXPR, TREE_TYPE (diff), decl, last);
+      iter_init = build2 (MINUS_EXPR, TREE_TYPE (diff), decl, last);
       iter_init = build_x_modify_expr (iter, PLUS_EXPR, iter_init);
       iter_init = build1 (NOP_EXPR, void_type_node, iter_init);
       finish_expr_stmt (iter_init);
       finish_expr_stmt (build_x_modify_expr (last, NOP_EXPR, decl));
       add_stmt (orig_body);
       body = pop_stmt_list (body);
+
+      if (c)
+	{
+	  OMP_CLAUSE_LASTPRIVATE_STMT (c) = push_stmt_list ();
+	  finish_expr_stmt (iter_incr);
+	  OMP_CLAUSE_LASTPRIVATE_STMT (c)
+	    = pop_stmt_list (OMP_CLAUSE_LASTPRIVATE_STMT (c));
+	}
     }
 
   if (IS_EMPTY_STMT (pre_body))
@@ -4143,6 +4207,8 @@ finish_omp_for (location_t locus, tree d
       if (processing_template_decl)
 	TREE_VEC_ELT (OMP_FOR_INCR (omp_for), 0) = orig_incr;
     }
+  if (omp_for != NULL)
+    OMP_FOR_CLAUSES (omp_for) = clauses;
   return omp_for;
 }
 
--- gcc/cp/parser.c	(revision 132255)
+++ gcc/cp/parser.c	(working copy)
@@ -19480,8 +19480,6 @@ cp_parser_omp_clause_collapse (cp_parser
   c = build_omp_clause (OMP_CLAUSE_COLLAPSE);
   OMP_CLAUSE_CHAIN (c) = list;
   OMP_CLAUSE_COLLAPSE_EXPR (c) = num;
-  OMP_CLAUSE_COLLAPSE_ITERVAR (c) = NULL;
-  OMP_CLAUSE_COLLAPSE_COUNT (c) = NULL;
 
   return c;
 }
@@ -20231,10 +20229,12 @@ cp_parser_omp_for_incr (cp_parser *parse
 /* Parse the restricted form of the for statment allowed by OpenMP.  */
 
 static tree
-cp_parser_omp_for_loop (cp_parser *parser, tree clauses)
+cp_parser_omp_for_loop (cp_parser *parser, tree clauses, tree *par_clauses)
 {
   tree init, cond, incr, body, decl, pre_body, ret, for_block = NULL_TREE;
+  tree real_decl;
   location_t loc;
+  bool add_private_clause = false;
 
   if (!cp_lexer_next_token_is_keyword (parser->lexer, RID_FOR))
     {
@@ -20245,7 +20245,7 @@ cp_parser_omp_for_loop (cp_parser *parse
   if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
     return NULL;
 
-  init = decl = NULL;
+  init = decl = real_decl = NULL;
   pre_body = push_stmt_list ();
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
     {
@@ -20329,38 +20329,25 @@ cp_parser_omp_for_loop (cp_parser *parse
 	      && DECL_P (decl)
 	      && CLASS_TYPE_P (TREE_TYPE (decl)))
 	    {
-	      tree rhs, c;
+	      tree rhs;
 
 	      cp_parser_parse_definitely (parser);
 	      cp_parser_require (parser, CPP_EQ, "`='");
 	      rhs = cp_parser_assignment_expression (parser, false);
 	      finish_expr_stmt (build_x_modify_expr (decl, NOP_EXPR, rhs));
-	      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
-		{
-		  if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
-		       || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
-		      && OMP_CLAUSE_DECL (c) == decl)
-		    break;
-		  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
-			   && OMP_CLAUSE_DECL (c) == decl)
-		    error ("iteration variable %qD should be firstprivate", decl);
-		  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
-			   && OMP_CLAUSE_DECL (c) == decl)
-		    error ("iteration variable %qD should be reduction", decl);
-		}
-	      if (c == NULL)
-		{
-		  c = build_omp_clause (OMP_CLAUSE_PRIVATE);
-		  OMP_CLAUSE_DECL (c) = decl;
-		  OMP_CLAUSE_CHAIN (c) = clauses;
-		  clauses = c;
-		}
+	      add_private_clause = true;
 	    }
 	  else
 	    {
 	      decl = NULL;
 	      cp_parser_abort_tentative_parse (parser);
 	      init = cp_parser_expression (parser, false);
+	      if (init)
+		{
+		  if (TREE_CODE (init) == MODIFY_EXPR
+		      || TREE_CODE (init) == MODOP_EXPR)
+		    real_decl = TREE_OPERAND (init, 0);
+		}
 	    }
 	}
     }
@@ -20368,6 +20355,73 @@ cp_parser_omp_for_loop (cp_parser *parse
   if (pre_body)
     pre_body = pop_stmt_list (pre_body);
 
+  if (decl)
+    real_decl = decl;
+  if (par_clauses != NULL && real_decl != NULL_TREE)
+    {
+      tree *c;
+      for (c = par_clauses; *c ; )
+	if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE
+	    && OMP_CLAUSE_DECL (*c) == real_decl)
+	  {
+	    error ("%Hiteration variable %qD should not be firstprivate",
+		   &loc, real_decl);
+	    *c = OMP_CLAUSE_CHAIN (*c);
+	  }
+	else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_LASTPRIVATE
+		 && OMP_CLAUSE_DECL (*c) == real_decl)
+	  {
+	    /* Add lastprivate (decl) clause to OMP_FOR_CLAUSES,
+	       change it to shared (decl) in OMP_PARALLEL_CLAUSES.  */
+	    tree l = build_omp_clause (OMP_CLAUSE_LASTPRIVATE);
+	    OMP_CLAUSE_DECL (l) = real_decl;
+	    OMP_CLAUSE_CHAIN (l) = clauses;
+	    CP_OMP_CLAUSE_INFO (l) = CP_OMP_CLAUSE_INFO (*c);
+	    clauses = l;
+	    OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
+	    CP_OMP_CLAUSE_INFO (*c) = NULL;
+	    add_private_clause = false;
+	  }
+	else
+	  {
+	    if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_PRIVATE
+		&& OMP_CLAUSE_DECL (*c) == real_decl)
+	      add_private_clause = false;
+	    c = &OMP_CLAUSE_CHAIN (*c);
+	  }
+    }
+
+  if (add_private_clause)
+    {
+      tree c;
+      for (c = clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+	{
+	  if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE
+	       || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
+	      && OMP_CLAUSE_DECL (c) == decl)
+	    break;
+	  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE
+		   && OMP_CLAUSE_DECL (c) == decl)
+	    error ("%Hiteration variable %qD should not be firstprivate",
+		   &loc, decl);
+	  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+		   && OMP_CLAUSE_DECL (c) == decl)
+	    error ("%Hiteration variable %qD should not be reduction",
+		   &loc, decl);
+	}
+      if (c == NULL)
+	{
+	  c = build_omp_clause (OMP_CLAUSE_PRIVATE);
+	  OMP_CLAUSE_DECL (c) = decl;
+	  c = finish_omp_clauses (c);
+	  if (c)
+	    {
+	      OMP_CLAUSE_CHAIN (c) = clauses;
+	      clauses = c;
+	    }
+	}
+    }
+
   cond = NULL;
   if (cp_lexer_next_token_is_not (parser->lexer, CPP_SEMICOLON))
     {
@@ -20410,9 +20464,7 @@ cp_parser_omp_for_loop (cp_parser *parse
   cp_parser_statement (parser, NULL_TREE, false, NULL);
   body = pop_stmt_list (body);
 
-  ret = finish_omp_for (loc, decl, init, cond, incr, body, pre_body);
-  if (ret)
-    OMP_FOR_CLAUSES (ret) = clauses;
+  ret = finish_omp_for (loc, decl, init, cond, incr, body, pre_body, clauses);
 
   if (for_block)
     add_stmt (pop_stmt_list (for_block));
@@ -20446,7 +20498,7 @@ cp_parser_omp_for (cp_parser *parser, cp
   sb = begin_omp_structured_block ();
   save = cp_parser_begin_omp_structured_block (parser);
 
-  ret = cp_parser_omp_for_loop (parser, clauses);
+  ret = cp_parser_omp_for_loop (parser, clauses, NULL);
 
   cp_parser_end_omp_structured_block (parser, save);
   add_stmt (finish_omp_structured_block (sb));
@@ -20644,7 +20696,7 @@ cp_parser_omp_parallel (cp_parser *parse
 
     case PRAGMA_OMP_PARALLEL_FOR:
       c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
-      cp_parser_omp_for_loop (parser, ws_clause);
+      cp_parser_omp_for_loop (parser, ws_clause, &par_clause);
       break;
 
     case PRAGMA_OMP_PARALLEL_SECTIONS:
--- gcc/fortran/trans-openmp.c	(revision 132090)
+++ gcc/fortran/trans-openmp.c	(working copy)
@@ -1,5 +1,5 @@
 /* OpenMP directive translation -- generate GCC trees from gfc_code.
-   Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Jakub Jelinek <jakub@redhat.com>
 
 This file is part of GCC.
@@ -693,8 +693,6 @@ gfc_trans_omp_clauses (stmtblock_t *bloc
     {
       c = build_omp_clause (OMP_CLAUSE_COLLAPSE);
       OMP_CLAUSE_COLLAPSE_EXPR (c) = build_int_cst (NULL, clauses->collapse);
-      OMP_CLAUSE_COLLAPSE_ITERVAR (c) = NULL;
-      OMP_CLAUSE_COLLAPSE_COUNT (c) = NULL;
       omp_clauses = gfc_trans_add_clause (c, omp_clauses);
     }
 
@@ -914,7 +912,7 @@ gfc_trans_omp_critical (gfc_code *code)
 
 static tree
 gfc_trans_omp_do (gfc_code *code, stmtblock_t *pblock,
-		  gfc_omp_clauses *do_clauses)
+		  gfc_omp_clauses *do_clauses, tree par_clauses)
 {
   gfc_se se;
   tree dovar, stmt, from, to, step, type, init, cond, incr;
@@ -947,7 +945,7 @@ gfc_trans_omp_do (gfc_code *code, stmtbl
   for (i = 0; i < collapse; i++)
     {
       int simple = 0;
-      bool dovar_found = false;
+      int dovar_found = 0;
 
       if (clauses)
 	{
@@ -956,12 +954,14 @@ gfc_trans_omp_do (gfc_code *code, stmtbl
 	       n = n->next)
 	    if (code->ext.iterator->var->symtree->n.sym == n->sym)
 	      break;
-	  if (n == NULL)
+	  if (n != NULL)
+	    dovar_found = 1;
+	  else if (n == NULL)
 	    for (n = clauses->lists[OMP_LIST_PRIVATE]; n != NULL; n = n->next)
 	      if (code->ext.iterator->var->symtree->n.sym == n->sym)
 		break;
 	  if (n != NULL)
-	    dovar_found = true;
+	    dovar_found++;
 	}
 
       /* Evaluate all the expressions in the iterator.  */
@@ -1038,6 +1038,46 @@ gfc_trans_omp_do (gfc_code *code, stmtbl
 	  OMP_CLAUSE_DECL (tmp) = dovar;
 	  omp_clauses = gfc_trans_add_clause (tmp, omp_clauses);
 	}
+      else if (dovar_found == 2)
+	{
+	  tree c = NULL;
+
+	  tmp = NULL;
+	  if (!simple)
+	    {
+	      /* If dovar is lastprivate, but different counter is used,
+		 dovar += step needs to be added to
+		 OMP_CLAUSE_LASTPRIVATE_STMT, otherwise the copied dovar
+		 will have the value on entry of the last loop, rather
+		 than value after iterator increment.  */
+	      tmp = gfc_evaluate_now (step, pblock);
+	      tmp = fold_build2 (PLUS_EXPR, type, dovar, tmp);
+	      tmp = build2 (GIMPLE_MODIFY_STMT, type, dovar, tmp);
+	      for (c = omp_clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+		    && OMP_CLAUSE_DECL (c) == dovar)
+		  {
+		    OMP_CLAUSE_LASTPRIVATE_STMT (c) = tmp;
+		    break;
+		  }
+	    }
+	  if (c == NULL && par_clauses != NULL)
+	    {
+	      for (c = par_clauses; c ; c = OMP_CLAUSE_CHAIN (c))
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+		    && OMP_CLAUSE_DECL (c) == dovar)
+		  {
+		    tree l = build_omp_clause (OMP_CLAUSE_LASTPRIVATE);
+		    OMP_CLAUSE_DECL (l) = dovar;
+		    OMP_CLAUSE_CHAIN (l) = omp_clauses;
+		    OMP_CLAUSE_LASTPRIVATE_STMT (l) = tmp;
+		    omp_clauses = l;
+		    OMP_CLAUSE_SET_CODE (c, OMP_CLAUSE_SHARED);
+		    break;
+		  }
+	    }
+	  gcc_assert (simple || c != NULL);
+	}
       if (!simple)
 	{
 	  tmp = build_omp_clause (OMP_CLAUSE_PRIVATE);
@@ -1168,7 +1208,7 @@ gfc_trans_omp_parallel_do (gfc_code *cod
     pblock = &block;
   else
     pushlevel (0);
-  stmt = gfc_trans_omp_do (code, pblock, &do_clauses);
+  stmt = gfc_trans_omp_do (code, pblock, &do_clauses, omp_clauses);
   if (TREE_CODE (stmt) != BIND_EXPR)
     stmt = build3_v (BIND_EXPR, NULL, stmt, poplevel (1, 0, 0));
   else
@@ -1311,7 +1351,7 @@ gfc_trans_omp_directive (gfc_code *code)
     case EXEC_OMP_CRITICAL:
       return gfc_trans_omp_critical (code);
     case EXEC_OMP_DO:
-      return gfc_trans_omp_do (code, NULL, code->ext.omp_clauses);
+      return gfc_trans_omp_do (code, NULL, code->ext.omp_clauses, NULL);
     case EXEC_OMP_FLUSH:
       return gfc_trans_omp_flush ();
     case EXEC_OMP_MASTER:
--- gcc/gimplify.c	(revision 132090)
+++ gcc/gimplify.c	(working copy)
@@ -5112,6 +5112,23 @@ gimplify_scan_omp_clauses (tree *list_p,
 	      pop_gimplify_context (OMP_CLAUSE_REDUCTION_MERGE (c));
 	      gimplify_omp_ctxp = outer_ctx;
 	    }
+	  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+		   && OMP_CLAUSE_LASTPRIVATE_STMT (c))
+	    {
+	      gimplify_omp_ctxp = ctx;
+	      push_gimplify_context ();
+	      if (TREE_CODE (OMP_CLAUSE_LASTPRIVATE_STMT (c)) != BIND_EXPR)
+		{
+		  tree bind = build3 (BIND_EXPR, void_type_node, NULL,
+				      NULL, NULL);
+		  TREE_SIDE_EFFECTS (bind) = 1;
+		  BIND_EXPR_BODY (bind) = OMP_CLAUSE_LASTPRIVATE_STMT (c);
+		  OMP_CLAUSE_LASTPRIVATE_STMT (c) = bind;
+		}
+	      gimplify_stmt (&OMP_CLAUSE_LASTPRIVATE_STMT (c));
+	      pop_gimplify_context (OMP_CLAUSE_LASTPRIVATE_STMT (c));
+	      gimplify_omp_ctxp = outer_ctx;
+	    }
 	  if (notice_outer)
 	    goto do_notice;
 	  break;
@@ -5489,6 +5506,28 @@ gimplify_omp_for (tree *expr_p, tree *pr
 
       if (init_decl)
 	append_to_statement_list (init_decl, &bodylist);
+
+      if (var != decl)
+	{
+	  tree c;
+	  for (c = OMP_FOR_CLAUSES (for_stmt); c ; c = OMP_CLAUSE_CHAIN (c))
+	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+	      && OMP_CLAUSE_DECL (c) == decl)
+	    {
+	      t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
+	      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_CODE (t) == PLUS_EXPR
+			  || TREE_CODE (t) == MINUS_EXPR);
+	      gcc_assert (TREE_OPERAND (t, 0) == var);
+	      gcc_assert (OMP_CLAUSE_LASTPRIVATE_STMT (c) == NULL);
+	      t = build2 (TREE_CODE (t), TREE_TYPE (decl), decl,
+			  TREE_OPERAND (t, 1));
+	      OMP_CLAUSE_LASTPRIVATE_STMT (c)
+		= build_gimple_modify_stmt (decl, t);
+	    }
+	}
     }
 
   body = OMP_FOR_BODY (for_stmt);
--- gcc/tree-nested.c	(revision 132256)
+++ gcc/tree-nested.c	(working copy)
@@ -1161,7 +1161,7 @@ static bool
 convert_nonlocal_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 {
   struct nesting_info *info = wi->info;
-  bool need_chain = false;
+  bool need_chain = false, need_stmts = false;
   tree clause, decl;
   int dummy;
   bitmap new_suppress;
@@ -1173,13 +1173,25 @@ convert_nonlocal_omp_clauses (tree *pcla
     {
       switch (OMP_CLAUSE_CODE (clause))
 	{
+	case OMP_CLAUSE_REDUCTION:
+	  if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+	    need_stmts = true;
+	  goto do_decl_clause;
+
+	case OMP_CLAUSE_LASTPRIVATE:
+	  if (OMP_CLAUSE_LASTPRIVATE_STMT (clause))
+	    need_stmts = true;
+	  goto do_decl_clause;
+
 	case OMP_CLAUSE_PRIVATE:
 	case OMP_CLAUSE_FIRSTPRIVATE:
-	case OMP_CLAUSE_LASTPRIVATE:
-	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_COPYPRIVATE:
 	case OMP_CLAUSE_SHARED:
+	do_decl_clause:
 	  decl = OMP_CLAUSE_DECL (clause);
+	  if (TREE_CODE (decl) == VAR_DECL
+	      && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+	    break;
 	  if (decl_function_context (decl) != info->context)
 	    {
 	      bitmap_set_bit (new_suppress, DECL_UID (decl));
@@ -1215,6 +1227,35 @@ convert_nonlocal_omp_clauses (tree *pcla
 
   info->suppress_expansion = new_suppress;
 
+  if (need_stmts)
+    for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+      switch (OMP_CLAUSE_CODE (clause))
+	{
+	case OMP_CLAUSE_REDUCTION:
+	  if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+	    {
+	      tree old_context
+		= DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause));
+	      walk_body (convert_nonlocal_reference, info,
+			 &OMP_CLAUSE_REDUCTION_INIT (clause));
+	      DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+		= info->context;
+	      walk_body (convert_nonlocal_reference, info,
+			 &OMP_CLAUSE_REDUCTION_MERGE (clause));
+	      DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+		= old_context;
+	    }
+	  break;
+
+	case OMP_CLAUSE_LASTPRIVATE:
+	  walk_body (convert_nonlocal_reference, info,
+		     &OMP_CLAUSE_LASTPRIVATE_STMT (clause));
+	  break;
+
+	default:
+	  break;
+	}
+
   return need_chain;
 }
 
@@ -1456,7 +1497,7 @@ static bool
 convert_local_omp_clauses (tree *pclauses, struct walk_stmt_info *wi)
 {
   struct nesting_info *info = wi->info;
-  bool need_frame = false;
+  bool need_frame = false, need_stmts = false;
   tree clause, decl;
   int dummy;
   bitmap new_suppress;
@@ -1468,13 +1509,25 @@ convert_local_omp_clauses (tree *pclause
     {
       switch (OMP_CLAUSE_CODE (clause))
 	{
+	case OMP_CLAUSE_REDUCTION:
+	  if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+	    need_stmts = true;
+	  goto do_decl_clause;
+
+	case OMP_CLAUSE_LASTPRIVATE:
+	  if (OMP_CLAUSE_LASTPRIVATE_STMT (clause))
+	    need_stmts = true;
+	  goto do_decl_clause;
+
 	case OMP_CLAUSE_PRIVATE:
 	case OMP_CLAUSE_FIRSTPRIVATE:
-	case OMP_CLAUSE_LASTPRIVATE:
-	case OMP_CLAUSE_REDUCTION:
 	case OMP_CLAUSE_COPYPRIVATE:
 	case OMP_CLAUSE_SHARED:
+	do_decl_clause:
 	  decl = OMP_CLAUSE_DECL (clause);
+	  if (TREE_CODE (decl) == VAR_DECL
+	      && (TREE_STATIC (decl) || DECL_EXTERNAL (decl)))
+	    break;
 	  if (decl_function_context (decl) == info->context
 	      && !use_pointer_in_frame (decl))
 	    {
@@ -1515,6 +1568,35 @@ convert_local_omp_clauses (tree *pclause
 
   info->suppress_expansion = new_suppress;
 
+  if (need_stmts)
+    for (clause = *pclauses; clause ; clause = OMP_CLAUSE_CHAIN (clause))
+      switch (OMP_CLAUSE_CODE (clause))
+	{
+	case OMP_CLAUSE_REDUCTION:
+	  if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+	    {
+	      tree old_context
+		= DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause));
+	      walk_body (convert_local_reference, info,
+			 &OMP_CLAUSE_REDUCTION_INIT (clause));
+	      DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+		= info->context;
+	      walk_body (convert_local_reference, info,
+			 &OMP_CLAUSE_REDUCTION_MERGE (clause));
+	      DECL_CONTEXT (OMP_CLAUSE_REDUCTION_PLACEHOLDER (clause))
+		= old_context;
+	    }
+	  break;
+
+	case OMP_CLAUSE_LASTPRIVATE:
+	  walk_body (convert_local_reference, info,
+		     &OMP_CLAUSE_LASTPRIVATE_STMT (clause));
+	  break;
+
+	default:
+	  break;
+	}
+
   return need_frame;
 }
 
--- gcc/c-parser.c	(revision 132090)
+++ gcc/c-parser.c	(working copy)
@@ -6955,8 +6955,6 @@ c_parser_omp_clause_collapse (c_parser *
     }
   c = build_omp_clause (OMP_CLAUSE_COLLAPSE);
   OMP_CLAUSE_COLLAPSE_EXPR (c) = num;
-  OMP_CLAUSE_COLLAPSE_ITERVAR (c) = NULL;
-  OMP_CLAUSE_COLLAPSE_COUNT (c) = NULL;
   OMP_CLAUSE_CHAIN (c) = list;
   return c;
 }
@@ -7608,7 +7606,7 @@ c_parser_omp_flush (c_parser *parser)
    so that we can push a new decl if necessary to make it private.  */
 
 static tree
-c_parser_omp_for_loop (c_parser *parser, tree clauses)
+c_parser_omp_for_loop (c_parser *parser, tree clauses, tree *par_clauses)
 {
   tree decl, cond, incr, save_break, save_cont, body, init, stmt, cl;
   location_t loc;
@@ -7694,7 +7692,34 @@ c_parser_omp_for_loop (c_parser *parser,
     {
       stmt = c_finish_omp_for (loc, decl, init, cond, incr, body, NULL);
       if (stmt)
-	OMP_FOR_CLAUSES (stmt) = clauses;
+	{
+	  if (par_clauses != NULL)
+	    {
+	      tree *c;
+	      for (c = par_clauses; *c ; )
+		if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE
+		    && OMP_CLAUSE_DECL (*c) == decl)
+		  {
+		    error ("%Hiteration variable %qD should not be firstprivate",
+			   &loc, decl);
+		    *c = OMP_CLAUSE_CHAIN (*c);
+		  }
+		else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_LASTPRIVATE
+			 && OMP_CLAUSE_DECL (*c) == decl)
+		  {
+		    /* Copy lastprivate (decl) clause to OMP_FOR_CLAUSES,
+		       change it to shared (decl) in OMP_PARALLEL_CLAUSES.  */
+		    tree l = build_omp_clause (OMP_CLAUSE_LASTPRIVATE);
+		    OMP_CLAUSE_DECL (l) = decl;
+		    OMP_CLAUSE_CHAIN (l) = clauses;
+		    clauses = l;
+		    OMP_CLAUSE_SET_CODE (*c, OMP_CLAUSE_SHARED);
+		  }
+		else
+		  c = &OMP_CLAUSE_CHAIN (*c);
+	    }
+	  OMP_FOR_CLAUSES (stmt) = clauses;
+	}
       return stmt;
     }
   return NULL;
@@ -7730,7 +7755,7 @@ c_parser_omp_for (c_parser *parser)
 				      "#pragma omp for");
 
   block = c_begin_compound_stmt (true);
-  ret = c_parser_omp_for_loop (parser, clauses);
+  ret = c_parser_omp_for_loop (parser, clauses, NULL);
   block = c_end_compound_stmt (block, true);
   add_stmt (block);
 
@@ -7935,7 +7960,7 @@ c_parser_omp_parallel (c_parser *parser)
     case PRAGMA_OMP_PARALLEL_FOR:
       block = c_begin_omp_parallel ();
       c_split_parallel_clauses (clauses, &par_clause, &ws_clause);
-      c_parser_omp_for_loop (parser, ws_clause);
+      c_parser_omp_for_loop (parser, ws_clause, &par_clause);
       stmt = c_finish_omp_parallel (par_clause, block);
       OMP_PARALLEL_COMBINED (stmt) = 1;
       break;
--- libgomp/testsuite/libgomp.c++/for-5.C	(revision 0)
+++ libgomp/testsuite/libgomp.c++/for-5.C	(revision 0)
@@ -0,0 +1,303 @@
+// { dg-do run }
+
+typedef __PTRDIFF_TYPE__ ptrdiff_t;
+extern "C" void abort ();
+
+template <typename T>
+class I
+{
+public:
+  typedef ptrdiff_t difference_type;
+  I ();
+  ~I ();
+  I (T *);
+  I (const I &);
+  T &operator * ();
+  T *operator -> ();
+  T &operator [] (const difference_type &) const;
+  I &operator = (const I &);
+  I &operator ++ ();
+  I operator ++ (int);
+  I &operator -- ();
+  I operator -- (int);
+  I &operator += (const difference_type &);
+  I &operator -= (const difference_type &);
+  I operator + (const difference_type &) const;
+  I operator - (const difference_type &) const;
+  template <typename S> friend bool operator == (I<S> &, I<S> &);
+  template <typename S> friend bool operator == (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator < (I<S> &, I<S> &);
+  template <typename S> friend bool operator < (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator <= (I<S> &, I<S> &);
+  template <typename S> friend bool operator <= (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator > (I<S> &, I<S> &);
+  template <typename S> friend bool operator > (const I<S> &, const I<S> &);
+  template <typename S> friend bool operator >= (I<S> &, I<S> &);
+  template <typename S> friend bool operator >= (const I<S> &, const I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (I<S> &, I<S> &);
+  template <typename S> friend typename I<S>::difference_type operator - (const I<S> &, const I<S> &);
+  template <typename S> friend I<S> operator + (typename I<S>::difference_type , const I<S> &);
+private:
+  T *p;
+};
+template <typename T> I<T>::I () : p (0) {}
+template <typename T> I<T>::~I () {}
+template <typename T> I<T>::I (T *x) : p (x) {}
+template <typename T> I<T>::I (const I &x) : p (x.p) {}
+template <typename T> T &I<T>::operator * () { return *p; }
+template <typename T> T *I<T>::operator -> () { return p; }
+template <typename T> T &I<T>::operator [] (const difference_type &x) const { return p[x]; }
+template <typename T> I<T> &I<T>::operator = (const I &x) { p = x.p; return *this; }
+template <typename T> I<T> &I<T>::operator ++ () { ++p; return *this; }
+template <typename T> I<T> I<T>::operator ++ (int) { return I (p++); }
+template <typename T> I<T> &I<T>::operator -- () { --p; return *this; }
+template <typename T> I<T> I<T>::operator -- (int) { return I (p--); }
+template <typename T> I<T> &I<T>::operator += (const difference_type &x) { p += x; return *this; }
+template <typename T> I<T> &I<T>::operator -= (const difference_type &x) { p -= x; return *this; }
+template <typename T> I<T> I<T>::operator + (const difference_type &x) const { return I (p + x); }
+template <typename T> I<T> I<T>::operator - (const difference_type &x) const { return I (p - x); }
+template <typename T> bool operator == (I<T> &x, I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator == (const I<T> &x, const I<T> &y) { return x.p == y.p; }
+template <typename T> bool operator != (I<T> &x, I<T> &y) { return !(x == y); }
+template <typename T> bool operator != (const I<T> &x, const I<T> &y) { return !(x == y); }
+template <typename T> bool operator < (I<T> &x, I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator < (const I<T> &x, const I<T> &y) { return x.p < y.p; }
+template <typename T> bool operator <= (I<T> &x, I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator <= (const I<T> &x, const I<T> &y) { return x.p <= y.p; }
+template <typename T> bool operator > (I<T> &x, I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator > (const I<T> &x, const I<T> &y) { return x.p > y.p; }
+template <typename T> bool operator >= (I<T> &x, I<T> &y) { return x.p >= y.p; }
+template <typename T> bool operator >= (const I<T> &x, const I<T> &y) { return x.p >= y.p; }
+template <typename T> typename I<T>::difference_type operator - (I<T> &x, I<T> &y) { return x.p - y.p; }
+template <typename T> typename I<T>::difference_type operator - (const I<T> &x, const I<T> &y) { return x.p - y.p; }
+template <typename T> I<T> operator + (typename I<T>::difference_type x, const I<T> &y) { return I<T> (x + y.p); }
+
+template <typename T>
+class J
+{
+public:
+  J(const I<T> &x, const I<T> &y) : b (x), e (y) {}
+  const I<T> &begin ();
+  const I<T> &end ();
+private:
+  I<T> b, e;
+};
+
+template <typename T> const I<T> &J<T>::begin () { return b; }
+template <typename T> const I<T> &J<T>::end () { return e; }
+
+int results[2000];
+
+template <typename T>
+void
+baz (I<T> &i)
+{
+  if (*i < 0 || *i >= 2000)
+    abort ();
+  results[*i]++;
+}
+
+I<int>
+f1 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel shared (i)
+  {
+  #pragma omp for lastprivate (i) schedule(runtime)
+    for (i = x; i < y - 1; ++i)
+      baz (i);
+  #pragma omp single
+    i += 3;
+  }
+  return I<int> (i);
+}
+
+I<int>
+f2 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x; i < y - 1; i = 1 - 6 + 7 + i)
+    baz (i);
+  return I<int> (i);
+}
+
+template <typename T>
+I<int>
+f3 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel
+  #pragma omp for lastprivate (i)
+    for (i = x + 1000 - 64; i <= y - 10; i++)
+      baz (i);
+  return i;
+}
+
+template <typename T>
+I<int>
+f4 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x + 2000 - 64; i > y + 10; --i)
+    baz (i);
+  return I<int> (i);
+}
+
+template <typename T>
+I<int>
+f5 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x; i > y + T (6); i--)
+    baz (i);
+  return i;
+}
+
+template <typename T>
+I<int>
+f6 (const I<int> &x, const I<int> &y)
+{
+  I<int> i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x - T (7); i > y; i -= T (2))
+    baz (i);
+  return I<int> (i);
+}
+
+template <int N>
+I<int>
+f7 (I<int> i, const I<int> &x, const I<int> &y)
+{
+#pragma omp parallel for lastprivate (i)
+  for (i = x - 10; i <= y + 10; i += N)
+    baz (i);
+  return I<int> (i);
+}
+
+template <int N>
+I<int>
+f8 (J<int> j)
+{
+  I<int> i;
+#pragma omp parallel shared (i)
+  #pragma omp for lastprivate (i)
+    for (i = j.begin (); i <= j.end () + N; i += 2)
+      baz (i);
+  return i;
+}
+
+I<int> i9;
+
+template <long N>
+I<int> &
+f9 (J<int> j)
+{
+#pragma omp parallel for lastprivate (i9)
+  for (i9 = j.begin () + N; i9 <= j.end () - N; i9 = i9 - N)
+    baz (i9);
+  return i9;
+}
+
+template <typename T, int N>
+I<T>
+f10 (const I<T> &x, const I<T> &y)
+{
+  I<T> i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x; i > y; i = i + N)
+    baz (i);
+  return i;
+}
+
+template <typename T, typename U>
+T
+f11 (T i, const T &x, const T &y)
+{
+#pragma omp parallel
+  #pragma omp for lastprivate (i)
+  for (i = x + U (2); i <= y + U (1); i = U (2) + U (3) + i)
+    baz (i);
+  return T (i);
+}
+
+template <typename T>
+T
+f12 (const T &x, const T &y)
+{
+  T i;
+#pragma omp parallel for lastprivate (i)
+  for (i = x; i > y; --i)
+    baz (i);
+  return i;
+}
+
+#define check(expr) \
+  for (int i = 0; i < 2000; i++)			\
+    if (expr)						\
+      {							\
+	if (results[i] != 1)				\
+	  abort ();					\
+	results[i] = 0;					\
+      }							\
+    else if (results[i])				\
+      abort ()
+
+int
+main ()
+{
+  int a[2000];
+  long b[2000];
+  for (int i = 0; i < 2000; i++)
+    {
+      a[i] = i;
+      b[i] = i;
+    }
+  if (*f1 (&a[10], &a[1873]) != 1875)
+    abort ();
+  check (i >= 10 && i < 1872);
+  if (*f2 (&a[0], &a[1998]) != 1998)
+    abort ();
+  check (i < 1997 && (i & 1) == 0);
+  if (*f3<int> (&a[10], &a[1971]) != 1962)
+    abort ();
+  check (i >= 946 && i <= 1961);
+  if (*f4<int> (&a[0], &a[30]) != 40)
+    abort ();
+  check (i > 40 && i <= 2000 - 64);
+  if (*f5<short> (&a[1931], &a[17]) != 23)
+    abort ();
+  check (i > 23 && i <= 1931);
+  if (*f6<long> (&a[1931], &a[17]) != 16)
+    abort ();
+  check (i > 17 && i <= 1924 && (i & 1) == 0);
+  if (*f7<6> (I<int> (), &a[12], &a[1800]) != 1814)
+    abort ();
+  check (i >= 2 && i <= 1808 && (i - 2) % 6 == 0);
+  if (*f8<121> (J<int> (&a[14], &a[1803])) != 1926)
+    abort ();
+  check (i >= 14 && i <= 1924 && (i & 1) == 0);
+  if (*f9<-3L> (J<int> (&a[27], &a[1761])) != 1767)
+    abort ();
+  check (i >= 24 && i <= 1764 && (i % 3) == 0);
+  if (*f10<int, -7> (&a[1939], &a[17]) != 14)
+    abort ();
+  check (i >= 21 && i <= 1939 && i % 7 == 0);
+  if (*f11<I<int>, short> (I<int> (), &a[71], &a[1941]) != 1943)
+    abort ();
+  check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0);
+  if (*f12<I<int> > (&a[1761], &a[37]) != 37)
+    abort ();
+  check (i > 37 && i <= 1761);
+  if (*f10<long, -7> (&b[1939], &b[17]) != 14)
+    abort ();
+  check (i >= 21 && i <= 1939 && i % 7 == 0);
+  if (*f11<I<long>, short> (I<long> (), &b[71], &b[1941]) != 1943)
+    abort ();
+  check (i >= 73 && i <= 1938 && (i - 73) % 5 == 0);
+  if (*f12<I<long> > (&b[1761], &b[37]) != 37)
+    abort ();
+  check (i > 37 && i <= 1761);
+}
--- libgomp/testsuite/libgomp.fortran/nestedfn4.f90	(revision 0)
+++ libgomp/testsuite/libgomp.fortran/nestedfn4.f90	(revision 0)
@@ -0,0 +1,41 @@
+program foo
+  integer :: i, j, k
+  integer :: a(10), c(10)
+  k = 2
+  a(:) = 0
+  call test1
+  call test2
+  do i = 1, 10
+    if (a(i) .ne. 10 * i) call abort
+  end do
+  !$omp parallel do reduction (+:c)
+  do i = 1, 10
+    c = c + a
+  end do
+  do i = 1, 10
+    if (c(i) .ne. 10 * a(i)) call abort
+  end do
+  !$omp parallel do lastprivate (j)
+  do j = 1, 10, k
+  end do
+  if (j .ne. 11) call abort
+contains
+  subroutine test1
+    integer :: i
+    integer :: b(10)
+    do i = 1, 10
+      b(i) = i
+    end do
+    c(:) = 0
+    !$omp parallel do reduction (+:a)
+    do i = 1, 10
+      a = a + b
+    end do
+  end subroutine test1
+  subroutine test2
+    !$omp parallel do lastprivate (j)
+    do j = 1, 10, k
+    end do
+    if (j .ne. 11) call abort
+  end subroutine test2
+end program foo
--- libgomp/testsuite/libgomp.fortran/collapse3.f90	(revision 132090)
+++ libgomp/testsuite/libgomp.fortran/collapse3.f90	(working copy)
@@ -24,7 +24,7 @@ contains
           end do
         end do
       end do
-!   if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
     if (m.ne.(600+40+18)) call abort
     do i = 1, 7
       do j = -3, 5
@@ -45,7 +45,7 @@ contains
     logical :: l
     l = .false.
     a(:, :, :) = 0
-    !$omp parallel do collapse (3) lastprivate (m) reduction (.or.:l)
+    !$omp parallel do collapse (3) lastprivate (i, j, k, m) reduction (.or.:l)
       do i = v1, v2
         do j = v3, v4
           do k = v5, v6
@@ -56,7 +56,7 @@ contains
           end do
         end do
       end do
-!   if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
     if (m.ne.(600+40+18)) call abort
     do i = 1, 7
       do j = -3, 5
@@ -77,7 +77,7 @@ contains
     logical :: l
     l = .false.
     a(:, :, :) = 0
-    !$omp parallel do collapse (3) lastprivate (m) reduction (.or.:l)
+    !$omp parallel do collapse (3) lastprivate (i, j, k, m) reduction (.or.:l)
       do i = v1, v2, v7
         do j = v3, v4, v8
           do k = v5, v6, v9
@@ -88,7 +88,7 @@ contains
           end do
         end do
       end do
-!   if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
     if (m.ne.(600+40+18)) call abort
     do i = 1, 7
       do j = -3, 5
@@ -120,7 +120,7 @@ contains
           end do
         end do
       end do
-!   if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
     if (m.ne.(600+40+18)) call abort
     do i = 1, 7
       do j = -3, 5
@@ -141,7 +141,7 @@ contains
     logical :: l
     l = .false.
     a(:, :, :) = 0
-    !$omp parallel do collapse (3) lastprivate (m) reduction (.or.:l) &
+    !$omp parallel do collapse (3) lastprivate (i, j, k, m) reduction (.or.:l) &
     !$omp & schedule (guided)
       do i = v1, v2
         do j = v3, v4
@@ -153,7 +153,7 @@ contains
           end do
         end do
       end do
-!   if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
     if (m.ne.(600+40+18)) call abort
     do i = 1, 7
       do j = -3, 5
@@ -174,7 +174,7 @@ contains
     logical :: l
     l = .false.
     a(:, :, :) = 0
-    !$omp parallel do collapse (3) lastprivate (m) reduction (.or.:l) &
+    !$omp parallel do collapse (3) lastprivate (i, j, k, m) reduction (.or.:l) &
     !$omp & schedule (dynamic)
       do i = v1, v2, v7
         do j = v3, v4, v8
@@ -186,7 +186,7 @@ contains
           end do
         end do
       end do
-!   if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
+    if (i.ne.7.or.j.ne.5.or.k.ne.19) call abort
     if (m.ne.(600+40+18)) call abort
     do i = 1, 7
       do j = -3, 5
--- libgomp/testsuite/libgomp.fortran/lastprivate1.f90	(revision 0)
+++ libgomp/testsuite/libgomp.fortran/lastprivate1.f90	(revision 0)
@@ -0,0 +1,126 @@
+program lastprivate
+  integer :: i
+  common /c/ i
+  !$omp parallel num_threads (4)
+  call test1
+  !$omp end parallel
+  if (i .ne. 21) call abort
+  !$omp parallel num_threads (4)
+  call test2
+  !$omp end parallel
+  if (i .ne. 64) call abort
+  !$omp parallel num_threads (4)
+  call test3
+  !$omp end parallel
+  if (i .ne. 14) call abort
+  call test4
+  call test5
+  call test6
+  call test7
+  call test8
+  call test9
+  call test10
+  call test11
+  call test12
+contains
+  subroutine test1
+    integer :: i
+    common /c/ i
+    !$omp do lastprivate (i)
+    do i = 1, 20
+    end do
+  end subroutine test1
+  subroutine test2
+    integer :: i
+    common /c/ i
+    !$omp do lastprivate (i)
+    do i = 7, 61, 3
+    end do
+  end subroutine test2
+  function ret3 ()
+    integer :: ret3
+    ret3 = 3
+  end function ret3
+  subroutine test3
+    integer :: i
+    common /c/ i
+    !$omp do lastprivate (i)
+    do i = -10, 11, ret3 ()
+    end do
+  end subroutine test3
+  subroutine test4
+    integer :: j
+    !$omp parallel do lastprivate (j) num_threads (4) default (none)
+    do j = 1, 20
+    end do
+    if (j .ne. 21) call abort
+  end subroutine test4
+  subroutine test5
+    integer :: j
+    !$omp parallel do lastprivate (j) num_threads (4) default (none)
+    do j = 7, 61, 3
+    end do
+    if (j .ne. 64) call abort
+  end subroutine test5
+  subroutine test6
+    integer :: j
+    !$omp parallel do lastprivate (j) num_threads (4) default (none)
+    do j = -10, 11, ret3 ()
+    end do
+    if (j .ne. 14) call abort
+  end subroutine test6
+  subroutine test7
+    integer :: i
+    common /c/ i
+    !$omp parallel do lastprivate (i) num_threads (4) default (none)
+    do i = 1, 20
+    end do
+    if (i .ne. 21) call abort
+  end subroutine test7
+  subroutine test8
+    integer :: i
+    common /c/ i
+    !$omp parallel do lastprivate (i) num_threads (4) default (none)
+    do i = 7, 61, 3
+    end do
+    if (i .ne. 64) call abort
+  end subroutine test8
+  subroutine test9
+    integer :: i
+    common /c/ i
+    !$omp parallel do lastprivate (i) num_threads (4) default (none)
+    do i = -10, 11, ret3 ()
+    end do
+    if (i .ne. 14) call abort
+  end subroutine test9
+  subroutine test10
+    integer :: i
+    common /c/ i
+    !$omp parallel num_threads (4) default (none) shared (i)
+    !$omp do lastprivate (i)
+    do i = 1, 20
+    end do
+    !$omp end parallel
+    if (i .ne. 21) call abort
+  end subroutine test10
+  subroutine test11
+    integer :: i
+    common /c/ i
+    !$omp parallel num_threads (4) default (none) shared (i)
+    !$omp do lastprivate (i)
+    do i = 7, 61, 3
+    end do
+    !$omp end parallel
+    if (i .ne. 64) call abort
+  end subroutine test11
+  subroutine test12
+    integer :: i
+    common /c/ i
+    !$omp parallel num_threads (4) default (none) shared (i)
+    !$omp do lastprivate (i)
+    do i = -10, 11, ret3 ()
+    end do
+    !$omp end parallel
+    if (i .ne. 14) call abort
+  end subroutine test12
+end program lastprivate
--- libgomp/testsuite/libgomp.fortran/lastprivate2.f90	(revision 0)
+++ libgomp/testsuite/libgomp.fortran/lastprivate2.f90	(revision 0)
@@ -0,0 +1,141 @@
+program lastprivate
+  integer :: i, k
+  common /c/ i, k
+  !$omp parallel num_threads (4)
+  call test1
+  !$omp end parallel
+  if (i .ne. 21 .or. k .ne. 20) call abort
+  !$omp parallel num_threads (4)
+  call test2
+  !$omp end parallel
+  if (i .ne. 64 .or. k .ne. 61) call abort
+  !$omp parallel num_threads (4)
+  call test3
+  !$omp end parallel
+  if (i .ne. 14 .or. k .ne. 11) call abort
+  call test4
+  call test5
+  call test6
+  call test7
+  call test8
+  call test9
+  call test10
+  call test11
+  call test12
+contains
+  subroutine test1
+    integer :: i, k
+    common /c/ i, k
+    !$omp do lastprivate (i, k)
+    do i = 1, 20
+      k = i
+    end do
+  end subroutine test1
+  subroutine test2
+    integer :: i, k
+    common /c/ i, k
+    !$omp do lastprivate (i, k)
+    do i = 7, 61, 3
+      k = i
+    end do
+  end subroutine test2
+  function ret3 ()
+    integer :: ret3
+    ret3 = 3
+  end function ret3
+  subroutine test3
+    integer :: i, k
+    common /c/ i, k
+    !$omp do lastprivate (i, k)
+    do i = -10, 11, ret3 ()
+      k = i
+    end do
+  end subroutine test3
+  subroutine test4
+    integer :: j, l
+    !$omp parallel do lastprivate (j, l) num_threads (4)
+    do j = 1, 20
+      l = j
+    end do
+    if (j .ne. 21 .or. l .ne. 20) call abort
+  end subroutine test4
+  subroutine test5
+    integer :: j, l
+    l = 77
+    !$omp parallel do lastprivate (j, l) num_threads (4) firstprivate (l)
+    do j = 7, 61, 3
+      l = j
+    end do
+    if (j .ne. 64 .or. l .ne. 61) call abort
+  end subroutine test5
+  subroutine test6
+    integer :: j, l
+    !$omp parallel do lastprivate (j, l) num_threads (4)
+    do j = -10, 11, ret3 ()
+      l = j
+    end do
+    if (j .ne. 14 .or. l .ne. 11) call abort
+  end subroutine test6
+  subroutine test7
+    integer :: i, k
+    common /c/ i, k
+    !$omp parallel do lastprivate (i, k) num_threads (4)
+    do i = 1, 20
+      k = i
+    end do
+    if (i .ne. 21 .or. k .ne. 20) call abort
+  end subroutine test7
+  subroutine test8
+    integer :: i, k
+    common /c/ i, k
+    !$omp parallel do lastprivate (i, k) num_threads (4)
+    do i = 7, 61, 3
+      k = i
+    end do
+    if (i .ne. 64 .or. k .ne. 61) call abort
+  end subroutine test8
+  subroutine test9
+    integer :: i, k
+    common /c/ i, k
+    k = 77
+    !$omp parallel do lastprivate (i, k) num_threads (4) firstprivate (k)
+    do i = -10, 11, ret3 ()
+      k = i
+    end do
+    if (i .ne. 14 .or. k .ne. 11) call abort
+  end subroutine test9
+  subroutine test10
+    integer :: i, k
+    common /c/ i, k
+    !$omp parallel num_threads (4)
+    !$omp do lastprivate (i, k)
+    do i = 1, 20
+      k = i
+    end do
+    !$omp end parallel
+    if (i .ne. 21 .or. k .ne. 20) call abort
+  end subroutine test10
+  subroutine test11
+    integer :: i, k
+    common /c/ i, k
+    !$omp parallel num_threads (4)
+    !$omp do lastprivate (i, k)
+    do i = 7, 61, 3
+      k = i
+    end do
+    !$omp end parallel
+    if (i .ne. 64 .or. k .ne. 61) call abort
+  end subroutine test11
+  subroutine test12
+    integer :: i, k
+    common /c/ i, k
+    k = 77
+    !$omp parallel num_threads (4)
+    !$omp do lastprivate (i, k) firstprivate (k)
+    do i = -10, 11, ret3 ()
+      k = i
+    end do
+    !$omp end parallel
+    if (i .ne. 14 .or. k .ne. 11) call abort
+  end subroutine test12
+end program lastprivate
--- libgomp/testsuite/libgomp.c/nestedfn-6.c	(revision 0)
+++ libgomp/testsuite/libgomp.c/nestedfn-6.c	(revision 0)
@@ -0,0 +1,21 @@
+extern void abort (void);
+
+int j;
+
+int
+main (void)
+{
+  int i;
+  void nested (void) { i = 0; }
+#pragma omp parallel for lastprivate (i)
+  for (i = 0; i < 50; i += 3)
+    ;
+  if (i != 51)
+    abort ();
+#pragma omp parallel for lastprivate (j)
+  for (j = -50; j < 70; j += 7)
+    ;
+  if (j != 76)
+    abort ();
+  return 0;
+}

	Jakub


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]