[gomp3] Initial C++ parser changes for OpenMP 3.0

Jakub Jelinek jakub@redhat.com
Wed Dec 19 14:50:00 GMT 2007


Hi!

Committed to gomp-3_0-branch.  Similarly to C and Fortran FEs, collapse
clause is parsed, but it is only remembered ATM and the loops are parsed
as if collapse clause wasn't present.

The check for integral constant collapse is perhaps too restrictive,
but I wonder if e.g.
template <int N> struct S
{
  static const int count = N;
  void foo ()
  {
    int i, j, k, l;
  #pragma omp for collapse (count)
    for (i = 0; i < N; i++)
      for (j = 0; j < N; j++)
        for (k = 0; k < N; k++)
	  for (l = 0; l < N; l++)
	    bar (i, j, k, l);
  }
}
is something we should accept (i.e. where collapse argument is type
dependent or value dependent and we won't know until instantiation
what value does it have (and whether it is integral).  Because already
during the parsing we'd better know exactly how many loops are collapsed,
because the loops need different parsing when collapsed and when not
collapsed.

2007-12-19  Jakub Jelinek  <jakub@redhat.com>

	* cp-tree.h (begin_omp_task, finish_omp_task, finish_omp_taskwait):
	New prototypes.
	* semantics.c (finish_omp_clauses): Handle OMP_CLAUSE_UNTIED and
	OMP_CLAUSE_COLLAPSE.
	(begin_omp_task, finish_omp_task, finish_omp_taskwait): New
	functions.
	* parser.c (cp_parser_omp_clause_name): Handle collapse and untied
	clauses.
	(cp_parser_omp_clause_collapse, cp_parser_omp_clause_untied): New
	functions.
	(cp_parser_omp_clause_schedule): Handle auto schedule.
	(cp_parser_omp_all_clauses): Handle PRAGMA_OMP_CLAUSE_COLLAPSE
	and PRAGMA_OMP_CLAUSE_UNTIED.
	(OMP_FOR_CLAUSE_MASK): Add PRAGMA_OMP_CLAUSE_COLLAPSE.
	(OMP_TASK_CLAUSE_MASK): Define.
	(cp_parser_omp_task, cp_parser_omp_taskwait): New functions.
	(cp_parser_omp_construct): Handle PRAGMA_OMP_TASK.
	(cp_parser_pragma): Handle PRAGMA_OMP_TASK and
	PRAGMA_OMP_TASKWAIT.

	* testsuite/libgomp.c/task-1.c (f3): New function.
	(main): Call it, also test from within parallel region.
	* testsuite/libgomp.c/collapse-1.c: New test.
	* testsuite/libgomp.c++/task-1.C: New test.
	* testsuite/libgomp.c++/collapse-1.C: New test.
	* testsuite/libgomp.fortran/collapse1.f90: New test.

--- gcc/cp/cp-tree.h	(revision 130773)
+++ gcc/cp/cp-tree.h	(working copy)
@@ -4660,11 +4660,14 @@ extern tree begin_omp_structured_block		
 extern tree finish_omp_structured_block		(tree);
 extern tree begin_omp_parallel			(void);
 extern tree finish_omp_parallel			(tree, 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);
 extern void finish_omp_atomic			(enum tree_code, tree, tree);
 extern void finish_omp_barrier			(void);
 extern void finish_omp_flush			(void);
+extern void finish_omp_taskwait			(void);
 extern enum omp_clause_default_kind cxx_omp_predetermined_sharing (tree);
 extern tree cxx_omp_clause_default_ctor		(tree, tree);
 extern tree cxx_omp_clause_copy_ctor		(tree, tree, tree);
--- gcc/cp/semantics.c	(revision 130773)
+++ gcc/cp/semantics.c	(working copy)
@@ -3451,6 +3451,8 @@ finish_omp_clauses (tree clauses)
 	case OMP_CLAUSE_NOWAIT:
 	case OMP_CLAUSE_ORDERED:
 	case OMP_CLAUSE_DEFAULT:
+	case OMP_CLAUSE_UNTIED:
+	case OMP_CLAUSE_COLLAPSE:
 	  break;
 
 	default:
@@ -3802,6 +3804,28 @@ finish_omp_parallel (tree clauses, tree 
   return add_stmt (stmt);
 }
 
+tree
+begin_omp_task (void)
+{
+  keep_next_level (true);
+  return begin_omp_structured_block ();
+}
+
+tree
+finish_omp_task (tree clauses, tree body)
+{
+  tree stmt;
+
+  body = finish_omp_structured_block (body);
+
+  stmt = make_node (OMP_TASK);
+  TREE_TYPE (stmt) = void_type_node;
+  OMP_TASK_CLAUSES (stmt) = clauses;
+  OMP_TASK_BODY (stmt) = body;
+
+  return add_stmt (stmt);
+}
+
 /* Build and validate an OMP_FOR statement.  CLAUSES, BODY, COND, INCR
    are directly for their associated operands in the statement.  DECL
    and INIT are a combo; if DECL is NULL then INIT ought to be a
@@ -3972,6 +3996,14 @@ finish_omp_flush (void)
   finish_expr_stmt (stmt);
 }
 
+void
+finish_omp_taskwait (void)
+{
+  tree fn = built_in_decls[BUILT_IN_GOMP_TASKWAIT];
+  tree stmt = finish_call_expr (fn, NULL, false, false);
+  finish_expr_stmt (stmt);
+}
+
 /* True if OpenMP sharing attribute of DECL is predetermined.  */
 
 enum omp_clause_default_kind
--- gcc/cp/parser.c	(revision 130773)
+++ gcc/cp/parser.c	(working copy)
@@ -19237,7 +19237,9 @@ cp_parser_omp_clause_name (cp_parser *pa
       switch (p[0])
 	{
 	case 'c':
-	  if (!strcmp ("copyin", p))
+	  if (!strcmp ("collapse", p))
+	    result = PRAGMA_OMP_CLAUSE_COLLAPSE;
+	  else if (!strcmp ("copyin", p))
 	    result = PRAGMA_OMP_CLAUSE_COPYIN;
 	  else if (!strcmp ("copyprivate", p))
 	    result = PRAGMA_OMP_CLAUSE_COPYPRIVATE;
@@ -19270,6 +19272,10 @@ cp_parser_omp_clause_name (cp_parser *pa
 	  else if (!strcmp ("shared", p))
 	    result = PRAGMA_OMP_CLAUSE_SHARED;
 	  break;
+	case 'u':
+	  if (!strcmp ("untied", p))
+	    result = PRAGMA_OMP_CLAUSE_UNTIED;
+	  break;
 	}
     }
 
@@ -19372,6 +19378,46 @@ cp_parser_omp_var_list (cp_parser *parse
   return list;
 }
 
+/* OpenMP 3.0:
+   collapse ( constant-expression ) */
+
+static tree
+cp_parser_omp_clause_collapse (cp_parser *parser, tree list)
+{
+  tree c, num;
+  location_t loc;
+  HOST_WIDE_INT n;
+
+  loc = cp_lexer_peek_token (parser->lexer)->location;
+  if (!cp_parser_require (parser, CPP_OPEN_PAREN, "`('"))
+    return list;
+
+  num = cp_parser_constant_expression (parser, false, NULL);
+
+  if (!cp_parser_require (parser, CPP_CLOSE_PAREN, "`)'"))
+    cp_parser_skip_to_closing_parenthesis (parser, /*recovering=*/true,
+					   /*or_comma=*/false,
+					   /*consume_paren=*/true);
+
+  if (num == error_mark_node)
+    return list;
+  if (!INTEGRAL_TYPE_P (TREE_TYPE (num))
+      || !host_integerp (num, 0)
+      || (n = tree_low_cst (num, 0)) <= 0
+      || (int) n != n)
+    {
+      error ("%Hcollapse argument needs positive constant integer expression", &loc);
+      return list;
+    }
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_COLLAPSE, "collapse");
+  c = build_omp_clause (OMP_CLAUSE_COLLAPSE);
+  OMP_CLAUSE_CHAIN (c) = list;
+  OMP_CLAUSE_COLLAPSE_EXPR (c) = num;
+
+  return c;
+}
+
 /* OpenMP 2.5:
    default ( shared | none ) */
 
@@ -19582,7 +19628,7 @@ cp_parser_omp_clause_reduction (cp_parse
    schedule ( schedule-kind , expression )
 
    schedule-kind:
-     static | dynamic | guided | runtime  */
+     static | dynamic | guided | runtime | auto  */
 
 static tree
 cp_parser_omp_clause_schedule (cp_parser *parser, tree list)
@@ -19625,6 +19671,8 @@ cp_parser_omp_clause_schedule (cp_parser
     }
   else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_STATIC))
     OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_STATIC;
