blob: 56d2b86e7efdb3925274b18eaedb7a760d11b4d4 [file] [edit]
! RUN: bbc -emit-hlfir -fopenacc -fcuda %s -o - | FileCheck %s
! Test CUDA Fortran data transfer using assignment statements.
module mod1
real, parameter :: pi = 0.9189385332046727417803297
real, constant :: rconst
real, constant :: csconst
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
real, constant :: c1 = 1.0
real, device :: d1 = 1.0
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<device>, uniq_name = "_QFsub1Eadev"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[AHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub1Eahost"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFsub1Ei"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[M:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda<device>, uniq_name = "_QFsub1Em"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[C1:.*]] = arith.constant 1 : i32
! CHECK: %[[LOADED_I:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: %[[ADD:.*]] = arith.addi %[[C1]], %[[LOADED_I]] : i32
! CHECK: %[[ASSOC:.*]]:3 = hlfir.associate %[[ADD]] {uniq_name = ".cuf_host_tmp"} : (i32) -> (!fir.ref<i32>, !fir.ref<i32>, i1)
! CHECK: cuf.data_transfer %[[ASSOC]]#0 to %[[M]]#0 {transfer_kind = #cuf.cuda_transfer<host_device>} : !fir.ref<i32>, !fir.ref<i32>
! CHECK: hlfir.end_associate %[[ASSOC]]#1, %[[ASSOC]]#2 : !fir.ref<i32>, i1
! CHECK: cuf.data_transfer %c1{{.*}} to %[[M]]#0 {transfer_kind = #cuf.cuda_transfer<host_device>} : i32, !fir.ref<i32>
! CHECK: cuf.data_transfer %[[AHOST]]#0 to %[[ADEV]]#0 {transfer_kind = #cuf.cuda_transfer<host_device>} : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>
! 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.array<10xi32>>, !fir.ref<!fir.array<10xi32>>, i1)
! CHECK: cuf.data_transfer %[[ASSOC]]#0 to %[[ADEV]]#0 {transfer_kind = #cuf.cuda_transfer<host_device>} : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>
! CHECK: hlfir.end_associate %[[ASSOC]]#1, %[[ASSOC]]#2 : !fir.ref<!fir.array<10xi32>>, i1
! CHECK: %[[DES_AHOST:.*]] = hlfir.designate %[[AHOST]]#0 (%c1{{.*}}:%c5{{.*}}:%c1{{.*}}) shape %{{.*}} : (!fir.ref<!fir.array<10xi32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<5xi32>>
! CHECK: %[[DES_ADEV:.*]] = hlfir.designate %[[ADEV]]#0 (%c1{{.*}}:%c5{{.*}}:%c1{{.*}}) shape %{{.*}} : (!fir.ref<!fir.array<10xi32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<5xi32>>
! CHECK: cuf.data_transfer %[[DES_AHOST]] to %[[DES_ADEV]] {transfer_kind = #cuf.cuda_transfer<host_device>} : !fir.ref<!fir.array<5xi32>>, !fir.ref<!fir.array<5xi32>>
! 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.array<10xi32>>, !fir.ref<!fir.array<10xi32>>, i1)
! CHECK: cuf.data_transfer %[[ASSOC]]#0 to %[[ADEV]]#0 {transfer_kind = #cuf.cuda_transfer<host_device>} : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>
! CHECK: hlfir.end_associate %[[ASSOC]]#1, %[[ASSOC]]#2 : !fir.ref<!fir.array<10xi32>>, i1
! CHECK: cuf.data_transfer %c10{{.*}} to %[[ADEV]]#0 {transfer_kind = #cuf.cuda_transfer<host_device>} : i32, !fir.ref<!fir.array<10xi32>>
! CHECK: cuf.data_transfer %c0{{.*}} to %{{.*}}#1, %{{.*}} : !fir.shapeshift<1> {transfer_kind = #cuf.cuda_transfer<host_device>} : i32, !fir.ref<!fir.array<10xi32>>
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<device>, uniq_name = "_QFsub2Eadev"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[AHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub2Eahost"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[BDEV:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {data_attr = #cuf.cuda<device>, uniq_name = "_QFsub2Ebdev"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[BHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub2Ebhost"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[I:.*]]:2 = hlfir.declare %{{.*}} {uniq_name = "_QFsub2Ei"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: %[[M:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda<device>, uniq_name = "_QFsub2Em"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: cuf.data_transfer %[[ADEV]]#0 to %[[AHOST]]#0 {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>
! CHECK: cuf.data_transfer %[[M]]#0 to %[[I]]#0 {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<i32>, !fir.ref<i32>
! CHECK: %[[DES_ADEV:.*]] = hlfir.designate %[[ADEV]]#0 (%{{.*}}:%{{.*}}:%{{.*}}) shape %{{.*}} : (!fir.ref<!fir.array<10xi32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<5xi32>>
! CHECK: %[[DES_AHOST:.*]] = hlfir.designate %[[AHOST]]#0 (%{{.*}}:%{{.*}}:%{{.*}}) shape %{{.*}} : (!fir.ref<!fir.array<10xi32>>, index, index, index, !fir.shape<1>) -> !fir.ref<!fir.array<5xi32>>
! CHECK: cuf.data_transfer %[[DES_ADEV]] to %[[DES_AHOST]] {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<!fir.array<5xi32>>, !fir.ref<!fir.array<5xi32>>
! CHECK: cuf.data_transfer %[[ADEV]]#0 to %[[BDEV]]#0 {transfer_kind = #cuf.cuda_transfer<device_device>} : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>
! 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.array<10xi32>>, !fir.shape<1>) -> (!fir.heap<!fir.array<10xi32>>, !fir.heap<!fir.array<10xi32>>)
! CHECK: %[[ADEV_TEMP:.*]]:2 = hlfir.declare %[[DECL_TEMP]]#0(%{{.*}}) {data_attr = #cuf.cuda<device>, uniq_name = "_QFsub2Eadev"} : (!fir.heap<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.heap<!fir.array<10xi32>>, !fir.heap<!fir.array<10xi32>>)
! CHECK: cuf.data_transfer %[[ADEV]]#0 to %[[DECL_TEMP]]#0 {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<!fir.array<10xi32>>, !fir.heap<!fir.array<10xi32>>
! CHECK: %[[ELEMENTAL:.*]] = hlfir.elemental %{{.*}} unordered : (!fir.shape<1>) -> !hlfir.expr<10xi32>
! CHECK: hlfir.assign %[[ELEMENTAL]] to %[[BHOST]]#0 : !hlfir.expr<10xi32>, !fir.ref<!fir.array<10xi32>>
! CHECK: fir.freemem %[[TEMP]] : !fir.heap<!fir.array<10xi32>>
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.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[BHOST:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub3Ebhost"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[T:.*]]:2 = hlfir.declare %{{.*}} {data_attr = #cuf.cuda<device>, uniq_name = "_QFsub3Et"} : (!fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>) -> (!fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>, !fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>)
! CHECK: %[[TMP_DECL:.*]]:2 = hlfir.declare %0 {uniq_name = ".tmp"} : (!fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>) -> (!fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>, !fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>)
! CHECK: cuf.data_transfer %[[T]]#0 to %[[TMP_DECL]]#0 {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>, !fir.ref<!fir.type<_QMmod1Tt1{i:i32}>>
! 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<!fir.box<!fir.heap<!fir.array<?xi32>>>> {cuf.data_attr = #cuf.cuda<device>, fir.bindc_name = "a"}, %[[ARG1:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {fir.bindc_name = "b"}, %[[ARG2:.*]]: !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>> {cuf.data_attr = #cuf.cuda<device>, fir.bindc_name = "c"}) {
! CHECK: %[[A:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %{{.*}} arg {{[0-9]+}} {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub7Ea"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
! CHECK: %[[B:.*]]:2 = hlfir.declare %[[ARG1]] dummy_scope %{{.*}} arg {{[0-9]+}} {fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub7Eb"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
! CHECK: %[[C:.*]]:2 = hlfir.declare %[[ARG2]] dummy_scope %0 arg {{[0-9]+}} {data_attr = #cuf.cuda<device>, fortran_attrs = #fir.var_attrs<allocatable>, uniq_name = "_QFsub7Ec"} : (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.dscope) -> (!fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>)
! CHECK: cuf.data_transfer %[[A]]#0 to %[[B]]#0 {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
! CHECK: cuf.data_transfer %[[B]]#0 to %[[A]]#0 {transfer_kind = #cuf.cuda_transfer<host_device>} : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
! CHECK: cuf.data_transfer %[[A]]#0 to %[[C]]#0 {transfer_kind = #cuf.cuda_transfer<device_device>} : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>, !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
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<!fir.array<?xi32>> {cuf.data_attr = #cuf.cuda<device>, fir.bindc_name = "a"}, %[[ARG1:.*]]: !fir.ref<!fir.array<10xi32>> {fir.bindc_name = "b"}, %[[ARG2:.*]]: !fir.ref<i32> {fir.bindc_name = "n"})
! CHECK: %[[B:.*]]:2 = hlfir.declare %[[ARG1]](%{{.*}}) dummy_scope %{{.*}} {{.*}} {uniq_name = "_QFsub8Eb"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>, !fir.dscope) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! CHECK: %[[A:.*]]:2 = hlfir.declare %[[ARG0]](%{{.*}}) dummy_scope %{{.*}} {{.*}} {data_attr = #cuf.cuda<device>, uniq_name = "_QFsub8Ea"} : (!fir.ref<!fir.array<?xi32>>, !fir.shape<1>, !fir.dscope) -> (!fir.box<!fir.array<?xi32>>, !fir.ref<!fir.array<?xi32>>)
! CHECK: cuf.data_transfer %[[A]]#1 to %[[B]]#0, %{{.*}} : !fir.shape<1> {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<!fir.array<?xi32>>, !fir.ref<!fir.array<10xi32>>
! CHECK: cuf.data_transfer %[[B]]#0 to %[[A]]#1, %{{.*}} : !fir.shape<1> {transfer_kind = #cuf.cuda_transfer<host_device>} : !fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<?xi32>>
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<i32> {cuf.data_attr = #cuf.cuda<device>, fir.bindc_name = "a"}
! CHECK: %[[A:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %1 {{.*}} {data_attr = #cuf.cuda<device>, uniq_name = "_QFsub10Ea"} : (!fir.ref<i32>, !fir.dscope) -> (!fir.ref<i32>, !fir.ref<i32>)
! CHECK: cuf.data_transfer %[[A]]#0 to %{{.*}}#0 {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<i32>, !fir.ref<i32>
! 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<!fir.array<?xf32>>, i64) -> !fir.ref<f32>
! CHECK: %[[LHS:.*]] = hlfir.designate %{{.*}} (%{{.*}}) : (!fir.ref<!fir.array<10xf32>>, i64) -> !fir.ref<f32>
! CHECK: cuf.data_transfer %[[RHS]] to %[[LHS]] {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<f32>, !fir.ref<f32>
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<?xi32>, %14#1 {bindc_name = ".tmp", uniq_name = ""}
! CHECK: cuf.data_transfer
! CHECK: fir.freemem %[[TEMP]] : !fir.heap<!fir.array<?xi32>>
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<host_device>} : i1, !fir.ref<!fir.array<10x!fir.logical<4>>>
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<!fir.array<?xf32>> {cuf.data_attr = #cuf.cuda<device>, fir.bindc_name = "a_dev"}, %[[ARG1:.*]]: !fir.ref<!fir.array<?xf32>> {fir.bindc_name = "a_host"}
! CHECK: %[[ADEV:.*]]:2 = hlfir.declare %[[ARG0]](%{{.*}}) dummy_scope %{{.*}} {{.*}} {data_attr = #cuf.cuda<device>, uniq_name = "_QFsub15Ea_dev"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.ref<!fir.array<?xf32>>)
! CHECK: %[[SHAPE:.*]] = fir.shape %{{.*}} : (index) -> !fir.shape<1>
! CHECK: %[[AHOST:.*]]:2 = hlfir.declare %[[ARG1]](%{{.*}}) dummy_scope %{{.*}} {{.*}} {uniq_name = "_QFsub15Ea_host"} : (!fir.ref<!fir.array<?xf32>>, !fir.shape<1>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.ref<!fir.array<?xf32>>)
! CHECK: cuf.data_transfer %[[AHOST]]#1 to %[[ADEV]]#1, %[[SHAPE]] : !fir.shape<1> {transfer_kind = #cuf.cuda_transfer<host_device>} : !fir.ref<!fir.array<?xf32>>, !fir.ref<!fir.array<?xf32>>
! 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<device>, uniq_name = "_QFsub19Eadev"} : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<10xi32>>, !fir.ref<!fir.array<10xi32>>)
! 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.array<10xi32>>, !fir.shape<1>) -> (!fir.heap<!fir.array<10xi32>>, !fir.heap<!fir.array<10xi32>>)
! CHECK: cuf.data_transfer %[[ADEV_DECL]]#0 to %[[TMP]]#0 {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<!fir.array<10xi32>>, !fir.heap<!fir.array<10xi32>>
! 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<device>, uniq_name = "_QFsub24Ed"} : (!fir.ref<!fir.array<4xf32>>, !fir.shape<1>) -> (!fir.ref<!fir.array<4xf32>>, !fir.ref<!fir.array<4xf32>>)
! CHECK: %[[M:.*]]:2 = hlfir.declare %4 {data_attr = #cuf.cuda<managed>, uniq_name = "_QFsub24Em"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
! CHECK: %[[D1:.*]] = hlfir.designate %[[D]]#0 (%c1{{.*}}) : (!fir.ref<!fir.array<4xf32>>, index) -> !fir.ref<f32>
! CHECK: cuf.data_transfer %[[D1]] to %[[M]]#0 {hasManagedOrUnifedSymbols, transfer_kind = #cuf.cuda_transfer<device_device>} : !fir.ref<f32>, !fir.ref<f32>
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<?xf64>, %{{.*}} {bindc_name = ".tmp", uniq_name = ""}
! CHECK: cuf.data_transfer %{{.*}} to %{{.*}} {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<!fir.box<!fir.heap<!fir.array<?xf64>>>>, !fir.box<!fir.array<?xf64>>
! CHECK: hlfir.assign %{{.*}} to %{{.*}} : f64, !fir.ref<f64>
! CHECK: fir.freemem %{{.*}} : !fir.heap<!fir.array<?xf64>>
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<?x?x?xf16>, %{{.*}}, %{{.*}}, %{{.*}} : index, index, index {bindc_name = "d", data_attr = #cuf.cuda<device>, uniq_name = "_QFsub26Ed"} -> !fir.ref<!fir.array<?x?x?xf16>>
! CHECK: %[[D:.*]]:2 = hlfir.declare %[[ALLOC_D]](%{{.*}}) {data_attr = #cuf.cuda<device>, uniq_name = "_QFsub26Ed"} : (!fir.ref<!fir.array<?x?x?xf16>>, !fir.shape<3>) -> (!fir.box<!fir.array<?x?x?xf16>>, !fir.ref<!fir.array<?x?x?xf16>>)
! CHECK: %[[HD:.*]]:2 = hlfir.declare %{{.*}}(%{{.*}}) {uniq_name = "_QFsub26Ehd"} : (!fir.ref<!fir.array<?x?x?xf32>>, !fir.shape<3>) -> (!fir.box<!fir.array<?x?x?xf32>>, !fir.ref<!fir.array<?x?x?xf32>>)
! CHECK: %[[ALLOC:.*]] = fir.allocmem !fir.array<?x?x?xf16>, %8, %13, %18 {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[TEMP:.*]]:2 = hlfir.declare %[[ALLOC]](%{{.*}}) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?x?x?xf16>>, !fir.shape<3>) -> (!fir.box<!fir.array<?x?x?xf16>>, !fir.heap<!fir.array<?x?x?xf16>>)
! CHECK: cuf.data_transfer %[[D]]#0 to %[[TEMP]]#0 {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.box<!fir.array<?x?x?xf16>>, !fir.box<!fir.array<?x?x?xf16>>
! CHECK: %[[ELE:.*]] = hlfir.elemental %{{.*}} unordered : (!fir.shape<3>) -> !hlfir.expr<?x?x?xf32> {
! CHECK: ^bb0(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index):
! CHECK: %[[DESIGNATE:.*]] = hlfir.designate %[[TEMP]]#0 (%{{.*}}, %{{.*}}, %{{.*}}) : (!fir.box<!fir.array<?x?x?xf16>>, index, index, index) -> !fir.ref<f16>
! CHECK: %[[LOAD:.*]] = fir.load %[[DESIGNATE]] : !fir.ref<f16>
! CHECK: %[[CONV:.*]] = fir.convert %[[LOAD]] : (f16) -> f32
! CHECK: hlfir.yield_element %[[CONV]] : f32
! CHECK: }
! CHECK: hlfir.assign %[[ELE]] to %[[HD]]#0 : !hlfir.expr<?x?x?xf32>, !fir.box<!fir.array<?x?x?xf32>>
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<device>, uniq_name = "_QFsub27Ed"} -> !fir.ref<!fir.array<10x20x30xf16>>
! CHECK: %[[D:.*]]:2 = hlfir.declare %[[ALLOC_D]](%{{.*}}) {data_attr = #cuf.cuda<device>, uniq_name = "_QFsub27Ed"} : (!fir.ref<!fir.array<10x20x30xf16>>, !fir.shape<3>) -> (!fir.ref<!fir.array<10x20x30xf16>>, !fir.ref<!fir.array<10x20x30xf16>>)
! 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.array<10x20x30xf32>>, !fir.shape<3>) -> (!fir.ref<!fir.array<10x20x30xf32>>, !fir.ref<!fir.array<10x20x30xf32>>)
! 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.array<10x20x30xf16>>, !fir.shape<3>) -> (!fir.heap<!fir.array<10x20x30xf16>>, !fir.heap<!fir.array<10x20x30xf16>>)
! CHECK: cuf.data_transfer %[[D]]#0 to %[[TEMP]]#0 {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.ref<!fir.array<10x20x30xf16>>, !fir.heap<!fir.array<10x20x30xf16>>
! CHECK: %[[ELE:.*]] = hlfir.elemental %{{.*}} unordered : (!fir.shape<3>) -> !hlfir.expr<10x20x30xf32> {
! CHECK: ^bb0(%{{.*}}: index, %{{.*}}: index, %{{.*}}: index):
! CHECK: %[[DESIGNATE:.*]] = hlfir.designate %[[TEMP]]#0 (%{{.*}}, %{{.*}}, %{{.*}}) : (!fir.heap<!fir.array<10x20x30xf16>>, index, index, index) -> !fir.ref<f16>
! CHECK: %[[LOAD:.*]] = fir.load %[[DESIGNATE]] : !fir.ref<f16>
! 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<!fir.array<10x20x30xf32>>
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: 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<?xf16>, %{{.*}}#1 {bindc_name = ".tmp", uniq_name = ""}
! CHECK: %[[TMP_BUFFER:.*]]:2 = hlfir.declare %[[TMP]](%{{.*}}) {uniq_name = ".tmp"} : (!fir.heap<!fir.array<?xf16>>, !fir.shape<1>) -> (!fir.box<!fir.array<?xf16>>, !fir.heap<!fir.array<?xf16>>)
! CHECK: cuf.data_transfer %{{.*}} to %[[TMP_BUFFER]]#0 {transfer_kind = #cuf.cuda_transfer<device_host>} : !fir.box<!fir.heap<!fir.array<?xf16>>>, !fir.box<!fir.array<?xf16>>
! 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<!fir.heap<!fir.array<?x!fir.type<_QMmod1Ts{c:!fir.array<3xf32>}>>>>}> {bindc_name = "t", data_attr = #cuf.cuda<managed>, uniq_name = "_QFsub30Et"} -> !fir.ref<!fir.type<_QMmod1Tt3{spheres:!fir.box<!fir.heap<!fir.array<?x!fir.type<_QMmod1Ts{c:!fir.array<3xf32>}>>>>}>>
! 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<!fir.heap<!fir.array<?x!fir.type<_QFsub31Tt30{q:!fir.box<!fir.heap<!fir.array<?xf32>>>}>>>>
! 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
! A section reference is assigned on the host even when it covers the whole array:
! what matters is the form of the reference, not the extent it happens to cover
! (CUDA Fortran Programming Guide 3.4.1).
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-NOT: cuf.data_transfer
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 generates a cuf.data_transfer:
! reading a whole managed array variable is a synchronous data transfer.
subroutine sub36()
use managed_mod
integer :: host_arr(10)
host_arr = marray
end subroutine
! CHECK-LABEL: func.func @_QPsub36()
! CHECK: cuf.data_transfer %{{.*}} to %{{.*}} {hasManagedOrUnifedSymbols, transfer_kind = #cuf.cuda_transfer<device_host>}
! 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
subroutine sub42()
use mod1
real :: a
a = c1 * c1
end subroutine
! CHECK-LABEL: func.func @_QPsub42()
! CHECK: %[[RES:.*]] = arith.mulf
! CHECK: fir.store %[[RES]] to %{{.*}} : !fir.ref<f32>
! CHECK-NOT: cuf.data_transfer
subroutine sub43()
use mod1
real :: a
a = d1 * d1
end subroutine
! CHECK-LABEL: func.func @_QPsub43()
! CHECK: %[[RES:.*]] = arith.mulf
! CHECK: fir.store %[[RES]] to %{{.*}} : !fir.ref<f32>
! CHECK-NOT: cuf.data_transfer
subroutine sub44()
use mod1
real :: a
a = -d1
end subroutine
! CHECK-LABEL: func.func @_QPsub44()
! CHECK: arith.negf
! CHECK-NOT: cuf.data_transfer
subroutine sub45(c0_d, n)
implicit none
integer :: n
complex(8), device :: c0_d(:,:)
complex(8), allocatable :: cx(:,:)
call compute(cx)
contains
subroutine compute(cx)
complex(8), intent(inout) :: cx(:,:)
c0_d = cx
end subroutine
end subroutine
! CHECK-LABEL: func.func @_QPsub45
! CHECK-LABEL: @_QFsub45Pcompute
! CHECK: cuf.data_transfer %{{.*}} to %{{.*}} {transfer_kind = #cuf.cuda_transfer<host_device>} : !fir.box<!fir.array<?x?xcomplex<f64>>>, !fir.box<!fir.array<?x?xcomplex<f64>>>
subroutine sub46()
use mod1
csconst = rconst * pi/6
end subroutine
! CHECK-LABEL: func.func @_QPsub46()
! CHECK: cuf.data_transfer
! CHECK: arith.mulf
! CHECK: arith.constant
! CHECK: arith.divf
! CHECK: hlfir.assign
! CHECK: cuf.data_transfer