This patch fixes a set of XFAILs in some recently-added patches by skipping a detach operation on "no-op" exit data operations for blocks with zero dynamic refcount. This takes advantage of the ordering of detach clauses with respect to associated data-movement clauses: i.e., they are grouped together adjacently.
OK? Julian ChangeLog libgomp/ * oacc-mem.c (find_group_last): Handle detach operations. (goacc_exit_data_internal): Detect detachments that are part of copyout operations, and suppress them if dynamic refcount is zero. * testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90: Remove XFAILs. * testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90: Fix typo. * testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90: Remove XFAILs. * testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90: Likewise. * testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90: Likewise. * testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90: Likewise. * testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90: Likewise. * testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90: Likewise. --- libgomp/oacc-mem.c | 54 ++++++++++++++++--- .../mdc-refcount-1-1-1.f90 | 6 +-- .../mdc-refcount-1-1-2.F90 | 2 +- .../mdc-refcount-1-2-1.f90 | 6 +-- .../mdc-refcount-1-2-2.f90 | 6 +-- .../mdc-refcount-1-3-1.f90 | 6 +-- .../mdc-refcount-1-3-2.f90 | 5 +- .../mdc-refcount-1-4-1.f90 | 6 +-- .../mdc-refcount-1-4-2.f90 | 5 +- 9 files changed, 55 insertions(+), 41 deletions(-) diff --git a/libgomp/oacc-mem.c b/libgomp/oacc-mem.c index 745cb132621..f852652c048 100644 --- a/libgomp/oacc-mem.c +++ b/libgomp/oacc-mem.c @@ -987,7 +987,9 @@ find_group_last (int pos, size_t mapnum, size_t *sizes, unsigned short *kinds) { case GOMP_MAP_TO_PSET: if (pos + 1 < mapnum - && (kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH) + && ((kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH + || (kinds[pos + 1] & 0xff) == GOMP_MAP_DETACH + || (kinds[pos + 1] & 0xff) == GOMP_MAP_FORCE_DETACH)) return pos + 1; while (pos + 1 < mapnum @@ -1010,6 +1012,8 @@ find_group_last (int pos, size_t mapnum, size_t *sizes, unsigned short *kinds) break; case GOMP_MAP_ATTACH: + case GOMP_MAP_DETACH: + case GOMP_MAP_FORCE_DETACH: return pos; default: @@ -1025,7 +1029,9 @@ find_group_last (int pos, size_t mapnum, size_t *sizes, unsigned short *kinds) /* We can have a single GOMP_MAP_ATTACH mapping after a to/from mapping. */ if (pos + 1 < mapnum - && (kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH) + && ((kinds[pos + 1] & 0xff) == GOMP_MAP_ATTACH + || (kinds[pos + 1] & 0xff) == GOMP_MAP_DETACH + || (kinds[pos + 1] & 0xff) == GOMP_MAP_FORCE_DETACH)) return pos + 1; /* We can have zero or more GOMP_MAP_POINTER mappings after a to/from @@ -1168,15 +1174,43 @@ goacc_exit_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum, { gomp_mutex_lock (&acc_dev->lock); - /* Handle "detach" before copyback/deletion of mapped data. */ - for (size_t i = 0; i < mapnum; ++i) + /* Handle "detach" before copyback/deletion of mapped data. If this isn't a + standalone "detach" clause, take care to skip the "detach" operation if + the dynamic refcount of the data to be detached is zero. */ + for (size_t grp = 0; grp < mapnum; grp++) { - unsigned char kind = kinds[i] & 0xff; + size_t i = grp, group_last = find_group_last (grp, mapnum, sizes, kinds); + unsigned char kind = kinds[grp] & 0xff; bool finalize = false; + switch (kind) { + case GOMP_MAP_TO_PSET: + case GOMP_MAP_TOFROM: + case GOMP_MAP_FROM: + case GOMP_MAP_FORCE_FROM: + case GOMP_MAP_RELEASE: + case GOMP_MAP_DELETE: + { + if (i + 1 >= mapnum) + break; + kind = kinds[i + 1] & 0xff; + if (kind != GOMP_MAP_FORCE_DETACH && kind != GOMP_MAP_DETACH) + break; + splay_tree_key n = lookup_host (acc_dev, hostaddrs[i], sizes[i]); + if (n == NULL) + { + gomp_mutex_unlock (&acc_dev->lock); + gomp_fatal ("target data not mapped for detach operation"); + } + i++; + if (n->dynamic_refcount == 0) + break; + } + /* Fallthrough. */ + case GOMP_MAP_FORCE_DETACH: - finalize = true; + finalize = (kind == GOMP_MAP_FORCE_DETACH); /* Fallthrough. */ case GOMP_MAP_DETACH: @@ -1197,9 +1231,15 @@ goacc_exit_data_internal (struct gomp_device_descr *acc_dev, size_t mapnum, gomp_detach_pointer (acc_dev, aq, n, hostaddr, finalize, NULL); } break; + case GOMP_MAP_STRUCT: + case GOMP_MAP_POINTER: + /* Ignore. */ + break; default: - ; + gomp_fatal (">>>> goacc_exit_data_internal UNHANDLED kind 0x%.2x", + kind); } + grp = group_last; } for (size_t i = 0; i < mapnum; ++i) diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90 index 445cbabb8ca..7171affb9f0 100644 --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90 +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-1.f90 @@ -24,12 +24,8 @@ program main print *, "CheCKpOInT1" ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" } !$acc exit data delete(var%a) finalize - !TODO goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed. - !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing). - !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all. - !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log. print *, "CheCKpOInT2" - ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } } + ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" } if (acc_is_present(var%a)) stop 3 if (.not. acc_is_present(var)) stop 4 diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90 index 7b206ac2042..2aa46189e9a 100644 --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90 +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-1-2.F90 @@ -6,4 +6,4 @@ #include "mdc-refcount-1-1-1.f90" ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" } -! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" } +! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" } diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90 index 8554534b2f2..9a10aa5a781 100644 --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90 +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-1.f90 @@ -26,12 +26,8 @@ program main print *, "CheCKpOInT1" ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" } !$acc exit data delete(var%a) finalize - !TODO goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed. - !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing). - !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all. - !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log. print *, "CheCKpOInT2" - ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } } + ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" } if (acc_is_present(var%a)) stop 3 if (.not. acc_is_present(var)) stop 4 diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90 index 8e696cc70e8..f506adf8e91 100644 --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90 +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-2-2.f90 @@ -26,12 +26,8 @@ program main print *, "CheCKpOInT1" ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" } !$acc exit data delete(var%a) - !TODO goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed. - !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing). - !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all. - !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log. print *, "CheCKpOInT2" - ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } } + ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" } if (acc_is_present(var%a)) stop 3 if (.not. acc_is_present(var)) stop 4 diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90 index 070a6f8e149..450d95d3686 100644 --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90 +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-1.f90 @@ -27,12 +27,8 @@ program main print *, "CheCKpOInT1" ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" } !$acc exit data delete(var%a) finalize - !TODO goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed. - !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing). - !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all. - !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log. print *, "CheCKpOInT2" - ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } } + ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" } if (acc_is_present(var%a)) stop 3 if (.not. acc_is_present(var)) stop 4 diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90 index 3c4bbda7f66..35efad4138a 100644 --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90 +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-3-2.f90 @@ -27,11 +27,8 @@ program main print *, "CheCKpOInT1" ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" } !$acc exit data delete(var%a) - !TODO { dg-output "(\n|\r\n|\r)libgomp: attach count underflow(\n|\r\n|\r)$" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing). - !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all. - !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log. print *, "CheCKpOInT2" - ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } } + ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" } if (acc_is_present(var%a)) stop 3 if (.not. acc_is_present(var)) stop 4 diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90 index b22e411567f..816562fc055 100644 --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90 +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-1.f90 @@ -26,12 +26,8 @@ program main print *, "CheCKpOInT1" ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" } !$acc exit data detach(var%a) finalize - !TODO goacc_exit_data_internal: Assertion `is_tgt_unmapped || num_mappings > 1' failed. - !TODO { dg-output ".*\[Aa\]ssert.*is_tgt_unmapped" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing). - !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all. - !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log. print *, "CheCKpOInT2" - ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } } + ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" } !$acc exit data delete(var%a) if (acc_is_present(var%a)) stop 3 if (.not. acc_is_present(var)) stop 4 diff --git a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90 b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90 index 476cd5c1bee..b98bfd74924 100644 --- a/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90 +++ b/libgomp/testsuite/libgomp.oacc-fortran/mdc-refcount-1-4-2.f90 @@ -27,11 +27,8 @@ program main print *, "CheCKpOInT1" ! { dg-output ".*CheCKpOInT1(\n|\r\n|\r)" } !$acc exit data delete(var%a) - !TODO { dg-output "(\n|\r\n|\r)libgomp: attach count underflow(\n|\r\n|\r)$" { target { ! openacc_host_selected } } } ! Scan for what we expect in the "XFAILed" case (without actually XFAILing). - !TODO { dg-shouldfail "XFAILed" { ! openacc_host_selected } } ! ... instead of 'dg-xfail-run-if' so that 'dg-output' is evaluated at all. - !TODO { dg-final { if { [dg-process-target { xfail { ! openacc_host_selected } }] == "F" } { xfail "[testname-for-summary] really is XFAILed" } } } ! ... so that we still get an XFAIL visible in the log. print *, "CheCKpOInT2" - ! { dg-output ".CheCKpOInT2(\n|\r\n|\r)" { target { openacc_host_selected } } } + ! { dg-output ".*CheCKpOInT2(\n|\r\n|\r)" } if (acc_is_present(var%a)) stop 3 if (.not. acc_is_present(var)) stop 4 -- 2.23.0