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]

[committed] Fix some linear/lastprivate omp issues


Hi!

As the testcase shows, this patch fixes some issues with lastprivate/linear
iteration vars of OpenMP loops (for/simd).

One issue was that we were disallowing explicit linear or lastprivate
clause for the iteration var, but in the final 4.0 standard while it
is predetermined linear (collapse == 1) or lastprivate (collapse > 1),
it is allowed to be listed in corresponding clause explicitly.

Another set of problems are the value of the iteration variable after
the loop when it is implicitly lastprivate or implicitly or explicitly
linear and is addressable during gimplification.

Fixed thusly, committed to trunk/4.9.

2014-04-24  Jakub Jelinek  <jakub@redhat.com>

	* tree.h (OMP_CLAUSE_LINEAR_GIMPLE_SEQ): Define.
	* gimplify.c (omp_is_private): Change last argument's type to int.
	Only diagnose lastprivate if the simd argument is 1, only diagnose
	linear if the simd argument is 2.
	(gimplify_omp_for): Adjust omp_is_private callers.  When adding
	lastprivate or private, add the clause to OMP_FOR_CLAUSES.  Pass
	GOVD_EXPLICIT to omp_add_variable.  For simd with collapse == 1
	create OMP_CLAUSE_LINEAR rather than OMP_CLAUSE_PRIVATE for var.
	If var != decl and decl is in OMP_CLAUSE_LINEAR, gimplify decl
	increment to OMP_CLAUSE_LINEAR_GIMPLE_SEQ.
	* omp-low.c (scan_sharing_clauses, lower_lastprivate_clauses): Handle
	OMP_CLAUSE_LINEAR_GIMPLE_SEQ.
	* tree-nested.c (convert_nonlocal_omp_clauses,
	convert_local_omp_clauses): Handle OMP_CLAUSE_LINEAR.

	* testsuite/libgomp.c/simd-7.c: New test.
	* testsuite/libgomp.c/simd-8.c: New test.
	* testsuite/libgomp.c/simd-9.c: New test.
	* testsuite/libgomp.c/loop-16.c: New test.

--- gcc/tree.h.jj	2014-04-16 11:10:48.000000000 +0200
+++ gcc/tree.h	2014-04-24 14:57:45.474583956 +0200
@@ -1330,6 +1330,9 @@ extern void protected_set_expr_location
 #define OMP_CLAUSE_LINEAR_STEP(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_LINEAR), 1)
 
+#define OMP_CLAUSE_LINEAR_GIMPLE_SEQ(NODE) \
+  (OMP_CLAUSE_CHECK (NODE))->omp_clause.gimple_reduction_init
+
 #define OMP_CLAUSE_ALIGNED_ALIGNMENT(NODE) \
   OMP_CLAUSE_OPERAND (OMP_CLAUSE_SUBCODE_CHECK (NODE, OMP_CLAUSE_ALIGNED), 1)
 
