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] C collapsed omp for loops


Hi!

The OpenMP 3.0 draft is a little bit vague on what exactly is considered to
be valid perfectly nested collapsed loops, this patch will allow just
optional braces and possibly empty statements in between the nested for
loops, nothing else.  If the final standard clarifies this, we can adjust
it.  But this at least allows us to test collapsed loops not just in Fortran, but
also in C.  C++ will follow later.

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

	* c-omp.c (c_finish_omp_for): Change decl/init/cond/incr arguments
	to TREE_VECs, check arguments for all collapsed loops.
	* c-parser.c (c_parser_omp_for_loop): Parse collapsed loops.

	* semantics.c (finish_omp_for): Adjust c_finish_omp_for caller,
	pass one entry TREE_VECs instead of decl/expressions.

	* gcc.dg/gomp/collapse-1.c: New test.

	* testsuite/libgomp.c/collapse-2.c: New test.

--- gcc/c-omp.c	(revision 132481)
+++ gcc/c-omp.c	(working copy)
@@ -1,7 +1,7 @@
 /* This file contains routines to construct GNU OpenMP constructs, 
    called from parsing in the C and C++ front ends.
 
-   Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
    Contributed by Richard Henderson <rth@redhat.com>,
 		  Diego Novillo <dnovillo@redhat.com>.
 
@@ -217,164 +217,184 @@ check_omp_for_incr_expr (tree exp, tree 
    DECL is the iteration variable.  */
 
 tree