+  else if (cp_lexer_next_token_is_keyword (parser->lexer, RID_AUTO))
+    OMP_CLAUSE_SCHEDULE_KIND (c) = OMP_CLAUSE_SCHEDULE_AUTO;
   else
     goto invalid_kind;
   cp_lexer_consume_token (parser->lexer);
@@ -19640,6 +19688,9 @@ cp_parser_omp_clause_schedule (cp_parser
       else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_RUNTIME)
 	error ("schedule %<runtime%> does not take "
 	       "a %<chunk_size%> parameter");
+      else if (OMP_CLAUSE_SCHEDULE_KIND (c) == OMP_CLAUSE_SCHEDULE_AUTO)
+	error ("schedule %<auto%> does not take "
+	       "a %<chunk_size%> parameter");
       else
 	OMP_CLAUSE_SCHEDULE_CHUNK_EXPR (c) = t;
 
@@ -19662,6 +19713,21 @@ cp_parser_omp_clause_schedule (cp_parser
   return list;
 }
 
+/* OpenMP 3.0:
+   untied */
+
+static tree
+cp_parser_omp_clause_untied (cp_parser *parser ATTRIBUTE_UNUSED, tree list)
+{
+  tree c;
+
+  check_no_duplicate_clause (list, OMP_CLAUSE_UNTIED, "untied");
+
+  c = build_omp_clause (OMP_CLAUSE_UNTIED);
+  OMP_CLAUSE_CHAIN (c) = list;
+  return c;
+}
+
 /* Parse all OpenMP clauses.  The set clauses allowed by the directive
    is a bitmask in MASK.  Return the list of clauses found; the result
    of clause default goes in *pdefault.  */
