diff mbox

[gomp4.1] Support C++ references in privatization clauses

Message ID 20150527145542.GI10247@tucnak.redhat.com
State New
Headers show

Commit Message

Jakub Jelinek May 27, 2015, 2:55 p.m. UTC
Hi!

In OpenMP 4.1, C++ references are allowed in {,first,last}private
and linear clauses (previously it has been only allowed in reduction),
but most of the support code in the middle-end has long been there for
invisible references and fortran already.

2015-05-27  Jakub Jelinek  <jakub@redhat.com>

	* omp-low.c (lower_rec_input_clauses): Unshare new_var
	before passing it to omp_clause_{default,copy}_ctor.
gcc/cp/
	* cp-gimplify.c (cxx_omp_finish_clause): Don't complain about
	reference type here.
	* semantics.c (finish_omp_clauses): Allow references in
	{{,first,last}private,linear} clauses.
gcc/testsuite/
	* g++.dg/gomp/task-1.C: Remove both dg-error directives.
	* g++.dg/gomp/reference-1.C: New test.
libgomp/
	* testsuite/libgomp.c++/ctor-13.C: New test.
	* testsuite/libgomp.c++/simd14.C: New test.
	* testsuite/libgomp.c++/reference-1.C: New test.


	Jakub
diff mbox

Patch

--- gcc/omp-low.c.jj	2015-05-21 11:12:09.000000000 +0200
+++ gcc/omp-low.c	2015-05-27 13:25:24.934324632 +0200
@@ -4038,7 +4038,8 @@  lower_rec_input_clauses (tree clauses, g
 		x = NULL;
 	    do_private:
 	      tree nx;
-	      nx = lang_hooks.decls.omp_clause_default_ctor (c, new_var, x);
+	      nx = lang_hooks.decls.omp_clause_default_ctor
+						(c, unshare_expr (new_var), x);
 	      if (is_simd)
 		{
 		  tree y = lang_hooks.decls.omp_clause_dtor (c, new_var);
@@ -4192,7 +4193,8 @@  lower_rec_input_clauses (tree clauses, g
 		      break;
 		    }
 		}
-	      x = lang_hooks.decls.omp_clause_copy_ctor (c, new_var, x);
+	      x = lang_hooks.decls.omp_clause_copy_ctor
+						(c, unshare_expr (new_var), x);
 	      gimplify_and_add (x, ilist);
 	      goto do_dtor;
 
--- gcc/cp/cp-gimplify.c.jj	2015-05-26 20:36:41.000000000 +0200
+++ gcc/cp/cp-gimplify.c	2015-05-27 14:33:01.690834022 +0200
@@ -1716,16 +1716,7 @@  cxx_omp_finish_clause (tree c, gimple_se
   if (decl == error_mark_node)
     make_shared = true;
   else if (TREE_CODE (TREE_TYPE (decl)) == REFERENCE_TYPE)
-    {
-      if (is_invisiref_parm (decl))
-	inner_type = TREE_TYPE (inner_type);
-      else
-	{
-	  error ("%qE implicitly determined as %<firstprivate%> has reference type",
-		 decl);
-	  make_shared = true;
-	}
-    }
+    inner_type = TREE_TYPE (inner_type);
 
   /* We're interested in the base element, not arrays.  */
   while (TREE_CODE (inner_type) == ARRAY_TYPE)
--- gcc/cp/semantics.c.jj	2015-05-26 17:07:46.000000000 +0200
+++ gcc/cp/semantics.c	2015-05-27 16:33:16.153576552 +0200
@@ -5330,14 +5330,19 @@  finish_omp_clauses (tree clauses)
 	  goto check_dup_generic;
 	case OMP_CLAUSE_LINEAR:
 	  t = OMP_CLAUSE_DECL (c);
-	  if (!type_dependent_expression_p (t)
-	      && !INTEGRAL_TYPE_P (TREE_TYPE (t))
-	      && TREE_CODE (TREE_TYPE (t)) != POINTER_TYPE)
+	  if (!type_dependent_expression_p (t))
 	    {
-	      error ("linear clause applied to non-integral non-pointer "
-		     "variable with %qT type", TREE_TYPE (t));
-	      remove = true;
-	      break;
+	      tree type = TREE_TYPE (t);
+	      if (TREE_CODE (type) == REFERENCE_TYPE)
+		type = TREE_TYPE (type);
+	      if (!INTEGRAL_TYPE_P (type)
+		  && TREE_CODE (type) != POINTER_TYPE)
+		{
+		  error ("linear clause applied to non-integral non-pointer "
+			 "variable with %qT type", TREE_TYPE (t));
+		  remove = true;
+		  break;
+		}
 	    }
 	  t = OMP_CLAUSE_LINEAR_STEP (c);
 	  if (t == NULL_TREE)
@@ -5362,14 +5367,16 @@  finish_omp_clauses (tree clauses)
 		  if (TREE_CODE (OMP_CLAUSE_DECL (c)) == PARM_DECL)
 		    t = maybe_constant_value (t);
 		  t = fold_build_cleanup_point_expr (TREE_TYPE (t), t);
-		  if (TREE_CODE (TREE_TYPE (OMP_CLAUSE_DECL (c)))
-		      == POINTER_TYPE)
+		  tree type = TREE_TYPE (OMP_CLAUSE_DECL (c));
+		  if (TREE_CODE (type) == REFERENCE_TYPE)
+		    type = TREE_TYPE (type);
+		  if (TREE_CODE (type) == POINTER_TYPE)
 		    {
+		      tree d = convert_from_reference (OMP_CLAUSE_DECL (c));
 		      t = pointer_int_sum (OMP_CLAUSE_LOCATION (c), PLUS_EXPR,
-					   OMP_CLAUSE_DECL (c), t);
+					   d, t);
 		      t = fold_build2_loc (OMP_CLAUSE_LOCATION (c),
-					   MINUS_EXPR, sizetype, t,
-					   OMP_CLAUSE_DECL (c));
+					   MINUS_EXPR, sizetype, t, d);
 		      if (t == error_mark_node)
 			{
 			  remove = true;
@@ -5377,7 +5384,7 @@  finish_omp_clauses (tree clauses)
 			}
 		    }
 		  else
