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 @@ -111,7 +111,8 @@ virtual void collectSymbolSet( pft::Evaluation &eval, llvm::SetVector &symbolSet, - Fortran::semantics::Symbol::Flag flag, bool isUltimateSymbol = true) = 0; + Fortran::semantics::Symbol::Flag flag, + bool checkHostAssoicatedSymbols = true) = 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,12 +556,19 @@ Fortran::lower::pft::Evaluation &eval, llvm::SetVector &symbolSet, Fortran::semantics::Symbol::Flag flag, - bool isUltimateSymbol) override final { + bool checkHostAssoicatedSymbols) 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) { + if (oriSymbol.test(flag)) + symbolSet.insert(&oriSymbol); + if (checkHostAssoicatedSymbols) + if (const auto *details{ + oriSymbol + .detailsIf()}) + insertSymbols(details->symbol()); + }; + insertSymbols(sym); }; 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 @@ -85,24 +85,66 @@ 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; + // The symbols in private/firstprivate clause or region under + // default(private/firstprivate) clause. + // TODO: Current implementation of default clause is very fragile. Implement + // it instead if a pre-FIR pass + llvm::SetVector symbols; + llvm::SetVector sharedSymbols; + std::map + uniqueSymbolMap; + 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); + } + }; + + auto removeDuplicateSymbols = + [&](llvm::SetVector &symbols) { + // default clause in nested directives can create two symbols belonging + // to the same entity resulting in double privatization. Reduce the + // count of such symbols to 1. + for (auto sym : symbols) + if (auto it{uniqueSymbolMap.find(sym->name())}; + it == uniqueSymbolMap.end()) + uniqueSymbolMap.insert( + std::pair(sym->name(), + sym)); + }; // We need just one ICmpOp for multiple LastPrivate clauses. mlir::arith::CmpIOp cmpOp; - + // 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); + collectOmpObjectListSymbol(privateClause->v, symbols); + removeDuplicateSymbols(symbols); } else if (const auto &firstPrivateClause = std::get_if( &clause.u)) { - createPrivateVarSyms(converter, firstPrivateClause); + collectOmpObjectListSymbol(firstPrivateClause->v, symbols); + removeDuplicateSymbols(symbols); hasFirstPrivateOp = true; + } else if (const auto &sharedClause = + std::get_if(&clause.u)) { + // `shared(...)` does not define a privatization flag. In case of nested + // block constructs, presence of `default(firstprivate)` or + // `default(private)` in the inner block construct may lead to privatizing + // a shared variable in the outer block construct. To prevent that, + // explicitly collect the shared symbols and remove them from the list of + // symbols to be privatized. + collectOmpObjectListSymbol(sharedClause->v, sharedSymbols); } else if (const auto &lastPrivateClause = std::get_if( &clause.u)) { @@ -166,7 +208,48 @@ hasLastPrivateOp = true; } } - if (hasFirstPrivateOp) + + 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) { + converter.collectSymbolSet(eval, symbols, + Fortran::semantics::Symbol::Flag::OmpPrivate, + /*checkHostAssoicatedSymbols=*/true); + removeDuplicateSymbols(symbols); + } else if (defaultClause->v.v == + Fortran::parser::OmpDefaultClause::Type::Firstprivate) { + converter.collectSymbolSet( + eval, symbols, Fortran::semantics::Symbol::Flag::OmpFirstPrivate, + /*checkHostAssoicatedSymbols=*/true); + removeDuplicateSymbols(symbols); + } + } + } + + for (auto sharedSymbol : sharedSymbols) { + auto it = uniqueSymbolMap.find(sharedSymbol->name()); + if (it != uniqueSymbolMap.end()) { + uniqueSymbolMap.erase(it); + } + } + for (auto uniqueSymbolMapPair : uniqueSymbolMap) { + // Privatization for symbols which are pre-determined (like loop index + // variables) happen separately, for everything else privatize here. + const Fortran::semantics::Symbol *sym = uniqueSymbolMapPair.second; + 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); + hasFirstPrivateOp = true; + } + } + + if (hasFirstPrivateOp || hasLastPrivateOp) firOpBuilder.create(converter.getCurrentLocation()); firOpBuilder.restoreInsertionPoint(insPt); return hasLastPrivateOp; @@ -458,7 +541,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,34 @@ } } } + std::vector defaultDSASymbols; + for (int dirContextIndex = 0; + dirContextIndex <= (int)dirContext_.size() - 1; dirContextIndex++) { + DirContext &dirContext = dirContext_[dirContextIndex]; + 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) + continue; + + if (dirContext.defaultDSA == semantics::Symbol::Flag::OmpPrivate || + dirContext.defaultDSA == semantics::Symbol::Flag::OmpFirstPrivate) { + if (!defaultDSASymbols.size()) + defaultDSASymbols.push_back(DeclarePrivateAccessEntity( + symbol->GetUltimate(), dirContext.defaultDSA, + context_.FindScope(dirContext.directiveSource))); + + else + defaultDSASymbols.push_back(DeclarePrivateAccessEntity( + *defaultDSASymbols.back(), dirContext.defaultDSA, + context_.FindScope(dirContext.directiveSource))); + } + } } // 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,323 @@ +! 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_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: %[[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: 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_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: %[[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: 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_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: %[[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: 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 + +!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: %[[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 +!CHECK: %[[temp_1:.*]] = fir.load %[[PRIVATE_Z]] : !fir.ref +!CHECK: %[[temp_2:.*]] = fir.load %[[TEMP]] : !fir.ref +!CHECK: %[[result:.*]] = arith.addi %[[temp_1]], %[[temp_2]] : i32 +!CHECK: fir.store %[[result]] 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 + +subroutine nested_default_clause_tests + integer :: x, y, z, w, k, a + +!CHECK: %[[A:.*]] = fir.alloca i32 {bindc_name = "a", uniq_name = "_QFnested_default_clause_testsEa"} +!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_A:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFnested_default_clause_testsEa"} +!CHECK: %[[PRIVATE_K:.*]] = fir.alloca i32 {bindc_name = "k", pinned, uniq_name = "_QFnested_default_clause_testsEk"} +!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: omp.barrier +!CHECK: omp.parallel { +!CHECK: %[[INNER_PRIVATE_A:.*]] = fir.alloca i32 {bindc_name = "a", pinned, uniq_name = "_QFnested_default_clause_testsEa"} +!CHECK: %[[INNER_PRIVATE_X:.*]] = fir.alloca i32 {bindc_name = "x", pinned, uniq_name = "_QFnested_default_clause_testsEx"} +!CHECK: %[[INNER_PRIVATE_Y:.*]] = fir.alloca i32 {bindc_name = "y", pinned, uniq_name = "_QFnested_default_clause_testsEy"} +!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.parallel { +!CHECK: %[[const:.*]] = arith.constant 10 : i32 +!CHECK: fir.store %[[const]] to %[[INNER_PRIVATE_A]] : !fir.ref +!CHECK: omp.terminator +!CHECK: } +!CHECK: omp.terminator +!CHECK: } +!CHECK: omp.parallel { +!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: %[[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: 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 parallel + a = 10 + !$omp end parallel + !$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_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFnested_default_clause_testsEw"} +!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: 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_W:.*]] = fir.alloca i32 {bindc_name = "w", pinned, uniq_name = "_QFnested_default_clause_testsEw"} +!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: 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:.*]]) : {{.*}} { diff --git a/flang/test/Semantics/OpenMP/omp-default-clause.f90 b/flang/test/Semantics/OpenMP/omp-default-clause.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenMP/omp-default-clause.f90 @@ -0,0 +1,45 @@ +! RUN: %flang_fc1 -fopenmp -fdebug-dump-symbols %s | FileCheck %s + +! Test symbols generated in block constructs in the +! presence of `default(...)` clause + +program sample + !CHECK: a size=4 offset=20: ObjectEntity type: INTEGER(4) + !CHECK: k size=4 offset=16: ObjectEntity type: INTEGER(4) + !CHECK: w size=4 offset=12: ObjectEntity type: INTEGER(4) + !CHECK: x size=4 offset=0: ObjectEntity type: INTEGER(4) + !CHECK: y size=4 offset=4: ObjectEntity type: INTEGER(4) + !CHECK: z size=4 offset=8: ObjectEntity type: INTEGER(4) + integer x, y, z, w, k, a + !$omp parallel firstprivate(x) private(y) shared(w) default(private) + !CHECK: OtherConstruct scope: size=0 alignment=1 + !CHECK: a (OmpPrivate): HostAssoc + !CHECK: k (OmpPrivate): HostAssoc + !CHECK: x (OmpFirstPrivate): HostAssoc + !CHECK: y (OmpPrivate): HostAssoc + !CHECK: z (OmpPrivate): HostAssoc + !$omp parallel default(private) + !CHECK: OtherConstruct scope: size=0 alignment=1 + !CHECK: a (OmpPrivate): HostAssoc + !CHECK: x (OmpPrivate): HostAssoc + !CHECK: y (OmpPrivate): HostAssoc + y = 20 + x = 10 + !$omp parallel + !CHECK: OtherConstruct scope: size=0 alignment=1 + a = 10 + !$omp end parallel + !$omp end parallel + + !$omp parallel default(firstprivate) shared(y) private(w) + !CHECK: OtherConstruct scope: size=0 alignment=1 + !CHECK: k (OmpFirstPrivate): HostAssoc + !CHECK: w (OmpPrivate): HostAssoc + !CHECK: z (OmpFirstPrivate): HostAssoc + y = 30 + w = 40 + z = 50 + k = 40 + !$omp end parallel + !$omp end parallel +end program sample