@@ -19680,6 +19746,10 @@ cp_parser_omp_all_clauses (cp_parser *pa
 
       switch (c_kind)
 	{
+	case PRAGMA_OMP_CLAUSE_COLLAPSE:
+	  clauses = cp_parser_omp_clause_collapse (parser, clauses);
+	  c_name = "collapse";
+	  break;
 	case PRAGMA_OMP_CLAUSE_COPYIN:
 	  clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_COPYIN, clauses);
 	  c_name = "copyin";
@@ -19737,6 +19807,10 @@ cp_parser_omp_all_clauses (cp_parser *pa
 					    clauses);
 	  c_name = "shared";
 	  break;
+	case PRAGMA_OMP_CLAUSE_UNTIED:
+	  clauses = cp_parser_omp_clause_untied (parser, clauses);
+	  c_name = "nowait";
+	  break;
 	default:
 	  cp_parser_error (parser, "expected %<#pragma omp%> clause");
 	  goto saw_error;
@@ -20056,7 +20130,8 @@ cp_parser_omp_for_loop (cp_parser *parse
 	| (1u << PRAGMA_OMP_CLAUSE_REDUCTION)		\
 	| (1u << PRAGMA_OMP_CLAUSE_ORDERED)		\
 	| (1u << PRAGMA_OMP_CLAUSE_SCHEDULE)		\
-	| (1u << PRAGMA_OMP_CLAUSE_NOWAIT))
+	| (1u << PRAGMA_OMP_CLAUSE_NOWAIT)		\
+	| (1u << PRAGMA_OMP_CLAUSE_COLLAPSE))
 
 static tree
 cp_parser_omp_for (cp_parser *parser, cp_token *pragma_tok)
@@ -20317,6 +20392,43 @@ cp_parser_omp_single (cp_parser *parser,
   return add_stmt (stmt);
 }
 
+/* OpenMP 3.0:
+   # pragma omp task task-clause[optseq] new-line
+     structured-block  */
+
+#define OMP_TASK_CLAUSE_MASK				\
+	( (1u << PRAGMA_OMP_CLAUSE_IF)			\
+	| (1u << PRAGMA_OMP_CLAUSE_UNTIED)		\
+	| (1u << PRAGMA_OMP_CLAUSE_DEFAULT)		\
+	| (1u << PRAGMA_OMP_CLAUSE_PRIVATE)		\
+	| (1u << PRAGMA_OMP_CLAUSE_FIRSTPRIVATE)	\
+	| (1u << PRAGMA_OMP_CLAUSE_SHARED))
+
+static tree
+cp_parser_omp_task (cp_parser *parser, cp_token *pragma_tok)
+{
+  tree clauses, block;
+  unsigned int save;
+
+  clauses = cp_parser_omp_all_clauses (parser, OMP_TASK_CLAUSE_MASK,
+				       "#pragma omp task", pragma_tok);
+  block = begin_omp_task ();
+  save = cp_parser_begin_omp_structured_block (parser);
+  cp_parser_statement (parser, NULL_TREE, false, NULL);
+  cp_parser_end_omp_structured_block (parser, save);
+  return finish_omp_task (clauses, block);
+}
+
+/* OpenMP 3.0:
+   # pragma omp taskwait new-line  */
+
+static void
+cp_parser_omp_taskwait (cp_parser *parser, cp_token *pragma_tok)
+{
+  cp_parser_require_pragma_eol (parser, pragma_tok);
+  finish_omp_taskwait ();
+}
+
 /* OpenMP 2.5:
    # pragma omp threadprivate (variable-list) */
 