-c_finish_omp_for (location_t locus, tree decl, tree init, tree cond,
-		  tree incr, tree body, tree pre_body)
+c_finish_omp_for (location_t locus, tree declv, tree initv, tree condv,
+		  tree incrv, tree body, tree pre_body)
 {
-  location_t elocus = locus;
+  location_t elocus;
   bool fail = false;
+  int i;
 
-  if (EXPR_HAS_LOCATION (init))
-    elocus = EXPR_LOCATION (init);
+  gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (initv));
+  gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (condv));
+  gcc_assert (TREE_VEC_LENGTH (declv) == TREE_VEC_LENGTH (incrv));
+  for (i = 0; i < TREE_VEC_LENGTH (declv); i++)
+    {
+      tree decl = TREE_VEC_ELT (declv, i);
+      tree init = TREE_VEC_ELT (initv, i);
+      tree cond = TREE_VEC_ELT (condv, i);
+      tree incr = TREE_VEC_ELT (incrv, i);
+
+      elocus = locus;
+      if (EXPR_HAS_LOCATION (init))
+	elocus = EXPR_LOCATION (init);
 
-  /* Validate the iteration variable.  */
-  if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)))
-    {
-      error ("%Hinvalid type for iteration variable %qE", &elocus, decl);
-      fail = true;
-    }
-  if (TYPE_UNSIGNED (TREE_TYPE (decl)))
-    warning (0, "%Hiteration variable %qE is unsigned", &elocus, decl);
-
-  /* In the case of "for (int i = 0...)", init will be a decl.  It should
-     have a DECL_INITIAL that we can turn into an assignment.  */
-  if (init == decl)
-    {
-      elocus = DECL_SOURCE_LOCATION (decl);
-
-      init = DECL_INITIAL (decl);
-      if (init == NULL)
+      /* Validate the iteration variable.  */
+      if (!INTEGRAL_TYPE_P (TREE_TYPE (decl)))
 	{
-	  error ("%H%qE is not initialized", &elocus, decl);
-	  init = integer_zero_node;
+	  error ("%Hinvalid type for iteration variable %qE", &elocus, decl);
 	  fail = true;
 	}
+      if (TYPE_UNSIGNED (TREE_TYPE (decl)))
+	warning (0, "%Hiteration variable %qE is unsigned", &elocus, decl);
 
-      init = build_modify_expr (decl, NOP_EXPR, init);
-      SET_EXPR_LOCATION (init, elocus);
-    }
-  gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
-  gcc_assert (TREE_OPERAND (init, 0) == decl);
-  
-  if (cond == NULL_TREE)
-    {
-      error ("%Hmissing controlling predicate", &elocus);
-      fail = true;
-    }
-  else
-    {
-      bool cond_ok = false;
+      /* In the case of "for (int i = 0...)", init will be a decl.  It should
+	 have a DECL_INITIAL that we can turn into an assignment.  */
+      if (init == decl)
+	{
+	  elocus = DECL_SOURCE_LOCATION (decl);
 
-      if (EXPR_HAS_LOCATION (cond))
-	elocus = EXPR_LOCATION (cond);
+	  init = DECL_INITIAL (decl);
+	  if (init == NULL)
+	    {
+	      error ("%H%qE is not initialized", &elocus, decl);
+	      init = integer_zero_node;
+	      fail = true;
+	    }
 
-      if (TREE_CODE (cond) == LT_EXPR
-	  || TREE_CODE (cond) == LE_EXPR
-	  || TREE_CODE (cond) == GT_EXPR
-	  || TREE_CODE (cond) == GE_EXPR)
+	  init = build_modify_expr (decl, NOP_EXPR, init);
+	  SET_EXPR_LOCATION (init, elocus);
+	}
+      gcc_assert (TREE_CODE (init) == MODIFY_EXPR);
+      gcc_assert (TREE_OPERAND (init, 0) == decl);
+
+      if (cond == NULL_TREE)
+	{
+	  error ("%Hmissing controlling predicate", &elocus);
+	  fail = true;
+	}
+      else
 	{
-	  tree op0 = TREE_OPERAND (cond, 0);
-	  tree op1 = TREE_OPERAND (cond, 1);
+	  bool cond_ok = false;
 
-	  /* 2.5.1.  The comparison in the condition is computed in the type
-	     of DECL, otherwise the behavior is undefined.
+	  if (EXPR_HAS_LOCATION (cond))
+	    elocus = EXPR_LOCATION (cond);
 
-	     For example:
-	     long n; int i;
-	     i < n;
-
-	     according to ISO will be evaluated as:
-	     (long)i < n;
-
-	     We want to force:
-	     i < (int)n;  */
-	  if (TREE_CODE (op0) == NOP_EXPR
-	      && decl == TREE_OPERAND (op0, 0))
-	    {
-	      TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0);
-	      TREE_OPERAND (cond, 1) = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
-						    TREE_OPERAND (cond, 1));
-	    }
-	  else if (TREE_CODE (op1) == NOP_EXPR
-		   && decl == TREE_OPERAND (op1, 0))
+	  if (TREE_CODE (cond) == LT_EXPR
+	      || TREE_CODE (cond) == LE_EXPR
+	      || TREE_CODE (cond) == GT_EXPR
+	      || TREE_CODE (cond) == GE_EXPR)
 	    {
-	      TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0);
-	      TREE_OPERAND (cond, 0) = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
-						    TREE_OPERAND (cond, 0));
+	      tree op0 = TREE_OPERAND (cond, 0);
+	      tree op1 = TREE_OPERAND (cond, 1);
+
+	      /* 2.5.1.  The comparison in the condition is computed in
+		 the type of DECL, otherwise the behavior is undefined.
+
+		 For example:
+		 long n; int i;
+		 i < n;
+
+		 according to ISO will be evaluated as:
+		 (long)i < n;
+
+		 We want to force:
+		 i < (int)n;  */
+	      if (TREE_CODE (op0) == NOP_EXPR
+		  && decl == TREE_OPERAND (op0, 0))
+		{
+		  TREE_OPERAND (cond, 0) = TREE_OPERAND (op0, 0);
+		  TREE_OPERAND (cond, 1)
+		    = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
+				   TREE_OPERAND (cond, 1));
+		}
+	      else if (TREE_CODE (op1) == NOP_EXPR
+		       && decl == TREE_OPERAND (op1, 0))
+		{
+		  TREE_OPERAND (cond, 1) = TREE_OPERAND (op1, 0);
+		  TREE_OPERAND (cond, 0)
+		    = fold_build1 (NOP_EXPR, TREE_TYPE (decl),
+				   TREE_OPERAND (cond, 0));
+		}
+
+	      if (decl == TREE_OPERAND (cond, 0))
+		cond_ok = true;
+	      else if (decl == TREE_OPERAND (cond, 1))
+		{
+		  TREE_SET_CODE (cond,
+				 swap_tree_comparison (TREE_CODE (cond)));
+		  TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
+		  TREE_OPERAND (cond, 0) = decl;
+		  cond_ok = true;
+		}
 	    }
 
