! RUN: bbc -emit-hlfir -fopenacc -fcuda %s -o - | FileCheck %s ! Test CUDA Fortran data transfer using assignment statements. module mod1 type :: t1 integer :: i end type type :: t2 integer, device, allocatable, dimension(:) :: x end type type :: s real :: c(3) end type type :: t3 type(s), managed, allocatable :: spheres(:) end type integer, device, dimension(11:20) :: cdev real(kind=8), device, allocatable, dimension(:) :: p interface function __sum(a_d) result(res_h) integer(4), managed, intent(in) :: a_d(:,:,:,:) integer(4), allocatable, managed :: res_h(:,:,:) end function end interface interface function somefunction(d, n) integer :: n real(8), device :: d(n,n) real(8) :: somefunction(n) end function end interface contains function dev1(a) integer, device :: a(:) integer :: dev1 dev1 = 1 end function end subroutine sub1() use mod1 integer, device :: m integer, device :: adev(10) integer :: i, ahost(10), bhost(10) m = 1 + i m = 1 adev = ahost adev = ahost + 1 adev(1:5) = ahost(1:5) adev = ahost + bhost adev = 10 cdev = 0 end ! CHECK-LABEL: func.func @_QPsub1() ! CHECK: %[[ADEV:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {data_attr = #cuf.cuda, uniq_name = "_QFsub1Eadev"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[AHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub1Eahost"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFsub1Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[M:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda, uniq_name = "_QFsub1Em"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[C1:.*]] = arith.constant 1 : i32 ! CHECK: %[[LOADED_I:.*]] = fir.load %[[I]]#0 : !fir.ref ! CHECK: %[[ADD:.*]] = arith.addi %[[C1]], %[[LOADED_I]] : i32 ! CHECK: %[[ASSOC:.*]]:3 = hlfir.associate %[[ADD]] {uniq_name = ".cuf_host_tmp"} : (i32) -> (!fir.ref, !fir.ref, i1) ! CHECK: cuf.data_transfer %[[ASSOC]]#0 to %[[M]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref, !fir.ref ! CHECK: hlfir.end_associate %[[ASSOC]]#1, %[[ASSOC]]#2 : !fir.ref, i1 ! CHECK: cuf.data_transfer %c1{{.*}} to %[[M]]#0 {transfer_kind = #cuf.cuda_transfer} : i32, !fir.ref ! CHECK: cuf.data_transfer %[[AHOST]]#0 to %[[ADEV]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.ref> ! CHECK: %[[ELEMENTAL:.*]] = hlfir.elemental %{{.*}} unordered : (!fir.shape<1>) -> !hlfir.expr<10xi32> { ! CHECK: %[[ASSOC:.*]]:3 = hlfir.associate %[[ELEMENTAL]](%{{.*}}) {uniq_name = ".cuf_host_tmp"} : (!hlfir.expr<10xi32>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>, i1) ! CHECK: cuf.data_transfer %[[ASSOC]]#0 to %[[ADEV]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.ref> ! CHECK: hlfir.end_associate %[[ASSOC]]#1, %[[ASSOC]]#2 : !fir.ref>, i1 ! CHECK: %[[DES_AHOST:.*]] = hlfir.designate %[[AHOST]]#0 (%c1{{.*}}:%c5{{.*}}:%c1{{.*}}) shape %{{.*}} : (!fir.ref>, index, index, index, !fir.shape<1>) -> !fir.ref> ! CHECK: %[[DES_ADEV:.*]] = hlfir.designate %[[ADEV]]#0 (%c1{{.*}}:%c5{{.*}}:%c1{{.*}}) shape %{{.*}} : (!fir.ref>, index, index, index, !fir.shape<1>) -> !fir.ref> ! CHECK: cuf.data_transfer %[[DES_AHOST]] to %[[DES_ADEV]] {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.ref> ! CHECK: %[[ELEMENTAL:.*]] = hlfir.elemental %{{.*}} unordered : (!fir.shape<1>) -> !hlfir.expr<10xi32> ! CHECK: %[[ASSOC:.*]]:3 = hlfir.associate %[[ELEMENTAL]](%{{.*}}) {uniq_name = ".cuf_host_tmp"} : (!hlfir.expr<10xi32>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>, i1) ! CHECK: cuf.data_transfer %[[ASSOC]]#0 to %[[ADEV]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.ref> ! CHECK: hlfir.end_associate %[[ASSOC]]#1, %[[ASSOC]]#2 : !fir.ref>, i1 ! CHECK: cuf.data_transfer %c10{{.*}} to %[[ADEV]]#0 {transfer_kind = #cuf.cuda_transfer} : i32, !fir.ref> ! CHECK: cuf.data_transfer %c0{{.*}} to %{{.*}}#1, %{{.*}} : !fir.shapeshift<1> {transfer_kind = #cuf.cuda_transfer} : i32, !fir.ref> subroutine sub2() integer, device :: m integer, device :: adev(10), bdev(10) integer :: i, ahost(10), bhost(10) ahost = adev i = m ahost(1:5) = adev(1:5) bdev = adev ! Implicit data transfer of adev before evaluation. bhost = ahost + adev end ! CHECK-LABEL: func.func @_QPsub2() ! CHECK: %[[ADEV:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {data_attr = #cuf.cuda, uniq_name = "_QFsub2Eadev"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[AHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub2Eahost"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[BDEV:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {data_attr = #cuf.cuda, uniq_name = "_QFsub2Ebdev"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[BHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub2Ebhost"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFsub2Ei"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[M:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda, uniq_name = "_QFsub2Em"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: cuf.data_transfer %[[ADEV]]#0 to %[[AHOST]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.ref> ! CHECK: cuf.data_transfer %[[M]]#0 to %[[I]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref, !fir.ref ! CHECK: %[[DES_ADEV:.*]] = hlfir.designate %[[ADEV]]#0 (%{{.*}}:%{{.*}}:%{{.*}}) shape %{{.*}} : (!fir.ref>, index, index, index, !fir.shape<1>) -> !fir.ref> ! CHECK: %[[DES_AHOST:.*]] = hlfir.designate %[[AHOST]]#0 (%{{.*}}:%{{.*}}:%{{.*}}) shape %{{.*}} : (!fir.ref>, index, index, index, !fir.shape<1>) -> !fir.ref> ! CHECK: cuf.data_transfer %[[DES_ADEV]] to %[[DES_AHOST]] {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.ref> ! CHECK: cuf.data_transfer %[[ADEV]]#0 to %[[BDEV]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.ref> ! CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array<10xi32> {bindc_name = ".tmp", uniq_name = ""} ! CHECK: %[[DECL_TEMP:.*]]:2 = hlfir.declare %[[TEMP]](%{{.*}}) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<1>) -> (!fir.heap>, !fir.heap>) ! CHECK: %[[ADEV_TEMP:.*]]:2 = hlfir.declare %[[DECL_TEMP]]#0(%{{.*}}) {data_attr = #cuf.cuda, uniq_name = "_QFsub2Eadev"} : (!fir.heap>, !fir.shape<1>) -> (!fir.heap>, !fir.heap>) ! CHECK: cuf.data_transfer %[[ADEV]]#0 to %[[DECL_TEMP]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.heap> ! CHECK: %[[ELEMENTAL:.*]] = hlfir.elemental %{{.*}} unordered : (!fir.shape<1>) -> !hlfir.expr<10xi32> ! CHECK: hlfir.assign %[[ELEMENTAL]] to %[[BHOST]]#0 : !hlfir.expr<10xi32>, !fir.ref> ! CHECK: fir.freemem %[[TEMP]] : !fir.heap> subroutine sub3() use mod1 type(t1), device :: t integer :: ahost(10), bhost(10) bhost = ahost + t%i end ! CHECK-LABEL: func.func @_QPsub3() ! CHECK: %[[TMP:.*]] = fir.alloca !fir.type<_QMmod1Tt1{i:i32}> {bindc_name = ".tmp"} ! CHECK: %[[AHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub3Eahost"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[BHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub3Ebhost"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[T:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda, uniq_name = "_QFsub3Et"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[TMP_DECL:.*]]:2 = hlfir.declare %0 {uniq_name = ".tmp"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) ! CHECK: cuf.data_transfer %[[T]]#0 to %[[TMP_DECL]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.ref> ! Check that cuf.data_transfer are not generated within cuf kernel subroutine sub4() integer, parameter :: n = 10 real, device :: adev(n) real :: ahost(n) real, managed :: b integer :: i adev = ahost !$cuf kernel do <<<*,*>>> do i = 1, n adev(i) = adev(i) + b enddo end subroutine ! CHECK-LABEL: func.func @_QPsub4() ! CHECK: cuf.data_transfer ! CHECK: cuf.kernel<<<*, *>>> ! CHECK-NOT: cuf.data_transfer ! CHECK: hlfir.assign attributes(global) subroutine sub5(a) integer, device :: a integer :: i a = i end subroutine ! CHECK-LABEL: func.func @_QPsub5 ! CHECK-NOT: cuf.data_transfer attributes(host,device) subroutine sub6(a) integer, device :: a integer :: i a = i end subroutine ! CHECK-LABEL: func.func @_QPsub6 ! CHECK: cuf.data_transfer subroutine sub7(a, b, c) integer, device, allocatable :: a(:), c(:) integer, allocatable :: b(:) b = a a = b c = a end subroutine ! CHECK-LABEL: func.func @_QPsub7( ! CHECK-SAME: %[[ARG0:.*]]: !fir.ref>>> {cuf.data_attr = #cuf.cuda, fir.bindc_name = "a"}, %[[ARG1:.*]]: !fir.ref>>> {fir.bindc_name = "b"}, %[[ARG2:.*]]: !fir.ref>>> {cuf.data_attr = #cuf.cuda, fir.bindc_name = "c"}) { ! CHECK: %[[A:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %{{.*}} arg {{[0-9]+}} {data_attr = #cuf.cuda, fortran_attrs = #fir.var_attrs, uniq_name = "_QFsub7Ea"} : (!fir.ref>>>, !fir.dscope) -> (!fir.ref>>>, !fir.ref>>>) ! CHECK: %[[B:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %{{.*}} arg {{[0-9]+}} {fortran_attrs = #fir.var_attrs, uniq_name = "_QFsub7Eb"} : (!fir.ref>>>, !fir.dscope) -> (!fir.ref>>>, !fir.ref>>>) ! CHECK: %[[C:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %0 arg {{[0-9]+}} {data_attr = #cuf.cuda, fortran_attrs = #fir.var_attrs, uniq_name = "_QFsub7Ec"} : (!fir.ref>>>, !fir.dscope) -> (!fir.ref>>>, !fir.ref>>>) ! CHECK: cuf.data_transfer %[[A]]#0 to %[[B]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>>>, !fir.ref>>> ! CHECK: cuf.data_transfer %[[B]]#0 to %[[A]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>>>, !fir.ref>>> ! CHECK: cuf.data_transfer %[[A]]#0 to %[[C]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>>>, !fir.ref>>> subroutine sub8(a, b, n) integer :: n integer, device :: a(n) integer :: b(10) b = a a = b end subroutine ! CHECK-LABEL: func.func @_QPsub8( ! CHECK-SAME: %[[ARG0:.*]]: !fir.ref> {cuf.data_attr = #cuf.cuda, fir.bindc_name = "a"}, %[[ARG1:.*]]: !fir.ref> {fir.bindc_name = "b"}, %[[ARG2:.*]]: !fir.ref {fir.bindc_name = "n"}) ! CHECK: %[[B:.*]]:2 = hlfir.declare %[[ARG1]](%{{.*}}) dummy_scope %{{.*}} {{.*}} {uniq_name = "_QFsub8Eb"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[A:.*]]:2 = hlfir.declare %[[ARG0]](%{{.*}}) dummy_scope %{{.*}} {{.*}} {data_attr = #cuf.cuda, uniq_name = "_QFsub8Ea"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> (!fir.box>, !fir.ref>) ! CHECK: cuf.data_transfer %[[A]]#1 to %[[B]]#0, %{{.*}} : !fir.shape<1> {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.ref> ! CHECK: cuf.data_transfer %[[B]]#0 to %[[A]]#1, %{{.*}} : !fir.shape<1> {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.ref> subroutine sub9(a) integer, pinned, allocatable :: a(:) do concurrent (i = 1 : 10) a(i) = 10 + a(i) end do end subroutine ! CHECK-LABEL: func.func @_QPsub9 ! CHECK-NOT: cuf.data_transfer subroutine sub10(a, b) integer, device :: a integer, allocatable, pinned :: b integer :: res res = a + b end subroutine ! CHECK-LABEL: func.func @_QPsub10( ! CHECK-SAME: %[[ARG0:.*]]: !fir.ref {cuf.data_attr = #cuf.cuda, fir.bindc_name = "a"} ! CHECK: %[[A:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %1 {{.*}} {data_attr = #cuf.cuda, uniq_name = "_QFsub10Ea"} : (!fir.ref, !fir.dscope) -> (!fir.ref, !fir.ref) ! CHECK: cuf.data_transfer %[[A]]#0 to %{{.*}}#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref, !fir.ref ! CHECK-NOT: cuf.data_transfer subroutine sub11(n) integer :: n real, dimension(10) :: h real, dimension(n), device :: d do i=1,10 h(i) = d(i) end do end subroutine ! CHECK-LABEL: func.func @_QPsub11 ! CHECK: %[[RHS:.*]] = hlfir.designate %{{.*}} (%{{.*}}) : (!fir.box>, i64) -> !fir.ref ! CHECK: %[[LHS:.*]] = hlfir.designate %{{.*}} (%{{.*}}) : (!fir.ref>, i64) -> !fir.ref ! CHECK: cuf.data_transfer %[[RHS]] to %[[LHS]] {transfer_kind = #cuf.cuda_transfer} : !fir.ref, !fir.ref subroutine sub12() use mod1 integer, device :: a(10) integer :: x x = dev1(a) end subroutine ! CHECK-LABEL: func.func @_QPsub12 ! CHECK: %{{.*}} = fir.call @_QMmod1Pdev1 ! CHECK: hlfir.assign ! CHECK-NOT: cuf.data_transfer subroutine sub13(a, b, n) integer :: n integer :: a(n) integer, allocatable, device :: b(:) integer :: res(10) res = a + b end subroutine ! CHECK-LABEL: func.func @_QPsub13 ! CHECK: %[[TEMP:.*]] = fir.allocmem !fir.array, %14#1 {bindc_name = ".tmp", uniq_name = ""} ! CHECK: cuf.data_transfer ! CHECK: fir.freemem %[[TEMP]] : !fir.heap> subroutine sub14() logical(4), device :: log(10) log = .true. end subroutine ! CHECK-LABEL: func.func @_QPsub14() ! CHECK: %[[TRUE:.*]] = arith.constant true ! CHECK: cuf.data_transfer %[[TRUE]] to %{{.*}}#0 {transfer_kind = #cuf.cuda_transfer} : i1, !fir.ref>> subroutine sub15(a_dev, a_host, n, m) integer, intent(in) :: n, m real, device :: a_dev(n*m) real :: a_host(n*m) a_dev = a_host end subroutine ! CHECK-LABEL: func.func @_QPsub15( ! CHECK-SAME: %[[ARG0:.*]]: !fir.ref> {cuf.data_attr = #cuf.cuda, fir.bindc_name = "a_dev"}, %[[ARG1:.*]]: !fir.ref> {fir.bindc_name = "a_host"} ! CHECK: %[[ADEV:.*]]:2 = hlfir.declare %[[ARG0]](%{{.*}}) dummy_scope %{{.*}} {{.*}} {data_attr = #cuf.cuda, uniq_name = "_QFsub15Ea_dev"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> (!fir.box>, !fir.ref>) ! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1> ! CHECK: %[[AHOST:.*]]:2 = hlfir.declare %[[ARG1]](%{{.*}}) dummy_scope %{{.*}} {{.*}} {uniq_name = "_QFsub15Ea_host"} : (!fir.ref>, !fir.shape<1>, !fir.dscope) -> (!fir.box>, !fir.ref>) ! CHECK: cuf.data_transfer %[[AHOST]]#1 to %[[ADEV]]#1, %[[SHAPE]] : !fir.shape<1> {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.ref> ! Check that cuf.data_transfer are not generated within OpenACC region subroutine sub16() integer, parameter :: n = 10 real, device :: adev(n) real :: ahost(n) real, managed :: b integer :: i adev = ahost !$acc parallel loop deviceptr(adev) do i = 1, n adev(i) = adev(i) + b enddo !$acc kernels deviceptr(adev) do i = 1, n adev(i) = adev(i) + b enddo !$acc end kernels !$acc serial deviceptr(adev) do i = 1, n adev(i) = adev(i) + b enddo !$acc end serial end subroutine ! CHECK-LABEL: func.func @_QPsub16() ! CHECK: cuf.data_transfer ! CHECK: acc.parallel ! CHECK-NOT: cuf.data_transfer ! CHECK: hlfir.assign ! CHECK: acc.kernels ! CHECK-NOT: cuf.data_transfer ! CHECK: hlfir.assign ! CHECK: acc.serial ! CHECK-NOT: cuf.data_transfer ! CHECK: hlfir.assign ! Check that cuf.data_transfer are not generated within cuf kernel and do not ! trigger semantic error. subroutine sub17() integer, parameter :: n = 10 real, device :: adev(n) real, device :: bdev(n) real :: ahost real, managed :: b integer :: i adev = ahost !$cuf kernel do <<<*,*>>> do i = 1, n ahost = adev(i) * bdev(i) + b enddo end subroutine ! CHECK-LABEL: func.func @_QPsub17() ! CHECK: cuf.kernel<<<*, *>>> ! CHECK-NOT: cuf.data_transfer subroutine sub18(o) integer, device, optional, allocatable :: o(:) integer, device, allocatable :: a(:) integer, device, pointer :: p(:) integer :: b integer :: s(1) logical :: l b = size(a) b = lbound(a, dim=1) b = ubound(a, dim=1) s = shape(a) l = allocated(a) l = associated(p) b = kind(a) l = present(o) end subroutine ! CHECK-LABEL: func.func @_QPsub18 ! CHECK-NOT: cuf.data_transfer subroutine sub19() integer, device :: adev(10) integer :: ahost(10) ! Implicit data transfer of adev and then addition on the host ahost = adev + 2 end subroutine ! CHECK-LABEL: func.func @_QPsub19() ! CHECK: %[[ADEV_DECL:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {data_attr = #cuf.cuda, uniq_name = "_QFsub19Eadev"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[ALLOC_TMP:.*]] = fir.allocmem !fir.array<10xi32> {bindc_name = ".tmp", uniq_name = ""} ! CHECK: %[[TMP:.*]]:2 = hlfir.declare %[[ALLOC_TMP]](%{{.*}}) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<1>) -> (!fir.heap>, !fir.heap>) ! CHECK: cuf.data_transfer %[[ADEV_DECL]]#0 to %[[TMP]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.heap> ! CHECK: hlfir.assign subroutine sub20() integer, managed :: a(10) a = a + 2 ! ok. No data transfer. Assignment on the host. end subroutine ! CHECK-LABEL: func.func @_QPsub20() ! CHECK-NOT: cuf.data_transfer ! CHECK: hlfir.assign subroutine sub21() real, allocatable,device:: a(:,:), b(:,:) real:: s integer:: i,j,N=16 allocate(a(N,N),b(N,N)) do concurrent(i=1:N, j=1:N) reduce(+:s) b(i,j)=a(i,j)**2 s=s+b(i,j) end do end subroutine ! CHECK-LABEL: func.func @_QPsub21() ! CHECK: fir.do_concurrent.loop ! CHECK-NOT: cuf.data_transfer ! CHECK: hlfir.assign subroutine sub22() use mod1 type(t2) :: a integer :: b(100) allocate(a%x(100)) b = a%x end subroutine ! CHECK-LABEL: func.func @_QPsub22() ! CHECK: cuf.data_transfer subroutine sub23(n) use mod1 integer :: n real(8), device :: d(n,n), x(n) x = somefunction(d,2) ! Was triggering Unsupported CUDA data transfer end subroutine ! CHECK-LABEL: func.func @_QPsub23 subroutine sub24() real, managed :: m real, device :: d(4) m = d(1) end ! CHECK-LABEL: func.func @_QPsub24() ! CHECK: %[[D:.*]]:2 = hlfir.declare %1(%2) {data_attr = #cuf.cuda, uniq_name = "_QFsub24Ed"} : (!fir.ref>, !fir.shape<1>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[M:.*]]:2 = hlfir.declare %4 {data_attr = #cuf.cuda, uniq_name = "_QFsub24Em"} : (!fir.ref) -> (!fir.ref, !fir.ref) ! CHECK: %[[D1:.*]] = hlfir.designate %[[D]]#0 (%c1{{.*}}) : (!fir.ref>, index) -> !fir.ref ! CHECK: cuf.data_transfer %[[D1]] to %[[M]]#0 {hasManagedOrUnifedSymbols, transfer_kind = #cuf.cuda_transfer} : !fir.ref, !fir.ref subroutine sub25() use mod1 integer :: i real(8) :: c do i = 1, 10 c = c + p(i) end do end ! CHECK-LABEL: func.func @_QPsub25() ! CHECK: fir.allocmem !fir.array, %15#1 {bindc_name = ".tmp", uniq_name = ""} ! CHECK: cuf.data_transfer %{{.*}} to %{{.*}} {transfer_kind = #cuf.cuda_transfer} : !fir.ref>>>, !fir.box> ! CHECK: hlfir.assign %{{.*}} to %{{.*}} : f64, !fir.ref ! CHECK: fir.freemem %{{.*}} : !fir.heap> subroutine sub26(i, j, k) integer :: i, j, k real(2), dimension(i,j,k), device :: d real(4), dimension(i,j,k) :: hd hd = d end subroutine ! CHECK-LABEL: func.func @_QPsub26 ! CHECK: %[[ALLOC_D:.*]] = cuf.alloc !fir.array, %{{.*}}, %{{.*}}, %{{.*}} : index, index, index {bindc_name = "d", data_attr = #cuf.cuda, uniq_name = "_QFsub26Ed"} -> !fir.ref> ! CHECK: %[[D:.*]]:2 = hlfir.declare %[[ALLOC_D]](%{{.*}}) {data_attr = #cuf.cuda, uniq_name = "_QFsub26Ed"} : (!fir.ref>, !fir.shape<3>) -> (!fir.box>, !fir.ref>) ! CHECK: %[[HD:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub26Ehd"} : (!fir.ref>, !fir.shape<3>) -> (!fir.box>, !fir.ref>) ! CHECK: %[[ALLOC:.*]] = fir.allocmem !fir.array, %8, %13, %18 {bindc_name = ".tmp", uniq_name = ""} ! CHECK: %[[TEMP:.*]]:2 = hlfir.declare %[[ALLOC]](%{{.*}}) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<3>) -> (!fir.box>, !fir.heap>) ! CHECK: cuf.data_transfer %[[D]]#0 to %[[TEMP]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.box>, !fir.box> ! CHECK: %[[ELE:.*]] = hlfir.elemental %{{.*}} unordered : (!fir.shape<3>) -> !hlfir.expr { ! CHECK: ^bb0(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index): ! CHECK: %[[DESIGNATE:.*]] = hlfir.designate %[[TEMP]]#0 (%{{.*}}, %{{.*}}, %{{.*}}) : (!fir.box>, index, index, index) -> !fir.ref ! CHECK: %[[LOAD:.*]] = fir.load %[[DESIGNATE]] : !fir.ref ! CHECK: %[[CONV:.*]] = fir.convert %[[LOAD]] : (f16) -> f32 ! CHECK: hlfir.yield_element %[[CONV]] : f32 ! CHECK: } ! CHECK: hlfir.assign %[[ELE]] to %[[HD]]#0 : !hlfir.expr, !fir.box> subroutine sub27() real(2), dimension(10, 20, 30), device :: d real(4), dimension(10, 20, 30) :: hd hd = d end subroutine ! CHECK-LABEL: func.func @_QPsub27() ! CHECK: %[[ALLOC_D:.*]] = cuf.alloc !fir.array<10x20x30xf16> {bindc_name = "d", data_attr = #cuf.cuda, uniq_name = "_QFsub27Ed"} -> !fir.ref> ! CHECK: %[[D:.*]]:2 = hlfir.declare %[[ALLOC_D]](%{{.*}}) {data_attr = #cuf.cuda, uniq_name = "_QFsub27Ed"} : (!fir.ref>, !fir.shape<3>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[ALLOC_HD:.*]] = fir.alloca !fir.array<10x20x30xf32> {bindc_name = "hd", uniq_name = "_QFsub27Ehd"} ! CHECK: %[[HD:.*]]:2 = hlfir.declare %[[ALLOC_HD]](%{{.*}}) {uniq_name = "_QFsub27Ehd"} : (!fir.ref>, !fir.shape<3>) -> (!fir.ref>, !fir.ref>) ! CHECK: %[[ALLOC_TEMP:.*]] = fir.allocmem !fir.array<10x20x30xf16> {bindc_name = ".tmp", uniq_name = ""} ! CHECK: %[[TEMP:.*]]:2 = hlfir.declare %[[ALLOC_TEMP]](%{{.*}}) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<3>) -> (!fir.heap>, !fir.heap>) ! CHECK: cuf.data_transfer %[[D]]#0 to %[[TEMP]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.ref>, !fir.heap> ! CHECK: %[[ELE:.*]] = hlfir.elemental %{{.*}} unordered : (!fir.shape<3>) -> !hlfir.expr<10x20x30xf32> { ! CHECK: ^bb0(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index): ! CHECK: %[[DESIGNATE:.*]] = hlfir.designate %[[TEMP]]#0 (%{{.*}}, %{{.*}}, %{{.*}}) : (!fir.heap>, index, index, index) -> !fir.ref ! CHECK: %[[LOAD:.*]] = fir.load %[[DESIGNATE]] : !fir.ref ! CHECK: %[[CONV:.*]] = fir.convert %[[LOAD]] : (f16) -> f32 ! CHECK: hlfir.yield_element %[[CONV]] : f32 ! CHECK: } ! CHECKL: hlfir.assign %[[ELE]] to %[[HD]]#0 : !hlfir.expr<10x20x30xf32>, !fir.ref> subroutine sub28(N1,N2,N3,N4) use mod1 integer(4), managed :: a(N1,N2,N3,N4) integer(4), managed :: bres(N1,N2,N3) bres = __sum(a) end subroutine ! CHECK-LABEL: func.func @_QPsub28 ! CHECK: fir.call @_QP__sum ! CHECK-NOT: cuf.data_transfer ! CHECK: hlfir.assign ! CHECK-NOT: cuf.data_transfer ! Data transfer with conversion with more complex elemental ! Check that the data transfer is placed before the elemental op. subroutine sub29() real(2), device, allocatable :: a(:) real(4), allocatable :: ha(:) allocate(a(10)) allocate(ha(10)) ha = a deallocate(a) end subroutine ! CHECK-LABEL: func.func @_QPsub29() ! CHECK: %[[TMP:.*]] = fir.allocmem !fir.array, %24#1 {bindc_name = ".tmp", uniq_name = ""} ! CHECK: %[[TMP_BUFFER:.*]]:2 = hlfir.declare %[[TMP]](%{{.*}}) {uniq_name = ".tmp"} : (!fir.heap>, !fir.shape<1>) -> (!fir.box>, !fir.heap>) ! CHECK: cuf.data_transfer %{{.*}} to %[[TMP_BUFFER]]#0 {transfer_kind = #cuf.cuda_transfer} : !fir.box>>, !fir.box> ! CHECK: hlfir.elemental subroutine sub30() use mod1 type(t3), managed :: t t%spheres(1) = s([0.0, 0.0, -1.0]) end subroutine ! CHECK-LABEL: func.func @_QPsub30() ! CHECK: %{{.*}} = cuf.alloc !fir.type<_QMmod1Tt3{spheres:!fir.box}>>>>}> {bindc_name = "t", data_attr = #cuf.cuda, uniq_name = "_QFsub30Et"} -> !fir.ref}>>>>}>> ! CHECK: hlfir.assign ! CHECK-NOT: cuf.data_transfer ! Test that assigment with only managed variables on both rhs and lhs is done ! on the host. subroutine sub31() type :: t30 real, managed, allocatable :: q(:) end type type(t30), managed, allocatable :: x(:) x(4)%q = x(3)%q end subroutine ! CHECK-LABEL: func.func @_QPsub31() ! CHECK: cuf.alloc !fir.box>>}>>>> ! CHECK: hlfir.assign ! CHECK-NOT: cuf.data_transfer subroutine sub32() integer, managed :: adev(10) integer :: a adev = a adev = 0 end subroutine ! CHECK-LABEL: func.func @_QPsub32() ! CHECK-COUNT-2: cuf.data_transfer subroutine sub33(m, n) integer :: m, n real(2), managed :: dc(m,n) real(4) :: c(m,n) c = (dc) end subroutine ! CHECK-LABEL: func.func @_QPsub33 ! CHECK-NOT: cuf.data_transfer subroutine sub34(n) integer :: n real(2), managed, allocatable :: dx(:) allocate(dx(1:n)) dx(1:n) = 7.0_2 end subroutine ! CHECK-LABEL: func.func @_QPsub34 ! CHECK: cuf.data_transfer %{{.*}} to %{{.*}} {hasManagedOrUnifedSymbols, transfer_kind = #cuf.cuda_transfer} : f16, !fir.box> module managed_mod integer, managed :: marray(10) end module subroutine sub35() use managed_mod integer :: host_arr(10) marray = host_arr marray = 0 end subroutine ! CHECK-LABEL: func.func @_QPsub35() ! CHECK-NOT: cuf.data_transfer ! Test that host_var = managed_module_var does NOT generate cuf.data_transfer ! (managed memory is host-accessible, so direct assignment suffices). subroutine sub36() use managed_mod integer :: host_arr(10) host_arr = marray end subroutine ! CHECK-LABEL: func.func @_QPsub36() ! CHECK-NOT: cuf.data_transfer ! Test that device_var = managed_module_var DOES generate cuf.data_transfer ! (device memory requires explicit cudaMemcpy). subroutine sub37() use managed_mod integer, device :: dev_arr(10) dev_arr = marray end subroutine ! CHECK-LABEL: func.func @_QPsub37() ! CHECK: cuf.data_transfer subroutine sub38() type :: bar integer, device, allocatable :: m(:) end type type(bar), unified :: a type(bar), managed :: ma integer :: lm(5) lm(1:5) = a%m(1:5) lm(1:5) = ma%m(1:5) end subroutine subroutine sub39() type :: foo integer, device, allocatable :: m(:) end type type :: bar type(foo) :: f end type type(bar) :: a integer :: lm(5) lm(1:5) = a%f%m(1:5) end subroutine function sub40_call(x, y, n) result(z) integer :: n real, device :: x(n) real, device :: y(n) real :: z z = 0.0 end function subroutine sub40() real, device :: x(10) real, device :: y(10) real :: res res = sub40_call(x, y, 10) end subroutine subroutine sub41() type :: bar integer, device, allocatable :: m(:) end type type(bar), managed :: a integer, managed :: lm(5) lm(1:5) = a%m(1:5) end subroutine