@@ -20364,6 +20476,9 @@ cp_parser_omp_construct (cp_parser *pars
     case PRAGMA_OMP_SINGLE:
       stmt = cp_parser_omp_single (parser, pragma_tok);
       break;
+    case PRAGMA_OMP_TASK:
+      stmt = cp_parser_omp_task (parser, pragma_tok);
+      break;
     default:
       gcc_unreachable ();
     }
@@ -20471,6 +20586,21 @@ cp_parser_pragma (cp_parser *parser, enu
 	}
       break;
 
+    case PRAGMA_OMP_TASKWAIT:
+      switch (context)
+	{
+	case pragma_compound:
+	  cp_parser_omp_taskwait (parser, pragma_tok);
+	  return false;
+	case pragma_stmt:
+	  error ("%<#pragma omp taskwait%> may only be "
+		 "used in compound statements");
+	  break;
+	default:
+	  goto bad_stmt;
+	}
+      break;
+
     case PRAGMA_OMP_THREADPRIVATE:
       cp_parser_omp_threadprivate (parser, pragma_tok);
       return false;
@@ -20483,6 +20613,7 @@ cp_parser_pragma (cp_parser *parser, enu
     case PRAGMA_OMP_PARALLEL:
     case PRAGMA_OMP_SECTIONS:
     case PRAGMA_OMP_SINGLE:
+    case PRAGMA_OMP_TASK:
       if (context == pragma_external)
 	goto bad_stmt;
       cp_parser_omp_construct (parser, pragma_tok);
--- libgomp/testsuite/libgomp.c++/task-1.C	(revision 0)
+++ libgomp/testsuite/libgomp.c++/task-1.C	(revision 0)
@@ -0,0 +1,83 @@
+extern "C" void abort ();
+
+int a = 18;
+
+void
+f1 (int i, int j, int k)
+{
+  int l = 6, m = 7, n = 8;
+#pragma omp task private(j, m) shared(k, n)
+  {
+    j = 6;
+    m = 5;
+    if (++a != 19 || ++i != 9 || j != 6 || ++l != 7 || m != 5 || ++n != 9)
+      #pragma omp atomic
+	k++;
+  }
+#pragma omp taskwait
+  if (a != 19 || i != 8 || j != 26 || k != 0 || l != 6 || m != 7 || n != 9)
+    abort ();
+}
+
+int v1 = 1, v2 = 2, v5 = 5;
+int err;
+
+void
+f2 (void)
+{
+  int v3 = 3;
+#pragma omp sections private (v1) firstprivate (v2)
+  {
+  #pragma omp section
+    {
+      int v4 = 4;
+      v1 = 7;
+      #pragma omp task
+	{
+	  if (++v1 != 8 || ++v2 != 3 || ++v3 != 4 || ++v4 != 5 || ++v5 != 6)
+	    err = 1;
+	}
+      #pragma omp taskwait
+      if (v1 != 7 || v2 != 2 || v3 != 3 || v4 != 4 || v5 != 6)
+	abort ();
+      if (err)
+	abort ();
+    }
+  }
+}
+
+void
+f3 (int i, int j, int k)
+{
+  int l = 6, m = 7, n = 8;
+#pragma omp task private(j, m) shared(k, n) untied
+  {
+    j = 6;
+    m = 5;
+    if (++a != 19 || ++i != 9 || j != 6 || ++l != 7 || m != 5 || ++n != 9)
+      #pragma omp atomic
+	k++;
+  }
+#pragma omp taskwait
+  if (a != 19 || i != 8 || j != 26 || k != 0 || l != 6 || m != 7 || n != 9)
+    abort ();
+}
+
+int
+main ()
+{
+  f1 (8, 26, 0);
+  f2 ();
+  a = 18;
+  f3 (8, 26, 0);
+  a = 18;
+#pragma omp parallel num_threads(4)
+  {
+    #pragma omp master
+      {
+	f1 (8, 26, 0);
+	a = 18;
+	f3 (8, 26, 0);
+      }
+  }
+}
--- libgomp/testsuite/libgomp.c++/collapse-1.C	(revision 0)
+++ libgomp/testsuite/libgomp.c++/collapse-1.C	(revision 0)
@@ -0,0 +1,29 @@
+// { dg-do run }
+
+#include <string.h>
+#include <stdlib.h>
+
+int
+main ()
+{
+  int i, j, k, l = 0;
+  int a[3][3][3];
+
+  memset (a, '\0', sizeof (a));
+  #pragma omp parallel for collapse(4 - 1) schedule(static, 4)
+    for (i = 0; i < 2; i++)
+      for (j = 0; j < 2; j++)
+	for (k = 0; k < 2; k++)
+	  a[i][j][k] = i + j * 4 + k * 16;
+  #pragma omp parallel
+    {
+      #pragma omp for collapse(2) reduction(|:l)
+	for (i = 0; i < 2; i++)
+	  for (j = 0; j < 2; j++)
+	    for (k = 0; k < 2; k++)
+	      if (a[i][j][k] != i + j * 4 + k * 16)
+		l = 1;
+    }
+  if (l)
+    abort ();
+}
--- libgomp/testsuite/libgomp.fortran/collapse1.f90	(revision 0)
+++ libgomp/testsuite/libgomp.fortran/collapse1.f90	(revision 0)
@@ -0,0 +1,26 @@
+! { dg-do run }
+
+program collapse1
+  integer :: i, j, k, a(1:3, 4:6, 5:7)
+  logical :: l
+  l = .false.
+  a(:, :, :) = 0
+  !$omp parallel do collapse(4 - 1) schedule(static, 4)
+    do i = 1, 3
+      do j = 4, 6
+        do k = 5, 7
+          a(i, j, k) = i + j + k
+        end do
+      end do
+    end do
+  !$omp parallel do collapse(2) reduction(.or.:l)
+    do i = 1, 3
+      do j = 4, 6
+        do k = 5, 7
+          if (a(i, j, k) .ne. (i + j + k)) l = .true.
+        end do
+      end do
+    end do
+  !$omp end parallel do
+  if (l) call abort
+end program collapse1
--- libgomp/testsuite/libgomp.c/task-1.c	(revision 130773)
+++ libgomp/testsuite/libgomp.c/task-1.c	(working copy)
@@ -46,10 +46,39 @@ f2 (void)
   }
 }
 
