1 ! Test OpenACC 'declare create' with allocatable arrays.
5 ! Note that we're not testing OpenACC semantics here, but rather documenting
6 ! current GCC behavior, specifically, behavior concerning updating of
7 ! host/device array descriptors.
8 ! { dg-skip-if n/a { *-*-* } { -DACC_MEM_SHARED=1 } }
10 !TODO-OpenACC-declare-allocate
11 ! Missing support for OpenACC "Changes from Version 2.0 to 2.5":
12 ! "The 'declare create' directive with a Fortran 'allocatable' has new behavior".
13 ! Thus, after 'allocate'/before 'deallocate', do
14 ! '!$acc enter data create'/'!$acc exit data delete' manually.
17 !TODO { dg-additional-options -fno-inline } for stable results regarding OpenACC 'routine'.
20 !TODO OpenACC 'serial' vs. GCC/nvptx:
21 !TODO { dg-prune-output {using 'vector_length \(32\)', ignoring 1} }
24 ! { dg-additional-options -fdump-tree-original }
25 ! { dg-additional-options -fdump-tree-gimple }
30 integer, parameter :: n1_lb
= -3
31 integer, parameter :: n1_ub
= 6
32 integer, parameter :: n2_lb
= -9999
33 integer, parameter :: n2_ub
= 22222
35 integer, allocatable
:: b(:)
36 !$acc declare create (b)
46 ! Identifiers for purposes of reliable '-fdump-tree-[...]' scanning.
47 integer :: id1_1
, id1_2
51 subroutine verify_initial
54 end subroutine verify_initial
56 subroutine verify_n1_allocated
59 end subroutine verify_n1_allocated
61 subroutine verify_n1_values (addend
)
64 integer, value
:: addend
65 end subroutine verify_n1_values
67 subroutine verify_n1_deallocated (expect_allocated
)
70 logical, value
:: expect_allocated
71 end subroutine verify_n1_deallocated
73 subroutine verify_n2_allocated
76 end subroutine verify_n2_allocated
78 subroutine verify_n2_values (addend
)
81 integer, value
:: addend
82 end subroutine verify_n2_values
84 subroutine verify_n2_deallocated (expect_allocated
)
87 logical, value
:: expect_allocated
88 end subroutine verify_n2_deallocated
92 call acc_create (id1_1
)
93 call acc_create (id1_2
)
96 ! It is important here (and similarly, following) that there is no data
97 ! clause for 'b' (explicit or implicit): no 'GOMP_MAP_TO_PSET'.
102 allocate (b(n1_lb
:n1_ub
))
103 call verify_n1_allocated
104 if (acc_is_present (b
)) error
stop
105 !$acc enter data create (b)
106 ! This is now OpenACC "present":
107 if (.not
.acc_is_present (b
)) error
stop
108 ! ..., and got the actual array descriptor installed:
110 call verify_n1_allocated
117 ! In 'declare-allocatable-array_descriptor-1-runtime.f90', this does "verify
118 ! that host-to-device copy doesn't touch the device-side (still initial)
119 ! array descriptor (but it does copy the array data"). This is here not
120 ! applicable anymore, as we've already gotten the actual array descriptor
121 ! installed. Thus now verify that it does copy the array data.
122 call acc_update_device (b
)
124 call verify_n1_allocated
129 !$acc parallel copyout (id1_1) ! No data clause for 'b' (explicit or implicit): no 'GOMP_MAP_TO_PSET'.
130 call verify_n1_values (-1)
133 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma acc parallel map\(from:id1_1\)$} 1 original } }
134 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma omp target oacc_parallel map\(from:id1_1 \[len: [0-9]+\]\)$} 1 gimple } }
136 !$acc parallel copy (b) copyout (id1_2)
137 ! As already present, 'copy (b)' doesn't copy; addend is still '-1'.
138 call verify_n1_values (-1)
141 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma acc parallel map\(tofrom:\*\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[len: [^\]]+\]\) map\(to:b \[pointer set, len: [0-9]+\]\) map\(alloc:\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[pointer assign, bias: 0\]\) map\(from:id1_2\)$} 1 original } }
142 !TODO ..., but without an actual use of 'b', the gimplifier removes the
143 !TODO 'GOMP_MAP_TO_PSET':
144 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma omp target oacc_parallel map\(tofrom:MEM <integer\(kind=[0-9]+\)\[0:\]> \[\(integer\(kind=[0-9]+\)\[0:\] \*\)[^\]]+\] \[len: [^\]]+\]\) map\(alloc:b\.data \[pointer assign, bias: 0\]\) map\(from:id1_2 \[len: [0-9]+\]\)$} 1 gimple } }
146 ! In 'declare-allocatable-array_descriptor-1-runtime.f90', this does "verify
147 ! that device-to-host copy doesn't touch the host-side array descriptor,
148 ! doesn't copy out the device-side (still initial) array descriptor (but it
149 ! does copy the array data)". This is here not applicable anymore, as we've
150 ! already gotten the actual array descriptor installed. Thus now verify that
151 ! it does copy the array data.
152 call acc_update_self (b
)
153 call verify_n1_allocated
156 if (b(i
) /= i
- 1) error
stop
160 ! The same using the OpenACC 'update' directive.
162 !$acc update device (b) self (id1_1)
163 ! We do have 'GOMP_MAP_TO_PSET' here:
164 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma acc update map\(force_to:\*\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[len: [^\]]+\]\) map\(to:b \[pointer set, len: [0-9]+\]\) map\(alloc:\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[pointer assign, bias: 0\]\) map\(force_from:id1_1\);$} 1 original } }
165 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma omp target oacc_update map\(force_to:MEM <integer\(kind=[0-9]+\)\[0:\]> \[\(integer\(kind=[0-9]+\)\[0:\] \*\)[^\]]+\] \[len: [^\]]+\]\) map\(to:b \[pointer set, len: [0-9]+\]\) map\(alloc:b\.data \[pointer assign, bias: 0\]\) map\(force_from:id1_1 \[len: [0-9]+\]\)$} 1 gimple } }
166 ! ..., but it's silently skipped in 'GOACC_update'.
168 call verify_n1_allocated
174 call verify_n1_values (1)
177 !$acc parallel copy (b)
178 call verify_n1_values (1)
181 !$acc update self (b) self (id1_2)
182 ! We do have 'GOMP_MAP_TO_PSET' here:
183 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma acc update map\(force_from:\*\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[len: [^\]]+\]\) map\(to:b \[pointer set, len: [0-9]+\]\) map\(alloc:\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[pointer assign, bias: 0\]\) map\(force_from:id1_2\);$} 1 original } }
184 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma omp target oacc_update map\(force_from:MEM <integer\(kind=[0-9]+\)\[0:\]> \[\(integer\(kind=[0-9]+\)\[0:\] \*\)[^\]]+\] \[len: [^\]]+\]\) map\(to:b \[pointer set, len: [0-9]+\]\) map\(alloc:b\.data \[pointer assign, bias: 0\]\) map\(force_from:id1_2 \[len: [0-9]+\]\)$} 1 gimple } }
185 ! ..., but it's silently skipped in 'GOACC_update'.
186 call verify_n1_allocated
189 if (b(i
) /= i
+ 1) error
stop
193 ! Now test that (potentially re-)installing the actual array descriptor is a
194 ! no-op, via a data clause for 'b' (explicit or implicit): must get a
195 ! 'GOMP_MAP_TO_PSET'.
196 !$acc serial present (b) copyin (id1_2)
197 call verify_n1_allocated
199 id1_2
= ubound (b
, 1)
201 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma acc serial map\(force_present:\*\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[len: [^\]]+\]\) map\(to:b \[pointer set, len: [0-9]+\]\) map\(alloc:\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[pointer assign, bias: 0\]\) map\(to:id1_2\)$} 1 original } }
202 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma omp target oacc_serial map\(force_present:MEM <integer\(kind=[0-9]+\)\[0:\]> \[\(integer\(kind=[0-9]+\)\[0:\] \*\)[^\]]+\] \[len: [^\]]+\]\) map\(to:b \[pointer set, len: [0-9]+\]\) map\(alloc:b\.data \[pointer assign, bias: 0\]\) map\(to:id1_2 \[len: [0-9]+\]\)$} 1 gimple } }
204 !$acc parallel copyin (id1_1) ! No data clause for 'b' (explicit or implicit): no 'GOMP_MAP_TO_PSET'.
205 call verify_n1_values (1)
208 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma acc parallel map\(to:id1_1\)$} 1 original } }
209 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma omp target oacc_parallel map\(to:id1_1 \[len: [0-9]+\]\)$} 1 gimple } }
211 !$acc parallel copy (b) copyin (id1_2)
212 ! As already present, 'copy (b)' doesn't copy; addend is still '1'.
213 call verify_n1_values (1)
216 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma acc parallel map\(tofrom:\*\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[len: [^\]]+\]\) map\(to:b \[pointer set, len: [0-9]+\]\) map\(alloc:\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[pointer assign, bias: 0\]\) map\(to:id1_2\)$} 1 original } }
217 !TODO ..., but without an actual use of 'b', the gimplifier removes the
218 !TODO 'GOMP_MAP_TO_PSET':
219 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma omp target oacc_parallel map\(tofrom:MEM <integer\(kind=[0-9]+\)\[0:\]> \[\(integer\(kind=[0-9]+\)\[0:\] \*\)[^\]]+\] \[len: [^\]]+\]\) map\(alloc:b\.data \[pointer assign, bias: 0\]\) map\(to:id1_2 \[len: [0-9]+\]\)$} 1 gimple } }
221 call verify_n1_allocated
222 if (.not
.acc_is_present (b
)) error
stop
224 !$acc exit data delete (b)
225 if (.not
.allocated (b
)) error
stop
226 if (acc_is_present (b
)) error
stop
227 ! The device-side array descriptor doesn't get updated, so 'b' still appears
230 call verify_n1_allocated
234 call verify_n1_deallocated (.false
.)
235 ! The device-side array descriptor doesn't get updated, so 'b' still appears
238 call verify_n1_allocated
241 ! Now try to install the actual array descriptor, via a data clause for 'b'
242 ! (explicit or implicit): must get a 'GOMP_MAP_TO_PSET', which then in
243 ! 'gomp_map_vars_internal' is handled as 'declare target', but because of
244 ! '*(void **) hostaddrs[i] == NULL', we've got 'has_always_ptrset == false',
245 ! 'always_to_cnt == 0', and therefore 'gomp_map_vars_existing' doesn't update
246 ! the 'GOMP_MAP_TO_PSET'.
247 ! The device-side array descriptor doesn't get updated, so 'b' still appears
249 !TODO Why does 'present (b)' still work here?
250 !$acc serial present (b) copyout (id1_2)
251 call verify_n1_deallocated (.true
.)
253 id1_2
= ubound (b
, 1)
255 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma acc serial map\(force_present:\*\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[len: [^\]]+\]\) map\(to:b \[pointer set, len: [0-9]+\]\) map\(alloc:\(integer\(kind=[0-9]+\)\[0:\] \* restrict\) b\.data \[pointer assign, bias: 0\]\) map\(from:id1_2\)$} 1 original } }
256 ! { dg-final { scan-tree-dump-times {(?n)^ *#pragma omp target oacc_serial map\(force_present:MEM <integer\(kind=[0-9]+\)\[0:\]> \[\(integer\(kind=[0-9]+\)\[0:\] \*\)[^\]]+\] \[len: [^\]]+\]\) map\(to:b \[pointer set, len: [0-9]+\]\) map\(alloc:b\.data \[pointer assign, bias: 0\]\) map\(from:id1_2 \[len: [0-9]+\]\)$} 1 gimple } }
259 ! Restart the procedure, with different array dimensions.
261 allocate (b(n2_lb
:n2_ub
))
262 call verify_n2_allocated
263 if (acc_is_present (b
)) error
stop
264 !$acc enter data create (b)
265 if (.not
.acc_is_present (b
)) error
stop
266 ! ..., and got the actual array descriptor installed:
268 call verify_n2_allocated
275 call acc_update_device (b
)
277 call verify_n2_allocated
283 call verify_n2_values (20)
286 !$acc parallel copy (b)
287 call verify_n2_values (20)
290 call acc_update_self (b
)
291 call verify_n2_allocated
294 if (b(i
) /= i
+ 20) error
stop
298 !$acc update device (b)
300 call verify_n2_allocated
306 call verify_n2_values (-20)
309 !$acc parallel copy (b)
310 call verify_n2_values (-20)
313 !$acc update self (b)
314 call verify_n2_allocated
317 if (b(i
) /= i
- 20) error
stop
321 !$acc serial present (b) copy (id1_2)
322 call verify_n2_allocated
324 id1_2
= ubound (b
, 1)
328 call verify_n2_values (-20)
331 !$acc parallel copy (b)
332 call verify_n2_values (-20)
335 call verify_n2_allocated
336 if (.not
.acc_is_present (b
)) error
stop
338 !$acc exit data delete (b)
339 if (.not
.allocated (b
)) error
stop
340 if (acc_is_present (b
)) error
stop
342 call verify_n2_allocated
346 call verify_n2_deallocated (.false
.)
348 call verify_n2_allocated
351 !$acc serial present (b) copy (id1_2)
352 call verify_n2_deallocated (.true
.)
354 id1_2
= ubound (b
, 1)
360 subroutine verify_initial
365 if (allocated (b
)) error
stop "verify_initial allocated"
366 if (any (lbound (b
) /= [0])) error
stop "verify_initial lbound"
367 if (any (ubound (b
) /= [0])) error
stop "verify_initial ubound"
368 end subroutine verify_initial
370 subroutine verify_n1_allocated
375 if (.not
.allocated (b
)) error
stop "verify_n1_allocated allocated"
376 if (any (lbound (b
) /= [n1_lb
])) error
stop "verify_n1_allocated lbound"
377 if (any (ubound (b
) /= [n1_ub
])) error
stop "verify_n1_allocated ubound"
378 end subroutine verify_n1_allocated
380 subroutine verify_n1_values (addend
)
384 integer, value
:: addend
389 if (b(i
) /= i
+ addend
) error
stop
391 end subroutine verify_n1_values
393 subroutine verify_n1_deallocated (expect_allocated
)
397 logical, value
:: expect_allocated
399 if (allocated(b
) .neqv
. expect_allocated
) error
stop "verify_n1_deallocated allocated"
400 ! Apparently 'deallocate'ing doesn't unset the bounds.
401 if (any (lbound (b
) /= [n1_lb
])) error
stop "verify_n1_deallocated lbound"
402 if (any (ubound (b
) /= [n1_ub
])) error
stop "verify_n1_deallocated ubound"
403 end subroutine verify_n1_deallocated
405 subroutine verify_n2_allocated
410 if (.not
.allocated(b
)) error
stop "verify_n2_allocated allocated"
411 if (any (lbound (b
) /= [n2_lb
])) error
stop "verify_n2_allocated lbound"
412 if (any (ubound (b
) /= [n2_ub
])) error
stop "verify_n2_allocated ubound"
413 end subroutine verify_n2_allocated
415 subroutine verify_n2_values (addend
)
419 integer, value
:: addend
424 if (b(i
) /= i
+ addend
) error
stop
426 end subroutine verify_n2_values
428 subroutine verify_n2_deallocated (expect_allocated
)
432 logical, value
:: expect_allocated
434 if (allocated(b
) .neqv
. expect_allocated
) error
stop "verify_n2_deallocated allocated"
435 ! Apparently 'deallocate'ing doesn't unset the bounds.
436 if (any (lbound (b
) /= [n2_lb
])) error
stop "verify_n2_deallocated lbound"
437 if (any (ubound (b
) /= [n2_ub
])) error
stop "verify_n2_deallocated ubound"
438 end subroutine verify_n2_deallocated