[flang-commits] [flang] c858f4d - [flang][OpenMP] Fix firstprivate with barrier
Shraiysh Vaishay via flang-commits
flang-commits at lists.llvm.org
Mon Jun 20 21:36:17 PDT 2022
Author: Shraiysh Vaishay
Date: 2022-06-21T10:06:05+05:30
New Revision: c858f4dbd5d06b227ff87bbe5ebd787d04148749
URL: https://github.com/llvm/llvm-project/commit/c858f4dbd5d06b227ff87bbe5ebd787d04148749
DIFF: https://github.com/llvm/llvm-project/commit/c858f4dbd5d06b227ff87bbe5ebd787d04148749.diff
LOG: [flang][OpenMP] Fix firstprivate with barrier
This patch fixes the unintentional data race in firstprivate
implementation. There is a Read-Write race when one thread tries
to copy the value inside the omp.parallel region while other
thread modifies it from inside the region (using pointers or
some other form of indirect access).
For detailed discussion please refer to [[ https://discourse.llvm.org/t/issues-with-the-current-implementation-of-privatization-in-openmp-with-fortran/62335 | discourse ]].
Reviewed By: kiranchandramohan, peixin, NimishMishra
Differential Revision: https://reviews.llvm.org/D125689
Added:
Modified:
flang/lib/Lower/OpenMP.cpp
flang/test/Lower/OpenMP/omp-parallel-firstprivate-clause-scalar.f90
flang/test/Lower/OpenMP/omp-parallel-wsloop.f90
Removed:
################################################################################
diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp
index bd893aaa6d3df..a895e6fea37e8 100644
--- a/flang/lib/Lower/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP.cpp
@@ -84,6 +84,7 @@ static void privatizeVars(Fortran::lower::AbstractConverter &converter,
fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder();
auto insPt = firOpBuilder.saveInsertionPoint();
firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock());
+ bool hasFirstPrivateOp = false;
for (const Fortran::parser::OmpClause &clause : opClauseList.v) {
if (const auto &privateClause =
std::get_if<Fortran::parser::OmpClause::Private>(&clause.u)) {
@@ -92,8 +93,11 @@ static void privatizeVars(Fortran::lower::AbstractConverter &converter,
std::get_if<Fortran::parser::OmpClause::Firstprivate>(
&clause.u)) {
createPrivateVarSyms(converter, firstPrivateClause);
+ hasFirstPrivateOp = true;
}
}
+ if (hasFirstPrivateOp)
+ firOpBuilder.create<mlir::omp::BarrierOp>(converter.getCurrentLocation());
firOpBuilder.restoreInsertionPoint(insPt);
}
diff --git a/flang/test/Lower/OpenMP/omp-parallel-firstprivate-clause-scalar.f90 b/flang/test/Lower/OpenMP/omp-parallel-firstprivate-clause-scalar.f90
index 06be9e5e0501c..0fb1b3ea7105f 100644
--- a/flang/test/Lower/OpenMP/omp-parallel-firstprivate-clause-scalar.f90
+++ b/flang/test/Lower/OpenMP/omp-parallel-firstprivate-clause-scalar.f90
@@ -3,71 +3,53 @@
! REQUIRES: shell
! RUN: bbc -fopenmp -emit-fir %s -o - | FileCheck %s --check-prefix=FIRDialect
-!FIRDialect: func @_QPfirstprivate_complex(%[[ARG1:.*]]: !fir.ref<!fir.complex<4>>{{.*}}, %[[ARG2:.*]]: !fir.ref<!fir.complex<8>>{{.*}}) {
-!FIRDialect-DAG: omp.parallel {
-!FIRDialect-DAG: %[[ARG1_PVT:.*]] = fir.alloca !fir.complex<4> {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_complexEarg1"}
-!FIRDialect-DAG: %[[ARG1_VAL:.*]] = fir.load %arg0 : !fir.ref<!fir.complex<4>>
-!FIRDialect-DAG: fir.store %[[ARG1_VAL]] to %[[ARG1_PVT]] : !fir.ref<!fir.complex<4>>
-!FIRDialect-DAG: %[[ARG2_PVT:.*]] = fir.alloca !fir.complex<8> {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_complexEarg2"}
-!FIRDialect-DAG: %[[ARG2_VAL:.*]] = fir.load %[[ARG2]] : !fir.ref<!fir.complex<8>>
-!FIRDialect-DAG: fir.store %[[ARG2_VAL]] to %[[ARG2_PVT]] : !fir.ref<!fir.complex<8>>
-!FIRDialect-DAG: %[[LIST_IO:.*]] = fir.call @_FortranAioBeginExternalListOutput
-!FIRDialect-DAG: %[[ARG1_PVT_VAL:.*]] = fir.load %[[ARG1_PVT]] : !fir.ref<!fir.complex<4>>
-!FIRDialect-DAG: %[[ARG1_PVT_REAL:.*]] = fir.extract_value %[[ARG1_PVT_VAL]], [0 : index] : (!fir.complex<4>) -> f32
-!FIRDialect-DAG: %[[ARG1_PVT_IMAG:.*]] = fir.extract_value %[[ARG1_PVT_VAL]], [1 : index] : (!fir.complex<4>) -> f32
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputComplex32(%[[LIST_IO]], %[[ARG1_PVT_REAL]], %[[ARG1_PVT_IMAG]]) : (!fir.ref<i8>, f32, f32) -> i1
-!FIRDialect-DAG: %[[ARG2_PVT_VAL:.*]] = fir.load %[[ARG2_PVT]] : !fir.ref<!fir.complex<8>>
-!FIRDialect-DAG: %[[ARG2_PVT_REAL:.*]] = fir.extract_value %[[ARG2_PVT_VAL]], [0 : index] : (!fir.complex<8>) -> f64
-!FIRDialect-DAG: %[[ARG2_PVT_IMAG:.*]] = fir.extract_value %[[ARG2_PVT_VAL]], [1 : index] : (!fir.complex<8>) -> f64
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputComplex64(%[[LIST_IO]], %[[ARG2_PVT_REAL]], %[[ARG2_PVT_IMAG]]) : (!fir.ref<i8>, f64, f64) -> i1
-!FIRDialect-DAG: omp.terminator
-!FIRDialect-DAG: }
+!FIRDialect-DAG: func @_QPfirstprivate_complex(%[[ARG1:.*]]: !fir.ref<!fir.complex<4>>{{.*}}, %[[ARG2:.*]]: !fir.ref<!fir.complex<8>>{{.*}}) {
+!FIRDialect: omp.parallel {
+!FIRDialect: %[[ARG1_PVT:.*]] = fir.alloca !fir.complex<4> {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_complexEarg1"}
+!FIRDialect: %[[ARG1_VAL:.*]] = fir.load %[[ARG1]] : !fir.ref<!fir.complex<4>>
+!FIRDialect: fir.store %[[ARG1_VAL]] to %[[ARG1_PVT]] : !fir.ref<!fir.complex<4>>
+!FIRDialect: %[[ARG2_PVT:.*]] = fir.alloca !fir.complex<8> {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_complexEarg2"}
+!FIRDialect: %[[ARG2_VAL:.*]] = fir.load %[[ARG2]] : !fir.ref<!fir.complex<8>>
+!FIRDialect: fir.store %[[ARG2_VAL]] to %[[ARG2_PVT]] : !fir.ref<!fir.complex<8>>
+!FIRDialect: omp.barrier
+!FIRDialect: fir.call @_QPfoo(%[[ARG1_PVT]], %[[ARG2_PVT]]) : (!fir.ref<!fir.complex<4>>, !fir.ref<!fir.complex<8>>) -> ()
+!FIRDialect: omp.terminator
+!FIRDialect: }
subroutine firstprivate_complex(arg1, arg2)
complex(4) :: arg1
complex(8) :: arg2
!$OMP PARALLEL FIRSTPRIVATE(arg1, arg2)
- print *, arg1, arg2
+ call foo(arg1, arg2)
!$OMP END PARALLEL
end subroutine
-!FIRDialect: 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>{{.*}}) {
-!FIRDialect-DAG: omp.parallel {
-!FIRDialect-DAG: %[[ARG1_PVT:.*]] = fir.alloca i32 {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_integerEarg1"}
-!FIRDialect-DAG: %[[ARG1_VAL:.*]] = fir.load %[[ARG1]] : !fir.ref<i32>
-!FIRDialect-DAG: fir.store %[[ARG1_VAL]] to %[[ARG1_PVT]] : !fir.ref<i32>
-!FIRDialect-DAG: %[[ARG2_PVT:.*]] = fir.alloca i8 {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_integerEarg2"}
-!FIRDialect-DAG: %[[ARG2_VAL:.*]] = fir.load %[[ARG2]] : !fir.ref<i8>
-!FIRDialect-DAG: fir.store %[[ARG2_VAL]] to %[[ARG2_PVT]] : !fir.ref<i8>
-!FIRDialect-DAG: %[[ARG3_PVT:.*]] = fir.alloca i16 {bindc_name = "arg3", pinned, uniq_name = "_QFfirstprivate_integerEarg3"}
-!FIRDialect-DAG: %[[ARG3_VAL:.*]] = fir.load %[[ARG3]] : !fir.ref<i16>
-!FIRDialect-DAG: fir.store %[[ARG3_VAL]] to %[[ARG3_PVT]] : !fir.ref<i16>
-!FIRDialect-DAG: %[[ARG4_PVT:.*]] = fir.alloca i32 {bindc_name = "arg4", pinned, uniq_name = "_QFfirstprivate_integerEarg4"}
-!FIRDialect-DAG: %[[ARG4_VAL:.*]] = fir.load %[[ARG4]] : !fir.ref<i32>
-!FIRDialect-DAG: fir.store %[[ARG4_VAL]] to %[[ARG4_PVT]] : !fir.ref<i32>
-!FIRDialect-DAG: %[[ARG5_PVT:.*]] = fir.alloca i64 {bindc_name = "arg5", pinned, uniq_name = "_QFfirstprivate_integerEarg5"}
-!FIRDialect-DAG: %[[ARG5_VAL:.*]] = fir.load %[[ARG5]] : !fir.ref<i64>
-!FIRDialect-DAG: fir.store %[[ARG5_VAL]] to %[[ARG5_PVT]] : !fir.ref<i64>
-!FIRDialect-DAG: %[[ARG6_PVT:.*]] = fir.alloca i128 {bindc_name = "arg6", pinned, uniq_name = "_QFfirstprivate_integerEarg6"}
-!FIRDialect-DAG: %[[ARG6_VAL:.*]] = fir.load %[[ARG6]] : !fir.ref<i128>
-!FIRDialect-DAG: fir.store %[[ARG6_VAL]] to %[[ARG6_PVT]] : !fir.ref<i128>
-!FIRDialect-DAG: %[[LIST_IO:.*]] = fir.call @_FortranAioBeginExternalListOutput
-!FIRDialect-DAG: %[[ARG1_PVT_VAL:.*]] = fir.load %[[ARG1_PVT]] : !fir.ref<i32>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputInteger32(%[[LIST_IO]], %[[ARG1_PVT_VAL]]) : (!fir.ref<i8>, i32) -> i1
-!FIRDialect-DAG: %[[ARG2_PVT_VAL:.*]] = fir.load %[[ARG2_PVT]] : !fir.ref<i8>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputInteger8(%[[LIST_IO]], %[[ARG2_PVT_VAL]]) : (!fir.ref<i8>, i8) -> i1
-!FIRDialect-DAG: %[[ARG3_PVT_VAL:.*]] = fir.load %[[ARG3_PVT]] : !fir.ref<i16>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputInteger16(%[[LIST_IO]], %[[ARG3_PVT_VAL]]) : (!fir.ref<i8>, i16) -> i1
-!FIRDialect-DAG: %[[ARG4_PVT_VAL:.*]] = fir.load %[[ARG4_PVT]] : !fir.ref<i32>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputInteger32(%[[LIST_IO]], %[[ARG4_PVT_VAL]]) : (!fir.ref<i8>, i32) -> i1
-!FIRDialect-DAG: %[[ARG5_PVT_VAL:.*]] = fir.load %[[ARG5_PVT]] : !fir.ref<i64>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputInteger64(%[[LIST_IO]], %[[ARG5_PVT_VAL]]) : (!fir.ref<i8>, i64) -> i1
-!FIRDialect-DAG: %[[ARG6_PVT_VAL:.*]] = fir.load %[[ARG6_PVT]] : !fir.ref<i128>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputInteger128(%[[LIST_IO]], %[[ARG6_PVT_VAL]]) : (!fir.ref<i8>, i128) -> i1
-!FIRDialect-DAG: omp.terminator
-!FIRDialect-DAG: }
+!FIRDialect-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>{{.*}}) {
+!FIRDialect: omp.parallel {
+!FIRDialect: %[[ARG1_PVT:.*]] = fir.alloca i32 {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_integerEarg1"}
+!FIRDialect: %[[ARG1_VAL:.*]] = fir.load %[[ARG1]] : !fir.ref<i32>
+!FIRDialect: fir.store %[[ARG1_VAL]] to %[[ARG1_PVT]] : !fir.ref<i32>
+!FIRDialect: %[[ARG2_PVT:.*]] = fir.alloca i8 {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_integerEarg2"}
+!FIRDialect: %[[ARG2_VAL:.*]] = fir.load %[[ARG2]] : !fir.ref<i8>
+!FIRDialect: fir.store %[[ARG2_VAL]] to %[[ARG2_PVT]] : !fir.ref<i8>
+!FIRDialect: %[[ARG3_PVT:.*]] = fir.alloca i16 {bindc_name = "arg3", pinned, uniq_name = "_QFfirstprivate_integerEarg3"}
+!FIRDialect: %[[ARG3_VAL:.*]] = fir.load %[[ARG3]] : !fir.ref<i16>
+!FIRDialect: fir.store %[[ARG3_VAL]] to %[[ARG3_PVT]] : !fir.ref<i16>
+!FIRDialect: %[[ARG4_PVT:.*]] = fir.alloca i32 {bindc_name = "arg4", pinned, uniq_name = "_QFfirstprivate_integerEarg4"}
+!FIRDialect: %[[ARG4_VAL:.*]] = fir.load %[[ARG4]] : !fir.ref<i32>
+!FIRDialect: fir.store %[[ARG4_VAL]] to %[[ARG4_PVT]] : !fir.ref<i32>
+!FIRDialect: %[[ARG5_PVT:.*]] = fir.alloca i64 {bindc_name = "arg5", pinned, uniq_name = "_QFfirstprivate_integerEarg5"}
+!FIRDialect: %[[ARG5_VAL:.*]] = fir.load %[[ARG5]] : !fir.ref<i64>
+!FIRDialect: fir.store %[[ARG5_VAL]] to %[[ARG5_PVT]] : !fir.ref<i64>
+!FIRDialect: %[[ARG6_PVT:.*]] = fir.alloca i128 {bindc_name = "arg6", pinned, uniq_name = "_QFfirstprivate_integerEarg6"}
+!FIRDialect: %[[ARG6_VAL:.*]] = fir.load %[[ARG6]] : !fir.ref<i128>
+!FIRDialect: fir.store %[[ARG6_VAL]] to %[[ARG6_PVT]] : !fir.ref<i128>
+!FIRDialect: omp.barrier
+!FIRDialect: fir.call @_QPbar(%[[ARG1_PVT]], %[[ARG2_PVT]], %[[ARG3_PVT]], %[[ARG4_PVT]], %[[ARG5_PVT]], %[[ARG6_PVT]]) : (!fir.ref<i32>, !fir.ref<i8>, !fir.ref<i16>, !fir.ref<i32>, !fir.ref<i64>, !fir.ref<i128>) -> ()
+!FIRDialect: omp.terminator
+!FIRDialect: }
subroutine firstprivate_integer(arg1, arg2, arg3, arg4, arg5, arg6)
integer :: arg1
@@ -78,46 +60,32 @@ subroutine firstprivate_integer(arg1, arg2, arg3, arg4, arg5, arg6)
integer(kind=16) :: arg6
!$OMP PARALLEL FIRSTPRIVATE(arg1, arg2, arg3, arg4, arg5, arg6)
- print *, arg1, arg2, arg3, arg4, arg5, arg6
+ call bar(arg1, arg2, arg3, arg4, arg5, arg6)
!$OMP END PARALLEL
end subroutine
-!FIRDialect: 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>>{{.*}}) {
-!FIRDialect-DAG: omp.parallel {
-!FIRDialect-DAG: %[[ARG1_PVT:.*]] = fir.alloca !fir.logical<4> {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_logicalEarg1"}
-!FIRDialect-DAG: %[[ARG1_VAL:.*]] = fir.load %[[ARG1]] : !fir.ref<!fir.logical<4>>
-!FIRDialect-DAG: fir.store %[[ARG1_VAL]] to %[[ARG1_PVT]] : !fir.ref<!fir.logical<4>>
-!FIRDialect-DAG: %[[ARG2_PVT:.*]] = fir.alloca !fir.logical<1> {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_logicalEarg2"}
-!FIRDialect-DAG: %[[ARG2_VAL:.*]] = fir.load %[[ARG2]] : !fir.ref<!fir.logical<1>>
-!FIRDialect-DAG: fir.store %[[ARG2_VAL]] to %[[ARG2_PVT]] : !fir.ref<!fir.logical<1>>
-!FIRDialect-DAG: %[[ARG3_PVT:.*]] = fir.alloca !fir.logical<2> {bindc_name = "arg3", pinned, uniq_name = "_QFfirstprivate_logicalEarg3"}
-!FIRDialect-DAG: %[[ARG3_VAL:.*]] = fir.load %[[ARG3]] : !fir.ref<!fir.logical<2>>
-!FIRDialect-DAG: fir.store %[[ARG3_VAL]] to %[[ARG3_PVT]] : !fir.ref<!fir.logical<2>>
-!FIRDialect-DAG: %[[ARG4_PVT:.*]] = fir.alloca !fir.logical<4> {bindc_name = "arg4", pinned, uniq_name = "_QFfirstprivate_logicalEarg4"}
-!FIRDialect-DAG: %[[ARG4_VAL:.*]] = fir.load %[[ARG4]] : !fir.ref<!fir.logical<4>>
-!FIRDialect-DAG: fir.store %[[ARG4_VAL]] to %[[ARG4_PVT]] : !fir.ref<!fir.logical<4>>
-!FIRDialect-DAG: %[[ARG5_PVT:.*]] = fir.alloca !fir.logical<8> {bindc_name = "arg5", pinned, uniq_name = "_QFfirstprivate_logicalEarg5"}
-!FIRDialect-DAG: %[[ARG5_VAL:.*]] = fir.load %[[ARG5]] : !fir.ref<!fir.logical<8>>
-!FIRDialect-DAG: fir.store %[[ARG5_VAL]] to %[[ARG5_PVT]] : !fir.ref<!fir.logical<8>>
-!FIRDialect-DAG: %[[LIST_IO:.*]] = fir.call @_FortranAioBeginExternalListOutput
-!FIRDialect-DAG: %[[ARG1_PVT_VAL:.*]] = fir.load %[[ARG1_PVT]] : !fir.ref<!fir.logical<4>>
-!FIRDialect-DAG: %[[ARG1_PVT_CVT:.*]] = fir.convert %[[ARG1_PVT_VAL]] : (!fir.logical<4>) -> i1
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputLogical(%[[LIST_IO]], %[[ARG1_PVT_CVT]]) : (!fir.ref<i8>, i1) -> i1
-!FIRDialect-DAG: %[[ARG2_PVT_VAL:.*]] = fir.load %[[ARG2_PVT]] : !fir.ref<!fir.logical<1>>
-!FIRDialect-DAG: %[[ARG2_PVT_CVT:.*]] = fir.convert %[[ARG2_PVT_VAL]] : (!fir.logical<1>) -> i1
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputLogical(%[[LIST_IO]], %[[ARG2_PVT_CVT]]) : (!fir.ref<i8>, i1) -> i1
-!FIRDialect-DAG: %[[ARG3_PVT_VAL:.*]] = fir.load %[[ARG3_PVT]] : !fir.ref<!fir.logical<2>>
-!FIRDialect-DAG: %[[ARG3_PVT_CVT:.*]] = fir.convert %[[ARG3_PVT_VAL]] : (!fir.logical<2>) -> i1
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputLogical(%[[LIST_IO]], %[[ARG3_PVT_CVT]]) : (!fir.ref<i8>, i1) -> i1
-!FIRDialect-DAG: %[[ARG4_PVT_VAL:.*]] = fir.load %[[ARG4_PVT]] : !fir.ref<!fir.logical<4>>
-!FIRDialect-DAG: %[[ARG4_PVT_CVT:.*]] = fir.convert %[[ARG4_PVT_VAL]] : (!fir.logical<4>) -> i1
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputLogical(%[[LIST_IO]], %[[ARG4_PVT_CVT]]) : (!fir.ref<i8>, i1) -> i1
-!FIRDialect-DAG: %[[ARG5_PVT_VAL:.*]] = fir.load %[[ARG5_PVT]] : !fir.ref<!fir.logical<8>>
-!FIRDialect-DAG: %[[ARG5_PVT_CVT:.*]] = fir.convert %[[ARG5_PVT_VAL]] : (!fir.logical<8>) -> i1
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputLogical(%[[LIST_IO]], %[[ARG5_PVT_CVT]]) : (!fir.ref<i8>, i1) -> i1
-!FIRDialect-DAG: omp.terminator
-!FIRDialect-DAG: }
+!FIRDialect-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>>{{.*}}) {
+!FIRDialect: omp.parallel {
+!FIRDialect: %[[ARG1_PVT:.*]] = fir.alloca !fir.logical<4> {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_logicalEarg1"}
+!FIRDialect: %[[ARG1_VAL:.*]] = fir.load %[[ARG1]] : !fir.ref<!fir.logical<4>>
+!FIRDialect: fir.store %[[ARG1_VAL]] to %[[ARG1_PVT]] : !fir.ref<!fir.logical<4>>
+!FIRDialect: %[[ARG2_PVT:.*]] = fir.alloca !fir.logical<1> {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_logicalEarg2"}
+!FIRDialect: %[[ARG2_VAL:.*]] = fir.load %[[ARG2]] : !fir.ref<!fir.logical<1>>
+!FIRDialect: fir.store %[[ARG2_VAL]] to %[[ARG2_PVT]] : !fir.ref<!fir.logical<1>>
+!FIRDialect: %[[ARG3_PVT:.*]] = fir.alloca !fir.logical<2> {bindc_name = "arg3", pinned, uniq_name = "_QFfirstprivate_logicalEarg3"}
+!FIRDialect: %[[ARG3_VAL:.*]] = fir.load %[[ARG3]] : !fir.ref<!fir.logical<2>>
+!FIRDialect: fir.store %[[ARG3_VAL]] to %[[ARG3_PVT]] : !fir.ref<!fir.logical<2>>
+!FIRDialect: %[[ARG4_PVT:.*]] = fir.alloca !fir.logical<4> {bindc_name = "arg4", pinned, uniq_name = "_QFfirstprivate_logicalEarg4"}
+!FIRDialect: %[[ARG4_VAL:.*]] = fir.load %[[ARG4]] : !fir.ref<!fir.logical<4>>
+!FIRDialect: fir.store %[[ARG4_VAL]] to %[[ARG4_PVT]] : !fir.ref<!fir.logical<4>>
+!FIRDialect: %[[ARG5_PVT:.*]] = fir.alloca !fir.logical<8> {bindc_name = "arg5", pinned, uniq_name = "_QFfirstprivate_logicalEarg5"}
+!FIRDialect: %[[ARG5_VAL:.*]] = fir.load %[[ARG5]] : !fir.ref<!fir.logical<8>>
+!FIRDialect: fir.store %[[ARG5_VAL]] to %[[ARG5_PVT]] : !fir.ref<!fir.logical<8>>
+!FIRDialect: omp.barrier
+!FIRDialect: fir.call @_QPbaz(%[[ARG1_PVT]], %[[ARG2_PVT]], %[[ARG3_PVT]], %[[ARG4_PVT]], %[[ARG5_PVT]]) : (!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>>) -> ()
+!FIRDialect: omp.terminator
+!FIRDialect: }
subroutine firstprivate_logical(arg1, arg2, arg3, arg4, arg5)
logical :: arg1
@@ -127,49 +95,35 @@ subroutine firstprivate_logical(arg1, arg2, arg3, arg4, arg5)
logical(kind=8) :: arg5
!$OMP PARALLEL FIRSTPRIVATE(arg1, arg2, arg3, arg4, arg5)
- print *, arg1, arg2, arg3, arg4, arg5
+ call baz(arg1, arg2, arg3, arg4, arg5)
!$OMP END PARALLEL
end subroutine
!FIRDialect-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>{{.*}}) {
-!FIRDialect-DAG: omp.parallel {
-!FIRDialect-DAG: %[[ARG1_PVT:.*]] = fir.alloca f32 {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_realEarg1"}
-!FIRDialect-DAG: %[[ARG1_VAL:.*]] = fir.load %[[ARG1]] : !fir.ref<f32>
-!FIRDialect-DAG: fir.store %[[ARG1_VAL]] to %[[ARG1_PVT]] : !fir.ref<f32>
-!FIRDialect-DAG: %[[ARG2_PVT:.*]] = fir.alloca f16 {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_realEarg2"}
-!FIRDialect-DAG: %[[ARG2_VAL:.*]] = fir.load %[[ARG2]] : !fir.ref<f16>
-!FIRDialect-DAG: fir.store %[[ARG2_VAL]] to %[[ARG2_PVT]] : !fir.ref<f16>
-!FIRDialect-DAG: %[[ARG3_PVT:.*]] = fir.alloca f32 {bindc_name = "arg3", pinned, uniq_name = "_QFfirstprivate_realEarg3"}
-!FIRDialect-DAG: %[[ARG3_VAL:.*]] = fir.load %[[ARG3]] : !fir.ref<f32>
-!FIRDialect-DAG: fir.store %[[ARG3_VAL]] to %[[ARG3_PVT]] : !fir.ref<f32>
-!FIRDialect-DAG: %[[ARG4_PVT:.*]] = fir.alloca f64 {bindc_name = "arg4", pinned, uniq_name = "_QFfirstprivate_realEarg4"}
-!FIRDialect-DAG: %[[ARG4_VAL:.*]] = fir.load %[[ARG4]] : !fir.ref<f64>
-!FIRDialect-DAG: fir.store %[[ARG4_VAL]] to %[[ARG4_PVT]] : !fir.ref<f64>
-!FIRDialect-DAG: %[[ARG5_PVT:.*]] = fir.alloca f80 {bindc_name = "arg5", pinned, uniq_name = "_QFfirstprivate_realEarg5"}
-!FIRDialect-DAG: %[[ARG5_VAL:.*]] = fir.load %[[ARG5]] : !fir.ref<f80>
-!FIRDialect-DAG: fir.store %[[ARG5_VAL]] to %[[ARG5_PVT]] : !fir.ref<f80>
-!FIRDialect-DAG: %[[ARG6_PVT:.*]] = fir.alloca f128 {bindc_name = "arg6", pinned, uniq_name = "_QFfirstprivate_realEarg6"}
-!FIRDialect-DAG: %[[ARG6_VAL:.*]] = fir.load %[[ARG6]] : !fir.ref<f128>
-!FIRDialect-DAG: fir.store %[[ARG6_VAL]] to %[[ARG6_PVT]] : !fir.ref<f128>
-!FIRDialect-DAG: %[[LIST_IO:.*]] = fir.call @_FortranAioBeginExternalListOutput
-!FIRDialect-DAG: %[[ARG1_PVT_VAL:.*]] = fir.load %[[ARG1_PVT]] : !fir.ref<f32>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputReal32(%[[LIST_IO]], %[[ARG1_PVT_VAL]]) : (!fir.ref<i8>, f32) -> i1
-!FIRDialect-DAG: %[[ARG2_PVT_VAL:.*]] = fir.embox %[[ARG2_PVT]] : (!fir.ref<f16>) -> !fir.box<f16>
-!FIRDialect-DAG: %[[ARG2_PVT_CVT:.*]] = fir.convert %[[ARG2_PVT_VAL]] : (!fir.box<f16>) -> !fir.box<none>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputDescriptor(%[[LIST_IO]], %[[ARG2_PVT_CVT]]) : (!fir.ref<i8>, !fir.box<none>) -> i1
-!FIRDialect-DAG: %[[ARG3_PVT_VAL:.*]] = fir.load %[[ARG3_PVT]] : !fir.ref<f32>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputReal32(%[[LIST_IO]], %[[ARG3_PVT_VAL]]) : (!fir.ref<i8>, f32) -> i1
-!FIRDialect-DAG: %[[ARG4_PVT_VAL:.*]] = fir.load %[[ARG4_PVT]] : !fir.ref<f64>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputReal64(%[[LIST_IO]], %[[ARG4_PVT_VAL]]) : (!fir.ref<i8>, f64) -> i1
-!FIRDialect-DAG: %[[ARG5_PVT_VAL:.*]] = fir.embox %[[ARG5_PVT]] : (!fir.ref<f80>) -> !fir.box<f80>
-!FIRDialect-DAG: %[[ARG5_PVT_CVT:.*]] = fir.convert %[[ARG5_PVT_VAL]] : (!fir.box<f80>) -> !fir.box<none>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputDescriptor(%[[LIST_IO]], %[[ARG5_PVT_CVT]]) : (!fir.ref<i8>, !fir.box<none>) -> i1
-!FIRDialect-DAG: %[[ARG6_PVT_VAL:.*]] = fir.embox %[[ARG6_PVT]] : (!fir.ref<f128>) -> !fir.box<f128>
-!FIRDialect-DAG: %[[ARG6_PVT_CVT:.*]] = fir.convert %[[ARG6_PVT_VAL]] : (!fir.box<f128>) -> !fir.box<none>
-!FIRDialect-DAG: %{{.*}} = fir.call @_FortranAioOutputDescriptor(%[[LIST_IO]], %[[ARG6_PVT_CVT]]) : (!fir.ref<i8>, !fir.box<none>) -> i1
-!FIRDialect-DAG: omp.terminator
-!FIRDialect-DAG: }
+!FIRDialect: omp.parallel {
+!FIRDialect: %[[ARG1_PVT:.*]] = fir.alloca f32 {bindc_name = "arg1", pinned, uniq_name = "_QFfirstprivate_realEarg1"}
+!FIRDialect: %[[ARG1_VAL:.*]] = fir.load %[[ARG1]] : !fir.ref<f32>
+!FIRDialect: fir.store %[[ARG1_VAL]] to %[[ARG1_PVT]] : !fir.ref<f32>
+!FIRDialect: %[[ARG2_PVT:.*]] = fir.alloca f16 {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_realEarg2"}
+!FIRDialect: %[[ARG2_VAL:.*]] = fir.load %[[ARG2]] : !fir.ref<f16>
+!FIRDialect: fir.store %[[ARG2_VAL]] to %[[ARG2_PVT]] : !fir.ref<f16>
+!FIRDialect: %[[ARG3_PVT:.*]] = fir.alloca f32 {bindc_name = "arg3", pinned, uniq_name = "_QFfirstprivate_realEarg3"}
+!FIRDialect: %[[ARG3_VAL:.*]] = fir.load %[[ARG3]] : !fir.ref<f32>
+!FIRDialect: fir.store %[[ARG3_VAL]] to %[[ARG3_PVT]] : !fir.ref<f32>
+!FIRDialect: %[[ARG4_PVT:.*]] = fir.alloca f64 {bindc_name = "arg4", pinned, uniq_name = "_QFfirstprivate_realEarg4"}
+!FIRDialect: %[[ARG4_VAL:.*]] = fir.load %[[ARG4]] : !fir.ref<f64>
+!FIRDialect: fir.store %[[ARG4_VAL]] to %[[ARG4_PVT]] : !fir.ref<f64>
+!FIRDialect: %[[ARG5_PVT:.*]] = fir.alloca f80 {bindc_name = "arg5", pinned, uniq_name = "_QFfirstprivate_realEarg5"}
+!FIRDialect: %[[ARG5_VAL:.*]] = fir.load %[[ARG5]] : !fir.ref<f80>
+!FIRDialect: fir.store %[[ARG5_VAL]] to %[[ARG5_PVT]] : !fir.ref<f80>
+!FIRDialect: %[[ARG6_PVT:.*]] = fir.alloca f128 {bindc_name = "arg6", pinned, uniq_name = "_QFfirstprivate_realEarg6"}
+!FIRDialect: %[[ARG6_VAL:.*]] = fir.load %[[ARG6]] : !fir.ref<f128>
+!FIRDialect: fir.store %[[ARG6_VAL]] to %[[ARG6_PVT]] : !fir.ref<f128>
+!FIRDialect: omp.barrier
+!FIRDialect: fir.call @_QPqux(%[[ARG1_PVT]], %[[ARG2_PVT]], %[[ARG3_PVT]], %[[ARG4_PVT]], %[[ARG5_PVT]], %[[ARG6_PVT]]) : (!fir.ref<f32>, !fir.ref<f16>, !fir.ref<f32>, !fir.ref<f64>, !fir.ref<f80>, !fir.ref<f128>) -> ()
+!FIRDialect: omp.terminator
+!FIRDialect: }
subroutine firstprivate_real(arg1, arg2, arg3, arg4, arg5, arg6)
real :: arg1
@@ -180,7 +134,32 @@ subroutine firstprivate_real(arg1, arg2, arg3, arg4, arg5, arg6)
real(kind=16) :: arg6
!$OMP PARALLEL FIRSTPRIVATE(arg1, arg2, arg3, arg4, arg5, arg6)
- print *, arg1, arg2, arg3, arg4, arg5, arg6
+ call qux(arg1, arg2, arg3, arg4, arg5, arg6)
!$OMP END PARALLEL
end subroutine
+
+!FIRDialect-LABEL: func.func @_QPmultiple_firstprivate(
+!FIRDialect-SAME: %[[A_ADDR:.*]]: !fir.ref<i32> {fir.bindc_name = "a"},
+!FIRDialect-SAME: %[[B_ADDR:.*]]: !fir.ref<i32> {fir.bindc_name = "b"}) {
+!FIRDialect: omp.parallel {
+!FIRDialect: %[[A_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFmultiple_firstprivateEa"}
+!FIRDialect: %[[A:.*]] = fir.load %[[A_ADDR]] : !fir.ref<i32>
+!FIRDialect: fir.store %[[A]] to %[[A_PRIV_ADDR]] : !fir.ref<i32>
+!FIRDialect: %[[B_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "b", pinned, uniq_name = "_QFmultiple_firstprivateEb"}
+!FIRDialect: %[[B:.*]] = fir.load %[[B_ADDR]] : !fir.ref<i32>
+!FIRDialect: fir.store %[[B]] to %[[B_PRIV_ADDR]] : !fir.ref<i32>
+!FIRDialect: omp.barrier
+!FIRDialect-NOT: omp.barrier
+!FIRDialect: fir.call @_QPquux(%[[A_PRIV_ADDR]], %[[B_PRIV_ADDR]]) : (!fir.ref<i32>, !fir.ref<i32>) -> ()
+!FIRDialect: omp.terminator
+!FIRDialect: }
+!FIRDialect: return
+!FIRDialect: }
+
+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/omp-parallel-wsloop.f90 b/flang/test/Lower/OpenMP/omp-parallel-wsloop.f90
index 67418a1320b09..cacd0d19df599 100644
--- a/flang/test/Lower/OpenMP/omp-parallel-wsloop.f90
+++ b/flang/test/Lower/OpenMP/omp-parallel-wsloop.f90
@@ -71,6 +71,11 @@ subroutine parallel_do_with_clauses(nt)
!$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)
@@ -82,6 +87,7 @@ subroutine parallel_do_with_privatisation_clauses(cond,nt)
! CHECK: %[[PRIVATE_NT_REF:.*]] = fir.alloca i32 {bindc_name = "nt", pinned, uniq_name = "_QFparallel_do_with_privatisation_clausesEnt"}
! CHECK: %[[NT_VAL:.*]] = fir.load %[[NT_REF]] : !fir.ref<i32>
! CHECK: fir.store %[[NT_VAL]] to %[[PRIVATE_NT_REF]] : !fir.ref<i32>
+ ! CHECK: omp.barrier
! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32
! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32
! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32
@@ -102,3 +108,178 @@ subroutine parallel_do_with_privatisation_clauses(cond,nt)
! 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: %[[I:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFparallel_private_doEi"}
+! CHECK: omp.parallel {
+! CHECK: %[[I_PRIV:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
+! CHECK: %[[COND_ADDR:.*]] = fir.alloca !fir.logical<4> {bindc_name = "cond", pinned, uniq_name = "_QFparallel_private_doEcond"}
+! CHECK: %[[NT_ADDR:.*]] = fir.alloca i32 {bindc_name = "nt", pinned, uniq_name = "_QFparallel_private_doEnt"}
+! CHECK: %[[NT:.*]] = fir.load %[[VAL_1]] : !fir.ref<i32>
+! CHECK: fir.store %[[NT]] to %[[NT_ADDR]] : !fir.ref<i32>
+! CHECK: omp.barrier
+! 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]] : !fir.ref<i32>
+! CHECK: fir.call @_QPfoo(%[[I_PRIV]], %[[COND_ADDR]], %[[NT_ADDR]]) : (!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 - multiple firstprivate clauses must emit
+! only one barrier
+! !$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: %[[I_ADDR:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFomp_parallel_multiple_firstprivate_doEi"}
+! CHECK: omp.parallel {
+! CHECK: %[[I_PRIV_ADDR:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
+! CHECK: %[[A_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFomp_parallel_multiple_firstprivate_doEa"}
+! CHECK: %[[A:.*]] = fir.load %[[A_ADDR]] : !fir.ref<i32>
+! CHECK: fir.store %[[A]] to %[[A_PRIV_ADDR]] : !fir.ref<i32>
+! CHECK: %[[B_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "b", pinned, uniq_name = "_QFomp_parallel_multiple_firstprivate_doEb"}
+! CHECK: %[[B:.*]] = fir.load %[[B_ADDR]] : !fir.ref<i32>
+! CHECK: fir.store %[[B]] to %[[B_PRIV_ADDR]] : !fir.ref<i32>
+! CHECK: omp.barrier
+! 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_ADDR]] : !fir.ref<i32>
+! CHECK: fir.call @_QPbar(%[[I_PRIV_ADDR]], %[[A_PRIV_ADDR]]) : (!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: %[[I_ADDR:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFparallel_do_privateEi"}
+! CHECK: omp.parallel {
+! CHECK: %[[COND_ADDR:.*]] = fir.alloca !fir.logical<4> {bindc_name = "cond", pinned, uniq_name = "_QFparallel_do_privateEcond"}
+! CHECK: %[[NT_ADDR:.*]] = fir.alloca i32 {bindc_name = "nt", pinned, uniq_name = "_QFparallel_do_privateEnt"}
+! CHECK: %[[NT:.*]] = fir.load %[[VAL_1]] : !fir.ref<i32>
+! CHECK: fir.store %[[NT]] to %[[NT_ADDR]] : !fir.ref<i32>
+! CHECK: omp.barrier
+! CHECK: %[[I_PRIV_ADDR:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
+! 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_ADDR]] : !fir.ref<i32>
+! CHECK: fir.call @_QPfoo(%[[I_PRIV_ADDR]], %[[COND_ADDR]], %[[NT_ADDR]]) : (!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 - multiple firstprivate clauses must emit
+! only one barrier
+! !$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: %[[I_ADDR:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFomp_parallel_do_multiple_firstprivateEi"}
+! CHECK: omp.parallel {
+! CHECK: %[[A_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFomp_parallel_do_multiple_firstprivateEa"}
+! CHECK: %[[A:.*]] = fir.load %[[A_ADDR]] : !fir.ref<i32>
+! CHECK: fir.store %[[A]] to %[[A_PRIV_ADDR]] : !fir.ref<i32>
+! CHECK: %[[B_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "b", pinned, uniq_name = "_QFomp_parallel_do_multiple_firstprivateEb"}
+! CHECK: %[[B:.*]] = fir.load %[[B_ADDR]] : !fir.ref<i32>
+! CHECK: fir.store %[[B]] to %[[B_PRIV_ADDR]] : !fir.ref<i32>
+! CHECK: omp.barrier
+! CHECK-NOT: omp.barrier
+! CHECK: %[[I_PRIV_ADDR:.*]] = fir.alloca i32 {adapt.valuebyref, pinned}
+! 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_ADDR]] : !fir.ref<i32>
+! CHECK: fir.call @_QPbar(%[[I_PRIV_ADDR]], %[[A_PRIV_ADDR]]) : (!fir.ref<i32>, !fir.ref<i32>) -> ()
+! CHECK: omp.yield
+! CHECK: }
+! CHECK: omp.terminator
+! CHECK: }
+! CHECK: return
+! CHECK: }
More information about the flang-commits
mailing list