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