--- gcc/gimplify.c.jj	2014-04-15 10:02:19.000000000 +0200
+++ gcc/gimplify.c	2014-04-24 16:57:53.905540116 +0200
@@ -5796,7 +5796,7 @@ omp_notice_variable (struct gimplify_omp
    to the contrary in the innermost scope, generate an error.  */
 
 static bool
-omp_is_private (struct gimplify_omp_ctx *ctx, tree decl, bool simd)
+omp_is_private (struct gimplify_omp_ctx *ctx, tree decl, int simd)
 {
   splay_tree_node n;
 
@@ -5830,13 +5830,13 @@ omp_is_private (struct gimplify_omp_ctx
 	  else if ((n->value & GOVD_REDUCTION) != 0)
 	    error ("iteration variable %qE should not be reduction",
 		   DECL_NAME (decl));
-	  else if (simd && (n->value & GOVD_LASTPRIVATE) != 0)
+	  else if (simd == 1 && (n->value & GOVD_LASTPRIVATE) != 0)
 	    error ("iteration variable %qE should not be lastprivate",
 		   DECL_NAME (decl));
 	  else if (simd && (n->value & GOVD_PRIVATE) != 0)
 	    error ("iteration variable %qE should not be private",
 		   DECL_NAME (decl));
-	  else if (simd && (n->value & GOVD_LINEAR) != 0)
+	  else if (simd == 2 && (n->value & GOVD_LINEAR) != 0)
 	    error ("iteration variable %qE is predetermined linear",
 		   DECL_NAME (decl));
 	}
@@ -6602,8 +6602,8 @@ gimplify_omp_for (tree *expr_p, gimple_s
 
   orig_for_stmt = for_stmt = *expr_p;
 
-  simd = TREE_CODE (for_stmt) == OMP_SIMD
-    || TREE_CODE (for_stmt) == CILK_SIMD;
+  simd = (TREE_CODE (for_stmt) == OMP_SIMD
+	  || TREE_CODE (for_stmt) == CILK_SIMD);
   gimplify_scan_omp_clauses (&OMP_FOR_CLAUSES (for_stmt), pre_p,
 			     simd ? ORT_SIMD : ORT_WORKSHARE);
 
@@ -6659,13 +6659,16 @@ gimplify_omp_for (tree *expr_p, gimple_s
 
       /* Make sure the iteration variable is private.  */
       tree c = NULL_TREE;
+      tree c2 = NULL_TREE;
       if (orig_for_stmt != for_stmt)
 	/* Do this only on innermost construct for combined ones.  */;
       else if (simd)
 	{
 	  splay_tree_node n = splay_tree_lookup (gimplify_omp_ctxp->variables,
 						 (splay_tree_key)decl);
-	  omp_is_private (gimplify_omp_ctxp, decl, simd);
+	  omp_is_private (gimplify_omp_ctxp, decl,
+			  1 + (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt))
+			       != 1));
 	  if (n != NULL && (n->value & GOVD_DATA_SHARE_CLASS) != 0)
 	    omp_notice_variable (gimplify_omp_ctxp, decl, true);
 	  else if (TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1)
@@ -6691,13 +6694,14 @@ gimplify_omp_for (tree *expr_p, gimple_s
 						: OMP_CLAUSE_PRIVATE);
 	      OMP_CLAUSE_DECL (c) = decl;
 	      OMP_CLAUSE_CHAIN (c) = OMP_FOR_CLAUSES (for_stmt);
+	      OMP_FOR_CLAUSES (for_stmt) = c;
 	      omp_add_variable (gimplify_omp_ctxp, decl,
 				(lastprivate ? GOVD_LASTPRIVATE : GOVD_PRIVATE)
-				| GOVD_SEEN);
+				| GOVD_EXPLICIT | GOVD_SEEN);
 	      c = NULL_TREE;
 	    }
 	}
-      else if (omp_is_private (gimplify_omp_ctxp, decl, simd))
+      else if (omp_is_private (gimplify_omp_ctxp, decl, 0))
 	omp_notice_variable (gimplify_omp_ctxp, decl, true);
       else
 	omp_add_variable (gimplify_omp_ctxp, decl, GOVD_PRIVATE | GOVD_SEEN);
@@ -6714,7 +6718,25 @@ gimplify_omp_for (tree *expr_p, gimple_s
 
 	  gimplify_seq_add_stmt (&for_body, gimple_build_assign (decl, var));
 
-	  omp_add_variable (gimplify_omp_ctxp, var, GOVD_PRIVATE | GOVD_SEEN);
+	  if (simd && TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) == 1)
+	    {
+	      c2 = build_omp_clause (input_location, OMP_CLAUSE_LINEAR);
+	      OMP_CLAUSE_LINEAR_NO_COPYIN (c2) = 1;
+	      OMP_CLAUSE_LINEAR_NO_COPYOUT (c2) = 1;
+	      OMP_CLAUSE_DECL (c2) = var;
+	      OMP_CLAUSE_CHAIN (c2) = OMP_FOR_CLAUSES (for_stmt);
+	      OMP_FOR_CLAUSES (for_stmt) = c2;
+	      omp_add_variable (gimplify_omp_ctxp, var,
+				GOVD_LINEAR | GOVD_EXPLICIT | GOVD_SEEN);
+	      if (c == NULL_TREE)
+		{
+		  c = c2;
+		  c2 = NULL_TREE;
+		}
+	    }
+	  else
+	    omp_add_variable (gimplify_omp_ctxp, var,
+			      GOVD_PRIVATE | GOVD_SEEN);
 	}
       else
 	var = decl;
