Index: flang/lib/Lower/OpenMP.cpp =================================================================== --- flang/lib/Lower/OpenMP.cpp +++ flang/lib/Lower/OpenMP.cpp @@ -83,7 +83,8 @@ fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); auto insPt = firOpBuilder.saveInsertionPoint(); firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock()); - bool hasFirstPrivateOp = false; + bool hasFirstprivateOp = false; + bool hasLastprivateOp = false; for (const Fortran::parser::OmpClause &clause : opClauseList.v) { if (const auto &privateClause = std::get_if(&clause.u)) { @@ -92,10 +93,20 @@ std::get_if( &clause.u)) { createPrivateVarSyms(converter, firstPrivateClause); - hasFirstPrivateOp = true; + hasFirstprivateOp = true; + } else if (std::get_if( + &clause.u)) { + hasLastprivateOp = true; } } - if (hasFirstPrivateOp) + // Emit implicit barrier to synchronize threads and avoid data races on + // initialization of firstprivate variables and post-update of lastprivate + // variables. + // FIXME: Emit barrier for lastprivate clause when 'sections' directive has + // 'nowait' clause. Otherwise, emit barrier when 'sections' directive has + // both firstprivate and lastprivate clause. + // TODO: Emit implicit barrier for linear clause. Maybe on somewhere else. + if (hasFirstprivateOp && hasLastprivateOp) firOpBuilder.create(converter.getCurrentLocation()); firOpBuilder.restoreInsertionPoint(insPt); } Index: flang/test/Lower/OpenMP/omp-parallel-firstprivate-clause-scalar.f90 =================================================================== --- flang/test/Lower/OpenMP/omp-parallel-firstprivate-clause-scalar.f90 +++ flang/test/Lower/OpenMP/omp-parallel-firstprivate-clause-scalar.f90 @@ -11,7 +11,7 @@ !FIRDialect: %[[ARG2_PVT:.*]] = fir.alloca !fir.complex<8> {bindc_name = "arg2", pinned, uniq_name = "_QFfirstprivate_complexEarg2"} !FIRDialect: %[[ARG2_VAL:.*]] = fir.load %[[ARG2]] : !fir.ref> !FIRDialect: fir.store %[[ARG2_VAL]] to %[[ARG2_PVT]] : !fir.ref> -!FIRDialect: omp.barrier +!FIRDialect-NOT: omp.barrier !FIRDialect: fir.call @_QPfoo(%[[ARG1_PVT]], %[[ARG2_PVT]]) : (!fir.ref>, !fir.ref>) -> () !FIRDialect: omp.terminator !FIRDialect: } @@ -46,7 +46,7 @@ !FIRDialect: %[[ARG6_PVT:.*]] = fir.alloca i128 {bindc_name = "arg6", pinned, uniq_name = "_QFfirstprivate_integerEarg6"} !FIRDialect: %[[ARG6_VAL:.*]] = fir.load %[[ARG6]] : !fir.ref !FIRDialect: fir.store %[[ARG6_VAL]] to %[[ARG6_PVT]] : !fir.ref -!FIRDialect: omp.barrier +!FIRDialect-NOT:omp.barrier !FIRDialect: fir.call @_QPbar(%[[ARG1_PVT]], %[[ARG2_PVT]], %[[ARG3_PVT]], %[[ARG4_PVT]], %[[ARG5_PVT]], %[[ARG6_PVT]]) : (!fir.ref, !fir.ref, !fir.ref, !fir.ref, !fir.ref, !fir.ref) -> () !FIRDialect: omp.terminator !FIRDialect: } @@ -82,7 +82,7 @@ !FIRDialect: %[[ARG5_PVT:.*]] = fir.alloca !fir.logical<8> {bindc_name = "arg5", pinned, uniq_name = "_QFfirstprivate_logicalEarg5"} !FIRDialect: %[[ARG5_VAL:.*]] = fir.load %[[ARG5]] : !fir.ref> !FIRDialect: fir.store %[[ARG5_VAL]] to %[[ARG5_PVT]] : !fir.ref> -!FIRDialect: omp.barrier +!FIRDialect-NOT: omp.barrier !FIRDialect: fir.call @_QPbaz(%[[ARG1_PVT]], %[[ARG2_PVT]], %[[ARG3_PVT]], %[[ARG4_PVT]], %[[ARG5_PVT]]) : (!fir.ref>, !fir.ref>, !fir.ref>, !fir.ref>, !fir.ref>) -> () !FIRDialect: omp.terminator !FIRDialect: } @@ -120,7 +120,7 @@ !FIRDialect: %[[ARG6_PVT:.*]] = fir.alloca f128 {bindc_name = "arg6", pinned, uniq_name = "_QFfirstprivate_realEarg6"} !FIRDialect: %[[ARG6_VAL:.*]] = fir.load %[[ARG6]] : !fir.ref !FIRDialect: fir.store %[[ARG6_VAL]] to %[[ARG6_PVT]] : !fir.ref -!FIRDialect: omp.barrier +!FIRDialect-NOT: omp.barrier !FIRDialect: fir.call @_QPqux(%[[ARG1_PVT]], %[[ARG2_PVT]], %[[ARG3_PVT]], %[[ARG4_PVT]], %[[ARG5_PVT]], %[[ARG6_PVT]]) : (!fir.ref, !fir.ref, !fir.ref, !fir.ref, !fir.ref, !fir.ref) -> () !FIRDialect: omp.terminator !FIRDialect: } @@ -149,7 +149,6 @@ !FIRDialect: %[[B_PRIV_ADDR:.*]] = fir.alloca i32 {bindc_name = "b", pinned, uniq_name = "_QFmultiple_firstprivateEb"} !FIRDialect: %[[B:.*]] = fir.load %[[B_ADDR]] : !fir.ref !FIRDialect: fir.store %[[B]] to %[[B_PRIV_ADDR]] : !fir.ref -!FIRDialect: omp.barrier !FIRDialect-NOT: omp.barrier !FIRDialect: fir.call @_QPquux(%[[A_PRIV_ADDR]], %[[B_PRIV_ADDR]]) : (!fir.ref, !fir.ref) -> () !FIRDialect: omp.terminator Index: flang/test/Lower/OpenMP/omp-parallel-wsloop.f90 =================================================================== --- flang/test/Lower/OpenMP/omp-parallel-wsloop.f90 +++ flang/test/Lower/OpenMP/omp-parallel-wsloop.f90 @@ -87,7 +87,7 @@ ! 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 ! CHECK: fir.store %[[NT_VAL]] to %[[PRIVATE_NT_REF]] : !fir.ref - ! CHECK: omp.barrier + ! CHECK-NOT:omp.barrier ! CHECK: %[[WS_LB:.*]] = arith.constant 1 : i32 ! CHECK: %[[WS_UB:.*]] = arith.constant 9 : i32 ! CHECK: %[[WS_STEP:.*]] = arith.constant 1 : i32 @@ -138,7 +138,7 @@ ! CHECK: %[[NT_ADDR:.*]] = fir.alloca i32 {bindc_name = "nt", pinned, uniq_name = "_QFparallel_private_doEnt"} ! CHECK: %[[NT:.*]] = fir.load %[[VAL_1]] : !fir.ref ! CHECK: fir.store %[[NT]] to %[[NT_ADDR]] : !fir.ref -! CHECK: omp.barrier +! CHECK-NOT: omp.barrier ! CHECK: %[[VAL_7:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_8:.*]] = arith.constant 9 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 1 : i32 @@ -153,8 +153,7 @@ ! CHECK: } !=============================================================================== -! Checking for the following construct - multiple firstprivate clauses must emit -! only one barrier +! Checking for the following construct ! !$omp parallel ! !$omp do firstprivate(...) firstprivate(...) !=============================================================================== @@ -182,7 +181,7 @@ ! 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 ! CHECK: fir.store %[[B]] to %[[B_PRIV_ADDR]] : !fir.ref -! CHECK: omp.barrier +! CHECK-NOT: omp.barrier ! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i32 ! CHECK: %[[VAL_9:.*]] = arith.constant 10 : i32 ! CHECK: %[[VAL_10:.*]] = arith.constant 1 : i32 @@ -224,7 +223,7 @@ ! CHECK: %[[NT_ADDR:.*]] = fir.alloca i32 {bindc_name = "nt", pinned, uniq_name = "_QFparallel_do_privateEnt"} ! CHECK: %[[NT:.*]] = fir.load %[[VAL_1]] : !fir.ref ! CHECK: fir.store %[[NT]] to %[[NT_ADDR]] : !fir.ref -! CHECK: omp.barrier +! CHECK-NOT: 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 @@ -240,8 +239,7 @@ ! CHECK: } !=============================================================================== -! Checking for the following construct - multiple firstprivate clauses must emit -! only one barrier +! Checking for the following construct ! !$omp parallel ! !$omp do firstprivate(...) firstprivate(...) !=============================================================================== @@ -268,7 +266,6 @@ ! 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 ! CHECK: fir.store %[[B]] to %[[B_PRIV_ADDR]] : !fir.ref -! CHECK: omp.barrier ! CHECK-NOT: omp.barrier ! CHECK: %[[I_PRIV_ADDR:.*]] = fir.alloca i32 {adapt.valuebyref, pinned} ! CHECK: %[[VAL_8:.*]] = arith.constant 1 : i32