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  <ja...@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

Reply via email to