blob: 5ff39a96982bcc79f75645d1b7e48c3fa158dc3a [file] [edit]
! RUN: %flang_fc1 -emit-fir -O3 %s -o - | \
! RUN: fir-opt --verify-each --loop-versioning | \
! RUN: FileCheck %s --enable-var-scope
! RUN: %flang -S -O3 -mmlir --mlir-disable-threading \
! RUN: -mmlir --mlir-print-ir-after=loop-versioning \
! RUN: %s -o /dev/null 2>&1 | FileCheck %s --enable-var-scope
! Verify that a loop accessing a local POINTER that is associated with an
! assumed-shape dummy, or with a section of one that keeps the first
! dimension contiguous, is versioned like a loop accessing the dummy itself.
! A loop that is versioned anyway also checks the stride of a local POINTER
! whose pointer assignment is not visible, unless the loop may modify it.
! Other POINTERs are not versioned. Where no loop is versioned, the dummy `a`
! is only there so that the pass has an assumed-shape argument to consider.
module loop_versioning_pointers
implicit none
type :: holder
real(8), pointer :: v(:) => null()
end type
real(8), pointer :: gp(:) => null(), hp(:) => null()
interface
subroutine ext(p)
real(8), pointer :: p(:)
end subroutine
end interface
contains
subroutine whole(a, b, n)
real(8), target :: a(:), b(:)
integer :: n, i
real(8), pointer :: p(:), q(:)
p => a
q => b
do i = 1, n
p(i) = p(i) + q(i)
end do
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPwhole(
! CHECK: arith.cmpi eq, %{{.*}}#2, %c8{{.*}} : index
! CHECK: arith.cmpi eq, %{{.*}}#2, %c8{{.*}} : index
! CHECK: fir.if
! CHECK: fir.coordinate_of {{.*}} : (!fir.ref<!fir.array<?xf64>>, index) -> !fir.ref<f64>
! CHECK: fir.coordinate_of {{.*}} : (!fir.ref<!fir.array<?xf64>>, index) -> !fir.ref<f64>
! CHECK: } else {
! CHECK: fir.array_coor {{.*}} : (!fir.box<!fir.ptr<!fir.array<?xf64>>>, !fir.shift<1>, i64) -> !fir.ref<f64>
subroutine columns(a, x, n)
real(8), target, intent(inout) :: a(:,:)
real(8), target, intent(in) :: x(:,:)
integer, intent(in) :: n
real(8), pointer :: p(:), q(:)
integer :: i, j
do j = 1, size(a, 2)
p => a(:, j)
q => x(:, j)
do i = 1, n
p(i) = p(i) + 2.0d0 * q(i)
end do
end do
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPcolumns(
! CHECK: arith.cmpi eq, %{{.*}}#2, %c8{{.*}} : index
! CHECK: arith.cmpi eq, %{{.*}}#2, %c8{{.*}} : index
! CHECK: fir.if
! CHECK: fir.coordinate_of {{.*}} : (!fir.ref<!fir.array<?xf64>>, index) -> !fir.ref<f64>
! CHECK: fir.coordinate_of {{.*}} : (!fir.ref<!fir.array<?xf64>>, index) -> !fir.ref<f64>
! CHECK: } else {
! CHECK: fir.array_coor {{.*}} : (!fir.box<!fir.ptr<!fir.array<?xf64>>>, !fir.shift<1>, i64) -> !fir.ref<f64>
subroutine cmplx_column(res, k, f, n)
complex(8), target, intent(inout) :: res(:,:)
real(8), target, intent(in) :: k(:,:)
real(8), intent(in) :: f
integer, intent(in) :: n
complex(8), pointer :: r(:)
real(8), pointer :: kx(:)
integer :: i
r => res(:, 1)
kx => k(:, 1)
do i = 1, n
r(i) = r(i) + cmplx(f, kx(i), kind=8)
end do
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPcmplx_column(
! CHECK-DAG: arith.cmpi eq, %{{.*}}#2, %c16{{.*}} : index
! CHECK-DAG: arith.cmpi eq, %{{.*}}#2, %c8{{.*}} : index
! CHECK: fir.if
! CHECK: fir.coordinate_of {{.*}} : (!fir.ref<!fir.array<?xcomplex<f64>>>, index) -> !fir.ref<complex<f64>>
! CHECK: } else {
! CHECK: fir.array_coor {{.*}} : (!fir.box<!fir.ptr<!fir.array<?xcomplex<f64>>>>, !fir.shift<1>, i64) -> !fir.ref<complex<f64>>
! A row of a dummy is not contiguous.
subroutine row(a, b, n)
real(8), target :: a(:,:), b(:,:)
integer :: n, i
real(8), pointer :: p(:), q(:)
p => a(1, :)
q => b(1, :)
do i = 1, n
p(i) = p(i) + q(i)
end do
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersProw(
! CHECK-NOT: fir.if
! CHECK: return
! The POINTERs are associated with local arrays, not with a dummy.
subroutine local_target(a, n)
real(8), intent(inout) :: a(:)
integer :: n, i
real(8), target :: t(1000), u(1000)
real(8), pointer :: p(:), q(:)
p => t
q => u
do i = 1, n
p(i) = p(i) + q(i)
end do
a(1) = p(1)
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPlocal_target(
! CHECK-NOT: fir.if
! CHECK: return
subroutine component(a, h, g, n)
real(8), intent(inout) :: a(:)
type(holder), intent(inout) :: h
type(holder), intent(in) :: g
integer, intent(in) :: n
integer :: i
do i = 1, n
h%v(i) = h%v(i) + g%v(i)
end do
a(1) = h%v(1)
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPcomponent(
! CHECK-NOT: fir.if
! CHECK: return
subroutine module_ptr(a, n)
real(8), intent(inout) :: a(:)
integer, intent(in) :: n
integer :: i
do i = 1, n
gp(i) = gp(i) + hp(i)
end do
a(1) = gp(1)
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPmodule_ptr(
! CHECK-NOT: fir.if
! CHECK: return
! The POINTER is re-associated inside the loop.
subroutine reassociated_in_loop(a, n, s)
real(8), target, intent(in) :: a(:,:)
integer, intent(in) :: n
real(8), intent(out) :: s
real(8), pointer :: p(:)
integer :: i
s = 0.0d0
p => a(:, 1)
do i = 1, n
s = s + p(i)
p => a(:, 2)
end do
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPreassociated_in_loop(
! CHECK-NOT: fir.if
! CHECK: return
! The call may re-associate the POINTERs after their assignment.
subroutine call_between(a, b, n)
real(8), target :: a(:), b(:)
integer :: n, i
real(8), pointer :: p(:), q(:)
p => a
q => b
call ext(p)
do i = 1, n
p(i) = p(i) + q(i)
end do
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPcall_between(
! CHECK-NOT: fir.if
! CHECK: return
! The loop is versioned for the dummy anyway, so it also checks the stride
! of the POINTER that the call associated.
subroutine ride_along(a, n)
real(8), intent(inout) :: a(:)
integer, intent(in) :: n
real(8), pointer :: q(:)
integer :: i
call ext(q)
do i = 1, n
a(i) = a(i) + q(i)
end do
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPride_along(
! CHECK: arith.cmpi eq, %{{.*}}#2, %c8{{.*}} : index
! CHECK: arith.cmpi eq, %{{.*}}#2, %c8{{.*}} : index
! CHECK: fir.if
! CHECK-NOT: fir.array_coor
! CHECK: } else {
! CHECK: fir.array_coor {{.*}} : (!fir.box<!fir.ptr<!fir.array<?xf64>>>, !fir.shift<1>, i64) -> !fir.ref<f64>
! The same, with the loop versioned for a POINTER to a column of a dummy.
subroutine view_ride_along(th, n)
real(8), target, intent(in) :: th(:,:)
integer, intent(in) :: n
real(8), pointer :: t(:), q(:)
integer :: i, j
call ext(q)
do j = 1, size(th, 2)
t => th(:, j)
do i = 1, n
q(i) = q(i) * t(i)
end do
end do
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPview_ride_along(
! CHECK: arith.cmpi eq, %{{.*}}#2, %c8{{.*}} : index
! CHECK: arith.cmpi eq, %{{.*}}#2, %c8{{.*}} : index
! CHECK: fir.if
! CHECK-NOT: fir.array_coor
! CHECK: } else {
! CHECK: fir.array_coor {{.*}} : (!fir.box<!fir.ptr<!fir.array<?xf64>>>, !fir.shift<1>, i64) -> !fir.ref<f64>
! The loop may re-associate the POINTER, so only the dummy is checked.
subroutine ride_along_modified(a, n)
real(8), intent(inout) :: a(:)
integer, intent(in) :: n
real(8), pointer :: q(:)
integer :: i
call ext(q)
do i = 1, n
a(i) = a(i) + q(i)
call ext(q)
end do
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPride_along_modified(
! CHECK: arith.cmpi eq, %{{.*}}#2, %c8{{.*}} : index
! CHECK-NOT: arith.cmpi eq
! CHECK: fir.if
! CHECK: fir.array_coor {{.*}} : (!fir.box<!fir.ptr<!fir.array<?xf64>>>, !fir.shift<1>, i64) -> !fir.ref<f64>
! CHECK: } else {
! The POINTER is associated with a row, which is not contiguous, so only
! the dummy is checked.
subroutine ride_along_row(a, b, n)
real(8), intent(inout) :: a(:)
real(8), target, intent(in) :: b(:,:)
integer, intent(in) :: n
real(8), pointer :: q(:)
integer :: i
q => b(1, :)
do i = 1, n
a(i) = a(i) + q(i)
end do
end subroutine
! CHECK-LABEL: func.func @_QMloop_versioning_pointersPride_along_row(
! CHECK: arith.cmpi eq, %{{.*}}#2, %c8{{.*}} : index
! CHECK-NOT: arith.cmpi eq
! CHECK: fir.if
! CHECK: fir.array_coor {{.*}} : (!fir.box<!fir.ptr<!fir.array<?xf64>>>, !fir.shift<1>, i64) -> !fir.ref<f64>
! CHECK: } else {
end module