diff --git a/flang/include/flang/Lower/AbstractConverter.h b/flang/include/flang/Lower/AbstractConverter.h --- a/flang/include/flang/Lower/AbstractConverter.h +++ b/flang/include/flang/Lower/AbstractConverter.h @@ -106,13 +106,15 @@ virtual void copyHostAssociateVar(const Fortran::semantics::Symbol &sym, mlir::Block *lastPrivBlock = nullptr) = 0; - /// Collect the set of ultimate symbols of symbols with \p flag in \p eval - /// region if \p isUltimateSymbol is true. Otherwise, collect the set of - /// symbols with \p flag. + /// Collect the set of symbols with \p flag in \p eval + /// region if \p collectSymbols is true. Likewise, collect the + /// set of the host symbols with \p flag of the associated symbols in \p eval + /// region if collectHostAssociatedSymbols is true. virtual void collectSymbolSet( pft::Evaluation &eval, llvm::SetVector &symbolSet, - Fortran::semantics::Symbol::Flag flag, bool isUltimateSymbol = true) = 0; + Fortran::semantics::Symbol::Flag flag, bool collectSymbols = true, + bool collectHostAssociatedSymbols = false) = 0; //===--------------------------------------------------------------------===// // Expressions diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -556,13 +556,21 @@ void collectSymbolSet( Fortran::lower::pft::Evaluation &eval, llvm::SetVector &symbolSet, - Fortran::semantics::Symbol::Flag flag, - bool isUltimateSymbol) override final { + Fortran::semantics::Symbol::Flag flag, bool collectSymbols, + bool checkHostAssociatedSymbols) override final { auto addToList = [&](const Fortran::semantics::Symbol &sym) { - const Fortran::semantics::Symbol &symbol = - isUltimateSymbol ? sym.GetUltimate() : sym; - if (symbol.test(flag)) - symbolSet.insert(&symbol); + std::function + insertSymbols = [&](const Fortran::semantics::Symbol &oriSymbol, + bool collectSymbol) { + if (collectSymbol && oriSymbol.test(flag)) + symbolSet.insert(&oriSymbol); + if (checkHostAssociatedSymbols) + if (const auto *details{ + oriSymbol + .detailsIf()}) + insertSymbols(details->symbol(), true); + }; + insertSymbols(sym, collectSymbols); }; Fortran::lower::pft::visitAllSymbols(eval, addToList); } 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 @@ -86,23 +86,34 @@ template static bool privatizeVars(Op &op, 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; bool hasLastPrivateOp = false; + // Symbols in private and/or firstprivate clauses. + llvm::SetVector privatizedSymbols; + auto collectOmpObjectListSymbol = + [&](const Fortran::parser::OmpObjectList &ompObjectList, + llvm::SetVector &symbolSet) { + for (const Fortran::parser::OmpObject &ompObject : ompObjectList.v) { + Fortran::semantics::Symbol *sym = getOmpObjectSymbol(ompObject); + symbolSet.insert(sym); + } + }; // We need just one ICmpOp for multiple LastPrivate clauses. mlir::arith::CmpIOp cmpOp; for (const Fortran::parser::OmpClause &clause : opClauseList.v) { if (const auto &privateClause = std::get_if(&clause.u)) { - createPrivateVarSyms(converter, privateClause); + collectOmpObjectListSymbol(privateClause->v, privatizedSymbols); } else if (const auto &firstPrivateClause = std::get_if( &clause.u)) { - createPrivateVarSyms(converter, firstPrivateClause); + collectOmpObjectListSymbol(firstPrivateClause->v, privatizedSymbols); hasFirstPrivateOp = true; } else if (const auto &lastPrivateClause = std::get_if( @@ -167,6 +178,65 @@ hasLastPrivateOp = true; } } + + // Symbols in regions with default(private/firstprivate) clause. + // FIXME: Collect the symbols with private/firstprivate flag in the region of + // the construct with default(private/firstprivate) clause excluding the + // symbols with the same private/firstprivate flag in the inner nested + // regions. + llvm::SetVector defaultSymbols; + llvm::SetVector symbolsInNestedRegions; + llvm::SetVector symbolsInParentRegions; + auto collectSymbols = [&](Fortran::semantics::Symbol::Flag flag) { + converter.collectSymbolSet(eval, defaultSymbols, flag, + /*collectSymbols=*/true, + /*collectHostAssociatedSymbols=*/true); + for (auto &e : eval.getNestedEvaluations()) { + if (e.hasNestedEvaluations()) + converter.collectSymbolSet(e, symbolsInNestedRegions, flag, + /*collectSymbols=*/true, + /*collectHostAssociatedSymbols=*/false); + else + converter.collectSymbolSet(e, symbolsInParentRegions, flag, + /*collectSymbols=*/false, + /*collectHostAssociatedSymbols=*/true); + } + }; + + for (const Fortran::parser::OmpClause &clause : opClauseList.v) { + if (const auto &defaultClause = + std::get_if(&clause.u)) { + if (defaultClause->v.v == + Fortran::parser::OmpDefaultClause::Type::Private) + collectSymbols(Fortran::semantics::Symbol::Flag::OmpPrivate); + else if (defaultClause->v.v == + Fortran::parser::OmpDefaultClause::Type::Firstprivate) + collectSymbols(Fortran::semantics::Symbol::Flag::OmpFirstPrivate); + } + } + + auto privatizeSymbol = [&](const Fortran::semantics::Symbol *sym) { + // 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)) + return; + 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); + hasFirstPrivateOp = true; + } + }; + + for (auto sym : privatizedSymbols) + privatizeSymbol(sym); + + for (auto sym : defaultSymbols) + if (!symbolsInNestedRegions.contains(sym) && + !symbolsInParentRegions.contains(sym) && + !privatizedSymbols.contains(sym)) + privatizeSymbol(sym); if (hasFirstPrivateOp) firOpBuilder.create(converter.getCurrentLocation()); firOpBuilder.restoreInsertionPoint(insPt); @@ -233,9 +303,9 @@ }; llvm::SetVector threadprivateSyms; - converter.collectSymbolSet(eval, threadprivateSyms, - Fortran::semantics::Symbol::Flag::OmpThreadprivate, - /*isUltimateSymbol=*/false); + converter.collectSymbolSet( + eval, threadprivateSyms, + Fortran::semantics::Symbol::Flag::OmpThreadprivate); std::set threadprivateSymNames; // For a COMMON block, the ThreadprivateOp is generated for itself instead of @@ -459,7 +529,7 @@ // Handle privatization. Do not privatize if this is the outer operation. if (clauses && !outerCombined) { - bool lastPrivateOp = privatizeVars(op, converter, *clauses); + bool lastPrivateOp = privatizeVars(op, converter, *clauses, eval); // LastPrivatization, due to introduction of // new control flow, changes the insertion point, // thus restore it. 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,35 @@ } } } + std::vector defaultDSASymbols; + for (int dirDepth{0}; dirDepth < (int)dirContext_.size(); ++dirDepth) { + DirContext &dirContext = dirContext_[dirDepth]; + bool hasDataSharingAttr{false}; + for (auto symMap : dirContext.objectWithDSA) { + // if the `symbol` already has a data-sharing attribute + if (symMap.first->name() == name.symbol->name()) { + hasDataSharingAttr = true; + break; + } + } + if (hasDataSharingAttr) { + if (defaultDSASymbols.size()) + symbol = &MakeAssocSymbol(symbol->name(), *defaultDSASymbols.back(), + context_.FindScope(dirContext.directiveSource)); + continue; + } + + if (dirContext.defaultDSA == semantics::Symbol::Flag::OmpPrivate || + dirContext.defaultDSA == semantics::Symbol::Flag::OmpFirstPrivate) { + Symbol *hostSymbol = defaultDSASymbols.size() ? defaultDSASymbols.back() + : &symbol->GetUltimate(); + defaultDSASymbols.push_back( + DeclarePrivateAccessEntity(*hostSymbol, dirContext.defaultDSA, + context_.FindScope(dirContext.directiveSource))); + } else if (defaultDSASymbols.size()) + symbol = &MakeAssocSymbol(symbol->name(), *defaultDSASymbols.back(), + context_.FindScope(dirContext.directiveSource)); + } } // within OpenMP construct } diff --git a/flang/test/Lower/OpenMP/Todo/omp-default-clause-inner-loop.f90 b/flang/test/Lower/OpenMP/Todo/omp-default-clause-inner-loop.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Lower/OpenMP/Todo/omp-default-clause-inner-loop.f90 @@ -0,0 +1,34 @@ +! This test checks the lowering of parallel do + +! RUN: %flang_fc1 -emit-fir -fopenmp %s -o - | FileCheck %s +! RUN: bbc -fopenmp -emit-fir %s -o - | FileCheck %s + +! The string "EXPECTED" denotes the expected FIR + +! CHECK: omp.parallel { +! EXPECTED: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFEy"} +! EXPECTED: %[[PRIVATE_Z:.*]] = fir.alloca i32 {bindc_name = "z", pinned, uniq_name = "_QFEz"} +! CHECK: %[[TEMP:.*]] = fir.alloca i32 {adapt.valuebyref, pinned} +! CHECK: %[[const_1:.*]] = arith.constant 1 : i32 +! CHECK: %[[const_2:.*]] = arith.constant 10 : i32 +! CHECK: %[[const_3:.*]] = arith.constant 1 : i32 +! CHECK: omp.wsloop for (%[[ARG:.*]]) : i32 = (%[[const_1]]) to (%[[const_2]]) inclusive step (%[[const_3]]) { +! CHECK: fir.store %[[ARG]] to %[[TEMP]] : !fir.ref +! EXPECTED: %[[temp_1:.*]] = fir.load %[[PRIVATE_Z]] : !fir.ref +! CHECK: %[[temp_1:.*]] = fir.load %{{.*}} : !fir.ref +! CHECK: %[[temp_2:.*]] = fir.load %[[TEMP]] : !fir.ref +! CHECK: %[[result:.*]] = arith.addi %[[temp_1]], %[[temp_2]] : i32 +! EXPECTED: fir.store %[[result]] to %[[PRIVATE_Y]] : !fir.ref +! CHECK: fir.store %[[result]] to %{{.*}} : !fir.ref +! CHECK: omp.yield +! CHECK: } +! CHECK: omp.terminator +! CHECK: } +subroutine nested_default_clause() + integer x, y, z + !$omp parallel do default(private) + do x = 1, 10 + y = z + x + enddo + !$omp end parallel do +end subroutine 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,290 @@ +! 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: %[[const:.*]] = fir.load %[[X]] : !fir.ref +!CHECK: fir.store %[[const]] 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: %[[const:.*]] = arith.constant 2 : i32 +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: %[[result:.*]] = arith.muli %[[const]], %[[temp]] : i32 +!CHECK: fir.store %[[result]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_W]] : !fir.ref +!CHECK: %[[const:.*]] = arith.constant 45 : i32 +!CHECK: %[[result:.*]] = arith.addi %[[temp]], %[[const]] : i32 +!CHECK: fir.store %[[result]] 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: %[[temp:.*]] = fir.load %[[Y]] : !fir.ref +!CHECK: fir.store %[[temp]] 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: %[[temp:.*]] = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: fir.store %[[temp]] 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: %[[temp:.*]] = fir.load %[[Y]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_Y]] : !fir.ref +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFEx"} +!CHECK: %[[temp:.*]] = fir.load %[[X]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: fir.store %[[temp]] 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: %[[temp:.*]] = fir.load %[[Y]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_Y]] : !fir.ref +!CHECK: %[[PRIVATE_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFEw"} +!CHECK: %[[temp:.*]] = fir.load %[[W]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_W]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %[[const:.*]] = arith.constant 2 : i32 +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: %[[result:.*]] = arith.muli %[[const]], %[[temp]] : i32 +!CHECK: fir.store %[[result]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_W]] : !fir.ref +!CHECK: %[[const:.*]] = arith.constant 45 : i32 +!CHECK: %[[result:.*]] = arith.addi %[[temp]], %[[const]] : i32 +!CHECK: fir.store %[[result]] 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: %[[temp:.*]] = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: fir.store %[[temp]] 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: %[[temp:.*]] = fir.load %[[W]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_W]] : !fir.ref +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFEx"} +!CHECK: %[[temp:.*]] = fir.load %[[X]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_X]] : !fir.ref +!CHECK: fir.store %[[temp]] 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 + +end program default_clause_lowering + +subroutine nested_default_clause_tests + integer :: x, y, z, w, k, a + +!CHECK: %[[K:.*]] = fir.alloca i32 {bindc_name = "k", uniq_name = "_QFnested_default_clause_testsEk"} +!CHECK: %[[W:.*]] = fir.alloca i32 {bindc_name = "w", uniq_name = "_QFnested_default_clause_testsEw"} +!CHECK: %[[X:.*]] = fir.alloca i32 {bindc_name = "x", uniq_name = "_QFnested_default_clause_testsEx"} +!CHECK: %[[Y:.*]] = fir.alloca i32 {bindc_name = "y", uniq_name = "_QFnested_default_clause_testsEy"} +!CHECK: %[[Z:.*]] = fir.alloca i32 {bindc_name = "z", uniq_name = "_QFnested_default_clause_testsEz"} +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_testsEx"} +!CHECK: %[[temp:.*]] = fir.load %[[X]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFnested_default_clause_testsEy"} +!CHECK: %[[PRIVATE_Z:.*]] = fir.alloca i32 {bindc_name = "z", pinned, uniq_name = "_QFnested_default_clause_testsEz"} +!CHECK: %[[PRIVATE_K:.*]] = fir.alloca i32 {bindc_name = "k", pinned, uniq_name = "_QFnested_default_clause_testsEk"} +!CHECK: omp.barrier +!CHECK: omp.parallel { +!CHECK: %[[INNER_PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFnested_default_clause_testsEy"} +!CHECK: %[[INNER_PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_testsEx"} +!CHECK: %[[const:.*]] = arith.constant 20 : i32 +!CHECK: fir.store %[[const]] to %[[INNER_PRIVATE_Y]] : !fir.ref +!CHECK: %[[const:.*]] = arith.constant 10 : i32 +!CHECK: fir.store %[[const]] to %[[INNER_PRIVATE_X]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } +!CHECK: omp.parallel { +!CHECK: %[[INNER_PRIVATE_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFnested_default_clause_testsEw"} +!CHECK: %[[INNER_PRIVATE_Z:.*]] = fir.alloca i32 {bindc_name = "z", pinned, uniq_name = "_QFnested_default_clause_testsEz"} +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_Z]] +!CHECK: fir.store %[[temp]] to %[[INNER_PRIVATE_Z]] : !fir.ref +!CHECK: %[[INNER_PRIVATE_K:.*]] = fir.alloca i32 {bindc_name = "k", pinned, uniq_name = "_QFnested_default_clause_testsEk"} +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_K]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[INNER_PRIVATE_K]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %[[const:.*]] = arith.constant 30 : i32 +!CHECK: fir.store %[[const]] to %[[PRIVATE_Y]] : !fir.ref +!CHECK: %[[const:.*]] = arith.constant 40 : i32 +!CHECK: fir.store %[[const]] to %[[INNER_PRIVATE_W]] : !fir.ref +!CHECK: %[[const:.*]] = arith.constant 50 : i32 +!CHECK: fir.store %[[const]] to %[[INNER_PRIVATE_Z]] : !fir.ref +!CHECK: %[[const:.*]] = arith.constant 40 : i32 +!CHECK: fir.store %[[const]] to %[[INNER_PRIVATE_K]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } +!CHECK: omp.terminator +!CHECK: } + !$omp parallel firstprivate(x) private(y) shared(w) default(private) + !$omp parallel default(private) + y = 20 + x = 10 + !$omp end parallel + + !$omp parallel default(firstprivate) shared(y) private(w) + y = 30 + w = 40 + z = 50 + k = 40 + !$omp end parallel + !$omp end parallel + + +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_testsEx"} +!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFnested_default_clause_testsEy"} +!CHECK: %[[PRIVATE_Z:.*]] = fir.alloca i32 {bindc_name = "z", pinned, uniq_name = "_QFnested_default_clause_testsEz"} +!CHECK: %[[PRIVATE_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFnested_default_clause_testsEw"} +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_INNER_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_testsEx"} +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_X]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_INNER_X]] : !fir.ref +!CHECK: %[[INNER_PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFnested_default_clause_testsEy"} +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[INNER_PRIVATE_Y]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %[[temp:.*]] = fir.load %[[INNER_PRIVATE_Y]] : !fir.ref +!CHECK: fir.store %[[temp]] 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 = "_QFnested_default_clause_testsEw"} +!CHECK: %[[PRIVATE_INNER_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_testsEx"} +!CHECK: %[[temp_1:.*]] = fir.load %[[PRIVATE_INNER_X]] : !fir.ref +!CHECK: %[[temp_2:.*]] = fir.load %[[PRIVATE_Z]] : !fir.ref +!CHECK: %[[result:.*]] = arith.addi %{{.*}}, %{{.*}} : i32 +!CHECK: fir.store %[[result]] to %[[PRIVATE_INNER_W]] : !fir.ref +!CHECK: omp.terminator +!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_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_testsEx"} +!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFnested_default_clause_testsEy"} +!CHECK: %[[PRIVATE_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFnested_default_clause_testsEw"} +!CHECK: %[[PRIVATE_Z:.*]] = fir.alloca i32 {bindc_name = "z", pinned, uniq_name = "_QFnested_default_clause_testsEz"} +!CHECK: omp.parallel { +!CHECK: %[[INNER_PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_testsEx"} +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_X]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[INNER_PRIVATE_X]] : !fir.ref +!CHECK: %[[INNER_PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFnested_default_clause_testsEy"} +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[INNER_PRIVATE_Y]] : !fir.ref +!CHECK: omp.barrier +!CHECK: %[[temp:.*]] = fir.load %[[INNER_PRIVATE_Y]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[INNER_PRIVATE_X]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } +!CHECK: omp.parallel { +!CHECK: %[[temp_1:.*]] = fir.load %[[PRIVATE_X]] : !fir.ref +!CHECK: %[[temp_2:.*]] = fir.load %[[PRIVATE_Z]] : !fir.ref +!CHECK: %[[temp_3:.*]] = arith.addi %[[temp_1]], %[[temp_2]] : i32 +!CHECK: fir.store %[[temp_3]] to %[[PRIVATE_W]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } +!CHECK: } + !$omp parallel default(private) + !$omp parallel default(firstprivate) + x = y + !$omp end parallel + + !$omp parallel default(shared) + w = x + z + !$omp end parallel + !$omp end parallel + +!CHECK: omp.parallel { +!CHECK: %[[PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_testsEx"} +!CHECK: %[[temp:.*]] = fir.load %[[X]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: %[[PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFnested_default_clause_testsEy"} +!CHECK: %[[temp:.*]] = fir.load %[[Y]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_Y]] : !fir.ref +!CHECK: omp.barrier +!CHECK: omp.single { +!CHECK: %[[temp:.*]] = fir.load %[[PRIVATE_Y]] : !fir.ref +!CHECK: fir.store %[[temp]] to %[[PRIVATE_X]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } +!CHECK: omp.terminator +!CHECK: } +!CHECK: } + !$omp parallel default(firstprivate) + !$omp single + x = y + !$omp end single + !$omp end parallel +end subroutine diff --git a/flang/test/Lower/OpenMP/omp-parallel-lastprivate-clause-scalar.f90 b/flang/test/Lower/OpenMP/omp-parallel-lastprivate-clause-scalar.f90 --- a/flang/test/Lower/OpenMP/omp-parallel-lastprivate-clause-scalar.f90 +++ b/flang/test/Lower/OpenMP/omp-parallel-lastprivate-clause-scalar.f90 @@ -150,12 +150,12 @@ !CHECK: func.func @_QPfirstpriv_lastpriv_int(%[[ARG1:.*]]: !fir.ref {fir.bindc_name = "arg1"}, %[[ARG2:.*]]: !fir.ref {fir.bindc_name = "arg2"}) { !CHECK-DAG: omp.parallel { +! Lastprivate Allocation +!CHECK-NEXT: %[[CLONE2:.*]] = fir.alloca i32 {bindc_name = "arg2" !CHECK-DAG: %[[CLONE1:.*]] = fir.alloca i32 {bindc_name = "arg1" ! Firstprivate update !CHECK-NEXT: %[[FPV_LD:.*]] = fir.load %[[ARG1]] : !fir.ref !CHECK-NEXT: fir.store %[[FPV_LD]] to %[[CLONE1]] : !fir.ref -! Lastprivate Allocation -!CHECK-NEXT: %[[CLONE2:.*]] = fir.alloca i32 {bindc_name = "arg2" !CHECK-NEXT: omp.barrier !CHECK: omp.wsloop for (%[[INDX_WS:.*]]) : {{.*}} {