This patch simplifies the representation of OpenMP loop wrapper operations by introducing the `NoTerminator` trait and updating accordingly the verifier for the `LoopWrapperInterface`. Since loop wrappers are already limited to having exactly one region containing exactly one block, and this block can only hold a single `omp.loop_nest` or loop wrapper and an `omp.terminator` that does not return any values, it makes sense to simplify the representation of loop wrappers by removing the terminator. There is an extensive list of Lit tests that needed updating to remove the `omp.terminator`s adding some noise to this patch, but actual changes are limited to the definition of the `omp.wsloop`, `omp.simd`, `omp.distribute` and `omp.taskloop` loop wrapper ops, Flang lowering for those, `LoopWrapperInterface::verifyImpl()`, SCF to OpenMP conversion and OpenMP dialect documentation.
367 lines
11 KiB
Fortran
367 lines
11 KiB
Fortran
! Test unstructured code adjacent to and inside OpenMP constructs.
|
|
|
|
! RUN: bbc %s -fopenmp -emit-hlfir -o "-" \
|
|
! RUN: | FileCheck %s
|
|
|
|
! CHECK-LABEL: func @_QPss1{{.*}} {
|
|
! CHECK: br ^bb1
|
|
! CHECK: ^bb1: // 2 preds: ^bb0, ^bb4
|
|
! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb5
|
|
! CHECK: ^bb2: // pred: ^bb1
|
|
! CHECK: cond_br %{{[0-9]*}}, ^bb3, ^bb4
|
|
! CHECK: ^bb4: // pred: ^bb2
|
|
! CHECK: fir.call @_FortranAioBeginExternalListOutput
|
|
! CHECK: br ^bb1
|
|
! CHECK: ^bb5: // 2 preds: ^bb1, ^bb3
|
|
! CHECK: omp.master {
|
|
! CHECK: @_FortranAioBeginExternalListOutput
|
|
! CHECK: omp.terminator
|
|
! CHECK: }
|
|
! CHECK: @_FortranAioBeginExternalListOutput
|
|
! CHECK: }
|
|
subroutine ss1(n) ! unstructured code followed by a structured OpenMP construct
|
|
do i = 1, 3
|
|
if (i .eq. n) exit
|
|
print*, 'ss1-A', i
|
|
enddo
|
|
!$omp master
|
|
print*, 'ss1-B', i
|
|
!$omp end master
|
|
print*
|
|
end
|
|
|
|
! CHECK-LABEL: func @_QPss2{{.*}} {
|
|
! CHECK: omp.master {
|
|
! CHECK: @_FortranAioBeginExternalListOutput
|
|
! CHECK: br ^bb1
|
|
! CHECK: ^bb1: // 2 preds: ^bb0, ^bb4
|
|
! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb5
|
|
! CHECK: ^bb2: // pred: ^bb1
|
|
! CHECK: cond_br %{{[0-9]*}}, ^bb3, ^bb4
|
|
! CHECK: ^bb3: // pred: ^bb2
|
|
! CHECK: @_FortranAioBeginExternalListOutput
|
|
! CHECK: br ^bb1
|
|
! CHECK: ^bb5: // 2 preds: ^bb1, ^bb3
|
|
! CHECK: omp.terminator
|
|
! CHECK: }
|
|
! CHECK: @_FortranAioBeginExternalListOutput
|
|
! CHECK: @_FortranAioBeginExternalListOutput
|
|
! CHECK: }
|
|
subroutine ss2(n) ! unstructured OpenMP construct; loop exit inside construct
|
|
!$omp master
|
|
print*, 'ss2-A', n
|
|
do i = 1, 3
|
|
if (i .eq. n) exit
|
|
print*, 'ss2-B', i
|
|
enddo
|
|
!$omp end master
|
|
print*, 'ss2-C', i
|
|
print*
|
|
end
|
|
|
|
! CHECK-LABEL: func @_QPss3{{.*}} {
|
|
! CHECK: omp.parallel private(@{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) {
|
|
! CHECK: %[[ALLOCA_K:.*]] = fir.alloca i32 {bindc_name = "k", pinned}
|
|
! CHECK: %[[K_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_K]] {uniq_name = "_QFss3Ek"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
|
|
|
|
! CHECK: br ^bb1
|
|
! CHECK: ^bb1: // 2 preds: ^bb0, ^bb3
|
|
! CHECK: cond_br %{{[0-9]*}}, ^bb2, ^bb4
|
|
! CHECK: ^bb2: // pred: ^bb1
|
|
|
|
! CHECK: %[[ALLOCA_2:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}}
|
|
! CHECK: %[[OMP_LOOP_K_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_2]] {uniq_name = "_QFss3Ek"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
|
|
! CHECK: omp.wsloop {
|
|
! CHECK: omp.loop_nest (%[[ARG1:.*]]) : {{.*}} {
|
|
! CHECK: fir.store %[[ARG1]] to %[[OMP_LOOP_K_DECL]]#1 : !fir.ref<i32>
|
|
! CHECK: @_FortranAioBeginExternalListOutput
|
|
! CHECK: %[[LOAD_1:.*]] = fir.load %[[OMP_LOOP_K_DECL]]#0 : !fir.ref<i32>
|
|
! CHECK: @_FortranAioOutputInteger32(%{{.*}}, %[[LOAD_1]])
|
|
! CHECK: omp.yield
|
|
! CHECK: }
|
|
! CHECK: }
|
|
|
|
! CHECK: %[[ALLOCA_1:.*]] = fir.alloca i32 {{{.*}}, pinned, {{.*}}}
|
|
! CHECK: %[[OMP_LOOP_J_DECL:.*]]:2 = hlfir.declare %[[ALLOCA_1]] {uniq_name = "_QFss3Ej"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
|
|
|
|
! CHECK: omp.wsloop {
|
|
! CHECK: omp.loop_nest (%[[ARG2:.*]]) : {{.*}} {
|
|
! CHECK: fir.store %[[ARG2]] to %[[OMP_LOOP_J_DECL]]#1 : !fir.ref<i32>
|
|
! CHECK: br ^bb1
|
|
! CHECK: ^bb2: // 2 preds: ^bb1, ^bb5
|
|
! CHECK: cond_br %{{[0-9]*}}, ^bb3, ^bb6
|
|
! CHECK: ^bb3: // pred: ^bb2
|
|
! CHECK: cond_br %{{[0-9]*}}, ^bb4, ^bb5
|
|
! CHECK: ^bb4: // pred: ^bb3
|
|
! CHECK: @_FortranAioBeginExternalListOutput
|
|
! CHECK: %[[LOAD_2:.*]] = fir.load %[[K_DECL]]#0 : !fir.ref<i32>
|
|
! CHECK: @_FortranAioOutputInteger32(%{{.*}}, %[[LOAD_2]])
|
|
! CHECK: br ^bb2
|
|
! CHECK: ^bb6: // 2 preds: ^bb2, ^bb4
|
|
! CHECK: omp.yield
|
|
! CHECK: }
|
|
! CHECK: }
|
|
! CHECK: br ^bb1
|
|
! CHECK: ^bb4: // pred: ^bb1
|
|
! CHECK: omp.terminator
|
|
! CHECK: }
|
|
! CHECK: }
|
|
subroutine ss3(n) ! nested unstructured OpenMP constructs
|
|
!$omp parallel
|
|
do i = 1, 3
|
|
!$omp do
|
|
do k = 1, 3
|
|
print*, 'ss3-A', k
|
|
enddo
|
|
!$omp end do
|
|
!$omp do
|
|
do j = 1, 3
|
|
do k = 1, 3
|
|
if (k .eq. n) exit
|
|
print*, 'ss3-B', k
|
|
enddo
|
|
enddo
|
|
!$omp end do
|
|
enddo
|
|
!$omp end parallel
|
|
end
|
|
|
|
! CHECK-LABEL: func @_QPss4{{.*}} {
|
|
! CHECK: omp.parallel private(@{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) {
|
|
! CHECK: %[[ALLOCA:.*]] = fir.alloca i32 {{{.*}}, pinned, uniq_name = "_QFss4Ej"}
|
|
! CHECK: %[[OMP_LOOP_J_DECL:.*]]:2 = hlfir.declare %[[ALLOCA]] {uniq_name = "_QFss4Ej"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
|
|
! CHECK: omp.wsloop {
|
|
! CHECK-NEXT: omp.loop_nest (%[[ARG:.*]]) : {{.*}} {
|
|
! CHECK: fir.store %[[ARG]] to %[[OMP_LOOP_J_DECL]]#1 : !fir.ref<i32>
|
|
! CHECK: %[[COND:.*]] = arith.cmpi eq, %{{.*}}, %{{.*}}
|
|
! CHECK: %[[COND_XOR:.*]] = arith.xori %[[COND]], %{{.*}}
|
|
! CHECK: fir.if %[[COND_XOR]] {
|
|
! CHECK: @_FortranAioBeginExternalListOutput
|
|
! CHECK: %[[LOAD:.*]] = fir.load %[[OMP_LOOP_J_DECL]]#0 : !fir.ref<i32>
|
|
! CHECK: @_FortranAioOutputInteger32(%{{.*}}, %[[LOAD]])
|
|
! CHECK: }
|
|
! CHECK-NEXT: omp.yield
|
|
! CHECK-NEXT: }
|
|
! CHECK-NEXT: }
|
|
! CHECK: omp.terminator
|
|
! CHECK-NEXT: }
|
|
subroutine ss4(n) ! CYCLE in OpenMP wsloop constructs
|
|
!$omp parallel
|
|
do i = 1, 3
|
|
!$omp do
|
|
do j = 1, 3
|
|
if (j .eq. n) cycle
|
|
print*, 'ss4', j
|
|
enddo
|
|
!$omp end do
|
|
enddo
|
|
!$omp end parallel
|
|
end
|
|
|
|
! CHECK-LABEL: func @_QPss5() {
|
|
! CHECK: omp.parallel private(@{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) {
|
|
! CHECK: omp.wsloop {
|
|
! CHECK: omp.loop_nest {{.*}} {
|
|
! CHECK: br ^[[BB1:.*]]
|
|
! CHECK: ^[[BB1]]:
|
|
! CHECK: br ^[[BB2:.*]]
|
|
! CHECK: ^[[BB2]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB3:.*]], ^[[BB6:.*]]
|
|
! CHECK: ^[[BB3]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB4:.*]], ^[[BB3:.*]]
|
|
! CHECK: ^[[BB4]]:
|
|
! CHECK: br ^[[BB6]]
|
|
! CHECK: ^[[BB3]]:
|
|
! CHECK: br ^[[BB2]]
|
|
! CHECK: ^[[BB6]]:
|
|
! CHECK: omp.yield
|
|
! CHECK: }
|
|
! CHECK: }
|
|
! CHECK: omp.terminator
|
|
! CHECK: }
|
|
subroutine ss5() ! EXIT inside OpenMP wsloop (inside parallel)
|
|
integer :: x
|
|
!$omp parallel private(x)
|
|
!$omp do
|
|
do j = 1, 3
|
|
x = j * i
|
|
do k = 1, 3
|
|
if (k .eq. n) exit
|
|
x = k
|
|
x = x + k
|
|
enddo
|
|
x = j - 222
|
|
enddo
|
|
!$omp end do
|
|
!$omp end parallel
|
|
end
|
|
|
|
! CHECK-LABEL: func @_QPss6() {
|
|
! CHECK: omp.parallel private(@{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) {
|
|
! CHECK: br ^[[BB1_OUTER:.*]]
|
|
! CHECK: ^[[BB1_OUTER]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB2_OUTER:.*]], ^[[BB3_OUTER:.*]]
|
|
! CHECK: ^[[BB2_OUTER]]:
|
|
! CHECK: omp.wsloop {
|
|
! CHECK: omp.loop_nest {{.*}} {
|
|
! CHECK: br ^[[BB1:.*]]
|
|
! CHECK: ^[[BB1]]:
|
|
! CHECK: br ^[[BB2:.*]]
|
|
! CHECK: ^[[BB2]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB3:.*]], ^[[BB6:.*]]
|
|
! CHECK: ^[[BB3]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB4:.*]], ^[[BB5:.*]]
|
|
! CHECK: ^[[BB4]]:
|
|
! CHECK: br ^[[BB6]]
|
|
! CHECK: ^[[BB5]]
|
|
! CHECK: br ^[[BB2]]
|
|
! CHECK: ^[[BB6]]:
|
|
! CHECK: omp.yield
|
|
! CHECK: }
|
|
! CHECK: }
|
|
! CHECK: br ^[[BB1_OUTER]]
|
|
! CHECK: ^[[BB3_OUTER]]:
|
|
! CHECK: omp.terminator
|
|
! CHECK: }
|
|
subroutine ss6() ! EXIT inside OpenMP wsloop in a do loop (inside parallel)
|
|
integer :: x
|
|
!$omp parallel private(x)
|
|
do i = 1, 3
|
|
!$omp do
|
|
do j = 1, 3
|
|
x = j * i
|
|
do k = 1, 3
|
|
if (k .eq. n) exit
|
|
x = k
|
|
x = x + k
|
|
enddo
|
|
x = j - 222
|
|
enddo
|
|
!$omp end do
|
|
enddo
|
|
!$omp end parallel
|
|
end
|
|
|
|
! CHECK-LABEL: func @_QPss7() {
|
|
! CHECK: br ^[[BB1_OUTER:.*]]
|
|
! CHECK: ^[[BB1_OUTER]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB2_OUTER:.*]], ^[[BB3_OUTER:.*]]
|
|
! CHECK-NEXT: ^[[BB2_OUTER:.*]]:
|
|
! CHECK: omp.parallel {
|
|
! CHECK: omp.wsloop {
|
|
! CHECK: omp.loop_nest {{.*}} {
|
|
! CHECK: br ^[[BB1:.*]]
|
|
! CHECK-NEXT: ^[[BB1]]:
|
|
! CHECK: br ^[[BB2:.*]]
|
|
! CHECK-NEXT: ^[[BB2]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB3:.*]], ^[[BB6:.*]]
|
|
! CHECK-NEXT: ^[[BB3]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB4:.*]], ^[[BB5:.*]]
|
|
! CHECK-NEXT: ^[[BB4]]:
|
|
! CHECK: br ^[[BB6]]
|
|
! CHECK-NEXT: ^[[BB5]]:
|
|
! CHECK: br ^[[BB2]]
|
|
! CHECK-NEXT: ^[[BB6]]:
|
|
! CHECK: omp.yield
|
|
! CHECK: }
|
|
! CHECK: }
|
|
! CHECK: omp.terminator
|
|
! CHECK: }
|
|
! CHECK: br ^[[BB1_OUTER]]
|
|
! CHECK-NEXT: ^[[BB3_OUTER]]:
|
|
! CHECK-NEXT: return
|
|
subroutine ss7() ! EXIT inside OpenMP parallel do (inside do loop)
|
|
integer :: x
|
|
do i = 1, 3
|
|
!$omp parallel do private(x)
|
|
do j = 1, 3
|
|
x = j * i
|
|
do k = 1, 3
|
|
if (k .eq. n) exit
|
|
x = k
|
|
x = x + k
|
|
enddo
|
|
enddo
|
|
!$omp end parallel do
|
|
enddo
|
|
end
|
|
|
|
! CHECK-LABEL: func @_QPss8() {
|
|
! CHECK: omp.parallel {
|
|
! CHECK: omp.wsloop {
|
|
! CHECK: omp.loop_nest {{.*}} {
|
|
! CHECK: br ^[[BB1:.*]]
|
|
! CHECK-NEXT: ^[[BB1]]:
|
|
! CHECK: br ^[[BB2:.*]]
|
|
! CHECK: ^[[BB2]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB3:.*]], ^[[BB6:.*]]
|
|
! CHECK: ^[[BB3]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB4:.*]], ^[[BB5:.*]]
|
|
! CHECK: ^[[BB4]]:
|
|
! CHECK-NEXT: br ^[[BB6]]
|
|
! CHECK: ^[[BB5]]:
|
|
! CHECK: br ^[[BB2]]
|
|
! CHECK-NEXT: ^[[BB6]]:
|
|
! CHECK: omp.yield
|
|
! CHECK: }
|
|
! CHECK: }
|
|
! CHECK: omp.terminator
|
|
! CHECK: }
|
|
subroutine ss8() ! EXIT inside OpenMP parallel do
|
|
integer :: x
|
|
!$omp parallel do private(x)
|
|
do j = 1, 3
|
|
x = j * i
|
|
do k = 1, 3
|
|
if (k .eq. n) exit
|
|
x = k
|
|
x = x + k
|
|
enddo
|
|
enddo
|
|
!$omp end parallel do
|
|
end
|
|
|
|
! CHECK-LABEL: func @_QPss9() {
|
|
! CHECK: omp.parallel {
|
|
! CHECK-NEXT: omp.parallel private(@{{.*}} %{{.*}}#0 -> %{{.*}}, @{{.*}} %{{.*}}#0 -> %{{.*}} : {{.*}}) {
|
|
! CHECK: br ^[[BB1:.*]]
|
|
! CHECK: ^[[BB1]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB2:.*]], ^[[BB5:.*]]
|
|
! CHECK-NEXT: ^[[BB2]]:
|
|
! CHECK: cond_br %{{.*}}, ^[[BB3:.*]], ^[[BB4:.*]]
|
|
! CHECK-NEXT: ^[[BB3]]:
|
|
! CHECK-NEXT: br ^[[BB5]]
|
|
! CHECK-NEXT: ^[[BB4]]:
|
|
! CHECK: br ^[[BB1]]
|
|
! CHECK-NEXT: ^[[BB5]]:
|
|
! CHECK: omp.terminator
|
|
! CHECK-NEXT: }
|
|
! CHECK: omp.terminator
|
|
! CHECK-NEXT }
|
|
! CHECK: }
|
|
subroutine ss9() ! EXIT inside OpenMP parallel (inside parallel)
|
|
integer :: x
|
|
!$omp parallel
|
|
!$omp parallel private(x)
|
|
do k = 1, 3
|
|
if (k .eq. n) exit
|
|
x = k
|
|
x = x + k
|
|
end do
|
|
!$omp end parallel
|
|
!$omp end parallel
|
|
end
|
|
|
|
! CHECK-LABEL: func @_QQmain
|
|
program p
|
|
call ss1(2)
|
|
call ss2(2)
|
|
call ss3(2)
|
|
call ss4(2)
|
|
call ss5()
|
|
call ss6()
|
|
call ss7()
|
|
call ss8()
|
|
call ss9()
|
|
end
|