[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