diff --git a/flang/test/Lower/OpenMP/parallel-firstprivate-clause-scalar.f90 b/flang/test/Lower/OpenMP/parallel-firstprivate-clause-scalar.f90 new file mode 100644 index 0000000000000..6402f98a2addc --- /dev/null +++ b/flang/test/Lower/OpenMP/parallel-firstprivate-clause-scalar.f90 @@ -0,0 +1,202 @@ +! This test checks lowering of `FIRSTPRIVATE` clause for scalar types. + +! REQUIRES: shell +! RUN: bbc -fopenmp -emit-hlfir %s -o - | FileCheck %s --check-prefix=CHECK + +!CHECK-DAG: func @_QPfirstprivate_complex(%[[ARG1:.*]]: !fir.ref>{{.*}}, %[[ARG2:.*]]: !fir.ref>{{.*}}) { +!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstprivate_complexEarg1"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFfirstprivate_complexEarg2"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: omp.parallel { +!CHECK: %[[ARG1_PVT:.*]] = fir.alloca !fir.complex<4> {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_complexEarg1"} +!CHECK: %[[ARG1_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG1_PVT]] {uniq_name = "_QFfirstprivate_complexEarg1"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG1_VAL:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref> +!CHECK: hlfir.assign %[[ARG1_VAL]] to %[[ARG1_PVT_DECL]]#0 temporary_lhs : !fir.complex<4>, !fir.ref> +!CHECK: %[[ARG2_PVT:.*]] = fir.alloca !fir.complex<8> {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_complexEarg2"} +!CHECK: %[[ARG2_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG2_PVT]] {uniq_name = "_QFfirstprivate_complexEarg2"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG2_VAL:.*]] = fir.load %[[ARG2_DECL]]#0 : !fir.ref> +!CHECK: hlfir.assign %[[ARG2_VAL]] to %[[ARG2_PVT_DECL]]#0 temporary_lhs : !fir.complex<8>, !fir.ref> +!CHECK: fir.call @_QPfoo(%[[ARG1_PVT_DECL]]#1, %[[ARG2_PVT_DECL]]#1) {{.*}}: (!fir.ref>, !fir.ref>) -> () +!CHECK: omp.terminator +!CHECK: } + +subroutine firstprivate_complex(arg1, arg2) + complex(4) :: arg1 + complex(8) :: arg2 + +!$OMP PARALLEL FIRSTPRIVATE(arg1, arg2) + call foo(arg1, arg2) +!$OMP END PARALLEL + +end subroutine + +!CHECK-DAG: func @_QPfirstprivate_integer(%[[ARG1:.*]]: !fir.ref{{.*}}, %[[ARG2:.*]]: !fir.ref{{.*}}, %[[ARG3:.*]]: !fir.ref{{.*}}, %[[ARG4:.*]]: !fir.ref{{.*}}, %[[ARG5:.*]]: !fir.ref{{.*}}, %[[ARG6:.*]]: !fir.ref{{.*}}) { +!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstprivate_integerEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFfirstprivate_integerEarg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG3_DECL:.*]]:2 = hlfir.declare %[[ARG3]] {uniq_name = "_QFfirstprivate_integerEarg3"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG4_DECL:.*]]:2 = hlfir.declare %[[ARG4]] {uniq_name = "_QFfirstprivate_integerEarg4"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG5_DECL:.*]]:2 = hlfir.declare %[[ARG5]] {uniq_name = "_QFfirstprivate_integerEarg5"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG6_DECL:.*]]:2 = hlfir.declare %[[ARG6]] {uniq_name = "_QFfirstprivate_integerEarg6"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.parallel { +!CHECK: %[[ARG1_PVT:.*]] = fir.alloca i32 {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_integerEarg1"} +!CHECK: %[[ARG1_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG1_PVT]] {uniq_name = "_QFfirstprivate_integerEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG1_VAL:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG1_VAL]] to %[[ARG1_PVT_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK: %[[ARG2_PVT:.*]] = fir.alloca i8 {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_integerEarg2"} +!CHECK: %[[ARG2_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG2_PVT]] {uniq_name = "_QFfirstprivate_integerEarg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG2_VAL:.*]] = fir.load %[[ARG2_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG2_VAL]] to %[[ARG2_PVT_DECL]]#0 temporary_lhs : i8, !fir.ref +!CHECK: %[[ARG3_PVT:.*]] = fir.alloca i16 {bindc_name = "arg3", pinned, uniq_name = "_QFfirstprivate_integerEarg3"} +!CHECK: %[[ARG3_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG3_PVT]] {uniq_name = "_QFfirstprivate_integerEarg3"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG3_VAL:.*]] = fir.load %[[ARG3_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG3_VAL]] to %[[ARG3_PVT_DECL]]#0 temporary_lhs : i16, !fir.ref +!CHECK: %[[ARG4_PVT:.*]] = fir.alloca i32 {bindc_name = "arg4", pinned, uniq_name = "_QFfirstprivate_integerEarg4"} +!CHECK: %[[ARG4_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG4_PVT]] {uniq_name = "_QFfirstprivate_integerEarg4"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG4_VAL:.*]] = fir.load %[[ARG4_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG4_VAL]] to %[[ARG4_PVT_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK: %[[ARG5_PVT:.*]] = fir.alloca i64 {bindc_name = "arg5", pinned, uniq_name = "_QFfirstprivate_integerEarg5"} +!CHECK: %[[ARG5_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG5_PVT]] {uniq_name = "_QFfirstprivate_integerEarg5"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG5_VAL:.*]] = fir.load %[[ARG5_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG5_VAL]] to %[[ARG5_PVT_DECL]]#0 temporary_lhs : i64, !fir.ref +!CHECK: %[[ARG6_PVT:.*]] = fir.alloca i128 {bindc_name = "arg6", pinned, uniq_name = "_QFfirstprivate_integerEarg6"} +!CHECK: %[[ARG6_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG6_PVT]] {uniq_name = "_QFfirstprivate_integerEarg6"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG6_VAL:.*]] = fir.load %[[ARG6_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG6_VAL]] to %[[ARG6_PVT_DECL]]#0 temporary_lhs : i128, !fir.ref +!CHECK: fir.call @_QPbar(%[[ARG1_PVT_DECL]]#1, %[[ARG2_PVT_DECL]]#1, %[[ARG3_PVT_DECL]]#1, %[[ARG4_PVT_DECL]]#1, +!%[[ARG5_PVT_DECL]]#1, %[[ARG6_PVT_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref, !fir.ref, !fir.ref, !fir.ref, !fir.ref) -> () +!CHECK: omp.terminator +!CHECK: } + +subroutine firstprivate_integer(arg1, arg2, arg3, arg4, arg5, arg6) + integer :: arg1 + integer(kind=1) :: arg2 + integer(kind=2) :: arg3 + integer(kind=4) :: arg4 + integer(kind=8) :: arg5 + integer(kind=16) :: arg6 + +!$OMP PARALLEL FIRSTPRIVATE(arg1, arg2, arg3, arg4, arg5, arg6) + call bar(arg1, arg2, arg3, arg4, arg5, arg6) +!$OMP END PARALLEL + +end subroutine + +!CHECK-DAG: func @_QPfirstprivate_logical(%[[ARG1:.*]]: !fir.ref>{{.*}}, %[[ARG2:.*]]: !fir.ref>{{.*}}, %[[ARG3:.*]]: !fir.ref>{{.*}}, %[[ARG4:.*]]: !fir.ref>{{.*}}, %[[ARG5:.*]]: !fir.ref>{{.*}}) { +!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstprivate_logicalEarg1"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFfirstprivate_logicalEarg2"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG3_DECL:.*]]:2 = hlfir.declare %[[ARG3]] {uniq_name = "_QFfirstprivate_logicalEarg3"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG4_DECL:.*]]:2 = hlfir.declare %[[ARG4]] {uniq_name = "_QFfirstprivate_logicalEarg4"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG5_DECL:.*]]:2 = hlfir.declare %[[ARG5]] {uniq_name = "_QFfirstprivate_logicalEarg5"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: omp.parallel { +!CHECK: %[[ARG1_PVT:.*]] = fir.alloca !fir.logical<4> {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_logicalEarg1"} +!CHECK: %[[ARG1_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG1_PVT]] {uniq_name = "_QFfirstprivate_logicalEarg1"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG1_VAL:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref> +!CHECK: hlfir.assign %[[ARG1_VAL]] to %[[ARG1_PVT_DECL]]#0 temporary_lhs : !fir.logical<4>, !fir.ref> +!CHECK: %[[ARG2_PVT:.*]] = fir.alloca !fir.logical<1> {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_logicalEarg2"} +!CHECK: %[[ARG2_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG2_PVT]] {uniq_name = "_QFfirstprivate_logicalEarg2"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG2_VAL:.*]] = fir.load %[[ARG2_DECL]]#0 : !fir.ref> +!CHECK: hlfir.assign %[[ARG2_VAL]] to %[[ARG2_PVT_DECL]]#0 temporary_lhs : !fir.logical<1>, !fir.ref> +!CHECK: %[[ARG3_PVT:.*]] = fir.alloca !fir.logical<2> {bindc_name = "arg3", pinned, uniq_name = "_QFfirstprivate_logicalEarg3"} +!CHECK: %[[ARG3_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG3_PVT]] {uniq_name = "_QFfirstprivate_logicalEarg3"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG3_VAL:.*]] = fir.load %[[ARG3_DECL]]#0 : !fir.ref> +!CHECK: hlfir.assign %[[ARG3_VAL]] to %[[ARG3_PVT_DECL]]#0 temporary_lhs : !fir.logical<2>, !fir.ref> +!CHECK: %[[ARG4_PVT:.*]] = fir.alloca !fir.logical<4> {bindc_name = "arg4", pinned, uniq_name = "_QFfirstprivate_logicalEarg4"} +!CHECK: %[[ARG4_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG4_PVT]] {uniq_name = "_QFfirstprivate_logicalEarg4"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG4_VAL:.*]] = fir.load %[[ARG4_DECL]]#0 : !fir.ref> +!CHECK: hlfir.assign %[[ARG4_VAL]] to %[[ARG4_PVT_DECL]]#0 temporary_lhs : !fir.logical<4>, !fir.ref> +!CHECK: %[[ARG5_PVT:.*]] = fir.alloca !fir.logical<8> {bindc_name = "arg5", pinned, uniq_name = "_QFfirstprivate_logicalEarg5"} +!CHECK: %[[ARG5_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG5_PVT]] {uniq_name = "_QFfirstprivate_logicalEarg5"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +!CHECK: %[[ARG5_VAL:.*]] = fir.load %[[ARG5_DECL]]#0 : !fir.ref> +!CHECK: hlfir.assign %[[ARG5_VAL]] to %[[ARG5_PVT_DECL]]#0 temporary_lhs : !fir.logical<8>, !fir.ref> +!CHECK: fir.call @_QPbaz(%[[ARG1_PVT_DECL]]#1, %[[ARG2_PVT_DECL]]#1, %[[ARG3_PVT_DECL]]#1, %[[ARG4_PVT_DECL]]#1, %[[ARG5_PVT_DECL]]#1) {{.*}}: (!fir.ref>, !fir.ref>, !fir.ref>, !fir.ref>, !fir.ref>) -> () +!CHECK: omp.terminator +!CHECK: } + +subroutine firstprivate_logical(arg1, arg2, arg3, arg4, arg5) + logical :: arg1 + logical(kind=1) :: arg2 + logical(kind=2) :: arg3 + logical(kind=4) :: arg4 + logical(kind=8) :: arg5 + +!$OMP PARALLEL FIRSTPRIVATE(arg1, arg2, arg3, arg4, arg5) + call baz(arg1, arg2, arg3, arg4, arg5) +!$OMP END PARALLEL + +end subroutine + +!CHECK-DAG: func @_QPfirstprivate_real(%[[ARG1:.*]]: !fir.ref{{.*}}, %[[ARG2:.*]]: !fir.ref{{.*}}, %[[ARG3:.*]]: !fir.ref{{.*}}, %[[ARG4:.*]]: !fir.ref{{.*}}, %[[ARG5:.*]]: !fir.ref{{.*}}, %[[ARG6:.*]]: !fir.ref{{.*}}) { +!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstprivate_realEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFfirstprivate_realEarg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG3_DECL:.*]]:2 = hlfir.declare %[[ARG3]] {uniq_name = "_QFfirstprivate_realEarg3"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG4_DECL:.*]]:2 = hlfir.declare %[[ARG4]] {uniq_name = "_QFfirstprivate_realEarg4"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG5_DECL:.*]]:2 = hlfir.declare %[[ARG5]] {uniq_name = "_QFfirstprivate_realEarg5"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG6_DECL:.*]]:2 = hlfir.declare %[[ARG6]] {uniq_name = "_QFfirstprivate_realEarg6"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.parallel { +!CHECK: %[[ARG1_PVT:.*]] = fir.alloca f32 {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_realEarg1"} +!CHECK: %[[ARG1_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG1_PVT]] {uniq_name = "_QFfirstprivate_realEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG1_VAL:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG1_VAL]] to %[[ARG1_PVT_DECL]]#0 temporary_lhs : f32, !fir.ref +!CHECK: %[[ARG2_PVT:.*]] = fir.alloca f16 {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_realEarg2"} +!CHECK: %[[ARG2_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG2_PVT]] {uniq_name = "_QFfirstprivate_realEarg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG2_VAL:.*]] = fir.load %[[ARG2_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG2_VAL]] to %[[ARG2_PVT_DECL]]#0 temporary_lhs : f16, !fir.ref +!CHECK: %[[ARG3_PVT:.*]] = fir.alloca f32 {bindc_name = "arg3", pinned, uniq_name = "_QFfirstprivate_realEarg3"} +!CHECK: %[[ARG3_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG3_PVT]] {uniq_name = "_QFfirstprivate_realEarg3"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG3_VAL:.*]] = fir.load %[[ARG3_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG3_VAL]] to %[[ARG3_PVT_DECL]]#0 temporary_lhs : f32, !fir.ref +!CHECK: %[[ARG4_PVT:.*]] = fir.alloca f64 {bindc_name = "arg4", pinned, uniq_name = "_QFfirstprivate_realEarg4"} +!CHECK: %[[ARG4_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG4_PVT]] {uniq_name = "_QFfirstprivate_realEarg4"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG4_VAL:.*]] = fir.load %[[ARG4_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG4_VAL]] to %[[ARG4_PVT_DECL]]#0 temporary_lhs : f64, !fir.ref +!CHECK: %[[ARG5_PVT:.*]] = fir.alloca f80 {bindc_name = "arg5", pinned, uniq_name = "_QFfirstprivate_realEarg5"} +!CHECK: %[[ARG5_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG5_PVT]] {uniq_name = "_QFfirstprivate_realEarg5"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG5_VAL:.*]] = fir.load %[[ARG5_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG5_VAL]] to %[[ARG5_PVT_DECL]]#0 temporary_lhs : f80, !fir.ref +!CHECK: %[[ARG6_PVT:.*]] = fir.alloca f128 {bindc_name = "arg6", pinned, uniq_name = "_QFfirstprivate_realEarg6"} +!CHECK: %[[ARG6_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG6_PVT]] {uniq_name = "_QFfirstprivate_realEarg6"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG6_VAL:.*]] = fir.load %[[ARG6_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[ARG6_VAL]] to %[[ARG6_PVT_DECL]]#0 temporary_lhs : f128, !fir.ref +!CHECK: fir.call @_QPqux(%[[ARG1_PVT_DECL]]#1, %[[ARG2_PVT_DECL]]#1, %[[ARG3_PVT_DECL]]#1, %[[ARG4_PVT_DECL]]#1, %[[ARG5_PVT_DECL]]#1, %[[ARG6_PVT_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref, !fir.ref, !fir.ref, !fir.ref, !fir.ref) -> () +!CHECK: omp.terminator +!CHECK: } + +subroutine firstprivate_real(arg1, arg2, arg3, arg4, arg5, arg6) + real :: arg1 + real(kind=2) :: arg2 + real(kind=4) :: arg3 + real(kind=8) :: arg4 + real(kind=10) :: arg5 + real(kind=16) :: arg6 + +!$OMP PARALLEL FIRSTPRIVATE(arg1, arg2, arg3, arg4, arg5, arg6) + call qux(arg1, arg2, arg3, arg4, arg5, arg6) +!$OMP END PARALLEL + +end subroutine + +!CHECK-LABEL: func.func @_QPmultiple_firstprivate( +!CHECK-SAME: %[[A_ADDR:.*]]: !fir.ref {fir.bindc_name = "a"}, +!CHECK-SAME: %[[B_ADDR:.*]]: !fir.ref {fir.bindc_name = "b"}) { +!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_ADDR]] {uniq_name = "_QFmultiple_firstprivateEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[B_DECL:.*]]:2 = hlfir.declare %[[B_ADDR]] {uniq_name = "_QFmultiple_firstprivateEb"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.parallel { +!CHECK: %[[A_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFmultiple_firstprivateEa"} +!CHECK: %[[A_PRIV_DECL:.*]]:2 = hlfir.declare %[[A_PRIV_ADDR]] {uniq_name = "_QFmultiple_firstprivateEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[A:.*]] = fir.load %[[A_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[A]] to %[[A_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK: %[[B_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "b", pinned, uniq_name = "_QFmultiple_firstprivateEb"} +!CHECK: %[[B_PRIV_DECL:.*]]:2 = hlfir.declare %[[B_PRIV_ADDR]] {uniq_name = "_QFmultiple_firstprivateEb"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[B:.*]] = fir.load %[[B_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[B]] to %[[B_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK: fir.call @_QPquux(%[[A_PRIV_DECL]]#1, %[[B_PRIV_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref) -> () +!CHECK: omp.terminator +!CHECK: } +!CHECK: return +!CHECK: } + +subroutine multiple_firstprivate(a, b) + integer :: a, b +!$OMP PARALLEL FIRSTPRIVATE(a) FIRSTPRIVATE(b) + call quux(a, b) +!$OMP END PARALLEL +end subroutine multiple_firstprivate diff --git a/flang/test/Lower/OpenMP/parallel-lastprivate-clause-scalar.f90 b/flang/test/Lower/OpenMP/parallel-lastprivate-clause-scalar.f90 new file mode 100644 index 0000000000000..abd14f455123b --- /dev/null +++ b/flang/test/Lower/OpenMP/parallel-lastprivate-clause-scalar.f90 @@ -0,0 +1,253 @@ +! This test checks lowering of `LASTPRIVATE` clause for scalar types. + +! RUN: bbc -fopenmp -emit-hlfir %s -o - | FileCheck %s +! RUN: flang-new -fc1 -fopenmp -emit-hlfir %s -o - | FileCheck %s + +!CHECK: func @_QPlastprivate_character(%[[ARG1:.*]]: !fir.boxchar<1>{{.*}}) { +!CHECK-DAG: %[[ARG1_UNBOX:.*]]:2 = fir.unboxchar +!CHECK-DAG: %[[FIVE:.*]] = arith.constant 5 : index +!CHECK-DAG: %[[ARG1_REF:.*]] = fir.convert %[[ARG1_UNBOX]]#0 : (!fir.ref>) -> !fir.ref> +!CHECK-DAG: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1_REF]] typeparams %[[FIVE]] {uniq_name = "_QFlastprivate_characterEarg1"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) + +!CHECK: omp.parallel { +!CHECK-DAG: %[[ARG1_PVT:.*]] = fir.alloca !fir.char<1,5> {bindc_name = "arg1", +!CHECK-DAG: %[[ARG1_PVT_DECL:.*]]:2 = hlfir.declare %[[ARG1_PVT]] typeparams %[[FIVE]] {uniq_name = "_QFlastprivate_characterEarg1"} : (!fir.ref>, index) -> (!fir.ref>, !fir.ref>) + +! Check that we are accessing the clone inside the loop +!CHECK-DAG: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} { +!CHECK-DAG: %[[NEG_ONE:.*]] = arith.constant -1 : i32 +!CHECK-NEXT: %[[ADDR:.*]] = fir.address_of(@_QQcl. +!CHECK-NEXT: %[[CVT0:.*]] = fir.convert %[[ADDR]] +!CHECK-NEXT: %[[CNST:.*]] = arith.constant +!CHECK-NEXT: %[[CALL_BEGIN_IO:.*]] = fir.call @_FortranAioBeginExternalListOutput(%[[NEG_ONE]], %[[CVT0]], %[[CNST]]) {{.*}}: (i32, !fir.ref, i32) -> !fir.ref +!CHECK-NEXT: %[[CVT_0_1:.*]] = fir.convert %[[ARG1_PVT_DECL]]#1 +!CHECK-NEXT: %[[CVT_0_2:.*]] = fir.convert %[[FIVE]] +!CHECK-NEXT: %[[CALL_OP_ASCII:.*]] = fir.call @_FortranAioOutputAscii(%[[CALL_BEGIN_IO]], %[[CVT_0_1]], %[[CVT_0_2]]) +!CHECK-NEXT: %[[CALL_END_IO:.*]] = fir.call @_FortranAioEndIoStatement(%[[CALL_BEGIN_IO]]) + +! Testing last iteration check +!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32 +!CHECK: %[[C0:.*]] = arith.constant 0 : i32 +!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32 +!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32 +!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32 +!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1 +!CHECK: fir.if %[[IV_CMP]] { +!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref + +! Testing lastprivate val update +!CHECK-DAG: hlfir.assign %[[ARG1_PVT_DECL]]#0 to %[[ARG1_DECL]]#0 temporary_lhs : !fir.ref>, !fir.ref> +!CHECK-DAG: } +!CHECK-DAG: omp.yield + +subroutine lastprivate_character(arg1) + character(5) :: arg1 +!$OMP PARALLEL +!$OMP DO LASTPRIVATE(arg1) +do n = 1, 5 + arg1(n:n) = 'c' + print *, arg1 +end do +!$OMP END DO +!$OMP END PARALLEL +end subroutine + +!CHECK: func @_QPlastprivate_int(%[[ARG1:.*]]: !fir.ref {fir.bindc_name = "arg1"}) { +!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFlastprivate_intEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK-DAG: omp.parallel { +!CHECK-DAG: %[[CLONE:.*]] = fir.alloca i32 {bindc_name = "arg1" +!CHECK-DAG: %[[CLONE_DECL:.*]]:2 = hlfir.declare %[[CLONE]] {uniq_name = "_QFlastprivate_intEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} { + +! Testing last iteration check +!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32 +!CHECK: %[[C0:.*]] = arith.constant 0 : i32 +!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32 +!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32 +!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32 +!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1 +!CHECK: fir.if %[[IV_CMP]] { +!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref + +! Testing lastprivate val update +!CHECK-NEXT: %[[CLONE_LD:.*]] = fir.load %[[CLONE_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[CLONE_LD]] to %[[ARG1_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK-DAG: } +!CHECK-DAG: omp.yield + +subroutine lastprivate_int(arg1) + integer :: arg1 +!$OMP PARALLEL +!$OMP DO LASTPRIVATE(arg1) +do n = 1, 5 + arg1 = 2 + print *, arg1 +end do +!$OMP END DO +!$OMP END PARALLEL +print *, arg1 +end subroutine + +!CHECK: func.func @_QPmult_lastprivate_int(%[[ARG1:.*]]: !fir.ref {fir.bindc_name = "arg1"}, %[[ARG2:.*]]: !fir.ref {fir.bindc_name = "arg2"}) { +!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFmult_lastprivate_intEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFmult_lastprivate_intEarg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.parallel { +!CHECK-DAG: %[[CLONE1:.*]] = fir.alloca i32 {bindc_name = "arg1" +!CHECK-DAG: %[[CLONE1_DECL:.*]]:2 = hlfir.declare %[[CLONE1]] {uniq_name = "_QFmult_lastprivate_intEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK-DAG: %[[CLONE2:.*]] = fir.alloca i32 {bindc_name = "arg2" +!CHECK-DAG: %[[CLONE2_DECL:.*]]:2 = hlfir.declare %[[CLONE2]] {uniq_name = "_QFmult_lastprivate_intEarg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} { + +! Testing last iteration check +!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32 +!CHECK: %[[C0:.*]] = arith.constant 0 : i32 +!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32 +!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32 +!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32 +!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1 +!CHECK: fir.if %[[IV_CMP]] { +!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref +! Testing lastprivate val update +!CHECK-DAG: %[[CLONE_LD1:.*]] = fir.load %[[CLONE1_DECL]]#0 : !fir.ref +!CHECK-DAG: hlfir.assign %[[CLONE_LD1]] to %[[ARG1_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK-DAG: %[[CLONE_LD2:.*]] = fir.load %[[CLONE2_DECL]]#0 : !fir.ref +!CHECK-DAG: hlfir.assign %[[CLONE_LD2]] to %[[ARG2_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK: } +!CHECK: omp.yield + +subroutine mult_lastprivate_int(arg1, arg2) + integer :: arg1, arg2 +!$OMP PARALLEL +!$OMP DO LASTPRIVATE(arg1) LASTPRIVATE(arg2) +do n = 1, 5 + arg1 = 2 + arg2 = 3 + print *, arg1, arg2 +end do +!$OMP END DO +!$OMP END PARALLEL +print *, arg1, arg2 +end subroutine + +!CHECK: func.func @_QPmult_lastprivate_int2(%[[ARG1:.*]]: !fir.ref {fir.bindc_name = "arg1"}, %[[ARG2:.*]]: !fir.ref {fir.bindc_name = "arg2"}) { +!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %arg0 {uniq_name = "_QFmult_lastprivate_int2Earg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %arg1 {uniq_name = "_QFmult_lastprivate_int2Earg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.parallel { +!CHECK-DAG: %[[CLONE1:.*]] = fir.alloca i32 {bindc_name = "arg1" +!CHECK-DAG: %[[CLONE1_DECL:.*]]:2 = hlfir.declare %[[CLONE1]] {uniq_name = "_QFmult_lastprivate_int2Earg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK-DAG: %[[CLONE2:.*]] = fir.alloca i32 {bindc_name = "arg2" +!CHECK-DAG: %[[CLONE2_DECL:.*]]:2 = hlfir.declare %[[CLONE2]] {uniq_name = "_QFmult_lastprivate_int2Earg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} { + +!Testing last iteration check +!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32 +!CHECK: %[[C0:.*]] = arith.constant 0 : i32 +!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32 +!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32 +!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32 +!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1 +!CHECK: fir.if %[[IV_CMP]] { +!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref +!Testing lastprivate val update +!CHECK-DAG: %[[CLONE_LD2:.*]] = fir.load %[[CLONE2_DECL]]#0 : !fir.ref +!CHECK-DAG: hlfir.assign %[[CLONE_LD2]] to %[[ARG2_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK-DAG: %[[CLONE_LD1:.*]] = fir.load %[[CLONE1_DECL]]#0 : !fir.ref +!CHECK-DAG: hlfir.assign %[[CLONE_LD1]] to %[[ARG1_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK: } +!CHECK: omp.yield + +subroutine mult_lastprivate_int2(arg1, arg2) + integer :: arg1, arg2 +!$OMP PARALLEL +!$OMP DO LASTPRIVATE(arg1, arg2) +do n = 1, 5 + arg1 = 2 + arg2 = 3 + print *, arg1, arg2 +end do +!$OMP END DO +!$OMP END PARALLEL +print *, arg1, arg2 +end subroutine + +!CHECK: func.func @_QPfirstpriv_lastpriv_int(%[[ARG1:.*]]: !fir.ref {fir.bindc_name = "arg1"}, %[[ARG2:.*]]: !fir.ref {fir.bindc_name = "arg2"}) { +!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstpriv_lastpriv_intEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFfirstpriv_lastpriv_intEarg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.parallel { +! Firstprivate update +!CHECK: %[[CLONE1:.*]] = fir.alloca i32 {bindc_name = "arg1" +!CHECK: %[[CLONE1_DECL:.*]]:2 = hlfir.declare %[[CLONE1]] {uniq_name = "_QFfirstpriv_lastpriv_intEarg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: %[[FPV_LD:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref +!CHECK: hlfir.assign %[[FPV_LD]] to %[[CLONE1_DECL]]#0 temporary_lhs : i32, !fir.ref +! Lastprivate Allocation +!CHECK: %[[CLONE2:.*]] = fir.alloca i32 {bindc_name = "arg2" +!CHECK: %[[CLONE2_DECL:.*]]:2 = hlfir.declare %[[CLONE2]] {uniq_name = "_QFfirstpriv_lastpriv_intEarg2"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK-NOT: omp.barrier +!CHECK: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} { + +! Testing last iteration check +!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32 +!CHECK: %[[C0:.*]] = arith.constant 0 : i32 +!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32 +!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32 +!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32 +!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1 +!CHECK: fir.if %[[IV_CMP]] { +!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref +! Testing lastprivate val update +!CHECK-NEXT: %[[CLONE_LD:.*]] = fir.load %[[CLONE2_DECL]]#0 : !fir.ref +!CHECK-NEXT: hlfir.assign %[[CLONE_LD]] to %[[ARG2_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK-NEXT: } +!CHECK-NEXT: omp.yield + +subroutine firstpriv_lastpriv_int(arg1, arg2) + integer :: arg1, arg2 +!$OMP PARALLEL +!$OMP DO FIRSTPRIVATE(arg1) LASTPRIVATE(arg2) +do n = 1, 5 + arg1 = 2 + arg2 = 3 + print *, arg1, arg2 +end do +!$OMP END DO +!$OMP END PARALLEL +print *, arg1, arg2 +end subroutine + +!CHECK: func.func @_QPfirstpriv_lastpriv_int2(%[[ARG1:.*]]: !fir.ref {fir.bindc_name = "arg1"}) { +!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstpriv_lastpriv_int2Earg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK: omp.parallel { +! Firstprivate update +!CHECK: %[[CLONE1:.*]] = fir.alloca i32 {bindc_name = "arg1" +!CHECK: %[[CLONE1_DECL:.*]]:2 = hlfir.declare %[[CLONE1]] {uniq_name = "_QFfirstpriv_lastpriv_int2Earg1"} : (!fir.ref) -> (!fir.ref, !fir.ref) +!CHECK-NEXT: %[[FPV_LD:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref +!CHECK-NEXT: hlfir.assign %[[FPV_LD]] to %[[CLONE1_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK-NEXT: omp.barrier +!CHECK: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} { +! Testing last iteration check +!CHECK: %[[V:.*]] = arith.addi %[[INDX_WS]], %{{.*}} : i32 +!CHECK: %[[C0:.*]] = arith.constant 0 : i32 +!CHECK: %[[T1:.*]] = arith.cmpi slt, %{{.*}}, %[[C0]] : i32 +!CHECK: %[[T2:.*]] = arith.cmpi slt, %[[V]], %{{.*}} : i32 +!CHECK: %[[T3:.*]] = arith.cmpi sgt, %[[V]], %{{.*}} : i32 +!CHECK: %[[IV_CMP:.*]] = arith.select %[[T1]], %[[T2]], %[[T3]] : i1 +!CHECK: fir.if %[[IV_CMP]] { +!CHECK: fir.store %[[V]] to %{{.*}} : !fir.ref +! Testing lastprivate val update +!CHECK-NEXT: %[[CLONE_LD:.*]] = fir.load %[[CLONE1_DECL]]#0 : !fir.ref +!CHECK-NEXT: hlfir.assign %[[CLONE_LD]] to %[[ARG1_DECL]]#0 temporary_lhs : i32, !fir.ref +!CHECK-NEXT: } +!CHECK-NEXT: omp.yield + +subroutine firstpriv_lastpriv_int2(arg1) + integer :: arg1 +!$OMP PARALLEL +!$OMP DO FIRSTPRIVATE(arg1) LASTPRIVATE(arg1) +do n = 1, 5 + arg1 = 2 + print *, arg1 +end do +!$OMP END DO +!$OMP END PARALLEL +print *, arg1 +end subroutine diff --git a/flang/test/Lower/OpenMP/parallel-private-clause.f90 b/flang/test/Lower/OpenMP/parallel-private-clause.f90 new file mode 100644 index 0000000000000..8d288f6483493 --- /dev/null +++ b/flang/test/Lower/OpenMP/parallel-private-clause.f90 @@ -0,0 +1,380 @@ +! This test checks lowering of OpenMP parallel Directive with +! `PRIVATE` clause present. + +! REQUIRES: shell +! RUN: bbc --use-desc-for-alloc=false -fopenmp -emit-fir %s -o - | \ +! RUN: FileCheck %s --check-prefix=FIRDialect + +!FIRDialect: func @_QPprivate_clause(%[[ARG1:.*]]: !fir.ref{{.*}}, %[[ARG2:.*]]: !fir.ref>{{.*}}, %[[ARG3:.*]]: !fir.boxchar<1>{{.*}}, %[[ARG4:.*]]: !fir.boxchar<1>{{.*}}) { +!FIRDialect-DAG: %[[ALPHA:.*]] = fir.alloca i32 {{{.*}}, uniq_name = "{{.*}}Ealpha"} +!FIRDialect-DAG: %[[ALPHA_ARRAY:.*]] = fir.alloca !fir.array<10xi32> {{{.*}}, uniq_name = "{{.*}}Ealpha_array"} +!FIRDialect-DAG: %[[BETA:.*]] = fir.alloca !fir.char<1,5> {{{.*}}, uniq_name = "{{.*}}Ebeta"} +!FIRDialect-DAG: %[[BETA_ARRAY:.*]] = fir.alloca !fir.array<10x!fir.char<1,5>> {{{.*}}, uniq_name = "{{.*}}Ebeta_array"} + +!FIRDialect-DAG: omp.parallel { +!FIRDialect-DAG: %[[ALPHA_PRIVATE:.*]] = fir.alloca i32 {{{.*}}, pinned, uniq_name = "{{.*}}Ealpha"} +!FIRDialect-DAG: %[[ALPHA_ARRAY_PRIVATE:.*]] = fir.alloca !fir.array<10xi32> {{{.*}}, pinned, uniq_name = "{{.*}}Ealpha_array"} +!FIRDialect-DAG: %[[BETA_PRIVATE:.*]] = fir.alloca !fir.char<1,5> {{{.*}}, pinned, uniq_name = "{{.*}}Ebeta"} +!FIRDialect-DAG: %[[BETA_ARRAY_PRIVATE:.*]] = fir.alloca !fir.array<10x!fir.char<1,5>> {{{.*}}, pinned, uniq_name = "{{.*}}Ebeta_array"} +!FIRDialect-DAG: %[[ARG1_PRIVATE:.*]] = fir.alloca i32 {{{.*}}, pinned, uniq_name = "{{.*}}Earg1"} +!FIRDialect-DAG: %[[ARG2_ARRAY_PRIVATE:.*]] = fir.alloca !fir.array<10xi32> {{{.*}}, pinned, uniq_name = "{{.*}}Earg2"} +!FIRDialect-DAG: %[[ARG3_PRIVATE:.*]] = fir.alloca !fir.char<1,5> {{{.*}}, pinned, uniq_name = "{{.*}}Earg3"} +!FIRDialect-DAG: %[[ARG4_ARRAY_PRIVATE:.*]] = fir.alloca !fir.array<10x!fir.char<1,5>> {{{.*}}, pinned, uniq_name = "{{.*}}Earg4"} +!FIRDialect: omp.terminator +!FIRDialect: } + +subroutine private_clause(arg1, arg2, arg3, arg4) + + integer :: arg1, arg2(10) + integer :: alpha, alpha_array(10) + character(5) :: arg3, arg4(10) + character(5) :: beta, beta_array(10) + +!$OMP PARALLEL PRIVATE(alpha, alpha_array, beta, beta_array, arg1, arg2, arg3, arg4) + alpha = 1 + alpha_array = 4 + beta = "hi" + beta_array = "hi" + arg1 = 2 + arg2 = 3 + arg3 = "world" + arg4 = "world" +!$OMP END PARALLEL + +end subroutine + +!FIRDialect: func @_QPprivate_clause_scalar() { +!FIRDialect-DAG: {{.*}} = fir.alloca !fir.complex<4> {bindc_name = "c", uniq_name = "{{.*}}Ec"} +!FIRDialect-DAG: {{.*}} = fir.alloca i8 {bindc_name = "i1", uniq_name = "{{.*}}Ei1"} +!FIRDialect-DAG: {{.*}} = fir.alloca i128 {bindc_name = "i16", uniq_name = "{{.*}}Ei16"} +!FIRDialect-DAG: {{.*}} = fir.alloca i16 {bindc_name = "i2", uniq_name = "{{.*}}Ei2"} +!FIRDialect-DAG: {{.*}} = fir.alloca i32 {bindc_name = "i4", uniq_name = "{{.*}}Ei4"} +!FIRDialect-DAG: {{.*}} = fir.alloca i64 {bindc_name = "i8", uniq_name = "{{.*}}Ei8"} +!FIRDialect-DAG: {{.*}} = fir.alloca !fir.logical<4> {bindc_name = "l", uniq_name = "{{.*}}El"} +!FIRDialect-DAG: {{.*}} = fir.alloca f32 {bindc_name = "r", uniq_name = "{{.*}}Er"} + +!FIRDialect: omp.parallel { +!FIRDialect-DAG: {{.*}} = fir.alloca i8 {bindc_name = "i1", pinned, uniq_name = "{{.*}}Ei1"} +!FIRDialect-DAG: {{.*}} = fir.alloca i16 {bindc_name = "i2", pinned, uniq_name = "{{.*}}Ei2"} +!FIRDialect-DAG: {{.*}} = fir.alloca i32 {bindc_name = "i4", pinned, uniq_name = "{{.*}}Ei4"} +!FIRDialect-DAG: {{.*}} = fir.alloca i64 {bindc_name = "i8", pinned, uniq_name = "{{.*}}Ei8"} +!FIRDialect-DAG: {{.*}} = fir.alloca i128 {bindc_name = "i16", pinned, uniq_name = "{{.*}}Ei16"} +!FIRDialect-DAG: {{.*}} = fir.alloca !fir.complex<4> {bindc_name = "c", pinned, uniq_name = "{{.*}}Ec"} +!FIRDialect-DAG: {{.*}} = fir.alloca !fir.logical<4> {bindc_name = "l", pinned, uniq_name = "{{.*}}El"} +!FIRDialect-DAG: {{.*}} = fir.alloca f32 {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"} + +subroutine private_clause_scalar() + + integer(kind=1) :: i1 + integer(kind=2) :: i2 + integer(kind=4) :: i4 + integer(kind=8) :: i8 + integer(kind=16) :: i16 + complex :: c + logical :: l + real :: r + +!$OMP PARALLEL PRIVATE(i1, i2, i4, i8, i16, c, l, r) + print *, i1, i2, i4, i8, i16, c, l, r +!$OMP END PARALLEL + +end subroutine + +!FIRDialect: func @_QPprivate_clause_derived_type() { +!FIRDialect: {{.*}} = fir.alloca !fir.type<{{.*}}{t_i:i32,t_arr:!fir.array<5xi32>}> {bindc_name = "t", uniq_name = "{{.*}}Et"} + +!FIRDialect: omp.parallel { +!FIRDialect: {{.*}} = fir.alloca !fir.type<{{.*}}{t_i:i32,t_arr:!fir.array<5xi32>}> {bindc_name = "t", pinned, uniq_name = "{{.*}}Et"} + +subroutine private_clause_derived_type() + + type my_type + integer :: t_i + integer :: t_arr(5) + end type my_type + type(my_type) :: t + +!$OMP PARALLEL PRIVATE(t) + print *, t%t_i +!$OMP END PARALLEL + +end subroutine + +!FIRDialect: func @_QPprivate_clause_allocatable() { +!FIRDialect-DAG: {{.*}} = fir.alloca !fir.box> {bindc_name = "x", uniq_name = "{{.*}}Ex"} +!FIRDialect-DAG: {{.*}} = fir.alloca !fir.heap {uniq_name = "{{.*}}Ex.addr"} +!FIRDialect-DAG: {{.*}} = fir.alloca !fir.box>> {bindc_name = "x2", uniq_name = "{{.*}}Ex2"} +!FIRDialect-DAG: {{.*}} = fir.alloca !fir.heap> {uniq_name = "{{.*}}Ex2.addr"} +!FIRDialect-DAG: {{.*}} = fir.address_of(@{{.*}}Ex3) : !fir.ref>> +!FIRDialect-DAG: [[TMP8:%.*]] = fir.address_of(@{{.*}}Ex4) : !fir.ref>>> + +!FIRDialect: omp.parallel { +!FIRDialect-DAG: [[TMP35:%.*]] = fir.alloca !fir.box> {bindc_name = "x", pinned, uniq_name = "{{.*}}Ex"} +!FIRDialect-DAG: [[TMP39:%.*]] = fir.alloca !fir.box>> {bindc_name = "x2", pinned, uniq_name = "{{.*}}Ex2"} +!FIRDialect-DAG: [[TMP45:%.*]] = fir.alloca !fir.box> {bindc_name = "x3", pinned, uniq_name = "{{.*}}Ex3"} + +!FIRDialect-DAG: [[TMP51:%.*]] = fir.load [[TMP8]] : !fir.ref>>> +!FIRDialect-DAG: [[TMP97:%.*]] = fir.load [[TMP8]] : !fir.ref>>> +!FIRDialect-DAG: [[TMP98:%.*]]:3 = fir.box_dims [[TMP97]], {{.*}} : (!fir.box>>, index) -> (index, index, index) +!FIRDialect-DAG: [[TMP50:%.*]] = fir.alloca !fir.box>> {bindc_name = "x4", pinned, uniq_name = "{{.*}}Ex4"} + +! FIRDialect-DAG: [[TMP101:%.*]] = fir.allocmem !fir.array, {{.*}} {fir.must_be_heap = true, uniq_name = "{{.*}}Ex4.alloc"} +! FIRDialect-DAG: [[TMP102:%.*]] = fir.shape_shift {{.*}}#0, {{.*}} : (index, index) -> !fir.shapeshift<1> +! FIRDialect-DAG: [[TMP103:%.*]] = fir.embox [[TMP101]]([[TMP102]]) : (!fir.heap>, !fir.shapeshift<1>) -> !fir.box>> +! FIRDialect-DAG: fir.store [[TMP103]] to [[TMP50]] : !fir.ref>>> + + +subroutine private_clause_allocatable() + + integer, allocatable :: x, x2(:) + integer, allocatable, save :: x3, x4(:) + + print *, x, x2, x3, x4 + +!$OMP PARALLEL PRIVATE(x, x2, x3, x4) + print *, x, x2, x3, x4 +!$OMP END PARALLEL + +end subroutine + + +!FIRDialect: func @_QPprivate_clause_real_call_allocatable() { +!FIRDialect-DAG: {{.*}} = fir.alloca !fir.box> {bindc_name = "x5", uniq_name = "{{.*}}Ex5"} +!FIRDialect-DAG: {{.*}} = fir.zero_bits !fir.heap +!FIRDialect-DAG: {{.*}} = fir.embox %1 : (!fir.heap) -> !fir.box> +!FIRDialect-DAG: fir.store %2 to %0 : !fir.ref>> +!FIRDialect-DAG: omp.parallel { +!FIRDialect-DAG: [[TMP203:%.*]] = fir.alloca !fir.box> {bindc_name = "x5", pinned, uniq_name = "{{.*}}Ex5"} + +!FIRDialect-DAG: fir.if %{{.*}} { + +!FIRDialect-DAG: fir.store %{{.*}} to [[TMP203]] : !fir.ref>> +!FIRDialect-DAG: } else { + +!FIRDialect-DAG: fir.store %{{.*}} to [[TMP203]] : !fir.ref>> +!FIRDialect-DAG: } +!FIRDialect-DAG: fir.call @_QFprivate_clause_real_call_allocatablePhelper_private_clause_real_call_allocatable([[TMP203]]) fastmath : (!fir.ref>>) -> () +!FIRDialect-DAG: %{{.*}} = fir.load [[TMP203]] : !fir.ref>> + +!FIRDialect-DAG: fir.if %{{.*}} { +!FIRDialect-DAG: %{{.*}} = fir.load [[TMP203]] : !fir.ref>> + +!FIRDialect-DAG: fir.store %{{.*}} to [[TMP203]] : !fir.ref>> +!FIRDialect-DAG: } +!FIRDialect-DAG: omp.terminator +!FIRDialect-DAG: } +!FIRDialect-DAG: return +!FIRDialect-DAG: } + + +subroutine private_clause_real_call_allocatable + real, allocatable :: x5 + !$omp parallel private(x5) + call helper_private_clause_real_call_allocatable(x5) + !$omp end parallel + contains + subroutine helper_private_clause_real_call_allocatable(x6) + real, allocatable :: x6 + print *, allocated(x6) + end subroutine +end subroutine + +!FIRDialect: func.func @_QPincrement_list_items(%arg0: !fir.ref>>}>>>> {fir.bindc_name = "head"}) { +!FIRDialect: {{%.*}} = fir.alloca !fir.box>>}>>> {bindc_name = "p", uniq_name = "_QFincrement_list_itemsEp"} +!FIRDialect: omp.parallel { +!FIRDialect: {{%.*}} = fir.alloca !fir.box>>}>>> {bindc_name = "p", pinned, uniq_name = "_QFincrement_list_itemsEp"} +!FIRDialect: omp.single { + +!FIRDialect: omp.terminator +!FIRDialect: omp.terminator +!FIRDialect: return + +subroutine increment_list_items (head) + type node + integer :: payload + type (node), pointer :: next + end type node + + type (node), pointer :: head + type (node), pointer :: p +!$omp parallel private(p) +!$omp single + p => head + do + p => p%next + if ( associated (p) .eqv. .false. ) exit + end do +!$omp end single +!$omp end parallel +end subroutine increment_list_items + +!FIRDialect: func.func @_QPparallel_pointer() { +!FIRDialect-DAG: [[PP0:%.*]] = fir.alloca !fir.box> {bindc_name = "y1", uniq_name = "{{.*}}Ey1"} +!FIRDialect-DAG: [[PP1:%.*]] = fir.alloca !fir.ptr {uniq_name = "{{.*}}Ey1.addr"} +!FIRDialect-DAG: [[PP2:%.*]] = fir.zero_bits !fir.ptr +!FIRDialect: fir.store [[PP2]] to [[PP1]] : !fir.ref> +!FIRDialect-DAG: [[PP3:%.*]] = fir.alloca !fir.box>> {bindc_name = "y2", uniq_name = "{{.*}}Ey2"} + +!FIRDialect: fir.store %6 to %3 : !fir.ref>>> +!FIRDialect-DAG: [[PP7:%.*]] = fir.alloca i32 {bindc_name = "z1", fir.target, uniq_name = "{{.*}}Ez1"} + +!FIRDialect-DAG: [[PP8:%.*]] = fir.alloca !fir.array<10xi32> {bindc_name = "z2", fir.target, uniq_name = "{{.*}}Ez2"} +!FIRDialect: omp.parallel { +!FIRDialect-DAG: [[PP9:%.*]] = fir.alloca !fir.box> {bindc_name = "y1", pinned, uniq_name = "{{.*}}Ey1"} +!FIRDialect-DAG: [[PP10:%.*]] = fir.alloca !fir.box>> {bindc_name = "y2", pinned, uniq_name = "{{.*}}Ey2"} +!FIRDialect-DAG: [[PP11:%.*]] = fir.embox [[PP7]] : (!fir.ref) -> !fir.box> +!FIRDialect: fir.store [[PP11]] to [[PP9]] : !fir.ref>> +!FIRDialect-DAG: [[PP12:%.*]] = fir.shape %c{{.*}} : (index) -> !fir.shape<1> +!FIRDialect-DAG: [[PP13:%.*]] = fir.embox [[PP8]]([[PP12]]) : (!fir.ref>, !fir.shape<1>) -> !fir.box>> +!FIRDialect: fir.store %13 to [[PP10]] : !fir.ref>>> +!FIRDialect: omp.terminator +!FIRDialect: } +!FIRDialect: return +!FIRDialect: } + +subroutine parallel_pointer() + integer, pointer :: y1, y2(:) + integer, target :: z1, z2(10) + +!$omp parallel private(y1, y2) + y1=>z1 + y2=>z2 +!$omp end parallel +end subroutine parallel_pointer + + +!FIRDialect-LABEL: func @_QPsimple_loop_1() +subroutine simple_loop_1 + integer :: i + real, allocatable :: r; + ! FIRDialect: omp.parallel + !$OMP PARALLEL PRIVATE(r) + ! FIRDialect: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned} + + ! FIRDialect: [[R:%.*]] = fir.alloca !fir.box> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"} + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + + ! FIRDialect: %[[WS_LB:.*]] = arith.constant 1 : i32 + ! FIRDialect: %[[WS_UB:.*]] = arith.constant 9 : i32 + ! FIRDialect: %[[WS_STEP:.*]] = arith.constant 1 : i32 + + ! FIRDialect: omp.wsloop for (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) + !$OMP DO + do i=1, 9 + ! FIRDialect: fir.store %[[I]] to %[[ALLOCA_IV:.*]] : !fir.ref + ! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV]] : !fir.ref + ! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 + print*, i + end do + ! FIRDialect: omp.yield + ! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref>> + ! FIRDialect: fir.if {{%.*}} { + ! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref>> + ! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box>) -> !fir.heap + ! FIRDialect: fir.freemem [[AD]] : !fir.heap + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + !$OMP END DO + ! FIRDialect: omp.terminator + !$OMP END PARALLEL +end subroutine + +!FIRDialect-LABEL: func @_QPsimple_loop_2() +subroutine simple_loop_2 + integer :: i + real, allocatable :: r; + ! FIRDialect: omp.parallel + !$OMP PARALLEL + ! FIRDialect: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned} + + ! FIRDialect: [[R:%.*]] = fir.alloca !fir.box> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"} + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + + ! FIRDialect: %[[WS_LB:.*]] = arith.constant 1 : i32 + ! FIRDialect: %[[WS_UB:.*]] = arith.constant 9 : i32 + ! FIRDialect: %[[WS_STEP:.*]] = arith.constant 1 : i32 + + ! FIRDialect: omp.wsloop for (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) + !$OMP DO PRIVATE(r) + do i=1, 9 + ! FIRDialect: fir.store %[[I]] to %[[ALLOCA_IV:.*]] : !fir.ref + ! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV]] : !fir.ref + ! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 + print*, i + end do + ! FIRDialect: omp.yield + ! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref>> + ! FIRDialect: fir.if {{%.*}} { + ! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref>> + ! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box>) -> !fir.heap + ! FIRDialect: fir.freemem [[AD]] : !fir.heap + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + !$OMP END DO + ! FIRDialect: omp.terminator + !$OMP END PARALLEL +end subroutine + +!FIRDialect-LABEL: func @_QPsimple_loop_3() +subroutine simple_loop_3 + integer :: i + real, allocatable :: r; + ! FIRDialect: omp.parallel + ! FIRDialect: %[[ALLOCA_IV:.*]] = fir.alloca i32 {{{.*}}, pinned} + + ! FIRDialect: [[R:%.*]] = fir.alloca !fir.box> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"} + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + + ! FIRDialect: %[[WS_LB:.*]] = arith.constant 1 : i32 + ! FIRDialect: %[[WS_UB:.*]] = arith.constant 9 : i32 + ! FIRDialect: %[[WS_STEP:.*]] = arith.constant 1 : i32 + + ! FIRDialect: omp.wsloop for (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) + !$OMP PARALLEL DO PRIVATE(r) + do i=1, 9 + ! FIRDialect: fir.store %[[I]] to %[[ALLOCA_IV:.*]] : !fir.ref + ! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV]] : !fir.ref + ! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 + print*, i + end do + ! FIRDialect: omp.yield + ! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref>> + ! FIRDialect: fir.if {{%.*}} { + ! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref>> + ! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box>) -> !fir.heap + ! FIRDialect: fir.freemem [[AD]] : !fir.heap + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + !$OMP END PARALLEL DO + ! FIRDialect: omp.terminator +end subroutine + +!CHECK-LABEL: func @_QPsimd_loop_1() +subroutine simd_loop_1 + integer :: i + real, allocatable :: r; + ! FIRDialect: [[R:%.*]] = fir.alloca !fir.box> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"} + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> + + ! FIRDialect: %[[LB:.*]] = arith.constant 1 : i32 + ! FIRDialect: %[[UB:.*]] = arith.constant 9 : i32 + ! FIRDialect: %[[STEP:.*]] = arith.constant 1 : i32 + + ! FIRDialect: omp.simdloop for (%[[I:.*]]) : i32 = (%[[LB]]) to (%[[UB]]) inclusive step (%[[STEP]]) { + !$OMP SIMD PRIVATE(r) + do i=1, 9 + ! FIRDialect: fir.store %[[I]] to %[[LOCAL:.*]] : !fir.ref + ! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[LOCAL]] : !fir.ref + ! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 + print*, i + end do + !$OMP END SIMD + ! FIRDialect: omp.yield + ! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref>> + ! FIRDialect: fir.if {{%.*}} { + ! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref>> + ! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box>) -> !fir.heap + ! FIRDialect: fir.freemem [[AD]] : !fir.heap + ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref>> +end subroutine diff --git a/flang/test/Lower/OpenMP/parallel-wsloop.f90 b/flang/test/Lower/OpenMP/parallel-wsloop.f90 new file mode 100644 index 0000000000000..c06f941b74b58 --- /dev/null +++ b/flang/test/Lower/OpenMP/parallel-wsloop.f90 @@ -0,0 +1,298 @@ +! This test checks lowering of OpenMP DO Directive (Worksharing). + +! RUN: bbc -fopenmp -emit-hlfir %s -o - | FileCheck %s + +! CHECK-LABEL: func @_QPsimple_parallel_do() +subroutine simple_parallel_do + integer :: i + ! CHECK: omp.parallel + ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 + ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 + ! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 + ! CHECK: omp.wsloop for (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) + !$OMP PARALLEL DO + do i=1, 9 + ! CHECK: fir.store %[[I]] to %[[IV_ADDR:.*]]#1 : !fir.ref + ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_ADDR]]#0 : !fir.ref + ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 + print*, i + end do + ! CHECK: omp.yield + ! CHECK: omp.terminator + !$OMP END PARALLEL DO +end subroutine + +! CHECK-LABEL: func @_QPparallel_do_with_parallel_clauses +! CHECK-SAME: %[[COND_REF:.*]]: !fir.ref> {fir.bindc_name = "cond"}, %[[NT_REF:.*]]: !fir.ref {fir.bindc_name = "nt"} +subroutine parallel_do_with_parallel_clauses(cond, nt) + ! CHECK: %[[COND_DECL:.*]]:2 = hlfir.declare %[[COND_REF]] {uniq_name = "_QFparallel_do_with_parallel_clausesEcond"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) + ! CHECK: %[[NT_DECL:.*]]:2 = hlfir.declare %[[NT_REF]] {uniq_name = "_QFparallel_do_with_parallel_clausesEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) + logical :: cond + integer :: nt + integer :: i + ! CHECK: %[[COND:.*]] = fir.load %[[COND_DECL]]#0 : !fir.ref> + ! CHECK: %[[COND_CVT:.*]] = fir.convert %[[COND]] : (!fir.logical<4>) -> i1 + ! CHECK: %[[NT:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref + ! CHECK: omp.parallel if(%[[COND_CVT]] : i1) num_threads(%[[NT]] : i32) proc_bind(close) + ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 + ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 + ! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 + ! CHECK: omp.wsloop for (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) + !$OMP PARALLEL DO IF(cond) NUM_THREADS(nt) PROC_BIND(close) + do i=1, 9 + ! CHECK: fir.store %[[I]] to %[[IV_ADDR:.*]]#1 : !fir.ref + ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_ADDR]]#0 : !fir.ref + ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 + print*, i + end do + ! CHECK: omp.yield + ! CHECK: omp.terminator + !$OMP END PARALLEL DO +end subroutine + +! CHECK-LABEL: func @_QPparallel_do_with_clauses +! CHECK-SAME: %[[NT_REF:.*]]: !fir.ref {fir.bindc_name = "nt"} +subroutine parallel_do_with_clauses(nt) + ! CHECK: %[[NT_DECL:.*]]:2 = hlfir.declare %[[NT_REF]] {uniq_name = "_QFparallel_do_with_clausesEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) + integer :: nt + integer :: i + ! CHECK: %[[NT:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref + ! CHECK: omp.parallel num_threads(%[[NT]] : i32) + ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 + ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 + ! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 + ! CHECK: omp.wsloop schedule(dynamic) for (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) + !$OMP PARALLEL DO NUM_THREADS(nt) SCHEDULE(dynamic) + do i=1, 9 + ! CHECK: fir.store %[[I]] to %[[IV_ADDR:.*]]#1 : !fir.ref + ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_ADDR]]#0 : !fir.ref + ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 + print*, i + end do + ! CHECK: omp.yield + ! CHECK: omp.terminator + !$OMP END PARALLEL DO +end subroutine + +!=============================================================================== +! Checking for the following construct: +! !$omp parallel do private(...) firstprivate(...) +!=============================================================================== + +! CHECK-LABEL: func @_QPparallel_do_with_privatisation_clauses +! CHECK-SAME: %[[COND_REF:.*]]: !fir.ref> {fir.bindc_name = "cond"}, %[[NT_REF:.*]]: !fir.ref {fir.bindc_name = "nt"} +subroutine parallel_do_with_privatisation_clauses(cond,nt) + ! CHECK: %[[COND_DECL:.*]]:2 = hlfir.declare %[[COND_REF]] {uniq_name = "_QFparallel_do_with_privatisation_clausesEcond"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) + ! CHECK: %[[NT_DECL:.*]]:2 = hlfir.declare %[[NT_REF]] {uniq_name = "_QFparallel_do_with_privatisation_clausesEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) + logical :: cond + integer :: nt + integer :: i + ! CHECK: omp.parallel + ! CHECK: %[[PRIVATE_COND_REF:.*]] = fir.alloca !fir.logical<4> {bindc_name = "cond", pinned, uniq_name = "_QFparallel_do_with_privatisation_clausesEcond"} + ! CHECK: %[[PRIVATE_COND_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_COND_REF]] {uniq_name = "_QFparallel_do_with_privatisation_clausesEcond"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) + ! CHECK: %[[PRIVATE_NT_REF:.*]] = fir.alloca i32 {bindc_name = "nt", pinned, uniq_name = "_QFparallel_do_with_privatisation_clausesEnt"} + ! CHECK: %[[PRIVATE_NT_DECL:.*]]:2 = hlfir.declare %[[PRIVATE_NT_REF]] {uniq_name = "_QFparallel_do_with_privatisation_clausesEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) + ! CHECK: %[[NT_VAL:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref + ! CHECK: hlfir.assign %[[NT_VAL]] to %[[PRIVATE_NT_DECL]]#0 temporary_lhs : i32, !fir.ref + ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 + ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 + ! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 + ! CHECK: omp.wsloop for (%[[I:.*]]) : i32 = (%[[WS_LB]]) to (%[[WS_UB]]) inclusive step (%[[WS_STEP]]) + !$OMP PARALLEL DO PRIVATE(cond) FIRSTPRIVATE(nt) + do i=1, 9 + ! CHECK: fir.store %[[I]] to %[[IV_ADDR:.*]]#1 : !fir.ref + ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_ADDR]]#0 : !fir.ref + ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref, i32) -> i1 + ! CHECK: %[[PRIVATE_COND_VAL:.*]] = fir.load %[[PRIVATE_COND_DECL]]#0 : !fir.ref> + ! CHECK: %[[PRIVATE_COND_VAL_CVT:.*]] = fir.convert %[[PRIVATE_COND_VAL]] : (!fir.logical<4>) -> i1 + ! CHECK: fir.call @_FortranAioOutputLogical({{.*}}, %[[PRIVATE_COND_VAL_CVT]]) {{.*}}: (!fir.ref, i1) -> i1 + ! CHECK: %[[PRIVATE_NT_VAL:.*]] = fir.load %[[PRIVATE_NT_DECL]]#0 : !fir.ref + ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[PRIVATE_NT_VAL]]) {{.*}}: (!fir.ref, i32) -> i1 + print*, i, cond, nt + end do + ! CHECK: omp.yield + ! CHECK: omp.terminator + !$OMP END PARALLEL DO +end subroutine + +!=============================================================================== +! Checking for the following construct +! !$omp parallel private(...) firstprivate(...) +! !$omp do +!=============================================================================== + +subroutine parallel_private_do(cond,nt) +logical :: cond + integer :: nt + integer :: i + !$OMP PARALLEL PRIVATE(cond) FIRSTPRIVATE(nt) + !$OMP DO + do i=1, 9 + call foo(i, cond, nt) + end do + !$OMP END DO + !$OMP END PARALLEL +end subroutine parallel_private_do + +! CHECK-LABEL: func.func @_QPparallel_private_do( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> {fir.bindc_name = "cond"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "nt"}) { +! CHECK: %[[NT_DECL:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFparallel_private_doEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: omp.parallel { +! CHECK: %[[I_PRIV:.*]] = fir.alloca i32 {adapt.valuebyref, pinned} +! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV]] {uniq_name = "_QFparallel_private_doEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[COND_ADDR:.*]] = fir.alloca !fir.logical<4> {bindc_name = "cond", pinned, uniq_name = "_QFparallel_private_doEcond"} +! CHECK: %[[COND_DECL:.*]]:2 = hlfir.declare %[[COND_ADDR]] {uniq_name = "_QFparallel_private_doEcond"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[NT_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "nt", pinned, uniq_name = "_QFparallel_private_doEnt"} +! CHECK: %[[NT_PRIV_DECL:.*]]:2 = hlfir.declare %[[NT_PRIV_ADDR]] {uniq_name = "_QFparallel_private_doEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[NT:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref +! CHECK: hlfir.assign %[[NT]] to %[[NT_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref +! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_8:.*]] = arith.constant 9 : i32 +! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 +! CHECK: omp.wsloop for (%[[I:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { +! CHECK: fir.store %[[I]] to %[[I_PRIV_DECL]]#1 : !fir.ref +! CHECK: fir.call @_QPfoo(%[[I_PRIV_DECL]]#1, %[[COND_DECL]]#1, %[[NT_PRIV_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref>, !fir.ref) -> () +! CHECK: omp.yield +! CHECK: } +! CHECK: omp.terminator +! CHECK: } +! CHECK: return +! CHECK: } + +!=============================================================================== +! Checking for the following construct +! !$omp parallel +! !$omp do firstprivate(...) firstprivate(...) +!=============================================================================== + +subroutine omp_parallel_multiple_firstprivate_do(a, b) + integer::a, b + !$OMP PARALLEL FIRSTPRIVATE(a) FIRSTPRIVATE(b) + !$OMP DO + do i=1, 10 + call bar(i, a) + end do + !$OMP END DO + !$OMP END PARALLEL +end subroutine omp_parallel_multiple_firstprivate_do + +! CHECK-LABEL: func.func @_QPomp_parallel_multiple_firstprivate_do( +! CHECK-SAME: %[[A_ADDR:.*]]: !fir.ref {fir.bindc_name = "a"}, +! CHECK-SAME: %[[B_ADDR:.*]]: !fir.ref {fir.bindc_name = "b"}) { +! CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_ADDR]] {uniq_name = "_QFomp_parallel_multiple_firstprivate_doEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[B_DECL:.*]]:2 = hlfir.declare %[[B_ADDR]] {uniq_name = "_QFomp_parallel_multiple_firstprivate_doEb"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: omp.parallel { +! CHECK: %[[I_PRIV_ADDR:.*]] = fir.alloca i32 {adapt.valuebyref, pinned} +! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_multiple_firstprivate_doEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[A_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFomp_parallel_multiple_firstprivate_doEa"} +! CHECK: %[[A_PRIV_DECL:.*]]:2 = hlfir.declare %[[A_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_multiple_firstprivate_doEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[A:.*]] = fir.load %[[A_DECL]]#0 : !fir.ref +! CHECK: hlfir.assign %[[A]] to %[[A_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref +! CHECK: %[[B_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "b", pinned, uniq_name = "_QFomp_parallel_multiple_firstprivate_doEb"} +! CHECK: %[[B_PRIV_DECL:.*]]:2 = hlfir.declare %[[B_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_multiple_firstprivate_doEb"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[B:.*]] = fir.load %[[B_DECL]]#0 : !fir.ref +! CHECK: hlfir.assign %[[B]] to %[[B_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref +! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_9:.*]] = arith.constant 10 : i32 +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i32 +! CHECK: omp.wsloop for (%[[I:.*]]) : i32 = (%[[VAL_8]]) to (%[[VAL_9]]) inclusive step (%[[VAL_10]]) { +! CHECK: fir.store %[[I]] to %[[I_PRIV_DECL]]#1 : !fir.ref +! CHECK: fir.call @_QPbar(%[[I_PRIV_DECL]]#1, %[[A_PRIV_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref) -> () +! CHECK: omp.yield +! CHECK: } +! CHECK: omp.terminator +! CHECK: } +! CHECK: return +! CHECK: } + +!=============================================================================== +! Checking for the following construct +! !$omp parallel +! !$omp do private(...) firstprivate(...) +!=============================================================================== + +subroutine parallel_do_private(cond,nt) +logical :: cond + integer :: nt + integer :: i + !$OMP PARALLEL + !$OMP DO PRIVATE(cond) FIRSTPRIVATE(nt) + do i=1, 9 + call foo(i, cond, nt) + end do + !$OMP END DO + !$OMP END PARALLEL +end subroutine parallel_do_private + +! CHECK-LABEL: func.func @_QPparallel_do_private( +! CHECK-SAME: %[[VAL_0:.*]]: !fir.ref> {fir.bindc_name = "cond"}, +! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref {fir.bindc_name = "nt"}) { +! CHECK: %[[NT_DECL:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFparallel_do_privateEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: omp.parallel { +! CHECK: %[[I_PRIV_ADDR:.*]] = fir.alloca i32 {adapt.valuebyref, pinned} +! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV_ADDR]] {uniq_name = "_QFparallel_do_privateEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[COND_PRIV_ADDR:.*]] = fir.alloca !fir.logical<4> {bindc_name = "cond", pinned, uniq_name = "_QFparallel_do_privateEcond"} +! CHECK: %[[COND_PRIV_DECL:.*]]:2 = hlfir.declare %[[COND_PRIV_ADDR]] {uniq_name = "_QFparallel_do_privateEcond"} : (!fir.ref>) -> (!fir.ref>, !fir.ref>) +! CHECK: %[[NT_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "nt", pinned, uniq_name = "_QFparallel_do_privateEnt"} +! CHECK: %[[NT_PRIV_DECL:.*]]:2 = hlfir.declare %[[NT_PRIV_ADDR]] {uniq_name = "_QFparallel_do_privateEnt"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[NT_VAL:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref +! CHECK: hlfir.assign %[[NT_VAL]] to %[[NT_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref +! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_8:.*]] = arith.constant 9 : i32 +! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 +! CHECK: omp.wsloop for (%[[I:.*]]) : i32 = (%[[VAL_7]]) to (%[[VAL_8]]) inclusive step (%[[VAL_9]]) { +! CHECK: fir.store %[[I]] to %[[I_PRIV_DECL]]#1 : !fir.ref +! CHECK: fir.call @_QPfoo(%[[I_PRIV_DECL]]#1, %[[COND_PRIV_DECL]]#1, %[[NT_PRIV_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref>, !fir.ref) -> () +! CHECK: omp.yield +! CHECK: } +! CHECK: omp.terminator +! CHECK: } +! CHECK: return +! CHECK: } + +!=============================================================================== +! Checking for the following construct +! !$omp parallel +! !$omp do firstprivate(...) firstprivate(...) +!=============================================================================== + +subroutine omp_parallel_do_multiple_firstprivate(a, b) + integer::a, b + !$OMP PARALLEL + !$OMP DO FIRSTPRIVATE(a) FIRSTPRIVATE(b) + do i=1, 10 + call bar(i, a) + end do + !$OMP END DO + !$OMP END PARALLEL +end subroutine omp_parallel_do_multiple_firstprivate + +! CHECK-LABEL: func.func @_QPomp_parallel_do_multiple_firstprivate( +! CHECK-SAME: %[[A_ADDR:.*]]: !fir.ref {fir.bindc_name = "a"}, +! CHECK-SAME: %[[B_ADDR:.*]]: !fir.ref {fir.bindc_name = "b"}) { +! CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[B_DECL:.*]]:2 = hlfir.declare %[[B_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEb"} : (!fir.ref) -> (!fir.ref, !fir.ref +! CHECK: omp.parallel { +! CHECK: %[[I_PRIV_ADDR:.*]] = fir.alloca i32 {adapt.valuebyref, pinned} +! CHECK: %[[I_PRIV_DECL:.*]]:2 = hlfir.declare %[[I_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEi"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[A_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFomp_parallel_do_multiple_firstprivateEa"} +! CHECK: %[[A_PRIV_DECL:.*]]:2 = hlfir.declare %[[A_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEa"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[A:.*]] = fir.load %[[A_DECL]]#0 : !fir.ref +! CHECK: hlfir.assign %[[A]] to %[[A_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref +! CHECK: %[[B_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "b", pinned, uniq_name = "_QFomp_parallel_do_multiple_firstprivateEb"} +! CHECK: %[[B_PRIV_DECL:.*]]:2 = hlfir.declare %[[B_PRIV_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEb"} : (!fir.ref) -> (!fir.ref, !fir.ref) +! CHECK: %[[B:.*]] = fir.load %[[B_DECL]]#0 : !fir.ref +! CHECK: hlfir.assign %[[B]] to %[[B_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref +! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i32 +! CHECK: %[[VAL_9:.*]] = arith.constant 10 : i32 +! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i32 +! CHECK: omp.wsloop for (%[[I:.*]]) : i32 = (%[[VAL_8]]) to (%[[VAL_9]]) inclusive step (%[[VAL_10]]) { +! CHECK: fir.store %[[I]] to %[[I_PRIV_DECL]]#1 : !fir.ref +! CHECK: fir.call @_QPbar(%[[I_PRIV_DECL]]#1, %[[A_PRIV_DECL]]#1) {{.*}}: (!fir.ref, !fir.ref) -> () +! CHECK: omp.yield +! CHECK: } +! CHECK: omp.terminator +! CHECK: } +! CHECK: return +! CHECK: } diff --git a/flang/test/Lower/OpenMP/parallel.f90 b/flang/test/Lower/OpenMP/parallel.f90 new file mode 100644 index 0000000000000..0e43244994cfd --- /dev/null +++ b/flang/test/Lower/OpenMP/parallel.f90 @@ -0,0 +1,206 @@ +!RUN: %flang_fc1 -emit-hlfir -fopenmp %s -o - | FileCheck %s + +!CHECK-LABEL: func @_QPparallel_simple +subroutine parallel_simple() + !CHECK: omp.parallel +!$omp parallel + !CHECK: fir.call + call f1() +!$omp end parallel +end subroutine parallel_simple + +!=============================================================================== +! `if` clause +!=============================================================================== + +!CHECK-LABEL: func @_QPparallel_if +subroutine parallel_if(alpha, beta, gamma) + integer, intent(in) :: alpha + logical, intent(in) :: beta + logical(1) :: logical1 + logical(2) :: logical2 + logical(4) :: logical4 + logical(8) :: logical8 + + !CHECK: omp.parallel if(%{{.*}} : i1) { + !$omp parallel if(alpha .le. 0) + !CHECK: fir.call + call f1() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel if(%{{.*}} : i1) { + !$omp parallel if(.false.) + !CHECK: fir.call + call f2() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel if(%{{.*}} : i1) { + !$omp parallel if(alpha .ge. 0) + !CHECK: fir.call + call f3() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel if(%{{.*}} : i1) { + !$omp parallel if(.true.) + !CHECK: fir.call + call f4() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel if(%{{.*}} : i1) { + !$omp parallel if(beta) + !CHECK: fir.call + call f1() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel if(%{{.*}} : i1) { + !$omp parallel if(logical1) + !CHECK: fir.call + call f1() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel if(%{{.*}} : i1) { + !$omp parallel if(logical2) + !CHECK: fir.call + call f1() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel if(%{{.*}} : i1) { + !$omp parallel if(logical4) + !CHECK: fir.call + call f1() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel if(%{{.*}} : i1) { + !$omp parallel if(logical8) + !CHECK: fir.call + call f1() + !CHECK: omp.terminator + !$omp end parallel + +end subroutine parallel_if + +!=============================================================================== +! `num_threads` clause +!=============================================================================== + +!CHECK-LABEL: func @_QPparallel_numthreads +subroutine parallel_numthreads(num_threads) + integer, intent(inout) :: num_threads + + !CHECK: omp.parallel num_threads(%{{.*}}: i32) { + !$omp parallel num_threads(16) + !CHECK: fir.call + call f1() + !CHECK: omp.terminator + !$omp end parallel + + num_threads = 4 + + !CHECK: omp.parallel num_threads(%{{.*}} : i32) { + !$omp parallel num_threads(num_threads) + !CHECK: fir.call + call f2() + !CHECK: omp.terminator + !$omp end parallel + +end subroutine parallel_numthreads + +!=============================================================================== +! `proc_bind` clause +!=============================================================================== + +!CHECK-LABEL: func @_QPparallel_proc_bind +subroutine parallel_proc_bind() + + !CHECK: omp.parallel proc_bind(master) { + !$omp parallel proc_bind(master) + !CHECK: fir.call + call f1() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel proc_bind(close) { + !$omp parallel proc_bind(close) + !CHECK: fir.call + call f2() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel proc_bind(spread) { + !$omp parallel proc_bind(spread) + !CHECK: fir.call + call f3() + !CHECK: omp.terminator + !$omp end parallel + +end subroutine parallel_proc_bind + +!=============================================================================== +! `allocate` clause +!=============================================================================== + +!CHECK-LABEL: func @_QPparallel_allocate +subroutine parallel_allocate() + use omp_lib + integer :: x + !CHECK: omp.parallel allocate( + !CHECK: %{{.+}} : i32 -> %{{.+}} : !fir.ref + !CHECK: ) { + !$omp parallel allocate(omp_high_bw_mem_alloc: x) private(x) + !CHECK: arith.addi + x = x + 12 + !CHECK: omp.terminator + !$omp end parallel +end subroutine parallel_allocate + +!=============================================================================== +! multiple clauses +!=============================================================================== + +!CHECK-LABEL: func @_QPparallel_multiple_clauses +subroutine parallel_multiple_clauses(alpha, num_threads) + use omp_lib + integer, intent(inout) :: alpha + integer, intent(in) :: num_threads + + !CHECK: omp.parallel if({{.*}} : i1) proc_bind(master) { + !$omp parallel if(alpha .le. 0) proc_bind(master) + !CHECK: fir.call + call f1() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel num_threads({{.*}} : i32) proc_bind(close) { + !$omp parallel proc_bind(close) num_threads(num_threads) + !CHECK: fir.call + call f2() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel if({{.*}} : i1) num_threads({{.*}} : i32) { + !$omp parallel num_threads(num_threads) if(alpha .le. 0) + !CHECK: fir.call + call f3() + !CHECK: omp.terminator + !$omp end parallel + + !CHECK: omp.parallel if({{.*}} : i1) num_threads({{.*}} : i32) allocate( + !CHECK: %{{.+}} : i32 -> %{{.+}} : !fir.ref + !CHECK: ) { + !$omp parallel num_threads(num_threads) if(alpha .le. 0) allocate(omp_high_bw_mem_alloc: alpha) private(alpha) + !CHECK: fir.call + call f3() + !CHECK: arith.addi + alpha = alpha + 12 + !CHECK: omp.terminator + !$omp end parallel + +end subroutine parallel_multiple_clauses