+void
+f3 (int i, int j, int k)
+{
+  int l = 6, m = 7, n = 8;
+#pragma omp task private(j, m) shared(k, n) untied
+  {
+    j = 6;
+    m = 5;
+    if (++a != 19 || ++i != 9 || j != 6 || ++l != 7 || m != 5 || ++n != 9)
+      #pragma omp atomic
+	k++;
+  }
+#pragma omp taskwait
+  if (a != 19 || i != 8 || j != 26 || k != 0 || l != 6 || m != 7 || n != 9)
+    abort ();
+}
+
 int
 main (void)
 {
   f1 (8, 26, 0);
   f2 ();
+  a = 18;
+  f3 (8, 26, 0);
+  a = 18;
+#pragma omp parallel num_threads(4)
+  {
+    #pragma omp master
+      {
+	f1 (8, 26, 0);
+	a = 18;
+	f3 (8, 26, 0);
+      }
+  }
   return 0;
 }
--- libgomp/testsuite/libgomp.c/collapse-1.c	(revision 0)
+++ libgomp/testsuite/libgomp.c/collapse-1.c	(revision 0)
@@ -0,0 +1,30 @@
+/* { dg-do run } */
+
+#include <string.h>
+#include <stdlib.h>
+
+int
+main (void)
+{
+  int i, j, k, l = 0;
+  int a[3][3][3];
+
+  memset (a, '\0', sizeof (a));
+  #pragma omp parallel for collapse(4 - 1) schedule(static, 4)
+    for (i = 0; i < 2; i++)
+      for (j = 0; j < 2; j++)
+	for (k = 0; k < 2; k++)
+	  a[i][j][k] = i + j * 4 + k * 16;
+  #pragma omp parallel
+    {
+      #pragma omp for collapse(2) reduction(|:l)
+	for (i = 0; i < 2; i++)
+	  for (j = 0; j < 2; j++)
+	    for (k = 0; k < 2; k++)
+	      if (a[i][j][k] != i + j * 4 + k * 16)
+		l = 1;
+    }
+  if (l)
+    abort ();
+  return 0;
+}

	Jakub



More information about the Gcc-patches mailing list