@@ -6817,13 +6839,22 @@ gimplify_omp_for (tree *expr_p, gimple_s
 	  gcc_unreachable ();
 	}
 
+      if (c2)
+	{
+	  gcc_assert (c);
+	  OMP_CLAUSE_LINEAR_STEP (c2) = OMP_CLAUSE_LINEAR_STEP (c);
+	}
+
       if ((var != decl || TREE_VEC_LENGTH (OMP_FOR_INIT (for_stmt)) > 1)
 	  && orig_for_stmt == for_stmt)
 	{
 	  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
-		&& OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) == NULL)
+	    if (((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
+		  && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) == NULL)
+		 || (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
+		     && !OMP_CLAUSE_LINEAR_NO_COPYOUT (c)
+		     && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c) == NULL))
+		&& OMP_CLAUSE_DECL (c) == decl)
 	      {
 		t = TREE_VEC_ELT (OMP_FOR_INCR (for_stmt), i);
 		gcc_assert (TREE_CODE (t) == MODIFY_EXPR);
@@ -6835,8 +6866,12 @@ gimplify_omp_for (tree *expr_p, gimple_s
 		gcc_assert (TREE_OPERAND (t, 0) == var);
 		t = build2 (TREE_CODE (t), TREE_TYPE (decl), decl,
 			    TREE_OPERAND (t, 1));
-		gimplify_assign (decl, t,
-				 &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c));
+		gimple_seq *seq;
+		if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE)
+		  seq = &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c);
+		else
+		  seq = &OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c);
+		gimplify_assign (decl, t, seq);
 	    }
 	}
     }
--- gcc/omp-low.c.jj	2014-04-23 19:47:29.000000000 +0200
+++ gcc/omp-low.c	2014-04-24 16:54:31.997581123 +0200
@@ -1730,6 +1730,9 @@ scan_sharing_clauses (tree clauses, omp_
 	  if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION
 	      && OMP_CLAUSE_REDUCTION_PLACEHOLDER (c))
 	    scan_array_reductions = true;
+	  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
+		   && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c))
+	    scan_array_reductions = true;
 	  break;
 
 	case OMP_CLAUSE_SHARED:
@@ -1816,6 +1819,9 @@ scan_sharing_clauses (tree clauses, omp_
       else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LASTPRIVATE
 	       && OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c))
 	scan_omp (&OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c), ctx);
+      else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
+	       && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c))
+	scan_omp (&OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c), ctx);
 }
 
 /* Create a new name for omp child function.  Returns an identifier.  */
@@ -3803,6 +3809,14 @@ lower_lastprivate_clauses (tree clauses,
 				  OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c));
 	      OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (c) = NULL;
 	    }
+	  else if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR
+		   && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c))
+	    {
+	      lower_omp (&OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c), ctx);
+	      gimple_seq_add_seq (stmt_list,
+				  OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c));
+	      OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c) = NULL;
+	    }
 
 	  x = build_outer_var_ref (var, ctx);
 	  if (is_reference (var))
--- gcc/tree-nested.c.jj	2014-01-17 15:42:23.000000000 +0100
+++ gcc/tree-nested.c	2014-04-24 16:31:47.646512510 +0200
@@ -1082,6 +1082,11 @@ convert_nonlocal_omp_clauses (tree *pcla
 	    need_stmts = true;
 	  goto do_decl_clause;
 
+	case OMP_CLAUSE_LINEAR:
+	  if (OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause))
+	    need_stmts = true;
+	  goto do_decl_clause;
+
 	case OMP_CLAUSE_PRIVATE:
 	case OMP_CLAUSE_FIRSTPRIVATE:
 	case OMP_CLAUSE_COPYPRIVATE:
@@ -1157,6 +1162,12 @@ convert_nonlocal_omp_clauses (tree *pcla
 		     &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
 	  break;
 
+	case OMP_CLAUSE_LINEAR:
+	  walk_body (convert_nonlocal_reference_stmt,
+		     convert_nonlocal_reference_op, info,
+		     &OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause));
+	  break;
+
 	default:
 	  break;
 	}
