This patch updates the way that private reductions are handled in gomp4 to be more like trunk. Before, omp lower was using a complicated mapping for private variables, but now it's treating them more like omp, with the exception of reference-type variables. This complication originated back when we were using ganglocal memory for private variables. Now that private variables just regular local variables, I was able to remove a lot of that old code.
It should be noted that reference-type variables still rely on gimplifier creating a special OMP_CLAUSE_REDUCTION_PRIVATE_DECL, which is basically a local copy of the reduction variable. Currently this is used when the reduction variables are dummy arguments in fortran or parallel (non-loop) reductions. I want to get rid of the localize_reductions pass from the gimplifier eventually, but for the time being this patch does fix pr/68813. In the process of removing removing that old private code, I noticed that lower_oacc_reductions couldn't handle reductions of the form #pragma acc loop reduction (+:v) for (...) #pragma acc loop reduction (+:v) for (...) That's fixed now. In addition to teaching lower_oacc_reductions about private variables, I also taught it how to update any intermediate reduction variable when present. I'll port over this change to trunk once I've resolved the localize_reductions issue in the gimplifier. I don't have recent baseline, but I am seeing these failures: g++.sum:c-c++-common/goacc/routine-7.c libgomp.oacc-c/../libgomp.oacc-c-c++-common/declare-4.c I'll work on routine-7.c tomorrow. Jim, can you look at the declare-4.c failure? This patch has been applied to gomp-4_0-branch. Cesar
2016-01-06 Cesar Philippidis <ce...@codesourcery.com> PR other/68813 gcc/ * omp-low.c (is_oacc_reduction_private): Delete. (build_outer_var_ref): Remove special handling for private reductions in openacc. (scan_sharing_clauses): Likewise. (lower_rec_input_clauses): Likewise. (lower_oacc_reductions): Update support for private reductions. libgomp/ * testsuite/libgomp.oacc-fortran/pr68813.f90: New test. * testsuite/libgomp.oacc-fortran/reduction-7.f90: New test. diff --git a/gcc/omp-low.c b/gcc/omp-low.c index 8a6dc5e..e11cefc 100644 --- a/gcc/omp-low.c +++ b/gcc/omp-low.c @@ -316,53 +316,6 @@ is_oacc_kernels (omp_context *ctx) == GF_OMP_TARGET_KIND_OACC_KERNELS)); } -/* Return true if VAR is a is private reduction variable. A reduction - variable is considered private if the variable is local to the - offloaded region, or if it is the first reduction to use a mapped - variable. E.g., if V is mapped as 'copy', and loops L1 and L2 contain - reductions on V, and L2 is nested inside L1, V is not private in L1 - but is private in L2. */ - -static bool -is_oacc_reduction_private (tree var, omp_context *ctx, bool initial = true) -{ - tree c, clauses, decl; - - if (ctx == NULL || !is_gimple_omp_oacc (ctx->stmt)) - return true; - - if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR) - clauses = gimple_omp_for_clauses (ctx->stmt); - else - clauses = gimple_omp_target_clauses (ctx->stmt); - - for (c = clauses; c; c = OMP_CLAUSE_CHAIN (c)) - { - switch (OMP_CLAUSE_CODE (c)) - { - case OMP_CLAUSE_PRIVATE: - decl = OMP_CLAUSE_DECL (c); - if (decl == var) - return true; - break; - case OMP_CLAUSE_MAP: - decl = OMP_CLAUSE_DECL (c); - if (decl == var) - return false; - break; - case OMP_CLAUSE_REDUCTION: - decl = OMP_CLAUSE_DECL (c); - if (!initial && decl == var) - return true; - break; - default: - break; - } - } - - return is_oacc_reduction_private (var, ctx->outer, false); -} - /* If DECL is the artificial dummy VAR_DECL created for non-static data member privatization, return the underlying "this" parameter, otherwise return NULL. */ @@ -1323,14 +1276,8 @@ static tree build_outer_var_ref (tree var, omp_context *ctx, bool lastprivate = false) { tree x; - tree outer_ref = maybe_lookup_decl_in_outer_ctx (var, ctx); - if (TREE_CODE (outer_ref) == INDIRECT_REF) - { - gcc_assert (is_gimple_omp_oacc (ctx->stmt)); - x = outer_ref; - } - else if (is_global_var (outer_ref)) + if (is_global_var (maybe_lookup_decl_in_outer_ctx (var, ctx))) x = var; else if (is_variable_sized (var)) { @@ -1384,26 +1331,9 @@ build_outer_var_ref (tree var, omp_context *ctx, bool lastprivate = false) x = build_simple_mem_ref (x); } } - else if (is_oacc_parallel (ctx)) - x = var; else if (ctx->outer) - { - /* OpenACC may have multiple outer contexts (one per loop). */ - if (gimple_code (ctx->stmt) == GIMPLE_OMP_FOR - && gimple_omp_for_kind (ctx->stmt) == GF_OMP_FOR_KIND_OACC_LOOP) - { - do - { - ctx = ctx->outer; - x = maybe_lookup_decl (var, ctx); - } - while(!x); - } - else - x = lookup_decl (var, ctx->outer); - } - else if (is_reference (var) - || get_oacc_fn_attrib (current_function_decl)) + x = lookup_decl (var, ctx->outer); + else if (is_reference (var)) /* This can happen with orphaned constructs. If var is reference, it is possible it is shared and as such valid. */ x = var; @@ -2026,9 +1956,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx, case OMP_CLAUSE_LINEAR: decl = OMP_CLAUSE_DECL (c); do_private: - if (!is_gimple_omp_oacc (ctx->stmt) - && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR) + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR) && is_gimple_omp_offloaded (ctx->stmt)) { if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) @@ -2060,27 +1989,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx, else if (!global) install_var_field (decl, by_ref, 3, ctx); } - if (!is_gimple_omp_oacc (ctx->stmt) - || !is_oacc_reduction_private (decl, ctx)) - install_var_local (decl, ctx); - else - { - gcc_assert (is_gimple_omp_oacc (ctx->stmt)); - /* This probably needs to be moved further up, next to the OpenMP - OMP_CLAUSE_FIRSTPRIVATE handling, in order to correctly handle - VLAs. */ - if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE) - { - install_var_field (decl, (TREE_CODE (TREE_TYPE (decl)) - != REFERENCE_TYPE), 3, ctx); - install_var_local (decl, ctx); - } - else - /* The gimplifier always includes a OMP_CLAUSE_MAP with - each parallel reduction variable. So don't install a - local variable here. */ - gcc_assert (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_REDUCTION); - } + install_var_local (decl, ctx); break; case OMP_CLAUSE_USE_DEVICE: @@ -2322,9 +2231,8 @@ scan_sharing_clauses (tree clauses, omp_context *ctx, decl = OMP_CLAUSE_DECL (c); if (is_variable_sized (decl)) { - if (!is_gimple_omp_oacc (ctx->stmt) - && (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE - || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR) + if ((OMP_CLAUSE_CODE (c) == OMP_CLAUSE_FIRSTPRIVATE + || OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IS_DEVICE_PTR) && is_gimple_omp_offloaded (ctx->stmt)) { tree decl2 = DECL_VALUE_EXPR (decl); @@ -2336,11 +2244,9 @@ scan_sharing_clauses (tree clauses, omp_context *ctx, } install_var_local (decl, ctx); } - if (!is_gimple_omp_oacc (ctx->stmt) - || !is_oacc_reduction_private (decl, ctx)) - fixup_remapped_decl (decl, ctx, - OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE - && OMP_CLAUSE_PRIVATE_DEBUG (c)); + fixup_remapped_decl (decl, ctx, + OMP_CLAUSE_CODE (c) == OMP_CLAUSE_PRIVATE + && OMP_CLAUSE_PRIVATE_DEBUG (c)); if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_LINEAR && OMP_CLAUSE_LINEAR_GIMPLE_SEQ (c)) scan_array_reductions = true; @@ -2352,9 +2258,7 @@ scan_sharing_clauses (tree clauses, omp_context *ctx, { if (is_variable_sized (decl)) install_var_local (decl, ctx); - if (!(is_gimple_omp_oacc (ctx->stmt) - && is_oacc_reduction_private (decl, ctx))) - fixup_remapped_decl (decl, ctx, false); + fixup_remapped_decl (decl, ctx, false); } if (OMP_CLAUSE_REDUCTION_PLACEHOLDER (c)) scan_array_reductions = true; @@ -4614,14 +4518,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, new_var = var; } if (c_kind != OMP_CLAUSE_COPYIN) - { - /* Not all OpenACC reductions require new mappings. */ - if (is_gimple_omp_oacc (ctx->stmt) - && (new_var = maybe_lookup_decl (var, ctx)) == NULL) - new_var = var; - else - new_var = lookup_decl (var, ctx); - } + new_var = lookup_decl (var, ctx); if (c_kind == OMP_CLAUSE_SHARED || c_kind == OMP_CLAUSE_COPYIN) { @@ -5317,13 +5214,7 @@ lower_rec_input_clauses (tree clauses, gimple_seq *ilist, gimple_seq *dlist, } else { - tree type; - if (is_oacc_parallel (ctx) && is_reference (var)) - type = TREE_TYPE (TREE_TYPE (new_var)); - else - type = TREE_TYPE (new_var); - - x = omp_reduction_init (c, type); + x = omp_reduction_init (c, TREE_TYPE (new_var)); gcc_assert (TREE_CODE (TREE_TYPE (new_var)) != ARRAY_TYPE); enum tree_code code = OMP_CLAUSE_REDUCTION_CODE (c); @@ -5689,7 +5580,9 @@ lower_oacc_reductions (location_t loc, tree clauses, tree level, bool inner, var = maybe_lookup_decl (orig, ctx); if (!var) var = orig; - gcc_assert (!is_reference (var)); + + if (is_reference (var)) + var = build_simple_mem_ref (var); incoming = outgoing = var; @@ -5731,29 +5624,55 @@ lower_oacc_reductions (location_t loc, tree clauses, tree level, bool inner, do_lookup: /* This is the outermost construct with this reduction, see if there's a mapping for it. */ - if (gimple_code (outer->stmt) == GIMPLE_OMP_TARGET - && maybe_lookup_field (orig, outer)) + if (gimple_code (outer->stmt) == GIMPLE_OMP_TARGET) { - ref_to_res = build_receiver_ref (orig, false, outer); - if (is_reference (orig)) - ref_to_res = build_simple_mem_ref (ref_to_res); + bool is_private = false; + bool is_mapped = false; + + /* Check for a private or firstprivate mapping. */ + for (tree cls = gimple_omp_target_clauses (outer->stmt); + cls; cls = OMP_CLAUSE_CHAIN (cls)) + { + if ((OMP_CLAUSE_CODE (cls) == OMP_CLAUSE_PRIVATE + || OMP_CLAUSE_CODE (cls) == OMP_CLAUSE_FIRSTPRIVATE) + && OMP_CLAUSE_DECL (cls) == orig) + { + tree t = lookup_decl (orig, ctx->outer); + if (is_reference (t)) + incoming = outgoing = build_simple_mem_ref (t); + else + incoming = outgoing = t; + is_private = true; + break; + } + } - outgoing = var; - incoming = omp_reduction_init_op (loc, rcode, TREE_TYPE (var)); + /* Check for a data mapping. */ + if (!is_private && maybe_lookup_field (orig, outer)) + { + ref_to_res = build_receiver_ref (orig, false, outer); + + if (is_reference (orig)) + ref_to_res = build_simple_mem_ref (ref_to_res); + + incoming = omp_reduction_init_op (loc, rcode, + TREE_TYPE (var)); + outgoing = var; + is_mapped = true; + } + + /* Update incoming and outgoing for reduction variables + local to the offloaded region. */ + if (!is_private && !is_mapped) + incoming = outgoing = orig; } - /* This is enabled on trunk, but has been disabled in the merge of - trunk r229767 into gomp-4_0-branch, as otherwise there were a - lot of regressions in libgomp reduction execution tests. It is - unclear if the problem is in the tests themselves, or here, or - elsewhere. Given the usage of "var = - OMP_CLAUSE_REDUCTION_PRIVATE_DECL (c)" on gomp-4_0-branch, maybe - we have to consider that here, too, instead of "orig"? */ -#if 0 else incoming = outgoing = orig; -#endif - - has_outer_reduction:; + + has_outer_reduction: + /* We found a reduction variable used by another reduction. */ + if (gimple_code (outer->stmt) != GIMPLE_OMP_TARGET) + incoming = outgoing = lookup_decl (orig, ctx->outer); } if (!ref_to_res) diff --git a/libgomp/testsuite/libgomp.oacc-fortran/pr68813.f90 b/libgomp/testsuite/libgomp.oacc-fortran/pr68813.f90 new file mode 100644 index 0000000..735350f --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/pr68813.f90 @@ -0,0 +1,19 @@ +program foo + implicit none + integer, parameter :: n = 100 + integer, dimension(n,n) :: a + integer :: i, j, sum = 0 + + a = 1 + + !$acc parallel copyin(a(1:n,1:n)) firstprivate (sum) + !$acc loop gang reduction(+:sum) + do i=1, n + !$acc loop vector reduction(+:sum) + do j=1, n + sum = sum + a(i, j) + enddo + enddo + !$acc end parallel + +end program foo diff --git a/libgomp/testsuite/libgomp.oacc-fortran/reduction-7.f90 b/libgomp/testsuite/libgomp.oacc-fortran/reduction-7.f90 new file mode 100644 index 0000000..e80004d --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/reduction-7.f90 @@ -0,0 +1,60 @@ +! { dg-do run } +! { dg-additional-options "-w" } + +! subroutine reduction with firstprivate variables + +program reduction + integer, parameter :: n = 100 + integer :: i, j, vsum, cs, arr(n) + + call redsub_bogus (cs, n) + call redsub_combined (cs, n, arr) + + vsum = 0 + + ! Verify the results + do i = 1, n + vsum = i + do j = 1, n + vsum = vsum + 1; + end do + if (vsum .ne. arr(i)) call abort () + end do +end program reduction + +! Bogus reduction on an impliclitly firstprivate variable. The results do +! survive the parallel region. The goal here is to ensure that gfortran +! doesn't ICE. + +subroutine redsub_bogus(sum, n) + integer :: sum, n, arr(n) + integer :: i + + !$acc parallel + !$acc loop gang worker vector reduction (+:sum) + do i = 1, n + sum = sum + 1 + end do + !$acc end parallel +end subroutine redsub_bogus + +! This reduction involving a firstprivate variable yields legitimate results. + +subroutine redsub_combined(sum, n, arr) + integer :: sum, n, arr(n) + integer :: i, j + + !$acc parallel copy (arr) + !$acc loop gang + do i = 1, n + sum = i; + + !$acc loop reduction(+:sum) + do j = 1, n + sum = sum + 1 + end do + + arr(i) = sum + end do + !$acc end parallel +end subroutine redsub_combined