diff --git a/flang/lib/Lower/OpenMP.cpp b/flang/lib/Lower/OpenMP.cpp --- a/flang/lib/Lower/OpenMP.cpp +++ b/flang/lib/Lower/OpenMP.cpp @@ -79,23 +79,63 @@ } static void privatizeVars(Fortran::lower::AbstractConverter &converter, - const Fortran::parser::OmpClauseList &opClauseList) { + const Fortran::parser::OmpClauseList &opClauseList, + Fortran::lower::pft::Evaluation &eval) { fir::FirOpBuilder &firOpBuilder = converter.getFirOpBuilder(); auto insPt = firOpBuilder.saveInsertionPoint(); firOpBuilder.setInsertionPointToStart(firOpBuilder.getAllocaBlock()); - bool hasFirstPrivateOp = false; + // Has firstprivate or default(firstprivate) clause? + bool hasFirstPrivate = false; + // The symbols in private/firstprivate clause or region under + // default(private/firstprivate) clause. + llvm::SetVector symbols; + + auto collectOmpObjectListSymbol = + [&](const Fortran::parser::OmpObjectList &ompObjectList) { + for (const Fortran::parser::OmpObject &ompObject : ompObjectList.v) { + Fortran::semantics::Symbol *sym = getOmpObjectSymbol(ompObject); + symbols.insert(sym); + } + }; + + // Collect the privatized symbols for private/firstprivate/default clause. for (const Fortran::parser::OmpClause &clause : opClauseList.v) { - if (const auto &privateClause = - std::get_if(&clause.u)) { - createPrivateVarSyms(converter, privateClause); + if (const auto &defaultClause = + std::get_if(&clause.u)) { + if (defaultClause->v.v == + Fortran::parser::OmpDefaultClause::Type::Private) + converter.collectSymbolSet(eval, symbols, + Fortran::semantics::Symbol::Flag::OmpPrivate, + /*isUltimateSymbol=*/false); + else if (defaultClause->v.v == + Fortran::parser::OmpDefaultClause::Type::Firstprivate) + converter.collectSymbolSet( + eval, symbols, Fortran::semantics::Symbol::Flag::OmpFirstPrivate, + /*isUltimateSymbol=*/false); + } else if (const auto &privateClause = + std::get_if( + &clause.u)) { + collectOmpObjectListSymbol(privateClause->v); } else if (const auto &firstPrivateClause = std::get_if( &clause.u)) { - createPrivateVarSyms(converter, firstPrivateClause); - hasFirstPrivateOp = true; + collectOmpObjectListSymbol(firstPrivateClause->v); + } + } + for (const Fortran::semantics::Symbol *sym : symbols) { + // Privatization for symbols which are pre-determined (like loop index + // variables) happen separately, for everything else privatize here. + if (sym->test(Fortran::semantics::Symbol::Flag::OmpPreDetermined)) + continue; + bool success = converter.createHostAssociateVarClone(*sym); + (void)success; + assert(success && "Privatization failed due to existing binding"); + if (sym->test(Fortran::semantics::Symbol::Flag::OmpFirstPrivate)) { + converter.copyHostAssociateVar(*sym); + hasFirstPrivate = true; } } - if (hasFirstPrivateOp) + if (hasFirstPrivate) firOpBuilder.create(converter.getCurrentLocation()); firOpBuilder.restoreInsertionPoint(insPt); } @@ -376,7 +416,7 @@ // Handle privatization. Do not privatize if this is the outer operation. if (clauses && !outerCombined) - privatizeVars(converter, *clauses); + privatizeVars(converter, *clauses, eval); if constexpr (std::is_same_v) { threadPrivatizeVars(converter, eval); diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp --- a/flang/lib/Semantics/resolve-directives.cpp +++ b/flang/lib/Semantics/resolve-directives.cpp @@ -1490,6 +1490,16 @@ } } } + if (GetContext().defaultDSA == semantics::Symbol::Flag::OmpPrivate && + !HasDataSharingAttributeObject(*name.symbol)) { + name.symbol = DeclarePrivateAccessEntity( + *name.symbol, semantics::Symbol::Flag::OmpPrivate, currScope()); + } else if (GetContext().defaultDSA == + semantics::Symbol::Flag::OmpFirstPrivate && + !HasDataSharingAttributeObject(*name.symbol)) { + name.symbol = DeclarePrivateAccessEntity( + *name.symbol, semantics::Symbol::Flag::OmpFirstPrivate, currScope()); + } } // within OpenMP construct } diff --git a/flang/test/Lower/OpenMP/default-clause.f90 b/flang/test/Lower/OpenMP/default-clause.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/OpenMP/default-clause.f90 @@ -0,0 +1,191 @@ +! This test checks lowering of OpenMP parallel directive +! with `DEFAULT` clause present. + +! RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s +! RUN: bbc -fopenmp -emit-fir %s -o - | FileCheck %s + + +!CHECK: func @_QQmain() { +!CHECK: %[[W:.*]] = fir.alloca i32 {bindc_name = "w", uniq_name = "_QFEw"} +!CHECK: %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFEx"} +!CHECK: %[[Y:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFEy"} +!CHECK: %[[Z:.*]] = fir.alloca i32 {bindc_name = "z", uniq_name = "_QFEz"} +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFEx"} +!CHECK: %{{.*}} = fir.load %[[X]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_X]] : !fir.ref +!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFEy"} +!CHECK: %[[PRIVATE_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFEw"} +!CHECK: omp.barrier +!CHECK: %{{.*}} = arith.constant 2 : i32 +!CHECK: %{{.*}} = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: %{{.*}} = arith.muli %{{.*}}, %{{.*}} : i32 +!CHECK: fir.store %{{.*}} to %[[PRIVATE_X]] : !fir.ref +!CHECK: %{{.*}} = fir.load %[[PRIVATE_W]] : !fir.ref +!CHECK: %{{.*}} = arith.constant 45 : i32 +!CHECK: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : i32 +!CHECK: fir.store %{{.*}} to %[[Z]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } + +program default_clause_lowering + integer :: x, y, z, w + + !$omp parallel default(private) firstprivate(x) shared(z) + x = y * 2 + z = w + 45 + !$omp end parallel + +!CHECK: omp.parallel { +!CHECK: %{{.*}} = fir.load %[[Y]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[X]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } + + !$omp parallel default(shared) + x = y + !$omp end parallel + +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFEx"} +!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFEy"} +!CHECK: %{{.*}} = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: fir.store {{.*}} to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } + + !$omp parallel default(none) private(x, y) + x = y + !$omp end parallel + +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFEy"} +!CHECK: %{{.*}} = fir.load %[[Y]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_Y]] : !fir.ref +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFEx"} +!CHECK: %{{.*}} = fir.load %[[X]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %{{.*}} = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } + + !$omp parallel default(firstprivate) firstprivate(y) + x = y + !$omp end parallel + +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFEx"} +!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFEy"} +!CHECK: %{{.*}} = fir.load %[[Y]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_Y]] : !fir.ref +!CHECK: %[[PRIVATE_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFEw"} +!CHECK: %{{.*}} = fir.load %[[W]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_W]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %{{.*}} = arith.constant 2 : i32 +!CHECK: %{{.*}} = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: %{{.*}} = arith.muli %{{.*}}, %{{.*}} : i32 +!CHECK: fir.store %{{.*}} to %[[PRIVATE_X]] : !fir.ref +!CHECK: %{{.*}} = fir.load %[[PRIVATE_W]] : !fir.ref +!CHECK: %{{.*}} = arith.constant 45 : i32 +!CHECK: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : i32 +!CHECK: fir.store %{{.*}} to %[[Z]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } + + !$omp parallel default(firstprivate) private(x) shared(z) + x = y * 2 + z = w + 45 + !$omp end parallel + +!CHECK: omp.parallel { +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFEx"} +!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFEy"} +!CHECK: {{.*}} = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: fir.store {{.*}} to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFEw"} +!CHECK: {{.*}} = fir.load %[[W]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_W]] : !fir.ref +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFEx"} +!CHECK: %{{.*}} = fir.load %[[X]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %{{.*}} = fir.load %[[PRIVATE_X]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_W]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } +!CHECK: omp.terminator +!CHECK: } + !$omp parallel + !$omp parallel default(private) + x = y + !$omp end parallel + + !$omp parallel default(firstprivate) + w = x + !$omp end parallel + !$omp end parallel + +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFEw"} +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFEx"} +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_INNER_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFEx"} +!CHECK: %{{.*}} = fir.load %[[PRIVATE_X]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_INNER_X]] : !fir.ref +!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFEy"} +!CHECK: %{{.*}} = fir.load %[[Y]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_Y]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %{{.*}} = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_INNER_X]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_INNER_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFEw"} +!CHECK: %[[PRIVATE_INNER_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFEx"} +!CHECK: %{{.*}} = fir.load %[[PRIVATE_INNER_X]] : !fir.ref +!CHECK: %{{.*}} = fir.load %[[Z]] : !fir.ref +!CHECK: %{{.*}} = arith.addi %{{.*}}, %{{.*}} : i32 +!CHECK: fir.store %{{.*}} to %[[PRIVATE_INNER_W]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } +!CHECK: } + !$omp parallel default(private) + !$omp parallel default(firstprivate) + x = y + !$omp end parallel + + !$omp parallel default(private) shared(z) + w = x + z + !$omp end parallel + !$omp end parallel + +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFEy"} +!CHECK: %[[PRIVATE_Z:.*]] = fir.alloca i32 {bindc_name = "z", pinned, uniq_name = "_QFEz"} +!CHECK: %[[TEMP:.*]] = fir.alloca i32 {adapt.valuebyref, pinned} +!CHECK: %{{.*}} = arith.constant 1 : i32 +!CHECK: %{{.*}} = arith.constant 10 : i32 +!CHECK: %{{.*}} = arith.constant 1 : i32 +!CHECK: omp.wsloop for (%[[ARG:.*]]) : i32 = ({{.*}}) to ({{.*}}) inclusive step ({{.*}}) { +!CHECK: fir.store %[[ARG]] to %[[TEMP]] : !fir.ref +!CHECK: %{{.*}} = fir.load %[[PRIVATE_Z]] : !fir.ref +!CHECK: %{{.*}} = fir.load %[[TEMP]] : !fir.ref +!CHECK: fir.store %{{.*}} to %[[PRIVATE_Y]] : !fir.ref +!CHECK: omp.yield +!CHECK: } +!CHECK: omp.terminator +!CHECK: } + !$omp parallel do default(private) + do x = 1, 10 + y = z + x + enddo + !$omp end parallel do +end program default_clause_lowering