@@ -1605,6 +1616,11 @@ convert_local_omp_clauses (tree *pclause
 	    need_stmts = true;
 	  goto do_decl_clause;
 
+	case OMP_CLAUSE_LINEAR:
+	  if (OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause))
+	    need_stmts = true;
+	  goto do_decl_clause;
+
 	case OMP_CLAUSE_PRIVATE:
 	case OMP_CLAUSE_FIRSTPRIVATE:
 	case OMP_CLAUSE_COPYPRIVATE:
@@ -1685,6 +1701,12 @@ convert_local_omp_clauses (tree *pclause
 		     &OMP_CLAUSE_LASTPRIVATE_GIMPLE_SEQ (clause));
 	  break;
 
+	case OMP_CLAUSE_LINEAR:
+	  walk_body (convert_local_reference_stmt,
+		     convert_local_reference_op, info,
+		     &OMP_CLAUSE_LINEAR_GIMPLE_SEQ (clause));
+	  break;
+
 	default:
 	  break;
 	}
--- libgomp/testsuite/libgomp.c/simd-7.c.jj	2014-04-24 13:12:02.511607661 +0200
+++ libgomp/testsuite/libgomp.c/simd-7.c	2014-04-24 15:46:24.902509361 +0200
@@ -0,0 +1,96 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+extern void abort ();
+int a[1024] __attribute__((aligned (32))) = { 1 };
+int b[1024] __attribute__((aligned (32))) = { 1 };
+int k, m;
+struct U { int u; };
+struct V { int v; };
+
+__attribute__((noinline, noclone)) int
+foo (int *p)
+{
+  int i, s = 0;
+  struct U u;
+  struct V v;
+  #pragma omp simd aligned(a, p : 32) linear(k: m + 1) \
+		   linear(i) reduction(+:s) lastprivate(u, v)
+  for (i = 0; i < 1024; i++)
+    {
+      int *q = &i;
+      a[i] *= p[i];
+      u.u = p[i] + k;
+      k += m + 1;
+      v.v = p[i] + k;
+      s += p[i] + k;
+    }
+  if (u.u != 36 + 4 + 3 * 1023 || v.v != 36 + 4 + 3 * 1024 || i != 1024)
+    abort ();
+  return s;
+}
+
+__attribute__((noinline, noclone)) int
+bar (int *p)
+{
+  int i, s = 0;
+  struct U u;
+  struct V v;
+  #pragma omp simd aligned(a, p : 32) linear(k: m + 1) \
+		   reduction(+:s) lastprivate(u, v)
+  for (i = 0; i < 1024; i++)
+    {
+      int *q = &i;
+      a[i] *= p[i];
+      u.u = p[i] + k;
+      k += m + 1;
+      v.v = p[i] + k;
+      s += p[i] + k;
+    }
+  if (u.u != 36 + 4 + 3 * 1023 || v.v != 36 + 4 + 3 * 1024 || i != 1024)
+    abort ();
+  return s;
+}
+
+int
+main ()
+{
+#if __SIZEOF_INT__ >= 4
+  int i;
+  k = 4;
+  m = 2;
+  for (i = 0; i < 1024; i++)
+    {
+      a[i] = i - 512;
+      b[i] = (i - 51) % 39;
+    }
+  int s = foo (b);
+  for (i = 0; i < 1024; i++)
+    {
+      if (b[i] != (i - 51) % 39
+	  || a[i] != (i - 512) * b[i])
+	abort ();
+    }
+  if (k != 4 + 3 * 1024 || s != 1596127)
+    abort ();
+  k = 4;
+  m = 2;
+  for (i = 0; i < 1024; i++)
+    {
+      a[i] = i - 512;
+      b[i] = (i - 51) % 39;
+    }
+  s = bar (b);
+  for (i = 0; i < 1024; i++)
+    {
+      if (b[i] != (i - 51) % 39
+	  || a[i] != (i - 512) * b[i])
+	abort ();
+    }
+  if (k != 4 + 3 * 1024 || s != 1596127)
+    abort ();
+#endif
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/simd-8.c.jj	2014-04-24 13:20:56.157794537 +0200
+++ libgomp/testsuite/libgomp.c/simd-8.c	2014-04-24 13:23:08.244097863 +0200
@@ -0,0 +1,44 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+extern void abort ();
+int a[32][32] __attribute__((aligned (32))) = { { 1 } };
+struct S { int s; };
+#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+__attribute__((noinline, noclone)) int
+foo (void)
+{
+  int i, j, u = 0;
+  struct S s, t;
+  s.s = 0; t.s = 0;
+  #pragma omp simd aligned(a : 32) reduction(+:s) reduction(foo:t, u) collapse(2)
+  for (i = 0; i < 32; i++)
+    for (j = 0; j < 32; j++)
+      {
+	int x = a[i][j];
+	s.s += x;
+	t.s += x;
+	u += x;
+      }
+  if (t.s != s.s || u != s.s)
+    abort ();
+  return s.s;
+}
+
+int
+main ()
+{
+  int i, j;
+  for (i = 0; i < 32; i++)
+    for (j = 0; j < 32; j++)
+      a[i][j] = j + (i / 4);
+  int s = foo ();
+  if (s != 19456)
+    abort ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/simd-9.c.jj	2014-04-24 13:50:32.581527897 +0200
+++ libgomp/testsuite/libgomp.c/simd-9.c	2014-04-24 14:10:51.943161091 +0200
@@ -0,0 +1,70 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+/* { dg-additional-options "-msse2" { target sse2_runtime } } */
+/* { dg-additional-options "-mavx" { target avx_runtime } } */
+
+extern void abort ();
+int a[32][32] __attribute__((aligned (32))) = { { 1 } };
+struct S { int s; };
+#pragma omp declare reduction (+:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:struct S:omp_out.s += omp_in.s)
+#pragma omp declare reduction (foo:int:omp_out += omp_in)
+
+__attribute__((noinline, noclone)) int
+foo (void)
+{
+  int i, j, u = 0;
+  struct S s, t;
+  s.s = 0; t.s = 0;
+  #pragma omp simd aligned(a : 32) lastprivate (i, j) reduction(+:s) reduction(foo:t, u) collapse(2)
+  for (i = 0; i < 32; i++)
+    for (j = 0; j < 32; j++)
+      {
+	int *q = &i;
+	int *r = &j;
+	int x = a[i][j];
+	s.s += x;
+	t.s += x;
+	u += x;
+      }
+  if (t.s != s.s || u != s.s || i != 32 || j != 32)
+    abort ();
+  return s.s;
+}
+
+__attribute__((noinline, noclone)) int
+bar (void)
+{
+  int i, j, u = 0;
+  struct S s, t;
+  s.s = 0; t.s = 0;
+  #pragma omp simd aligned(a:32)reduction(+:s)reduction(foo:t,u)collapse(2)
+  for (i = 0; i < 32; i++)
+    for (j = 0; j < 32; j++)
+      {
+	int *q = &i;
+	int *r = &j;
+	int x = a[i][j];
+	s.s += x;
+	t.s += x;
+	u += x;
+      }
+  if (t.s != s.s || u != s.s || i != 32 || j != 32)
+    abort ();
+  return s.s;
+}
+
+int
+main ()
+{
+  int i, j;
+  for (i = 0; i < 32; i++)
+    for (j = 0; j < 32; j++)
+      a[i][j] = j + (i / 4);
+  int s = foo ();
+  if (s != 19456)
+    abort ();
+  if (bar () != 19456)
+    abort ();
+  return 0;
+}
--- libgomp/testsuite/libgomp.c/loop-16.c.jj	2014-04-24 14:11:53.611843451 +0200
+++ libgomp/testsuite/libgomp.c/loop-16.c	2014-04-24 14:12:13.521743668 +0200
@@ -0,0 +1,27 @@
+/* { dg-do run } */
+
+extern void abort (void);
+
+volatile int count;
+static int test (void)
+{
+  return ++count > 0;
+}
+
+int i;
+
+int
+main ()
+{
+  #pragma omp for lastprivate (i)
+  for (i = 0; i < 10; ++i)
+    {
+      int *p = &i;
+      if (test ())
+	continue;
+      abort ();
+    }
+  if (i != count)
+    abort ();
+  return 0;
+}

	Jakub


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