-	  if (decl == TREE_OPERAND (cond, 0))
-	    cond_ok = true;
-	  else if (decl == TREE_OPERAND (cond, 1))
+	  if (!cond_ok)
 	    {
-	      TREE_SET_CODE (cond, swap_tree_comparison (TREE_CODE (cond)));
-	      TREE_OPERAND (cond, 1) = TREE_OPERAND (cond, 0);
-	      TREE_OPERAND (cond, 0) = decl;
-	      cond_ok = true;
+	      error ("%Hinvalid controlling predicate", &elocus);
+	      fail = true;
 	    }
 	}
 
-      if (!cond_ok)
+      if (incr == NULL_TREE)
 	{
-	  error ("%Hinvalid controlling predicate", &elocus);
+	  error ("%Hmissing increment expression", &elocus);
 	  fail = true;
 	}
-    }
-
-  if (incr == NULL_TREE)
-    {
-      error ("%Hmissing increment expression", &elocus);
-      fail = true;
-    }
-  else
-    {
-      bool incr_ok = false;
-
-      if (EXPR_HAS_LOCATION (incr))
-	elocus = EXPR_LOCATION (incr);
-
-      /* Check all the valid increment expressions: v++, v--, ++v, --v,
-	 v = v + incr, v = incr + v and v = v - incr.  */
-      switch (TREE_CODE (incr))
+      else
 	{
-	case POSTINCREMENT_EXPR:
-	case PREINCREMENT_EXPR:
-	case POSTDECREMENT_EXPR:
-	case PREDECREMENT_EXPR:
-	  incr_ok = (TREE_OPERAND (incr, 0) == decl);
-	  break;
+	  bool incr_ok = false;
 
-	case MODIFY_EXPR:
-	  if (TREE_OPERAND (incr, 0) != decl)
-	    break;
-	  if (TREE_OPERAND (incr, 1) == decl)
-	    break;
-	  if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR
-	      && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl
-		  || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl))
-	    incr_ok = true;
-	  else if (TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR
-		   && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl)
-	    incr_ok = true;
-	  else
+	  if (EXPR_HAS_LOCATION (incr))
+	    elocus = EXPR_LOCATION (incr);
+
+	  /* Check all the valid increment expressions: v++, v--, ++v, --v,
+	     v = v + incr, v = incr + v and v = v - incr.  */
+	  switch (TREE_CODE (incr))
 	    {
-	      tree t = check_omp_for_incr_expr (TREE_OPERAND (incr, 1), decl);
-	      if (t != error_mark_node)
+	    case POSTINCREMENT_EXPR:
+	    case PREINCREMENT_EXPR:
+	    case POSTDECREMENT_EXPR:
+	    case PREDECREMENT_EXPR:
+	      incr_ok = (TREE_OPERAND (incr, 0) == decl);
+	      break;
+
+	    case MODIFY_EXPR:
+	      if (TREE_OPERAND (incr, 0) != decl)
+		break;
+	      if (TREE_OPERAND (incr, 1) == decl)
+		break;
+	      if (TREE_CODE (TREE_OPERAND (incr, 1)) == PLUS_EXPR
+		  && (TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl
+		      || TREE_OPERAND (TREE_OPERAND (incr, 1), 1) == decl))
+		incr_ok = true;
+	      else if (TREE_CODE (TREE_OPERAND (incr, 1)) == MINUS_EXPR
+		       && TREE_OPERAND (TREE_OPERAND (incr, 1), 0) == decl)
+		incr_ok = true;
+	      else
 		{
-		  incr_ok = true;
-		  t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
-		  incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
+		  tree t = check_omp_for_incr_expr (TREE_OPERAND (incr, 1),
+						    decl);
+		  if (t != error_mark_node)
+		    {
+		      incr_ok = true;
+		      t = build2 (PLUS_EXPR, TREE_TYPE (decl), decl, t);
+		      incr = build2 (MODIFY_EXPR, void_type_node, decl, t);
+		    }
 		}
-	    }
-	  break;
+	      break;
 
-	default:
-	  break;
-	}
-      if (!incr_ok)
-	{
-	  error ("%Hinvalid increment expression", &elocus);
-	  fail = true;
+	    default:
+	      break;
+	    }
+	  if (!incr_ok)
+	    {
+	      error ("%Hinvalid increment expression", &elocus);
+	      fail = true;
+	    }
 	}
+
+      TREE_VEC_ELT (initv, i) = init;
+      TREE_VEC_ELT (incrv, i) = incr;
     }
 
   if (fail)
