[flang-commits] [flang] a13696f - [Flang][OpenMP] Port a few parallel tests to HLFIR flow
Kiran Chandramohan via flang-commits
flang-commits at lists.llvm.org
Thu Oct 26 09:12:04 PDT 2023
Author: Kiran Chandramohan
Date: 2023-10-26T16:11:27Z
New Revision: a13696fd8490f67b6ad119fcb6fda20e1fd3a089
URL: https://github.com/llvm/llvm-project/commit/a13696fd8490f67b6ad119fcb6fda20e1fd3a089
DIFF: https://github.com/llvm/llvm-project/commit/a13696fd8490f67b6ad119fcb6fda20e1fd3a089.diff
LOG: [Flang][OpenMP] Port a few parallel tests to HLFIR flow
These are copies of tests in flang/test/Lower/OpenMP/FIR.
Added:
flang/test/Lower/OpenMP/parallel-firstprivate-clause-scalar.f90
flang/test/Lower/OpenMP/parallel-lastprivate-clause-scalar.f90
flang/test/Lower/OpenMP/parallel-private-clause.f90
flang/test/Lower/OpenMP/parallel-wsloop.f90
flang/test/Lower/OpenMP/parallel.f90
Modified:
Removed:
################################################################################
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 000000000000000..6402f98a2addc4d
--- /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<!fir.complex<4>>{{.*}}, %[[ARG2:.*]]: !fir.ref<!fir.complex<8>>{{.*}}) {
+!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstprivate_complexEarg1"} : (!fir.ref<!fir.complex<4>>) -> (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<4>>)
+!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFfirstprivate_complexEarg2"} : (!fir.ref<!fir.complex<8>>) -> (!fir.ref<!fir.complex<8>>, !fir.ref<!fir.complex<8>>)
+!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.complex<4>>) -> (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<4>>)
+!CHECK: %[[ARG1_VAL:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref<!fir.complex<4>>
+!CHECK: hlfir.assign %[[ARG1_VAL]] to %[[ARG1_PVT_DECL]]#0 temporary_lhs : !fir.complex<4>, !fir.ref<!fir.complex<4>>
+!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.complex<8>>) -> (!fir.ref<!fir.complex<8>>, !fir.ref<!fir.complex<8>>)
+!CHECK: %[[ARG2_VAL:.*]] = fir.load %[[ARG2_DECL]]#0 : !fir.ref<!fir.complex<8>>
+!CHECK: hlfir.assign %[[ARG2_VAL]] to %[[ARG2_PVT_DECL]]#0 temporary_lhs : !fir.complex<8>, !fir.ref<!fir.complex<8>>
+!CHECK: fir.call @_QPfoo(%[[ARG1_PVT_DECL]]#1, %[[ARG2_PVT_DECL]]#1) {{.*}}: (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<8>>) -> ()
+!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<i32>{{.*}}, %[[ARG2:.*]]: !fir.ref<i8>{{.*}}, %[[ARG3:.*]]: !fir.ref<i16>{{.*}}, %[[ARG4:.*]]: !fir.ref<i32>{{.*}}, %[[ARG5:.*]]: !fir.ref<i64>{{.*}}, %[[ARG6:.*]]: !fir.ref<i128>{{.*}}) {
+!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstprivate_integerEarg1"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFfirstprivate_integerEarg2"} : (!fir.ref<i8>) -> (!fir.ref<i8>, !fir.ref<i8>)
+!CHECK: %[[ARG3_DECL:.*]]:2 = hlfir.declare %[[ARG3]] {uniq_name = "_QFfirstprivate_integerEarg3"} : (!fir.ref<i16>) -> (!fir.ref<i16>, !fir.ref<i16>)
+!CHECK: %[[ARG4_DECL:.*]]:2 = hlfir.declare %[[ARG4]] {uniq_name = "_QFfirstprivate_integerEarg4"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[ARG5_DECL:.*]]:2 = hlfir.declare %[[ARG5]] {uniq_name = "_QFfirstprivate_integerEarg5"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
+!CHECK: %[[ARG6_DECL:.*]]:2 = hlfir.declare %[[ARG6]] {uniq_name = "_QFfirstprivate_integerEarg6"} : (!fir.ref<i128>) -> (!fir.ref<i128>, !fir.ref<i128>)
+!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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[ARG1_VAL:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref<i32>
+!CHECK: hlfir.assign %[[ARG1_VAL]] to %[[ARG1_PVT_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!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<i8>) -> (!fir.ref<i8>, !fir.ref<i8>)
+!CHECK: %[[ARG2_VAL:.*]] = fir.load %[[ARG2_DECL]]#0 : !fir.ref<i8>
+!CHECK: hlfir.assign %[[ARG2_VAL]] to %[[ARG2_PVT_DECL]]#0 temporary_lhs : i8, !fir.ref<i8>
+!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<i16>) -> (!fir.ref<i16>, !fir.ref<i16>)
+!CHECK: %[[ARG3_VAL:.*]] = fir.load %[[ARG3_DECL]]#0 : !fir.ref<i16>
+!CHECK: hlfir.assign %[[ARG3_VAL]] to %[[ARG3_PVT_DECL]]#0 temporary_lhs : i16, !fir.ref<i16>
+!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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[ARG4_VAL:.*]] = fir.load %[[ARG4_DECL]]#0 : !fir.ref<i32>
+!CHECK: hlfir.assign %[[ARG4_VAL]] to %[[ARG4_PVT_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!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<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
+!CHECK: %[[ARG5_VAL:.*]] = fir.load %[[ARG5_DECL]]#0 : !fir.ref<i64>
+!CHECK: hlfir.assign %[[ARG5_VAL]] to %[[ARG5_PVT_DECL]]#0 temporary_lhs : i64, !fir.ref<i64>
+!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<i128>) -> (!fir.ref<i128>, !fir.ref<i128>)
+!CHECK: %[[ARG6_VAL:.*]] = fir.load %[[ARG6_DECL]]#0 : !fir.ref<i128>
+!CHECK: hlfir.assign %[[ARG6_VAL]] to %[[ARG6_PVT_DECL]]#0 temporary_lhs : i128, !fir.ref<i128>
+!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<i32>, !fir.ref<i8>, !fir.ref<i16>, !fir.ref<i32>, !fir.ref<i64>, !fir.ref<i128>) -> ()
+!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<!fir.logical<4>>{{.*}}, %[[ARG2:.*]]: !fir.ref<!fir.logical<1>>{{.*}}, %[[ARG3:.*]]: !fir.ref<!fir.logical<2>>{{.*}}, %[[ARG4:.*]]: !fir.ref<!fir.logical<4>>{{.*}}, %[[ARG5:.*]]: !fir.ref<!fir.logical<8>>{{.*}}) {
+!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstprivate_logicalEarg1"} : (!fir.ref<!fir.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFfirstprivate_logicalEarg2"} : (!fir.ref<!fir.logical<1>>) -> (!fir.ref<!fir.logical<1>>, !fir.ref<!fir.logical<1>>)
+!CHECK: %[[ARG3_DECL:.*]]:2 = hlfir.declare %[[ARG3]] {uniq_name = "_QFfirstprivate_logicalEarg3"} : (!fir.ref<!fir.logical<2>>) -> (!fir.ref<!fir.logical<2>>, !fir.ref<!fir.logical<2>>)
+!CHECK: %[[ARG4_DECL:.*]]:2 = hlfir.declare %[[ARG4]] {uniq_name = "_QFfirstprivate_logicalEarg4"} : (!fir.ref<!fir.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+!CHECK: %[[ARG5_DECL:.*]]:2 = hlfir.declare %[[ARG5]] {uniq_name = "_QFfirstprivate_logicalEarg5"} : (!fir.ref<!fir.logical<8>>) -> (!fir.ref<!fir.logical<8>>, !fir.ref<!fir.logical<8>>)
+!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.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+!CHECK: %[[ARG1_VAL:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref<!fir.logical<4>>
+!CHECK: hlfir.assign %[[ARG1_VAL]] to %[[ARG1_PVT_DECL]]#0 temporary_lhs : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+!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.logical<1>>) -> (!fir.ref<!fir.logical<1>>, !fir.ref<!fir.logical<1>>)
+!CHECK: %[[ARG2_VAL:.*]] = fir.load %[[ARG2_DECL]]#0 : !fir.ref<!fir.logical<1>>
+!CHECK: hlfir.assign %[[ARG2_VAL]] to %[[ARG2_PVT_DECL]]#0 temporary_lhs : !fir.logical<1>, !fir.ref<!fir.logical<1>>
+!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.logical<2>>) -> (!fir.ref<!fir.logical<2>>, !fir.ref<!fir.logical<2>>)
+!CHECK: %[[ARG3_VAL:.*]] = fir.load %[[ARG3_DECL]]#0 : !fir.ref<!fir.logical<2>>
+!CHECK: hlfir.assign %[[ARG3_VAL]] to %[[ARG3_PVT_DECL]]#0 temporary_lhs : !fir.logical<2>, !fir.ref<!fir.logical<2>>
+!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.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+!CHECK: %[[ARG4_VAL:.*]] = fir.load %[[ARG4_DECL]]#0 : !fir.ref<!fir.logical<4>>
+!CHECK: hlfir.assign %[[ARG4_VAL]] to %[[ARG4_PVT_DECL]]#0 temporary_lhs : !fir.logical<4>, !fir.ref<!fir.logical<4>>
+!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.logical<8>>) -> (!fir.ref<!fir.logical<8>>, !fir.ref<!fir.logical<8>>)
+!CHECK: %[[ARG5_VAL:.*]] = fir.load %[[ARG5_DECL]]#0 : !fir.ref<!fir.logical<8>>
+!CHECK: hlfir.assign %[[ARG5_VAL]] to %[[ARG5_PVT_DECL]]#0 temporary_lhs : !fir.logical<8>, !fir.ref<!fir.logical<8>>
+!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.logical<4>>, !fir.ref<!fir.logical<1>>, !fir.ref<!fir.logical<2>>, !fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<8>>) -> ()
+!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<f32>{{.*}}, %[[ARG2:.*]]: !fir.ref<f16>{{.*}}, %[[ARG3:.*]]: !fir.ref<f32>{{.*}}, %[[ARG4:.*]]: !fir.ref<f64>{{.*}}, %[[ARG5:.*]]: !fir.ref<f80>{{.*}}, %[[ARG6:.*]]: !fir.ref<f128>{{.*}}) {
+!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstprivate_realEarg1"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFfirstprivate_realEarg2"} : (!fir.ref<f16>) -> (!fir.ref<f16>, !fir.ref<f16>)
+!CHECK: %[[ARG3_DECL:.*]]:2 = hlfir.declare %[[ARG3]] {uniq_name = "_QFfirstprivate_realEarg3"} : (!fir.ref<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+!CHECK: %[[ARG4_DECL:.*]]:2 = hlfir.declare %[[ARG4]] {uniq_name = "_QFfirstprivate_realEarg4"} : (!fir.ref<f64>) -> (!fir.ref<f64>, !fir.ref<f64>)
+!CHECK: %[[ARG5_DECL:.*]]:2 = hlfir.declare %[[ARG5]] {uniq_name = "_QFfirstprivate_realEarg5"} : (!fir.ref<f80>) -> (!fir.ref<f80>, !fir.ref<f80>)
+!CHECK: %[[ARG6_DECL:.*]]:2 = hlfir.declare %[[ARG6]] {uniq_name = "_QFfirstprivate_realEarg6"} : (!fir.ref<f128>) -> (!fir.ref<f128>, !fir.ref<f128>)
+!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<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+!CHECK: %[[ARG1_VAL:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref<f32>
+!CHECK: hlfir.assign %[[ARG1_VAL]] to %[[ARG1_PVT_DECL]]#0 temporary_lhs : f32, !fir.ref<f32>
+!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<f16>) -> (!fir.ref<f16>, !fir.ref<f16>)
+!CHECK: %[[ARG2_VAL:.*]] = fir.load %[[ARG2_DECL]]#0 : !fir.ref<f16>
+!CHECK: hlfir.assign %[[ARG2_VAL]] to %[[ARG2_PVT_DECL]]#0 temporary_lhs : f16, !fir.ref<f16>
+!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<f32>) -> (!fir.ref<f32>, !fir.ref<f32>)
+!CHECK: %[[ARG3_VAL:.*]] = fir.load %[[ARG3_DECL]]#0 : !fir.ref<f32>
+!CHECK: hlfir.assign %[[ARG3_VAL]] to %[[ARG3_PVT_DECL]]#0 temporary_lhs : f32, !fir.ref<f32>
+!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<f64>) -> (!fir.ref<f64>, !fir.ref<f64>)
+!CHECK: %[[ARG4_VAL:.*]] = fir.load %[[ARG4_DECL]]#0 : !fir.ref<f64>
+!CHECK: hlfir.assign %[[ARG4_VAL]] to %[[ARG4_PVT_DECL]]#0 temporary_lhs : f64, !fir.ref<f64>
+!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<f80>) -> (!fir.ref<f80>, !fir.ref<f80>)
+!CHECK: %[[ARG5_VAL:.*]] = fir.load %[[ARG5_DECL]]#0 : !fir.ref<f80>
+!CHECK: hlfir.assign %[[ARG5_VAL]] to %[[ARG5_PVT_DECL]]#0 temporary_lhs : f80, !fir.ref<f80>
+!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<f128>) -> (!fir.ref<f128>, !fir.ref<f128>)
+!CHECK: %[[ARG6_VAL:.*]] = fir.load %[[ARG6_DECL]]#0 : !fir.ref<f128>
+!CHECK: hlfir.assign %[[ARG6_VAL]] to %[[ARG6_PVT_DECL]]#0 temporary_lhs : f128, !fir.ref<f128>
+!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<f32>, !fir.ref<f16>, !fir.ref<f32>, !fir.ref<f64>, !fir.ref<f80>, !fir.ref<f128>) -> ()
+!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<i32> {fir.bindc_name = "a"},
+!CHECK-SAME: %[[B_ADDR:.*]]: !fir.ref<i32> {fir.bindc_name = "b"}) {
+!CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_ADDR]] {uniq_name = "_QFmultiple_firstprivateEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[B_DECL:.*]]:2 = hlfir.declare %[[B_ADDR]] {uniq_name = "_QFmultiple_firstprivateEb"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[A:.*]] = fir.load %[[A_DECL]]#0 : !fir.ref<i32>
+!CHECK: hlfir.assign %[[A]] to %[[A_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[B:.*]] = fir.load %[[B_DECL]]#0 : !fir.ref<i32>
+!CHECK: hlfir.assign %[[B]] to %[[B_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!CHECK: fir.call @_QPquux(%[[A_PRIV_DECL]]#1, %[[B_PRIV_DECL]]#1) {{.*}}: (!fir.ref<i32>, !fir.ref<i32>) -> ()
+!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 000000000000000..abd14f455123b5b
--- /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.char<1,?>>) -> !fir.ref<!fir.char<1,5>>
+!CHECK-DAG: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1_REF]] typeparams %[[FIVE]] {uniq_name = "_QFlastprivate_characterEarg1"} : (!fir.ref<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
+
+!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<!fir.char<1,5>>, index) -> (!fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>)
+
+! 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<i8>, i32) -> !fir.ref<i8>
+!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<i32>
+
+! Testing lastprivate val update
+!CHECK-DAG: hlfir.assign %[[ARG1_PVT_DECL]]#0 to %[[ARG1_DECL]]#0 temporary_lhs : !fir.ref<!fir.char<1,5>>, !fir.ref<!fir.char<1,5>>
+!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<i32> {fir.bindc_name = "arg1"}) {
+!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFlastprivate_intEarg1"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!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<i32>
+
+! Testing lastprivate val update
+!CHECK-NEXT: %[[CLONE_LD:.*]] = fir.load %[[CLONE_DECL]]#0 : !fir.ref<i32>
+!CHECK: hlfir.assign %[[CLONE_LD]] to %[[ARG1_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!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<i32> {fir.bindc_name = "arg1"}, %[[ARG2:.*]]: !fir.ref<i32> {fir.bindc_name = "arg2"}) {
+!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFmult_lastprivate_intEarg1"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFmult_lastprivate_intEarg2"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK-DAG: %[[CLONE2:.*]] = fir.alloca i32 {bindc_name = "arg2"
+!CHECK-DAG: %[[CLONE2_DECL:.*]]:2 = hlfir.declare %[[CLONE2]] {uniq_name = "_QFmult_lastprivate_intEarg2"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!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<i32>
+! Testing lastprivate val update
+!CHECK-DAG: %[[CLONE_LD1:.*]] = fir.load %[[CLONE1_DECL]]#0 : !fir.ref<i32>
+!CHECK-DAG: hlfir.assign %[[CLONE_LD1]] to %[[ARG1_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!CHECK-DAG: %[[CLONE_LD2:.*]] = fir.load %[[CLONE2_DECL]]#0 : !fir.ref<i32>
+!CHECK-DAG: hlfir.assign %[[CLONE_LD2]] to %[[ARG2_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!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<i32> {fir.bindc_name = "arg1"}, %[[ARG2:.*]]: !fir.ref<i32> {fir.bindc_name = "arg2"}) {
+!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %arg0 {uniq_name = "_QFmult_lastprivate_int2Earg1"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %arg1 {uniq_name = "_QFmult_lastprivate_int2Earg2"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK-DAG: %[[CLONE2:.*]] = fir.alloca i32 {bindc_name = "arg2"
+!CHECK-DAG: %[[CLONE2_DECL:.*]]:2 = hlfir.declare %[[CLONE2]] {uniq_name = "_QFmult_lastprivate_int2Earg2"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!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<i32>
+!Testing lastprivate val update
+!CHECK-DAG: %[[CLONE_LD2:.*]] = fir.load %[[CLONE2_DECL]]#0 : !fir.ref<i32>
+!CHECK-DAG: hlfir.assign %[[CLONE_LD2]] to %[[ARG2_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!CHECK-DAG: %[[CLONE_LD1:.*]] = fir.load %[[CLONE1_DECL]]#0 : !fir.ref<i32>
+!CHECK-DAG: hlfir.assign %[[CLONE_LD1]] to %[[ARG1_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!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<i32> {fir.bindc_name = "arg1"}, %[[ARG2:.*]]: !fir.ref<i32> {fir.bindc_name = "arg2"}) {
+!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstpriv_lastpriv_intEarg1"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[ARG2_DECL:.*]]:2 = hlfir.declare %[[ARG2]] {uniq_name = "_QFfirstpriv_lastpriv_intEarg2"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK: %[[FPV_LD:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref<i32>
+!CHECK: hlfir.assign %[[FPV_LD]] to %[[CLONE1_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+! Lastprivate Allocation
+!CHECK: %[[CLONE2:.*]] = fir.alloca i32 {bindc_name = "arg2"
+!CHECK: %[[CLONE2_DECL:.*]]:2 = hlfir.declare %[[CLONE2]] {uniq_name = "_QFfirstpriv_lastpriv_intEarg2"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!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<i32>
+! Testing lastprivate val update
+!CHECK-NEXT: %[[CLONE_LD:.*]] = fir.load %[[CLONE2_DECL]]#0 : !fir.ref<i32>
+!CHECK-NEXT: hlfir.assign %[[CLONE_LD]] to %[[ARG2_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!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<i32> {fir.bindc_name = "arg1"}) {
+!CHECK: %[[ARG1_DECL:.*]]:2 = hlfir.declare %[[ARG1]] {uniq_name = "_QFfirstpriv_lastpriv_int2Earg1"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+!CHECK-NEXT: %[[FPV_LD:.*]] = fir.load %[[ARG1_DECL]]#0 : !fir.ref<i32>
+!CHECK-NEXT: hlfir.assign %[[FPV_LD]] to %[[CLONE1_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!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<i32>
+! Testing lastprivate val update
+!CHECK-NEXT: %[[CLONE_LD:.*]] = fir.load %[[CLONE1_DECL]]#0 : !fir.ref<i32>
+!CHECK-NEXT: hlfir.assign %[[CLONE_LD]] to %[[ARG1_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+!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 000000000000000..8d288f6483493e6
--- /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<i32>{{.*}}, %[[ARG2:.*]]: !fir.ref<!fir.array<10xi32>>{{.*}}, %[[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<!fir.heap<i32>> {bindc_name = "x", uniq_name = "{{.*}}Ex"}
+!FIRDialect-DAG: {{.*}} = fir.alloca !fir.heap<i32> {uniq_name = "{{.*}}Ex.addr"}
+!FIRDialect-DAG: {{.*}} = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "x2", uniq_name = "{{.*}}Ex2"}
+!FIRDialect-DAG: {{.*}} = fir.alloca !fir.heap<!fir.array<?xi32>> {uniq_name = "{{.*}}Ex2.addr"}
+!FIRDialect-DAG: {{.*}} = fir.address_of(@{{.*}}Ex3) : !fir.ref<!fir.box<!fir.heap<i32>>>
+!FIRDialect-DAG: [[TMP8:%.*]] = fir.address_of(@{{.*}}Ex4) : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+
+!FIRDialect: omp.parallel {
+!FIRDialect-DAG: [[TMP35:%.*]] = fir.alloca !fir.box<!fir.heap<i32>> {bindc_name = "x", pinned, uniq_name = "{{.*}}Ex"}
+!FIRDialect-DAG: [[TMP39:%.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "x2", pinned, uniq_name = "{{.*}}Ex2"}
+!FIRDialect-DAG: [[TMP45:%.*]] = fir.alloca !fir.box<!fir.heap<i32>> {bindc_name = "x3", pinned, uniq_name = "{{.*}}Ex3"}
+
+!FIRDialect-DAG: [[TMP51:%.*]] = fir.load [[TMP8]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!FIRDialect-DAG: [[TMP97:%.*]] = fir.load [[TMP8]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+!FIRDialect-DAG: [[TMP98:%.*]]:3 = fir.box_dims [[TMP97]], {{.*}} : (!fir.box<!fir.heap<!fir.array<?xi32>>>, index) -> (index, index, index)
+!FIRDialect-DAG: [[TMP50:%.*]] = fir.alloca !fir.box<!fir.heap<!fir.array<?xi32>>> {bindc_name = "x4", pinned, uniq_name = "{{.*}}Ex4"}
+
+! FIRDialect-DAG: [[TMP101:%.*]] = fir.allocmem !fir.array<?xi32>, {{.*}} {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.array<?xi32>>, !fir.shapeshift<1>) -> !fir.box<!fir.heap<!fir.array<?xi32>>>
+! FIRDialect-DAG: fir.store [[TMP103]] to [[TMP50]] : !fir.ref<!fir.box<!fir.heap<!fir.array<?xi32>>>>
+
+
+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<!fir.heap<f32>> {bindc_name = "x5", uniq_name = "{{.*}}Ex5"}
+!FIRDialect-DAG: {{.*}} = fir.zero_bits !fir.heap<f32>
+!FIRDialect-DAG: {{.*}} = fir.embox %1 : (!fir.heap<f32>) -> !fir.box<!fir.heap<f32>>
+!FIRDialect-DAG: fir.store %2 to %0 : !fir.ref<!fir.box<!fir.heap<f32>>>
+!FIRDialect-DAG: omp.parallel {
+!FIRDialect-DAG: [[TMP203:%.*]] = fir.alloca !fir.box<!fir.heap<f32>> {bindc_name = "x5", pinned, uniq_name = "{{.*}}Ex5"}
+
+!FIRDialect-DAG: fir.if %{{.*}} {
+
+!FIRDialect-DAG: fir.store %{{.*}} to [[TMP203]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+!FIRDialect-DAG: } else {
+
+!FIRDialect-DAG: fir.store %{{.*}} to [[TMP203]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+!FIRDialect-DAG: }
+!FIRDialect-DAG: fir.call @_QFprivate_clause_real_call_allocatablePhelper_private_clause_real_call_allocatable([[TMP203]]) fastmath<contract> : (!fir.ref<!fir.box<!fir.heap<f32>>>) -> ()
+!FIRDialect-DAG: %{{.*}} = fir.load [[TMP203]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+
+!FIRDialect-DAG: fir.if %{{.*}} {
+!FIRDialect-DAG: %{{.*}} = fir.load [[TMP203]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+
+!FIRDialect-DAG: fir.store %{{.*}} to [[TMP203]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+!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.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode{payload:i32,next:!fir.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode>>>}>>>> {fir.bindc_name = "head"}) {
+!FIRDialect: {{%.*}} = fir.alloca !fir.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode{payload:i32,next:!fir.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode>>>}>>> {bindc_name = "p", uniq_name = "_QFincrement_list_itemsEp"}
+!FIRDialect: omp.parallel {
+!FIRDialect: {{%.*}} = fir.alloca !fir.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode{payload:i32,next:!fir.box<!fir.ptr<!fir.type<_QFincrement_list_itemsTnode>>>}>>> {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<!fir.ptr<i32>> {bindc_name = "y1", uniq_name = "{{.*}}Ey1"}
+!FIRDialect-DAG: [[PP1:%.*]] = fir.alloca !fir.ptr<i32> {uniq_name = "{{.*}}Ey1.addr"}
+!FIRDialect-DAG: [[PP2:%.*]] = fir.zero_bits !fir.ptr<i32>
+!FIRDialect: fir.store [[PP2]] to [[PP1]] : !fir.ref<!fir.ptr<i32>>
+!FIRDialect-DAG: [[PP3:%.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>> {bindc_name = "y2", uniq_name = "{{.*}}Ey2"}
+
+!FIRDialect: fir.store %6 to %3 : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+!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<!fir.ptr<i32>> {bindc_name = "y1", pinned, uniq_name = "{{.*}}Ey1"}
+!FIRDialect-DAG: [[PP10:%.*]] = fir.alloca !fir.box<!fir.ptr<!fir.array<?xi32>>> {bindc_name = "y2", pinned, uniq_name = "{{.*}}Ey2"}
+!FIRDialect-DAG: [[PP11:%.*]] = fir.embox [[PP7]] : (!fir.ref<i32>) -> !fir.box<!fir.ptr<i32>>
+!FIRDialect: fir.store [[PP11]] to [[PP9]] : !fir.ref<!fir.box<!fir.ptr<i32>>>
+!FIRDialect-DAG: [[PP12:%.*]] = fir.shape %c{{.*}} : (index) -> !fir.shape<1>
+!FIRDialect-DAG: [[PP13:%.*]] = fir.embox [[PP8]]([[PP12]]) : (!fir.ref<!fir.array<10xi32>>, !fir.shape<1>) -> !fir.box<!fir.ptr<!fir.array<?xi32>>>
+!FIRDialect: fir.store %13 to [[PP10]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?xi32>>>>
+!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<!fir.heap<f32>> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"}
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+
+ ! 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<i32>
+ ! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV]] : !fir.ref<i32>
+ ! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, i32) -> i1
+ print*, i
+ end do
+ ! FIRDialect: omp.yield
+ ! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: fir.if {{%.*}} {
+ ! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+ ! FIRDialect: fir.freemem [[AD]] : !fir.heap<f32>
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ !$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<!fir.heap<f32>> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"}
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+
+ ! 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<i32>
+ ! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV]] : !fir.ref<i32>
+ ! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, i32) -> i1
+ print*, i
+ end do
+ ! FIRDialect: omp.yield
+ ! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: fir.if {{%.*}} {
+ ! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+ ! FIRDialect: fir.freemem [[AD]] : !fir.heap<f32>
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ !$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<!fir.heap<f32>> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"}
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+
+ ! 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<i32>
+ ! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[ALLOCA_IV]] : !fir.ref<i32>
+ ! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, i32) -> i1
+ print*, i
+ end do
+ ! FIRDialect: omp.yield
+ ! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: fir.if {{%.*}} {
+ ! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+ ! FIRDialect: fir.freemem [[AD]] : !fir.heap<f32>
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ !$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<!fir.heap<f32>> {bindc_name = "r", pinned, uniq_name = "{{.*}}Er"}
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+
+ ! 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<i32>
+ ! FIRDialect: %[[LOAD_IV:.*]] = fir.load %[[LOCAL]] : !fir.ref<i32>
+ ! FIRDialect: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, i32) -> i1
+ print*, i
+ end do
+ !$OMP END SIMD
+ ! FIRDialect: omp.yield
+ ! FIRDialect: {{%.*}} = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: fir.if {{%.*}} {
+ ! FIRDialect: [[LD:%.*]] = fir.load [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+ ! FIRDialect: [[AD:%.*]] = fir.box_addr [[LD]] : (!fir.box<!fir.heap<f32>>) -> !fir.heap<f32>
+ ! FIRDialect: fir.freemem [[AD]] : !fir.heap<f32>
+ ! FIRDialect: fir.store {{%.*}} to [[R]] : !fir.ref<!fir.box<!fir.heap<f32>>>
+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 000000000000000..c06f941b74b582c
--- /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<i32>
+ ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_ADDR]]#0 : !fir.ref<i32>
+ ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, 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.logical<4>> {fir.bindc_name = "cond"}, %[[NT_REF:.*]]: !fir.ref<i32> {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.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+ ! CHECK: %[[NT_DECL:.*]]:2 = hlfir.declare %[[NT_REF]] {uniq_name = "_QFparallel_do_with_parallel_clausesEnt"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ logical :: cond
+ integer :: nt
+ integer :: i
+ ! CHECK: %[[COND:.*]] = fir.load %[[COND_DECL]]#0 : !fir.ref<!fir.logical<4>>
+ ! CHECK: %[[COND_CVT:.*]] = fir.convert %[[COND]] : (!fir.logical<4>) -> i1
+ ! CHECK: %[[NT:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref<i32>
+ ! 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<i32>
+ ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_ADDR]]#0 : !fir.ref<i32>
+ ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, 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<i32> {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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ integer :: nt
+ integer :: i
+ ! CHECK: %[[NT:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref<i32>
+ ! 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<i32>
+ ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_ADDR]]#0 : !fir.ref<i32>
+ ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, 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.logical<4>> {fir.bindc_name = "cond"}, %[[NT_REF:.*]]: !fir.ref<i32> {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.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+ ! CHECK: %[[NT_DECL:.*]]:2 = hlfir.declare %[[NT_REF]] {uniq_name = "_QFparallel_do_with_privatisation_clausesEnt"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ 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.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+ ! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+ ! CHECK: %[[NT_VAL:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref<i32>
+ ! CHECK: hlfir.assign %[[NT_VAL]] to %[[PRIVATE_NT_DECL]]#0 temporary_lhs : i32, !fir.ref<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 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<i32>
+ ! CHECK: %[[LOAD_IV:.*]] = fir.load %[[IV_ADDR]]#0 : !fir.ref<i32>
+ ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[LOAD_IV]]) {{.*}}: (!fir.ref<i8>, i32) -> i1
+ ! CHECK: %[[PRIVATE_COND_VAL:.*]] = fir.load %[[PRIVATE_COND_DECL]]#0 : !fir.ref<!fir.logical<4>>
+ ! CHECK: %[[PRIVATE_COND_VAL_CVT:.*]] = fir.convert %[[PRIVATE_COND_VAL]] : (!fir.logical<4>) -> i1
+ ! CHECK: fir.call @_FortranAioOutputLogical({{.*}}, %[[PRIVATE_COND_VAL_CVT]]) {{.*}}: (!fir.ref<i8>, i1) -> i1
+ ! CHECK: %[[PRIVATE_NT_VAL:.*]] = fir.load %[[PRIVATE_NT_DECL]]#0 : !fir.ref<i32>
+ ! CHECK: fir.call @_FortranAioOutputInteger32({{.*}}, %[[PRIVATE_NT_VAL]]) {{.*}}: (!fir.ref<i8>, 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.logical<4>> {fir.bindc_name = "cond"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<i32> {fir.bindc_name = "nt"}) {
+! CHECK: %[[NT_DECL:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFparallel_private_doEnt"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! 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.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[NT:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref<i32>
+! CHECK: hlfir.assign %[[NT]] to %[[NT_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+! 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<i32>
+! CHECK: fir.call @_QPfoo(%[[I_PRIV_DECL]]#1, %[[COND_DECL]]#1, %[[NT_PRIV_DECL]]#1) {{.*}}: (!fir.ref<i32>, !fir.ref<!fir.logical<4>>, !fir.ref<i32>) -> ()
+! 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<i32> {fir.bindc_name = "a"},
+! CHECK-SAME: %[[B_ADDR:.*]]: !fir.ref<i32> {fir.bindc_name = "b"}) {
+! CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_ADDR]] {uniq_name = "_QFomp_parallel_multiple_firstprivate_doEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[B_DECL:.*]]:2 = hlfir.declare %[[B_ADDR]] {uniq_name = "_QFomp_parallel_multiple_firstprivate_doEb"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[A:.*]] = fir.load %[[A_DECL]]#0 : !fir.ref<i32>
+! CHECK: hlfir.assign %[[A]] to %[[A_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[B:.*]] = fir.load %[[B_DECL]]#0 : !fir.ref<i32>
+! CHECK: hlfir.assign %[[B]] to %[[B_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+! 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<i32>
+! CHECK: fir.call @_QPbar(%[[I_PRIV_DECL]]#1, %[[A_PRIV_DECL]]#1) {{.*}}: (!fir.ref<i32>, !fir.ref<i32>) -> ()
+! 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.logical<4>> {fir.bindc_name = "cond"},
+! CHECK-SAME: %[[VAL_1:.*]]: !fir.ref<i32> {fir.bindc_name = "nt"}) {
+! CHECK: %[[NT_DECL:.*]]:2 = hlfir.declare %[[VAL_1]] {uniq_name = "_QFparallel_do_privateEnt"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! 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.logical<4>>) -> (!fir.ref<!fir.logical<4>>, !fir.ref<!fir.logical<4>>)
+! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[NT_VAL:.*]] = fir.load %[[NT_DECL]]#0 : !fir.ref<i32>
+! CHECK: hlfir.assign %[[NT_VAL]] to %[[NT_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+! 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<i32>
+! CHECK: fir.call @_QPfoo(%[[I_PRIV_DECL]]#1, %[[COND_PRIV_DECL]]#1, %[[NT_PRIV_DECL]]#1) {{.*}}: (!fir.ref<i32>, !fir.ref<!fir.logical<4>>, !fir.ref<i32>) -> ()
+! 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<i32> {fir.bindc_name = "a"},
+! CHECK-SAME: %[[B_ADDR:.*]]: !fir.ref<i32> {fir.bindc_name = "b"}) {
+! CHECK: %[[A_DECL:.*]]:2 = hlfir.declare %[[A_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEa"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[B_DECL:.*]]:2 = hlfir.declare %[[B_ADDR]] {uniq_name = "_QFomp_parallel_do_multiple_firstprivateEb"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>
+! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[A:.*]] = fir.load %[[A_DECL]]#0 : !fir.ref<i32>
+! CHECK: hlfir.assign %[[A]] to %[[A_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+! 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<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
+! CHECK: %[[B:.*]] = fir.load %[[B_DECL]]#0 : !fir.ref<i32>
+! CHECK: hlfir.assign %[[B]] to %[[B_PRIV_DECL]]#0 temporary_lhs : i32, !fir.ref<i32>
+! 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<i32>
+! CHECK: fir.call @_QPbar(%[[I_PRIV_DECL]]#1, %[[A_PRIV_DECL]]#1) {{.*}}: (!fir.ref<i32>, !fir.ref<i32>) -> ()
+! 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 000000000000000..0e43244994cfdb2
--- /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<i32>
+ !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<i32>
+ !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
More information about the flang-commits
mailing list