Currently gfortran largely lacks support for fortran common blocks in OpenACC. The notable exception is acc declare link which does support common block arguments to some extent. This patch does two things:
1) Adds support for common blocks in the appropriate OpenACC data clauses. 2) Privatizes the underlying common block struct during gimplification. It also teaches the gimplifier to how to defer the expansion of DECL_VALUE_EXPR for common block decls until omp lowering. The first item allows allows common block names to be listed in data clauses. Such names need to be surrounded by slashes. E.g. common /BLOCK/ a, b, c !$acc enter data copyin(/BLOCK/) Note that common block names are treated in a similar manner to OpenMP common block arguments; gfc_match_omp_map_clauses expands the common block names to individual data clauses for each variable in the common block. The second item updates how common blocks behave on the accelerator. Using the BLOCK example from above, if an OpenACC offloading region only utilized, say, variable 'b', the gimplifier will now only transfer and remap 'b' on the accelerator. The actual common block struct will have a private clause. Without this patch, both the common block struct and the individual variable were transferred to the accelerator separately, and that would result in duplicate data mapping errors at runtime. The second item also defers the expansion of DECL_VALUE_EXPR because otherwise the privatized common block data would be used instead of one that was explicitly or implicitly transferred to the accelerator. This patch has been committed to gomp-4_0-branch. Cesar
2016-09-15 Cesar Philippidis <ce...@codesourcery.com> gcc/fortrann/ * openmp.c (gfc_match_omp_map_clause): Add new common_blocks argument. Propagate it to gfc_match_omp_variable_list. (gfc_match_omp_clauses): Update calls to gfc_match_omp_map_clauses. gcc/ * gimplify.c (oacc_default_clause): Privatize fortran common blocks. (omp_notice_variable): Defer the expansion of DECL_VALUE_EXPR for common block decls. gcc/testsuite/ * gfortran.dg/goacc/common-block-1.f90: New test. * gfortran.dg/goacc/common-block-2.f90: New test. libgomp/ * testsuite/libgomp.oacc-fortran/common-block-1.f90: New test. * testsuite/libgomp.oacc-fortran/common-block-2.f90: New test. * testsuite/libgomp.oacc-fortran/common-block-3.f90: New test. diff --git a/gcc/fortran/openmp.c b/gcc/fortran/openmp.c index 83c6419..92b9afe 100644 --- a/gcc/fortran/openmp.c +++ b/gcc/fortran/openmp.c @@ -633,10 +633,11 @@ cleanup: mapping. */ static bool -gfc_match_omp_map_clause (gfc_omp_namelist **list, gfc_omp_map_op map_op) +gfc_match_omp_map_clause (gfc_omp_namelist **list, gfc_omp_map_op map_op, + bool common_blocks) { gfc_omp_namelist **head = NULL; - if (gfc_match_omp_variable_list ("", list, false, NULL, &head, true) + if (gfc_match_omp_variable_list ("", list, common_blocks, NULL, &head, true) == MATCH_YES) { gfc_omp_namelist *n; @@ -772,7 +773,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, uint64_t mask, if ((mask & OMP_CLAUSE_COPY) && gfc_match ("copy ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_TOFROM)) + OMP_MAP_FORCE_TOFROM, openacc)) continue; if (mask & OMP_CLAUSE_COPYIN) { @@ -780,7 +781,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, uint64_t mask, { if (gfc_match ("copyin ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_TO)) + OMP_MAP_FORCE_TO, true)) continue; } else if (gfc_match_omp_variable_list ("copyin (", @@ -791,7 +792,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, uint64_t mask, if ((mask & OMP_CLAUSE_COPYOUT) && gfc_match ("copyout ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_FROM)) + OMP_MAP_FORCE_FROM, true)) continue; if ((mask & OMP_CLAUSE_COPYPRIVATE) && gfc_match_omp_variable_list ("copyprivate (", @@ -801,14 +802,14 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, uint64_t mask, if ((mask & OMP_CLAUSE_CREATE) && gfc_match ("create ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_ALLOC)) + OMP_MAP_FORCE_ALLOC, true)) continue; break; case 'd': if ((mask & OMP_CLAUSE_DELETE) && gfc_match ("delete ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_DELETE)) + OMP_MAP_DELETE, true)) continue; if ((mask & OMP_CLAUSE_DEFAULT) && c->default_sharing == OMP_DEFAULT_UNKNOWN) @@ -861,12 +862,12 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, uint64_t mask, if ((mask & OMP_CLAUSE_OACC_DEVICE) && gfc_match ("device ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_TO)) + OMP_MAP_FORCE_TO, false)) continue; if ((mask & OMP_CLAUSE_DEVICEPTR) && gfc_match ("deviceptr ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_DEVICEPTR)) + OMP_MAP_FORCE_DEVICEPTR, false)) continue; if ((mask & OMP_CLAUSE_DEVICE_RESIDENT) && gfc_match_omp_variable_list @@ -990,7 +991,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, uint64_t mask, && gfc_match ("host ( ") == MATCH_YES /* "self" is a synonym for "host". */ && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_FROM)) + OMP_MAP_FORCE_FROM, true)) continue; break; case 'i': @@ -1135,47 +1136,47 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, uint64_t mask, if ((mask & OMP_CLAUSE_PRESENT_OR_COPY) && gfc_match ("pcopy ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_TOFROM)) + OMP_MAP_TOFROM, true)) continue; if ((mask & OMP_CLAUSE_PRESENT_OR_COPYIN) && gfc_match ("pcopyin ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_TO)) + OMP_MAP_TO, true)) continue; if ((mask & OMP_CLAUSE_PRESENT_OR_COPYOUT) && gfc_match ("pcopyout ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FROM)) + OMP_MAP_FROM, true)) continue; if ((mask & OMP_CLAUSE_PRESENT_OR_CREATE) && gfc_match ("pcreate ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_ALLOC)) + OMP_MAP_ALLOC, true)) continue; if ((mask & OMP_CLAUSE_PRESENT) && gfc_match ("present ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_PRESENT)) + OMP_MAP_FORCE_PRESENT, false)) continue; if ((mask & OMP_CLAUSE_PRESENT_OR_COPY) && gfc_match ("present_or_copy ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_TOFROM)) + OMP_MAP_TOFROM, true)) continue; if ((mask & OMP_CLAUSE_PRESENT_OR_COPYIN) && gfc_match ("present_or_copyin ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_TO)) + OMP_MAP_TO, true)) continue; if ((mask & OMP_CLAUSE_PRESENT_OR_COPYOUT) && gfc_match ("present_or_copyout ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FROM)) + OMP_MAP_FROM, true)) continue; if ((mask & OMP_CLAUSE_PRESENT_OR_CREATE) && gfc_match ("present_or_create ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_ALLOC)) + OMP_MAP_ALLOC, true)) continue; if ((mask & OMP_CLAUSE_PRIVATE) && gfc_match_omp_variable_list ("private (", @@ -1355,7 +1356,7 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, uint64_t mask, if ((mask & OMP_CLAUSE_HOST) && gfc_match ("self ( ") == MATCH_YES && gfc_match_omp_map_clause (&c->lists[OMP_LIST_MAP], - OMP_MAP_FORCE_FROM)) + OMP_MAP_FORCE_FROM, true)) continue; if ((mask & OMP_CLAUSE_SEQ) && !c->seq diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 5db8424..1ecfaaa 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -6102,14 +6102,19 @@ oacc_default_clause (struct gimplify_omp_ctx *ctx, tree decl, unsigned flags) { const char *rkind; bool on_device = false; + bool is_private = false; tree type = TREE_TYPE (decl); if (lang_hooks.decls.omp_privatize_by_reference (decl)) type = TREE_TYPE (type); + if (RECORD_OR_UNION_TYPE_P (type)) + is_private = lang_hooks.decls.omp_disregard_value_expr (decl, false); + if ((ctx->region_type & (ORT_ACC_PARALLEL | ORT_ACC_KERNELS)) != 0 && is_global_var (decl) - && device_resident_p (decl)) + && device_resident_p (decl) + && !is_private) { on_device = true; flags |= GOVD_MAP_TO_ONLY; @@ -6124,7 +6129,7 @@ oacc_default_clause (struct gimplify_omp_ctx *ctx, tree decl, unsigned flags) /* Scalars are default 'copy' under kernels, non-scalars are default 'present_or_copy'. */ flags |= GOVD_MAP; - if (!AGGREGATE_TYPE_P (type)) + if (!AGGREGATE_TYPE_P (type) && !is_private) flags |= GOVD_MAP_FORCE; rkind = "kernels"; @@ -6132,7 +6137,7 @@ oacc_default_clause (struct gimplify_omp_ctx *ctx, tree decl, unsigned flags) case ORT_ACC_PARALLEL: { - if (on_device || AGGREGATE_TYPE_P (type)) + if (!is_private && (on_device || AGGREGATE_TYPE_P (type))) /* Aggregates default to 'present_or_copy'. */ flags |= GOVD_MAP; else @@ -6187,7 +6192,8 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) { tree value = get_base_address (DECL_VALUE_EXPR (decl)); - if (value && DECL_P (value) && DECL_THREAD_LOCAL_P (value)) + if (!(ctx->region_type & ORT_ACC) + && value && DECL_P (value) && DECL_THREAD_LOCAL_P (value)) return omp_notice_threadprivate_variable (ctx, decl, value); } @@ -6219,7 +6225,8 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) n = splay_tree_lookup (ctx->variables, (splay_tree_key)decl); if ((ctx->region_type & ORT_TARGET) != 0) { - ret = lang_hooks.decls.omp_disregard_value_expr (decl, true); + shared = !(ctx->region_type & ORT_ACC); + ret = lang_hooks.decls.omp_disregard_value_expr (decl, shared); if (n == NULL) { unsigned nflags = flags; @@ -6382,6 +6389,8 @@ omp_notice_variable (struct gimplify_omp_ctx *ctx, tree decl, bool in_code) } shared = ((flags | n->value) & GOVD_SHARED) != 0; + if (ctx->region_type & ORT_ACC) + shared = false; ret = lang_hooks.decls.omp_disregard_value_expr (decl, shared); /* If nothing changed, there's nothing left to do. */ diff --git a/gcc/testsuite/gfortran.dg/goacc/common-block-1.f90 b/gcc/testsuite/gfortran.dg/goacc/common-block-1.f90 new file mode 100644 index 0000000..c9de125 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/common-block-1.f90 @@ -0,0 +1,69 @@ +! Test data clauses involving common blocks and common block data. +! Specifically, validate early matching errors. + +subroutine subtest + implicit none + integer, parameter :: n = 10 + integer a(n), b(n), c, d(n), e + real*4 x(n), y(n), z, w(n), v + common /blockA/ a, c, x + common /blockB/ b, y, z + !$acc declare link(/blockA/, /blockB/, e, v) +end subroutine subtest + +program test + implicit none + integer, parameter :: n = 10 + integer a(n), b(n), c, d(n), e + real*4 x(n), y(n), z, w(n), v + common /blockA/ a, c, x + common /blockB/ b, y, z + !$acc declare link(/blockA/, /blockB/, e, v) + + !$acc data copy(/blockA/, /blockB/, e, v) + !$acc end data + + !$acc data copyin(/blockA/, /blockB/, e, v) + !$acc end data + + !$acc data copyout(/blockA/, /blockB/, e, v) + !$acc end data + + !$acc data create(/blockA/, /blockB/, e, v) + !$acc end data + + !$acc data copyout(/blockA/, /blockB/, e, v) + !$acc end data + + !$acc data pcopy(/blockA/, /blockB/, e, v) + !$acc end data + + !$acc data pcopyin(/blockA/, /blockB/, e, v) + !$acc end data + + !$acc data pcopyout(/blockA/, /blockB/, e, v) + !$acc end data + + !$acc data pcreate(/blockA/, /blockB/, e, v) + !$acc end data + + !$acc data pcopyout(/blockA/, /blockB/, e, v) + !$acc end data + + !$acc data present(/blockA/, /blockB/, e, v) ! { dg-error "" } + !$acc end data ! { dg-error "Unexpected ..ACC END DATA statement" } + + !$acc parallel private(/blockA/, /blockB/, e, v) + !$acc end parallel + + !$acc parallel firstprivate(/blockA/, /blockB/, e, v) + !$acc end parallel + + !$acc exit data delete(/blockA/, /blockB/, e, v) + + !$acc data deviceptr(/blockA/, /blockB/, e, v) ! { dg-error "Syntax error" } + !$acc end data ! { dg-error "Unexpected ..ACC END DATA statement" } + + !$acc data deviceptr(/blockA/, /blockB/, e, v) ! { dg-error "Syntax error" } + !$acc end data ! { dg-error "Unexpected ..ACC END DATA statement" } +end program test diff --git a/gcc/testsuite/gfortran.dg/goacc/common-block-2.f90 b/gcc/testsuite/gfortran.dg/goacc/common-block-2.f90 new file mode 100644 index 0000000..b836389 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/goacc/common-block-2.f90 @@ -0,0 +1,49 @@ +! Test data clauses involving common blocks and common block data. +! Specifically, resolver errors such as duplicate data clauses. + +program test + implicit none + integer, parameter :: n = 10 + integer a(n), b(n), c, d(n), e + real*4 x(n), y(n), z, w(n), v + common /blockA/ a, c, x + common /blockB/ b, y, z + + !$acc data copy(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end data + + !$acc data copyin(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end data + + !$acc data copyout(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end data + + !$acc data create(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end data + + !$acc data copyout(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end data + + !$acc data pcopy(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end data + + !$acc data pcopyin(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end data + + !$acc data pcopyout(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end data + + !$acc data pcreate(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end data + + !$acc data pcopyout(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end data + + !$acc parallel private(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end parallel + + !$acc parallel firstprivate(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } + !$acc end parallel + + !$acc exit data delete(/blockA/, /blockB/, e, v, a) ! { dg-error "Symbol .a. present on multiple clauses" } +end program test diff --git a/libgomp/testsuite/libgomp.oacc-fortran/common-block-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/common-block-1.f90 new file mode 100644 index 0000000..9f40297 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/common-block-1.f90 @@ -0,0 +1,105 @@ +! Test data located inside common blocks. This test does not execrise +! ACC DECLARE. + +module const + integer, parameter :: n = 100 +end module const + +subroutine check + use const + + implicit none + integer i, x(n), y + common /BLOCK/ x, y + + do i = 1, n + if (x(i) .ne. y) call abort + end do +end subroutine check + +module m + use const + integer a(n), b + common /BLOCK/ a, b + +contains + subroutine mod_implicit_incr + implicit none + integer i + + !$acc parallel loop + do i = 1, n + a(i) = b + end do + !$acc end parallel loop + + call check + end subroutine mod_implicit_incr + + subroutine mod_explicit_incr + implicit none + integer i + + !$acc parallel loop copy(a(1:n)) copyin(b) + do i = 1, n + a(i) = b + end do + !$acc end parallel loop + + call check + end subroutine mod_explicit_incr +end module m + +subroutine sub_implicit_incr + use const + + implicit none + integer i, x(n), y + common /BLOCK/ x, y + + !$acc parallel loop + do i = 1, n + x(i) = y + end do + !$acc end parallel loop + + call check +end subroutine sub_implicit_incr + +subroutine sub_explicit_incr + use const + + implicit none + integer i, x(n), y + common /BLOCK/ x, y + + !$acc parallel loop copy(x(1:n)) copyin(y) + do i = 1, n + x(i) = y + end do + !$acc end parallel loop + + call check +end subroutine sub_explicit_incr + +program main + use m + + implicit none + + a(:) = -1 + b = 5 + call mod_implicit_incr + + a(:) = -2 + b = 6 + call mod_explicit_incr + + a(:) = -3 + b = 7 + call sub_implicit_incr + + a(:) = -4 + b = 8 + call sub_explicit_incr +end program main diff --git a/libgomp/testsuite/libgomp.oacc-fortran/common-block-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/common-block-2.f90 new file mode 100644 index 0000000..bf17fc5 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/common-block-2.f90 @@ -0,0 +1,150 @@ +! Test data located inside common blocks. This test does not execrise +! ACC DECLARE. All data clauses are explicit. + +module consts + integer, parameter :: n = 100 +end module consts + +subroutine validate + use consts + + implicit none + integer i, j + real*4 x(n), y(n), z + common /BLOCK/ x, y, z, j + + do i = 1, n + if (abs(x(i) - i - z) .ge. 0.0001) call abort + end do +end subroutine validate + +subroutine incr + use consts + + implicit none + integer i, j + real*4 x(n), y(n), z + common /BLOCK/ x, y, z, j + + !$acc parallel loop pcopy(/BLOCK/) + do i = 1, n + x(i) = x(i) + z + end do + !$acc end parallel loop +end subroutine incr + +program main + use consts + + implicit none + integer i, j + real*4 a(n), b(n), c + common /BLOCK/ a, b, c, j + + ! Test copyout, pcopy, device + + !$acc data copyout(a, c) + + c = 1.0 + + !$acc update device(c) + + !$acc parallel loop pcopy(a) + do i = 1, n + a(i) = i + end do + !$acc end parallel loop + + call incr + call incr + call incr + !$acc end data + + c = 3.0 + call validate + + ! Test pcopy without copyout + + c = 2.0 + call incr + c = 5.0 + call validate + + ! Test create, delete, host, copyout, copyin + + !$acc enter data create(b) + + !$acc parallel loop pcopy(b) + do i = 1, n + b(i) = i + end do + !$acc end parallel loop + + !$acc update host (b) + + !$acc parallel loop pcopy(b) copyout(a) copyin(c) + do i = 1, n + a(i) = b(i) + c + end do + !$acc end parallel loop + + !$acc exit data delete(b) + + call validate + + a(:) = b(:) + c = 0.0 + call validate + + ! Test copy + + c = 1.0 + !$acc parallel loop copy(/BLOCK/) + do i = 1, n + a(i) = b(i) + c + end do + !$acc end parallel loop + + call validate + + ! Test pcopyin, pcopyout FIXME + + c = 2.0 + !$acc data copyin(b, c) copyout(a) + + !$acc parallel loop pcopyin(b, c) pcopyout(a) + do i = 1, n + a(i) = b(i) + c + end do + !$acc end parallel loop + + !$acc end data + + call validate + + ! Test reduction, private + + j = 0 + + !$acc parallel private(i) copy(j) + !$acc loop reduction(+:j) + do i = 1, n + j = j + 1 + end do + !$acc end parallel + + if (j .ne. n) call abort + + ! Test firstprivate, copy + + a(:) = 0 + c = j + + !$acc parallel loop firstprivate(c) copyout(a) + do i = 1, n + a(i) = i + c + end do + !$acc end parallel loop + + call validate +end program main diff --git a/libgomp/testsuite/libgomp.oacc-fortran/common-block-3.f90 b/libgomp/testsuite/libgomp.oacc-fortran/common-block-3.f90 new file mode 100644 index 0000000..134e2d1 --- /dev/null +++ b/libgomp/testsuite/libgomp.oacc-fortran/common-block-3.f90 @@ -0,0 +1,137 @@ +! Test data located inside common blocks. This test does not execrise +! ACC DECLARE. Most of the data clauses are implicit. + +module consts + integer, parameter :: n = 100 +end module consts + +subroutine validate + use consts + + implicit none + integer i, j + real*4 x(n), y(n), z + common /BLOCK/ x, y, z, j + + do i = 1, n + if (abs(x(i) - i - z) .ge. 0.0001) call abort + end do +end subroutine validate + +subroutine incr_parallel + use consts + + implicit none + integer i, j + real*4 x(n), y(n), z + common /BLOCK/ x, y, z, j + + !$acc parallel loop + do i = 1, n + x(i) = x(i) + z + end do + !$acc end parallel loop +end subroutine incr_parallel + +subroutine incr_kernels + use consts + + implicit none + integer i, j + real*4 x(n), y(n), z + common /BLOCK/ x, y, z, j + + !$acc kernels + do i = 1, n + x(i) = x(i) + z + end do + !$acc end kernels +end subroutine incr_kernels + +program main + use consts + + implicit none + integer i, j + real*4 a(n), b(n), c + common /BLOCK/ a, b, c, j + + !$acc data copyout(a, c) + + c = 1.0 + + !$acc update device(c) + + !$acc parallel loop + do i = 1, n + a(i) = i + end do + !$acc end parallel loop + + call incr_parallel + call incr_parallel + call incr_parallel + !$acc end data + + c = 3.0 + call validate + + ! Test pcopy without copyout + + c = 2.0 + call incr_kernels + c = 5.0 + call validate + + !$acc kernels + do i = 1, n + b(i) = i + end do + !$acc end kernels + + !$acc parallel loop + do i = 1, n + a(i) = b(i) + c + end do + !$acc end parallel loop + + call validate + + a(:) = b(:) + c = 0.0 + call validate + + ! Test copy + + c = 1.0 + !$acc parallel loop + do i = 1, n + a(i) = b(i) + c + end do + !$acc end parallel loop + + call validate + + c = 2.0 + !$acc data copyin(b, c) copyout(a) + + !$acc kernels + do i = 1, n + a(i) = b(i) + c + end do + !$acc end kernels + + !$acc end data + + call validate + + j = 0 + + !$acc parallel loop reduction(+:j) + do i = 1, n + j = j + 1 + end do + !$acc end parallel loop + + if (j .ne. n) call abort +end program main