@@ -384,12 +404,9 @@ c_finish_omp_for (location_t locus, tree
       tree t = make_node (OMP_FOR);
 
       TREE_TYPE (t) = void_type_node;
-      OMP_FOR_INIT (t) = make_tree_vec (1);
-      TREE_VEC_ELT (OMP_FOR_INIT (t), 0) = init;
-      OMP_FOR_COND (t) = make_tree_vec (1);
-      TREE_VEC_ELT (OMP_FOR_COND (t), 0) = cond;
-      OMP_FOR_INCR (t) = make_tree_vec (1);
-      TREE_VEC_ELT (OMP_FOR_INCR (t), 0) = incr;
+      OMP_FOR_INIT (t) = initv;
+      OMP_FOR_COND (t) = condv;
+      OMP_FOR_INCR (t) = incrv;
       OMP_FOR_BODY (t) = body;
       OMP_FOR_PRE_BODY (t) = pre_body;
 
--- gcc/c-parser.c	(revision 132481)
+++ gcc/c-parser.c	(working copy)
@@ -7610,13 +7610,22 @@ static tree
 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;
+  tree declv, condv, incrv, initv;
   location_t loc;
-  int collapse = 1;
+  bool fail = false, open_brace_parsed = false;
+  int i, collapse = 1, nbraces = 0;
 
   for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
     if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
       collapse = tree_low_cst (OMP_CLAUSE_COLLAPSE_EXPR (cl), 0);
 
+  gcc_assert (collapse >= 1);
+
+  declv = make_tree_vec (collapse);
+  initv = make_tree_vec (collapse);
+  condv = make_tree_vec (collapse);
+  incrv = make_tree_vec (collapse);
+
   if (!c_parser_next_token_is_keyword (parser, RID_FOR))
     {
       c_parser_error (parser, "for statement expected");
@@ -7625,61 +7634,130 @@ c_parser_omp_for_loop (c_parser *parser,
   loc = c_parser_peek_token (parser)->location;
   c_parser_consume_token (parser);
 
-  if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
-    return NULL;
-
-  /* Parse the initialization declaration or expression.  */
-  if (c_parser_next_token_starts_declspecs (parser))
+  for (i = 0; i < collapse; i++)
     {
-      c_parser_declaration_or_fndef (parser, true, true, true, true);
-      decl = check_for_loop_decls ();
-      if (decl == NULL)
-	goto error_init;
-      if (DECL_INITIAL (decl) == error_mark_node)
-	decl = error_mark_node;
-      init = decl;
-    }
-  else if (c_parser_next_token_is (parser, CPP_NAME)
-	   && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
-    {
-      decl = c_parser_postfix_expression (parser).value;
-
-      c_parser_require (parser, CPP_EQ, "expected %<=%>");
-
-      init = c_parser_expr_no_commas (parser, NULL).value;
-      init = build_modify_expr (decl, NOP_EXPR, init);
-      init = c_process_expr_stmt (init);
+      int bracecount = 0;
+
+      if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+	return NULL;
+
+      /* Parse the initialization declaration or expression.  */
+      if (c_parser_next_token_starts_declspecs (parser))
+	{
+	  c_parser_declaration_or_fndef (parser, true, true, true, true);
+	  decl = check_for_loop_decls ();
+	  if (decl == NULL)
+	    goto error_init;
+	  if (DECL_INITIAL (decl) == error_mark_node)
+	    decl = error_mark_node;
+	  init = decl;
+	}
+      else if (c_parser_next_token_is (parser, CPP_NAME)
+	       && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+	{
+	  decl = c_parser_postfix_expression (parser).value;
+
+	  c_parser_require (parser, CPP_EQ, "expected %<=%>");
+
+	  init = c_parser_expr_no_commas (parser, NULL).value;
+	  init = build_modify_expr (decl, NOP_EXPR, init);
+	  init = c_process_expr_stmt (init);
+
+	  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+	}
+      else
+	{
+	error_init:
+	  c_parser_error (parser,
+			  "expected iteration declaration or initialization");
+	  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+				     "expected %<)%>");
+	  fail = true;
+	  goto parse_next;
+	}
 
+      /* Parse the loop condition.  */
+      cond = NULL_TREE;
+      if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+	{
+	  cond = c_parser_expression_conv (parser).value;
+	  cond = c_objc_common_truthvalue_conversion (cond);
+	  if (CAN_HAVE_LOCATION_P (cond))
+	    SET_EXPR_LOCATION (cond, input_location);
+	}
       c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
-    }
-  else
-    goto error_init;
 
-  /* Parse the loop condition.  */
-  cond = NULL_TREE;
-  if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
-    {
-      cond = c_parser_expression_conv (parser).value;
-      cond = c_objc_common_truthvalue_conversion (cond);
-      if (CAN_HAVE_LOCATION_P (cond))
-	SET_EXPR_LOCATION (cond, input_location);
-    }
-  c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
-
-  /* Parse the increment expression.  */
-  incr = NULL_TREE;
-  if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
-    incr = c_process_expr_stmt (c_parser_expression (parser).value);
-  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+      /* Parse the increment expression.  */
+      incr = NULL_TREE;
+      if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+	incr = c_process_expr_stmt (c_parser_expression (parser).value);
+      c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
+
+      if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+	fail = true;
+      else
+	{
+	  TREE_VEC_ELT (declv, i) = decl;
+	  TREE_VEC_ELT (initv, i) = init;
+	  TREE_VEC_ELT (condv, i) = cond;
+	  TREE_VEC_ELT (incrv, i) = incr;
+	}
+
+    parse_next:
+      if (i == collapse - 1)
+	break;
+
+      /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
+	 in between the collapsed for loops to be still considered perfectly
+	 nested.  Hopefully the final version clarifies this.
+	 For now handle (multiple) {'s and empty statements.  */
+      do
+	{
+	  if (c_parser_next_token_is_keyword (parser, RID_FOR))
+	    {
+	      c_parser_consume_token (parser);
+	      break;
+	    }
+	  else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+	    {
+	      c_parser_consume_token (parser);
+	      bracecount++;
+	    }
+	  else if (bracecount
+		   && c_parser_next_token_is (parser, CPP_SEMICOLON))
+	    c_parser_consume_token (parser);
+	  else
+	    {
+	      c_parser_error (parser, "not enough perfectly nested loops");
+	      if (bracecount)
+		{
+		  open_brace_parsed = true;
+		  bracecount--;
+		}
+	      fail = true;
+	      collapse = 0;
+	      break;
+	    }
+	}
+      while (1);
+
+      nbraces += bracecount;
+    }
 
- parse_body:
   save_break = c_break_label;
   c_break_label = size_one_node;
   save_cont = c_cont_label;
   c_cont_label = NULL_TREE;
   body = push_stmt_list ();
 
-  add_stmt (c_parser_c99_block_statement (parser));
+  if (open_brace_parsed)
+    {
+      stmt = c_begin_compound_stmt (true);
+      c_parser_compound_statement_nostart (parser);
+      add_stmt (c_end_compound_stmt (stmt, true));
+    }
+  else
+    add_stmt (c_parser_c99_block_statement (parser));
   if (c_cont_label)
     add_stmt (build1 (LABEL_EXPR, void_type_node, c_cont_label));
 
@@ -7687,49 +7765,75 @@ c_parser_omp_for_loop (c_parser *parser,
   c_break_label = save_break;
   c_cont_label = save_cont;
 
+  while (nbraces)
+    {
+      if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+	{
+	  c_parser_consume_token (parser);
+	  nbraces--;
+	}
+      else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
+	c_parser_consume_token (parser);
+      else
+	{
+	  c_parser_error (parser, "collapsed loops not perfectly nested");
+	  while (nbraces)
+	    {
+	      stmt = c_begin_compound_stmt (true);
+	      add_stmt (body);
+	      c_parser_compound_statement_nostart (parser);
+	      body = c_end_compound_stmt (stmt, true);
+	      nbraces--;
+	    }
+	  return NULL;
+	}
+    }
+
   /* Only bother calling c_finish_omp_for if we haven't already generated
      an error from the initialization parsing.  */
-  if (decl != NULL && decl != error_mark_node && init != error_mark_node)
+  if (!fail)
     {
-      stmt = c_finish_omp_for (loc, decl, init, cond, incr, body, NULL);
+      stmt = c_finish_omp_for (loc, declv, initv, condv, incrv, body, NULL);
       if (stmt)
 	{
 	  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)
+		if (OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_FIRSTPRIVATE
+		    && OMP_CLAUSE_CODE (*c) != OMP_CLAUSE_LASTPRIVATE)
+		  c = &OMP_CLAUSE_CHAIN (*c);
+		else
 		  {
-		    /* 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);
+		    for (i = 0; i < collapse; i++)
+		      if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
+			break;
+		    if (i == collapse)
+		      c = &OMP_CLAUSE_CHAIN (*c);
+		    else if (OMP_CLAUSE_CODE (*c) == OMP_CLAUSE_FIRSTPRIVATE)
+		      {
+			error ("%Hiteration variable %qD should not be firstprivate",
+			       &loc, OMP_CLAUSE_DECL (*c));
+			*c = OMP_CLAUSE_CHAIN (*c);
+		      }
+		    else
+		      {
+			/* 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) = OMP_CLAUSE_DECL (*c);
+			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;
-
- error_init:
-  c_parser_error (parser, "expected iteration declaration or initialization");
-  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, "expected %<)%>");
-  decl = init = cond = incr = NULL_TREE;
-  goto parse_body;
 }
 
 /* OpenMP 2.5:
--- gcc/cp/semantics.c	(revision 132492)
+++ gcc/cp/semantics.c	(working copy)
@@ -4205,7 +4205,19 @@ finish_omp_for (location_t locus, tree d
 	  = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
     }
   if (decl != error_mark_node && init != error_mark_node)
-    omp_for = c_finish_omp_for (locus, decl, init, cond, incr, body, pre_body);
+    {
+      tree declv = make_tree_vec (1);
+      tree initv = make_tree_vec (1);
+      tree condv = make_tree_vec (1);
+      tree incrv = make_tree_vec (1);
+
+      TREE_VEC_ELT (declv, 0) = decl;
+      TREE_VEC_ELT (initv, 0) = init;
+      TREE_VEC_ELT (condv, 0) = cond;
+      TREE_VEC_ELT (incrv, 0) = incr;
+      omp_for = c_finish_omp_for (locus, declv, initv, condv, incrv,
+				  body, pre_body);
+    }
   if (omp_for != NULL
       && TREE_CODE (TREE_VEC_ELT (OMP_FOR_INCR (omp_for), 0)) == MODIFY_EXPR)
     {
--- gcc/testsuite/gcc.dg/gomp/collapse-1.c	(revision 0)
+++ gcc/testsuite/gcc.dg/gomp/collapse-1.c	(revision 0)
@@ -0,0 +1,92 @@
+/* { dg-do compile } */
+/* { dg-options "-fopenmp" } */
+
+int i, j, k;
+extern int foo (void);
+
+void
+f1 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    ;					/* { dg-error "not enough perfectly nested" } */
+  {
+    for (j = 0; j < 5; j++)
+      ;
+  }
+}
+
+void
+f2 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    {
+      {
+	{
+	  for (j = 0; j < 5; j++)
+	    {
+	    }
+	}
+      }
+    }
+}
+
+void
+f3 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    {
+      int k = foo ();			/* { dg-error "not enough perfectly nested" } */
+      {
+	{
+	  for (j = 0; j < 5; j++)
+	    {
+	    }
+	}
+      }
+    }
+}
+
+void
+f4 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    {
+      {
+	for (j = 0; j < 5; j++)
+	  ;
+	foo ();				/* { dg-error "collapsed loops not perfectly nested before" } */
+      }
+    }
+}
+
+void
+f5 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    {
+      {
+	for (j = 0; j < 5; j++)
+	  ;
+      }
+      foo ();				/* { dg-error "collapsed loops not perfectly nested before" } */
+    }
+}
+
+void
+f6 (void)
+{
+  #pragma omp for collapse (2)
+  for (i = 0; i < 5; i++)
+    {
+      {
+	for (j = 0; j < 5; j++)
+	  ;
+      }
+    }
+  foo ();
+}
--- libgomp/testsuite/libgomp.c/collapse-2.c	(revision 0)
+++ libgomp/testsuite/libgomp.c/collapse-2.c	(revision 0)
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+
+#include <stdlib.h>
+#include <omp.h>
+
+int
+main (void)
+{
+  int i, j, k, l = 0, f = 0;
+  int m1 = 4, m2 = -5, m3 = 17;
+
+  #pragma omp parallel for num_threads (8) collapse(3) \
+		       schedule(static, 9) reduction(+:l) \
+		       firstprivate(f)
+    for (i = -2; i < m1; i++)
+      for (j = m2; j < -2; j++)
+	{
+	  for (k = 13; k < m3; k++)
+	    {
+	      if (omp_get_num_threads () == 8
+		  && ((i + 2) * 12 + (j + 5) * 4 + (k - 13)
+		      != (omp_get_thread_num () * 9
+			  + f++)))
+		l++;
+	    }
+	}
+  if (l)
+    abort ();
+  return 0;
+}

	Jakub


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