-		    t = fold_convert (TREE_TYPE (OMP_CLAUSE_DECL (c)), t);
+		    t = fold_convert (type, t);
 		}
 	      OMP_CLAUSE_LINEAR_STEP (c) = t;
 	    }
@@ -6019,7 +6026,7 @@  finish_omp_clauses (tree clauses)
     {
       enum omp_clause_code c_kind = OMP_CLAUSE_CODE (c);
       bool remove = false;
-      bool need_complete_non_reference = false;
+      bool need_complete_type = false;
       bool need_default_ctor = false;
       bool need_copy_ctor = false;
       bool need_copy_assignment = false;
@@ -6033,19 +6040,19 @@  finish_omp_clauses (tree clauses)
 	  need_implicitly_determined = true;
 	  break;
 	case OMP_CLAUSE_PRIVATE:
-	  need_complete_non_reference = true;
+	  need_complete_type = true;
 	  need_default_ctor = true;
 	  need_dtor = true;
 	  need_implicitly_determined = true;
 	  break;
 	case OMP_CLAUSE_FIRSTPRIVATE:
-	  need_complete_non_reference = true;
+	  need_complete_type = true;
 	  need_copy_ctor = true;
 	  need_dtor = true;
 	  need_implicitly_determined = true;
 	  break;
 	case OMP_CLAUSE_LASTPRIVATE:
-	  need_complete_non_reference = true;
+	  need_complete_type = true;
 	  need_copy_assignment = true;
 	  need_implicitly_determined = true;
 	  break;
@@ -6125,18 +6132,14 @@  finish_omp_clauses (tree clauses)
 	  break;
 	}
 
