! Test lower of elemental user defined assignments ! RUN: bbc -emit-hlfir %s -o - | FileCheck %s module defined_assignments type t integer :: i end type interface assignment(=) elemental subroutine assign_t(a,b) import t type(t),intent(out) :: a type(t),intent(in) :: b end end interface interface assignment(=) elemental subroutine assign_logical_to_real(a,b) real, intent(out) :: a logical, intent(in) :: b end end interface interface assignment(=) elemental subroutine assign_real_to_logical(a,b) logical, intent(out) :: a real, intent(in) :: b end end interface end module ! CHECK-LABEL: func @_QPtest_derived( ! CHECK-SAME: %[[arg0:.*]]: !fir.ref>> {fir.bindc_name = "x"}) { ! CHECK: %[[x:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: hlfir.region_assign { ! CHECK: %[[slice:.*]] = hlfir.designate %[[x]]#0 ({{.*}}) ! CHECK: hlfir.yield %[[slice]] ! CHECK: } to { ! CHECK: hlfir.yield %[[x]]#0 ! CHECK: } user_defined_assign (%[[rhs:.*]]: !fir.ref>) to (%[[lhs:.*]]: !fir.ref>) { ! CHECK: fir.call @_QPassign_t(%[[lhs]], %[[rhs]]) ! CHECK: } ! CHECK-LABEL: func @_QPtest_intrinsic( ! CHECK-SAME: %[[arg0:.*]]: !fir.ref> {fir.bindc_name = "x"}) { ! CHECK: %[[x:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield %{{.*}} : !hlfir.expr<100x!fir.logical<4>> ! CHECK: } to { ! CHECK: hlfir.yield %[[x]]#0 ! CHECK: } user_defined_assign (%[[rhs:.*]]: !fir.logical<4>) to (%[[lhs:.*]]: !fir.ref) { ! CHECK: %[[assoc:.*]]:3 = hlfir.associate %[[rhs]] ! CHECK: fir.call @_QPassign_logical_to_real(%[[lhs]], %[[assoc]]#0) ! CHECK: } ! CHECK-LABEL: func @_QPtest_intrinsic_2( ! CHECK-SAME: %[[arg0:.*]]: !fir.ref>> {fir.bindc_name = "x"}, %[[arg1:.*]]: !fir.ref> {fir.bindc_name = "y"}) { ! CHECK: %[[x:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: %[[y:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield %[[y]]#0 ! CHECK: } to { ! CHECK: hlfir.yield %[[x]]#0 ! CHECK: } user_defined_assign (%[[rhs:.*]]: !fir.ref) to (%[[lhs:.*]]: !fir.ref>) { ! CHECK: fir.call @_QPassign_real_to_logical(%[[lhs]], %[[rhs]]) ! CHECK: } ! CHECK-LABEL: func @_QPfrom_char( ! CHECK-SAME: %[[arg0:.*]]: !fir.box> {fir.bindc_name = "i"}, %[[arg1:.*]]: !fir.box>> {fir.bindc_name = "c"}) { ! CHECK: %[[c:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: %[[i:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield %[[c]]#0 ! CHECK: } to { ! CHECK: hlfir.yield %[[i]]#0 ! CHECK: } user_defined_assign (%[[rhs:.*]]: !fir.boxchar<1>) to (%[[lhs:.*]]: !fir.ref) { ! CHECK: fir.call @_QPsfrom_char(%[[lhs]], %[[rhs]]) ! CHECK: } ! CHECK-LABEL: func @_QPto_char( ! CHECK-SAME: %[[arg0:.*]]: !fir.box> {fir.bindc_name = "i"}, %[[arg1:.*]]: !fir.box>> {fir.bindc_name = "c"}) { ! CHECK: %[[c:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: %[[i:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield %[[i]]#0 ! CHECK: } to { ! CHECK: hlfir.yield %[[c]]#0 ! CHECK: } user_defined_assign (%[[rhs:.*]]: !fir.ref) to (%[[lhs:.*]]: !fir.boxchar<1>) { ! CHECK: fir.call @_QPsto_char(%[[lhs]], %[[rhs]]) ! CHECK: } subroutine test_derived(x) use defined_assignments type(t) :: x(100) x = x(100:1:-1) end subroutine subroutine test_intrinsic(x) use defined_assignments real :: x(100) x = x(100:1:-1) .lt. 0. end subroutine subroutine test_intrinsic_2(x, y) use defined_assignments logical :: x(100) real :: y(100) x = y end subroutine subroutine from_char(i, c) interface assignment(=) elemental subroutine sfrom_char(a,b) integer, intent(out) :: a character(*),intent(in) :: b end subroutine end interface integer :: i(:) character(*) :: c(:) i = c end subroutine subroutine to_char(i, c) interface assignment(=) elemental subroutine sto_char(a,b) character(*), intent(out) :: a integer,intent(in) :: b end subroutine end interface integer :: i(:) character(*) :: c(:) c = i end subroutine ! ----------------------------------------------------------------------------- ! Test user defined assignments inside FORALL and WHERE ! ----------------------------------------------------------------------------- ! CHECK-LABEL: func @_QPtest_in_forall_1( ! CHECK-SAME: %[[arg0:.*]]: !fir.ref>> {fir.bindc_name = "x"}, %[[arg1:.*]]: !fir.ref> {fir.bindc_name = "y"}) { ! CHECK: %[[x:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: %[[y:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: hlfir.forall {{.*}} { ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield {{.*}} : f32 ! CHECK: } to { ! CHECK: hlfir.yield {{.*}} : !fir.ref> ! CHECK: } user_defined_assign (%[[rhs:.*]]: f32) to (%[[lhs:.*]]: !fir.ref>) { ! CHECK: %[[assoc:.*]]:3 = hlfir.associate %[[rhs]] ! CHECK: fir.call @_QPassign_real_to_logical(%[[lhs]], %[[assoc]]#0) ! CHECK: } ! CHECK: } ! CHECK-LABEL: func @_QPtest_in_forall_2( ! CHECK-SAME: %[[arg0:.*]]: !fir.ref>> {fir.bindc_name = "x"}, %[[arg1:.*]]: !fir.ref> {fir.bindc_name = "y"}) { ! CHECK: %[[y:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: hlfir.forall {{.*}} { ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield {{.*}} : i1 ! CHECK: } to { ! CHECK: hlfir.yield {{.*}} : !fir.ref ! CHECK: } user_defined_assign (%[[rhs:.*]]: i1) to (%[[lhs:.*]]: !fir.ref) { ! CHECK: %[[cast:.*]] = fir.convert %[[rhs]] ! CHECK: %[[assoc:.*]]:3 = hlfir.associate %[[cast]] ! CHECK: fir.call @_QPassign_logical_to_real(%[[lhs]], %[[assoc]]#0) ! CHECK: } ! CHECK: } ! CHECK-LABEL: func @_QPtest_intrinsic_where_1( ! CHECK-SAME: %[[arg0:.*]]: !fir.ref>> {fir.bindc_name = "x"}, %[[arg1:.*]]: !fir.ref> {fir.bindc_name = "y"}, %[[arg2:.*]]: !fir.ref>> {fir.bindc_name = "l"}) { ! CHECK: %[[l:.*]]:2 = hlfir.declare %[[arg2]] ! CHECK: %[[x:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: %[[y:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: hlfir.where { ! CHECK: hlfir.yield %[[l]]#0 ! CHECK: } do { ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield %[[y]]#0 ! CHECK: } to { ! CHECK: hlfir.yield %[[x]]#0 ! CHECK: } user_defined_assign (%[[rhs:.*]]: !fir.ref) to (%[[lhs:.*]]: !fir.ref>) { ! CHECK: fir.call @_QPassign_real_to_logical(%[[lhs]], %[[rhs]]) ! CHECK: } ! CHECK: } ! CHECK-LABEL: func @_QPtest_intrinsic_where_2( ! CHECK-SAME: %[[arg0:.*]]: !fir.ref>> {fir.bindc_name = "x"}, %[[arg1:.*]]: !fir.ref> {fir.bindc_name = "y"}, %[[arg2:.*]]: !fir.ref>> {fir.bindc_name = "l"}) { ! CHECK: %[[l:.*]]:2 = hlfir.declare %[[arg2]] ! CHECK: %[[x:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: %[[y:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: hlfir.where { ! CHECK: hlfir.yield %[[l]]#0 ! CHECK: } do { ! CHECK: hlfir.region_assign { ! CHECK: %[[res:.*]] = hlfir.elemental %{{.*}} unordered : (!fir.shape<1>) -> !hlfir.expr<10x!fir.logical<4>> { ! CHECK: hlfir.yield_element ! CHECK: } ! CHECK: hlfir.yield %[[res]] : !hlfir.expr<10x!fir.logical<4>> cleanup { ! CHECK: hlfir.destroy %[[res]] ! CHECK: } ! CHECK: } to { ! CHECK: hlfir.yield %[[y]]#0 ! CHECK: } user_defined_assign (%[[rhs:.*]]: !fir.logical<4>) to (%[[lhs:.*]]: !fir.ref) { ! CHECK: %[[assoc:.*]]:3 = hlfir.associate %[[rhs]] ! CHECK: fir.call @_QPassign_logical_to_real(%[[lhs]], %[[assoc]]#0) ! CHECK: } ! CHECK: } ! CHECK-LABEL: func @_QPtest_scalar_func_but_not_elemental( ! CHECK-SAME: %[[arg0:.*]]: !fir.ref>> {fir.bindc_name = "x"}, %[[arg1:.*]]: !fir.ref> {fir.bindc_name = "y"}) { ! CHECK: %[[x:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: %[[y:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: hlfir.forall {{.*}} { ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield {{.*}} : i32 ! CHECK: } to { ! CHECK: hlfir.yield {{.*}} : !fir.ref> ! CHECK: } user_defined_assign (%[[rhs:.*]]: i32) to (%[[lhs:.*]]: !fir.ref>) { ! CHECK: %[[assoc:.*]]:3 = hlfir.associate %[[rhs]] ! CHECK: fir.call @_QPassign_integer_to_logical(%[[lhs]], %[[assoc]]#0) ! CHECK: } ! CHECK: } ! CHECK-LABEL: func @_QPtest_in_forall_with_cleanup( ! CHECK-SAME: %[[arg0:.*]]: !fir.ref>> {fir.bindc_name = "x"}, %[[arg1:.*]]: !fir.ref> {fir.bindc_name = "y"}) { ! CHECK: %[[x:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: %[[y:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: hlfir.forall {{.*}} { ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield {{.*}} : f32 cleanup { ! CHECK: } ! CHECK: } to { ! CHECK: hlfir.yield {{.*}} : !fir.ref> ! CHECK: } user_defined_assign (%[[rhs:.*]]: f32) to (%[[lhs:.*]]: !fir.ref>) { ! CHECK: %[[assoc:.*]]:3 = hlfir.associate %[[rhs]] ! CHECK: fir.call @_QPassign_real_to_logical(%[[lhs]], %[[assoc]]#0) ! CHECK: } ! CHECK: } subroutine test_in_forall_1(x, y) use defined_assignments logical :: x(10) real :: y(10) forall (i=1:10) x(i) = y(i) end subroutine subroutine test_in_forall_2(x, y) use defined_assignments logical :: x(10) real :: y(10) forall (i=1:10) y(i) = y(i).lt.0. end subroutine subroutine test_intrinsic_where_1(x, y, l) use defined_assignments logical :: x(10), l(10) real :: y(10) where(l) x = y end subroutine subroutine test_intrinsic_where_2(x, y, l) use defined_assignments logical :: x(10), l(10) real :: y(10) where(l) y = y.lt.0. end subroutine subroutine test_scalar_func_but_not_elemental(x, y) interface assignment(=) ! scalar, but not elemental elemental subroutine assign_integer_to_logical(a,b) logical, intent(out) :: a integer, intent(in) :: b end end interface logical :: x(100) integer :: y(100) ! Scalar assignment in forall should be treated just like elemental ! functions. forall(i=1:10) x(i) = y(i) end subroutine subroutine test_in_forall_with_cleanup(x, y) use defined_assignments interface pure function returns_alloc(i) integer, intent(in) :: i real, allocatable :: returns_alloc end function end interface logical :: x(10) real :: y(10) forall (i=1:10) x(i) = returns_alloc(i) end subroutine ! CHECK-LABEL: func @_QPtest_forall_array( ! CHECK-SAME: %[[arg0:.*]]: !fir.box>> {fir.bindc_name = "x"}, %[[arg1:.*]]: !fir.box> {fir.bindc_name = "y"}) { ! CHECK: %[[x:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: %[[y:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: hlfir.forall {{.*}} { ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield {{.*}} : !fir.box> ! CHECK: } to { ! CHECK: hlfir.yield {{.*}} : !fir.box>> ! CHECK: } user_defined_assign (%[[rhs:.*]]: !fir.ref) to (%[[lhs:.*]]: !fir.ref>) { ! CHECK: fir.call @_QPassign_real_to_logical(%[[lhs]], %[[rhs]]) ! CHECK: } ! CHECK: } ! CHECK-LABEL: func @_QPfrom_char_forall_array( ! CHECK-SAME: %[[arg0:.*]]: !fir.box> {fir.bindc_name = "i"}, %[[arg1:.*]]: !fir.box>> {fir.bindc_name = "c"}) { ! CHECK: %[[c:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: %[[i:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: hlfir.forall {{.*}} { ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield {{.*}} : !fir.box>> ! CHECK: } to { ! CHECK: hlfir.yield {{.*}} : !fir.box> ! CHECK: } user_defined_assign (%[[rhs:.*]]: !fir.boxchar<1>) to (%[[lhs:.*]]: !fir.ref) { ! CHECK: fir.call @_QPsfrom_char(%[[lhs]], %[[rhs]]) ! CHECK: } ! CHECK: } ! CHECK-LABEL: func @_QPto_char_forall_array( ! CHECK-SAME: %[[arg0:.*]]: !fir.box> {fir.bindc_name = "i"}, %[[arg1:.*]]: !fir.box>> {fir.bindc_name = "c"}) { ! CHECK: %[[c:.*]]:2 = hlfir.declare %[[arg1]] ! CHECK: %[[i:.*]]:2 = hlfir.declare %[[arg0]] ! CHECK: hlfir.forall {{.*}} { ! CHECK: hlfir.region_assign { ! CHECK: hlfir.yield {{.*}} : !fir.box> ! CHECK: } to { ! CHECK: hlfir.yield {{.*}} : !fir.box>> ! CHECK: } user_defined_assign (%[[rhs:.*]]: !fir.ref) to (%[[lhs:.*]]: !fir.boxchar<1>) { ! CHECK: fir.call @_QPsto_char(%[[lhs]], %[[rhs]]) ! CHECK: } ! CHECK: } subroutine test_forall_array(x, y) use defined_assignments logical :: x(:, :) real :: y(:, :) forall (i=1:10) x(i, :) = y(i, :) end subroutine subroutine from_char_forall_array(i, c) interface assignment(=) elemental subroutine sfrom_char(a,b) integer, intent(out) :: a character(*),intent(in) :: b end subroutine end interface integer :: i(:, :) character(*) :: c(:, :) forall (j=1:10) i(j, :) = c(j, :) end subroutine subroutine to_char_forall_array(i, c) interface assignment(=) elemental subroutine sto_char(a,b) character(*), intent(out) :: a integer,intent(in) :: b end subroutine end interface integer :: i(:, :) character(*) :: c(:, :) forall (j=1:10) c(j, :) = i(j, :) end subroutine ! TODO: test array user defined assignment inside FORALL. subroutine test_todo(x, y) interface assignment(=) ! User assignment is not elemental, it takes array arguments. pure subroutine assign_array(a,b) logical, intent(out) :: a(:) integer, intent(in) :: b(:) end end interface logical :: x(10, 10) integer :: y(10, 10) ! forall(i=1:10) x(i, :) = y(i, :) end subroutine