llvm-project/flang/test/Lower/OpenMP/loop-directive.f90
Tom Eccles aeaafce464
[mlir][OpenMP][flang] make private variable allocation implicit in omp.private (#124019)
The intention of this work is to give MLIR->LLVMIR conversion freedom to
control how the private variable is allocated so that it can be
allocated on the stack in ordinary cases or as part of a structure used
to give closure context for tasks which might outlive the current stack
frame. See RFC:

https://discourse.llvm.org/t/rfc-openmp-supporting-delayed-task-execution-with-firstprivate-variables/83084

For example, a privatizer for an integer used to look like
```mlir
  omp.private {type = private} @x.privatizer : !fir.ref<i32> alloc {
  ^bb0(%arg0: !fir.ref<i32>):
    %0 = ... allocate proper memory for the private clone ...
    omp.yield(%0 : !fir.ref<i32>)
  }
```

After this change, allocation become implicit in the operation:
```mlir
  omp.private {type = private} @x.privatizer : i32
```

For more complex types that require initialization after allocation, an
init region can be used:
``` mlir
  omp.private {type = private} @x.privatizer : !some.type init {
  ^bb0(%arg0: !some.pointer<!some.type>, %arg1: !some.pointer<!some.type>):
    // initialize %arg1, using %arg0 as a mold for allocations
    omp.yield(%arg1 : !some.pointer<!some.type>)
  } dealloc {
    ^bb0(%arg0: !some.pointer<!some.type>):
    ... deallocate memory allocated by the init region ...
    omp.yield
  }
```

This patch lays the groundwork for delayed task execution but is not
enough on its own.

After this patch all gfortran tests which previously passed still pass.
There
are the following changes to the Fujitsu test suite:
- 0380_0009 and 0435_0009 are fixed
- 0688_0041 now fails at runtime. This patch is testing firstprivate
variables with tasks. Previously we got lucky with the undefined
behavior and won the race. After these changes we no longer get lucky.
This patch lays the groundwork for a proper fix for this issue.

In flang the lowering re-uses the existing lowering used for reduction
init and dealloc regions.

In flang, before this patch we hit a TODO with the same wording when
generating the copy region for firstprivate polymorphic variables. After
this patch the box-like fir.class is passed by reference into the copy
region, leading to a different path that didn't hit that old TODO but
the generated code still didn't work so I added a new TODO in
DataSharingProcessor.
2025-01-31 09:35:26 +00:00

182 lines
5.3 KiB
Fortran

! This test checks lowering of OpenMP loop Directive.
! RUN: bbc -emit-hlfir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s
! RUN: %flang_fc1 -emit-hlfir -fopenmp -fopenmp-version=50 -o - %s 2>&1 | FileCheck %s
! CHECK: omp.declare_reduction @[[RED:add_reduction_i32]] : i32
! CHECK: omp.private {type = private} @[[DUMMY_PRIV:.*test_privateEdummy_private.*]] : i32
! CHECK: omp.private {type = private} @[[I_PRIV:.*test_no_clausesEi.*]] : i32
! CHECK-LABEL: func.func @_QPtest_no_clauses
subroutine test_no_clauses()
integer :: i, j, dummy = 1
! CHECK: omp.simd private(@[[I_PRIV]] %{{.*}}#0 -> %[[ARG:.*]] : !fir.ref<i32>) {
! CHECK-NEXT: omp.loop_nest (%[[IV:.*]]) : i32 = (%{{.*}}) to (%{{.*}}) {{.*}} {
! CHECK: %[[ARG_DECL:.*]]:2 = hlfir.declare %[[ARG]]
! CHECK: fir.store %[[IV]] to %[[ARG_DECL]]#1 : !fir.ref<i32>
! CHECK: }
! CHECK: }
!$omp loop
do i=1,10
dummy = dummy + 1
end do
!$omp end loop
end subroutine
! CHECK-LABEL: func.func @_QPtest_collapse
subroutine test_collapse()
integer :: i, j, dummy = 1
! CHECK: omp.simd private(@{{.*}} %{{.*}}#0 -> %{{.*}}, @{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) {
! CHECK-NEXT: omp.loop_nest (%{{.*}}, %{{.*}}) : i32 {{.*}} {
! CHECK: }
! CHECK: }
!$omp loop collapse(2)
do i=1,10
do j=2,20
dummy = dummy + 1
end do
end do
!$omp end loop
end subroutine
! CHECK-LABEL: func.func @_QPtest_private
subroutine test_private()
integer :: i, dummy = 1
! CHECK: omp.simd private(@[[DUMMY_PRIV]] %{{.*}}#0 -> %[[DUMMY_ARG:.*]], @{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) {
! CHECK-NEXT: omp.loop_nest (%{{.*}}) : i32 = (%{{.*}}) to (%{{.*}}) {{.*}} {
! CHECK: %[[DUMMY_DECL:.*]]:2 = hlfir.declare %[[DUMMY_ARG]] {uniq_name = "_QFtest_privateEdummy"}
! CHECK: %{{.*}} = fir.load %[[DUMMY_DECL]]#0
! CHECK: hlfir.assign %{{.*}} to %[[DUMMY_DECL]]#0
! CHECK: }
! CHECK: }
!$omp loop private(dummy)
do i=1,10
dummy = dummy + 1
end do
!$omp end loop
end subroutine
! CHECK-LABEL: func.func @_QPtest_order
subroutine test_order()
integer :: i, dummy = 1
! CHECK: omp.loop order(reproducible:concurrent) private(@{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) {
! CHECK: }
!$omp loop order(concurrent)
do i=1,10
dummy = dummy + 1
end do
!$omp end loop
end subroutine
! CHECK-LABEL: func.func @_QPtest_reduction
subroutine test_reduction()
integer :: i, dummy = 1
! CHECK: omp.loop private(@{{.*}} %{{.*}}#0 -> %{{.*}} : !{{.*}}) reduction
! CHECK-SAME: (@[[RED]] %{{.*}}#0 -> %[[DUMMY_ARG:.*]] : !{{.*}}) {
! CHECK-NEXT: omp.loop_nest (%{{.*}}) : i32 = (%{{.*}}) to (%{{.*}}) {{.*}} {
! CHECK: %[[DUMMY_DECL:.*]]:2 = hlfir.declare %[[DUMMY_ARG]] {uniq_name = "_QFtest_reductionEdummy"}
! CHECK: %{{.*}} = fir.load %[[DUMMY_DECL]]#0
! CHECK: hlfir.assign %{{.*}} to %[[DUMMY_DECL]]#0
! CHECK: }
! CHECK: }
!$omp loop reduction(+:dummy)
do i=1,10
dummy = dummy + 1
end do
!$omp end loop
end subroutine
! CHECK-LABEL: func.func @_QPtest_bind
subroutine test_bind()
integer :: i, dummy = 1
! CHECK: omp.simd private(@{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) {
! CHECK: }
!$omp loop bind(thread)
do i=1,10
dummy = dummy + 1
end do
!$omp end loop
end subroutine
! CHECK-LABEL: func.func @_QPtest_nested_directives
subroutine test_nested_directives
implicit none
integer, parameter :: N = 100000
integer a(N), b(N), c(N)
integer j,i, num, flag;
num = N
! CHECK: omp.teams {
! Verify the first `loop` directive was combined with `target teams` into
! `target teams distribute parallel do`.
! CHECK: omp.parallel {{.*}} {
! CHECK: omp.distribute {
! CHECK: omp.wsloop {
! CHECK: omp.loop_nest {{.*}} {
! Very the second `loop` directive was rewritten to `simd`.
! CHECK: omp.simd {{.*}} {
! CHECK: omp.loop_nest {{.*}} {
! CHECK: }
! CHECK: }
! CHECK: }
! CHECK: } {omp.composite}
! CHECK: } {omp.composite}
! CHECK: } {omp.composite}
! CHECK: }
!$omp target teams map(to: a,b) map(from: c)
!$omp loop
do j=1,1000
!$omp loop
do i=1,N
c(i) = a(i) * b(i)
end do
end do
!$omp end target teams
end subroutine
! CHECK-LABEL: func.func @_QPtest_standalone_bind_teams
subroutine test_standalone_bind_teams
implicit none
integer, parameter :: N = 100000
integer a(N), b(N), c(N)
integer j,i, num, flag;
num = N
! CHECK: omp.distribute
! CHECK-SAME: private(@{{.*}}Ea_private_box_100000xi32 {{[^,]*}},
! CHECK-SAME: @{{.*}}Ei_private_i32 {{.*}} : {{.*}}) {
! CHECK: omp.loop_nest {{.*}} {
! CHECK: }
! CHECK: }
!$omp loop bind(teams) private(a)
do i=1,N
c(i) = a(i) * b(i)
end do
end subroutine
! CHECK-LABEL: func.func @_QPtest_standalone_bind_parallel
subroutine test_standalone_bind_parallel
implicit none
integer, parameter :: N = 100000
integer a(N), b(N), c(N)
integer j,i, num, flag;
num = N
! CHECK: omp.wsloop
! CHECK-SAME: private(@{{.*}}Ea_private_box_100000xi32 {{[^,]*}},
! CHECK-SAME: @{{.*}}Ei_private_i32 {{.*}} : {{.*}}) {
! CHECK: omp.loop_nest {{.*}} {
! CHECK: }
! CHECK: }
!$omp loop bind(parallel) private(a)
do i=1,N
c(i) = a(i) * b(i)
end do
end subroutine