-      if (need_complete_non_reference || need_copy_assignment)
+      if (need_complete_type || need_copy_assignment)
 	{
 	  t = require_complete_type (t);
 	  if (t == error_mark_node)
 	    remove = true;
 	  else if (TREE_CODE (TREE_TYPE (t)) == REFERENCE_TYPE
-		   && need_complete_non_reference)
-	    {
-	      error ("%qE has reference type for %qs", t,
-		     omp_clause_code_name[OMP_CLAUSE_CODE (c)]);
-	      remove = true;
-	    }
+		   && !complete_type_or_else (TREE_TYPE (TREE_TYPE (t)), t))
+	    remove = true;
 	}
       if (need_implicitly_determined)
 	{
@@ -6171,12 +6174,13 @@  finish_omp_clauses (tree clauses)
 
       /* We're interested in the base element, not arrays.  */
       inner_type = type = TREE_TYPE (t);
-      while (TREE_CODE (inner_type) == ARRAY_TYPE)
-	inner_type = TREE_TYPE (inner_type);
-
-      if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
+      if ((need_complete_type
+	   || need_copy_assignment
+	   || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION)
 	  && TREE_CODE (inner_type) == REFERENCE_TYPE)
 	inner_type = TREE_TYPE (inner_type);
+      while (TREE_CODE (inner_type) == ARRAY_TYPE)
+	inner_type = TREE_TYPE (inner_type);
 
       /* Check for special function availability by building a call to one.
 	 Save the results, because later we won't be in the right context
--- gcc/testsuite/g++.dg/gomp/task-1.C.jj	2015-04-24 12:31:59.000000000 +0200
+++ gcc/testsuite/g++.dg/gomp/task-1.C	2015-05-27 15:27:12.060612616 +0200
@@ -10,8 +10,8 @@  const A a;
 void foo (A &p)
 {
   const A &q = a;
-#pragma omp task	// { dg-error "has reference type" }
+#pragma omp task
   bar (p);
-#pragma omp task	// { dg-error "has reference type" }
+#pragma omp task
   bar (q);
 }
--- gcc/testsuite/g++.dg/gomp/reference-1.C.jj	2015-05-27 16:40:39.208545177 +0200
+++ gcc/testsuite/g++.dg/gomp/reference-1.C	2015-05-27 16:40:06.000000000 +0200
@@ -0,0 +1,26 @@ 
+// { dg-do compile }
+
+struct S;	// { dg-message "forward declaration" }
+void foo (S &);
+
+void
+f1 (S &x)	// { dg-error "has incomplete type" }
+{
+#pragma omp parallel private (x)
+  foo (x);
+}
+
+void
+f2 (S &x)	// { dg-error "has incomplete type" }
+{
+#pragma omp parallel firstprivate (x)
+  foo (x);
+}
+
+void
+f3 (S &x)	// { dg-error "has incomplete type" }
+{
+#pragma omp parallel for lastprivate (x)
+  for (int i = 0; i < 10; i++)
+    foo (x);
+}
--- libgomp/testsuite/libgomp.c++/ctor-13.C.jj	2015-05-27 13:26:38.375175340 +0200
+++ libgomp/testsuite/libgomp.c++/ctor-13.C	2015-05-27 13:34:05.000000000 +0200
@@ -0,0 +1,242 @@ 
+// { dg-do run }
+
+#include <omp.h>
+#include <assert.h>
+
+struct B
+{
+  static int ic, dc, xc, ac, cc;
+
+  B();
+  B(const B &);
+  ~B();
+  B& operator=(const B &);
+  void doit();
+  static void clear();
+};
+
+int B::ic;
+int B::dc;
+int B::xc;
+int B::cc;
+int B::ac;
+
+B::B()
+{
+  #pragma omp atomic 
+    ic++;
+}
+
+B::~B()
+{
+  #pragma omp atomic
+    dc++;
+}
+
+B::B(const B &)
+{
+  #pragma omp atomic
+    cc++;
+}
+
+B& B::operator=(const B &)
+{
+  #pragma omp atomic
+    ac++;
+  return *this;
+}
+
+void B::doit()
+{
+  #pragma omp atomic
+    xc++;
+}
+
+void B::clear()
+{
+  ic = 0;
+  dc = 0;
+  cc = 0;
+  ac = 0;
+  xc = 0;
+}
+
+static int n;
+
+void f1(B &a)
+{
+  B b;
+  B &c = b;
+  #pragma omp parallel default(none) private(a, c) shared (n)
+    {
+      #pragma omp master
+	n = omp_get_num_threads ();
+      a.doit();
+      c.doit();
+    }
+}
+
+void f2(B &a)
+{
+  B b;
+  B &c = b;
+  #pragma omp parallel default(none) firstprivate(a, c) shared(n)
+    {
+      #pragma omp master
+	n = omp_get_num_threads ();
+      a.doit();
+      c.doit();
+    }
+}
+
+void f3(B &a)
+{
+  B b;
+  B &c = b;
+  #pragma omp parallel default(none) shared(n, a, c)
+    {
+      #pragma omp master
+	n = omp_get_num_threads ();
+      #pragma omp for lastprivate (a, c)
+      for (int i = 0; i < omp_get_num_threads (); i++)
+	{
+	  a.doit();
+	  c.doit();
+	}
+    }
+}
+
+void f4()
+{
+  B b;
+  B &c = b;
+  #pragma omp parallel default(none) private (c) shared (n)
+    {
+      B d;
+      B &e = d;
+      #pragma omp single copyprivate (c, e)
+      {
+	c.doit();
+	e.doit();
+      }
+      c.doit();
+      e.doit();
+    }
+}
+
+void f5(B (&a)[2])
+{
+  B b[2];
+  B (&c)[2] = b;
+  #pragma omp parallel default(none) private(a, c) shared (n)
+    {
+      #pragma omp master
+	n = omp_get_num_threads ();
+      a[0].doit();
+      a[1].doit();
+      c[0].doit();
+      c[1].doit();
+    }
+}
+
+void f6(B (&a)[2])
+{
+  B b[2];
+  B (&c)[2] = b;
+  #pragma omp parallel default(none) firstprivate(a, c) shared (n)
+    {
+      #pragma omp master
+	n = omp_get_num_threads ();
+      a[0].doit();
+      a[1].doit();
+      c[0].doit();
+      c[1].doit();
+    }
+}
+
+void f7(B (&a)[2])
+{
+  B b[2];
+  B (&c)[2] = b;
+  #pragma omp parallel default(none) shared(n, a, c)
+    {
+      #pragma omp master
+	n = omp_get_num_threads ();
+      #pragma omp for lastprivate (a, c)
+      for (int i = 0; i < omp_get_num_threads (); i++)
+	{
+	  a[0].doit();
+	  a[1].doit();
+	  c[0].doit();
+	  c[1].doit();
+	}
+    }
+}
+
+void f8()
+{
+  B b[2];
+  B (&c)[2] = b;
+  #pragma omp parallel default(none) private (c) shared (n)
+    {
+      B d[2];
+      B (&e)[2] = d;
+      #pragma omp single copyprivate (c, e)
+      {
+	c[0].doit();
+	c[1].doit();
+	e[0].doit();
+	e[1].doit();
+      }
+      c[0].doit();
+      c[1].doit();
+      e[0].doit();
+      e[1].doit();
+    }
+}
+
+int main()
+{
+  {
+    B a;
+    f1(a);
+  }
+  assert (B::xc == 2*n && B::ic == 2*n+2 && B::dc == 2*n+2 && B::ac == 0 && B::cc == 0);
+  B::clear();
+  {
+    B a;
+    f2(a);
+  }
+  assert (B::xc == 2*n && B::ic == 2 && B::dc == 2*n+2 && B::ac == 0 && B::cc == 2*n);
+  B::clear();
+  {
+    B a;
+    f3(a);
+  }
+  assert (B::xc == 2*n && B::ic == 2*n+2 && B::dc == 2*n+2 && B::ac == 2 && B::cc == 0);
+  B::clear();
+  f4();
+  assert (B::xc == 2*n+2 && B::ic == 2*n+1 && B::dc == 2*n+1 && B::ac == 2*n-2 && B::cc == 0);
+  B::clear();
+  {
+    B a[2];
+    f5(a);
+  }
+  assert (B::xc == 4*n && B::ic == 4*n+4 && B::dc == 4*n+4 && B::ac == 0 && B::cc == 0);
+  B::clear();
+  {
+    B a[2];
+    f6(a);
+  }
+  assert (B::xc == 4*n && B::ic == 4 && B::dc == 4*n+4 && B::ac == 0 && B::cc == 4*n);
+  B::clear();
+  {
+    B a[2];
+    f7(a);
+  }
+  assert (B::xc == 4*n && B::ic == 4*n+4 && B::dc == 4*n+4 && B::ac == 4 && B::cc == 0);
+  B::clear();
+  f8();
+  assert (B::xc == 4*n+4 && B::ic == 4*n+2 && B::dc == 4*n+2 && B::ac == 4*n-4 && B::cc == 0);
+  return 0;
+}
--- libgomp/testsuite/libgomp.c++/simd14.C.jj	2015-05-27 14:57:53.683724066 +0200
+++ libgomp/testsuite/libgomp.c++/simd14.C	2015-05-27 14:58:53.270765657 +0200
@@ -0,0 +1,43 @@ 
+// { dg-do run }
+// { dg-options "-O2" }
+// { dg-additional-options "-msse2" { target sse2_runtime } }
+// { dg-additional-options "-mavx" { target avx_runtime } }
+
+int a[1024];
+short b[2048];
+
+static inline void
+bar (int &x, unsigned long long &y, short *&z)
+{
+  a[x] = x + y + *z;
+  x++;
+  y += 17;
+  z += 2;
+}
+
+__attribute__((noinline, noclone)) int
+foo (unsigned long long &s, short *&t)
+{
+  int i, j = 0;
+  int &r = j;
+#pragma omp parallel for simd linear(r) linear(s:17ULL) linear(t:2)
+  for (i = 0; i < 1024; i++)
+    bar (r, s, t);
+  return j;
+}
+
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 2048; i++)
+    b[i] = 3 * i;
+  unsigned long long s = 12;
+  short *t = b;
+  int j = foo (s, t);
+  for (i = 0; i < 1024; i++)
+    if (a[i] != 12 + 24 * i)
+      __builtin_abort ();
+  if (j != 1024 || s != 12 + 1024 * 17ULL || t != &b[2048])
+    __builtin_abort ();
+}
--- libgomp/testsuite/libgomp.c++/reference-1.C.jj	2015-05-27 14:59:53.711797319 +0200
+++ libgomp/testsuite/libgomp.c++/reference-1.C	2015-05-27 15:11:27.286685406 +0200
@@ -0,0 +1,57 @@ 
+// { dg-do run }
+
+#include <omp.h>
+
+__attribute__((noinline, noclone)) void
+foo (int &a, short &d, char &g)
+{
+  unsigned long b = 12;
+  unsigned long &c = b;
+  long long e = 21;
+  long long &f = e;
+  unsigned int h = 12;
+  unsigned int &k = h;
+  #pragma omp parallel default(none) private(a, c) firstprivate(d, f) shared(g, k)
+    {
+      int i = omp_get_thread_num ();
+      a = i;
+      c = 2 * i;
+      if (d != 27 || f != 21)
+	__builtin_abort ();
+      d = 3 * (i & 0xfff);
+      f = 4 * i;
+      #pragma omp barrier
+      if (a != i || c != 2 * i || d != 3 * (i & 0xfff) || f != 4 * i)
+	__builtin_abort ();
+      #pragma omp for lastprivate(g, k)
+      for (int j = 0; j < 32; j++)
+	{
+	  g = j;
+	  k = 3 * j;
+	}
+    }
+  if (g != 31 || k != 31 * 3)
+    __builtin_abort ();
+  #pragma omp parallel for firstprivate (g, k) lastprivate (g, k)
+  for (int j = 0; j < 32; j++)
+    {
+      if (g != 31 || k != 31 * 3)
+	__builtin_abort ();
+      if (j == 31)
+	{
+	  g = 29;
+	  k = 138;
+	}
+    }
+  if (g != 29 || k != 138)
+    __builtin_abort ();
+}
+
+int
+main ()
+{
+  int a = 5;
+  short d = 27;
+  char g = ' ';
+  foo (a, d, g);
+}