diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h --- a/flang/lib/Semantics/check-directive-structure.h +++ b/flang/lib/Semantics/check-directive-structure.h @@ -206,6 +206,15 @@ return nullptr; } + DirectiveContext *GetEnclosingDirContext() { + CHECK(!dirContext_.empty()); + auto it{dirContext_.rbegin()}; + if (++it != dirContext_.rend()) { + return &(*it); + } + return nullptr; + } + void PushContext(const parser::CharBlock &source, D dir) { dirContext_.emplace_back(source, dir); } diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h --- a/flang/lib/Semantics/check-omp-structure.h +++ b/flang/lib/Semantics/check-omp-structure.h @@ -204,8 +204,9 @@ void CheckDependArraySection( const common::Indirection &, const parser::Name &); void CheckIsVarPartOfAnotherVar(const parser::OmpObjectList &objList); - void CheckIntentInPointer( + void CheckIntentInPointerAndDefinable( const parser::OmpObjectList &, const llvm::omp::Clause); + void GetSymbolsInObjectList( const parser::OmpObjectList &, std::vector &); const parser::Name GetLoopIndex(const parser::DoConstruct *x); @@ -213,6 +214,15 @@ void CheckIsLoopIvPartOfClause( llvmOmpClause clause, const parser::OmpObjectList &ompObjectList); void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock); + + bool CheckReductionOperators(const parser::OmpClause::Reduction &); + bool CheckIntrinsicOperator( + const parser::DefinedOperator::IntrinsicOperator &); + void CheckReductionTypeList(const parser::OmpClause::Reduction &); + void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList); + void CheckArraySection(const parser::ArrayElement &arrayElement, + const parser::Name &name, const llvm::omp::Clause clause); + void CheckMultipleAppearanceAcrossContext(std::vector &); }; } // namespace Fortran::semantics #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_ diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp --- a/flang/lib/Semantics/check-omp-structure.cpp +++ b/flang/lib/Semantics/check-omp-structure.cpp @@ -489,7 +489,6 @@ CHECK_SIMPLE_CLAUSE(Nogroup, OMPC_nogroup) CHECK_SIMPLE_CLAUSE(Notinbranch, OMPC_notinbranch) CHECK_SIMPLE_CLAUSE(Nowait, OMPC_nowait) -CHECK_SIMPLE_CLAUSE(Reduction, OMPC_reduction) CHECK_SIMPLE_CLAUSE(TaskReduction, OMPC_task_reduction) CHECK_SIMPLE_CLAUSE(To, OMPC_to) CHECK_SIMPLE_CLAUSE(Uniform, OMPC_uniform) @@ -518,6 +517,140 @@ // Restrictions specific to each clause are implemented apart from the // generalized restrictions. +void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) { + CheckAllowed(llvm::omp::Clause::OMPC_reduction); + if (CheckReductionOperators(x)) { + CheckReductionTypeList(x); + } +} +bool OmpStructureChecker::CheckReductionOperators( + const parser::OmpClause::Reduction &x) { + + const auto &definedOp{std::get<0>(x.v.t)}; + bool ok = false; + std::visit( + common::visitors{ + [&](const parser::DefinedOperator &dOpr) { + const auto &intrinsicOp{ + std::get(dOpr.u)}; + ok = CheckIntrinsicOperator(intrinsicOp); + }, + [&](const parser::ProcedureDesignator &procD) { + const parser::Name *name{std::get_if(&procD.u)}; + if (name->symbol) { + std::string procName = + parser::ToUpperCaseLetters(name->symbol->name().ToString()); + if (procName == "MAX" || procName == "MIN" || + procName == "IAND" || procName == "IOR" || + procName == "IEOR") { + ok = true; + } else { + context_.Say(GetContext().clauseSource, + "Invalid reduction identifier in REDUCTION clause."_err_en_US, + ContextDirectiveAsFortran()); + } + } + }, + }, + definedOp.u); + + return ok; +} +bool OmpStructureChecker::CheckIntrinsicOperator( + const parser::DefinedOperator::IntrinsicOperator &op) { + + switch (op) { + case parser::DefinedOperator::IntrinsicOperator::Add: + case parser::DefinedOperator::IntrinsicOperator::Subtract: + case parser::DefinedOperator::IntrinsicOperator::Multiply: + case parser::DefinedOperator::IntrinsicOperator::AND: + case parser::DefinedOperator::IntrinsicOperator::OR: + case parser::DefinedOperator::IntrinsicOperator::EQV: + case parser::DefinedOperator::IntrinsicOperator::NEQV: + return true; + default: + context_.Say(GetContext().clauseSource, + "Invalid reduction operator in REDUCTION clause."_err_en_US, + ContextDirectiveAsFortran()); + } + return false; +} + +void OmpStructureChecker::CheckReductionTypeList( + const parser::OmpClause::Reduction &x) { + const auto &ompObjectList{std::get(x.v.t)}; + + std::vector currentSymbols; + GetSymbolsInObjectList(ompObjectList, currentSymbols); + CheckIntentInPointerAndDefinable( + ompObjectList, llvm::omp::Clause::OMPC_reduction); + CheckReductionArraySection(ompObjectList); + CheckMultipleAppearanceAcrossContext(currentSymbols); +} + +void OmpStructureChecker::CheckReductionArraySection( + const parser::OmpObjectList &ompObjectList) { + for (const auto &ompObject : ompObjectList.v) { + if (const auto *dataRef{parser::Unwrap(ompObject)}) { + if (const auto *arrayElement{ + parser::Unwrap(ompObject)}) { + if (arrayElement) { + CheckArraySection(*arrayElement, GetLastName(*dataRef), + llvm::omp::Clause::OMPC_reduction); + } + } + } + } +} + +void OmpStructureChecker::CheckMultipleAppearanceAcrossContext( + std::vector ¤tSymbols) { + const parser::OmpObjectList *objList{nullptr}; + if (auto *enclosingContext{GetEnclosingDirContext()}) { + for (auto it : enclosingContext->clauseInfo) { + llvmOmpClause type = it.first; + const auto *clause = it.second; + + if (type == llvm::omp::Clause::OMPC_private) { + const auto &pClause{std::get(clause->u)}; + objList = &pClause.v; + } else if (type == llvm::omp::Clause::OMPC_firstprivate) { + const auto &fpClause{ + std::get(clause->u)}; + objList = &fpClause.v; + } else if (type == llvm::omp::Clause::OMPC_lastprivate) { + const auto &lpClause{ + std::get(clause->u)}; + objList = &lpClause.v; + } else if (type == llvm::omp::Clause::OMPC_reduction) { + const auto &rClause{std::get(clause->u)}; + const auto &olist{std::get<1>(rClause.v.t)}; + objList = &olist; + } + if (objList) { + std::vector outerSymbols; + GetSymbolsInObjectList(*objList, outerSymbols); + if (!outerSymbols.empty()) { + for (const auto *symbol : currentSymbols) { + if (std::find(outerSymbols.begin(), outerSymbols.end(), symbol) != + outerSymbols.end()) { + context_.Say(GetContext().clauseSource, + "%s variable '%s' is %s in outer context must" + " be shared in the parallel regions to which any" + " of the worksharing regions arising from the worksharing" + " construct bind."_err_en_US, + parser::ToUpperCaseLetters( + getClauseName(llvm::omp::Clause::OMPC_reduction).str()), + symbol->name(), + parser::ToUpperCaseLetters(getClauseName(type).str())); + } + } + } + } + } + } +} + void OmpStructureChecker::Enter(const parser::OmpClause::Ordered &x) { CheckAllowed(llvm::omp::Clause::OMPC_ordered); // the parameter of ordered clause is optional @@ -540,29 +673,19 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) { CheckAllowed(llvm::omp::Clause::OMPC_private); CheckIsVarPartOfAnotherVar(x.v); - CheckIntentInPointer(x.v, llvm::omp::Clause::OMPC_private); + CheckIntentInPointerAndDefinable(x.v, llvm::omp::Clause::OMPC_private); } void OmpStructureChecker::CheckIsVarPartOfAnotherVar( const parser::OmpObjectList &objList) { - for (const auto &ompObject : objList.v) { - std::visit( - common::visitors{ - [&](const parser::Designator &designator) { - if (std::get_if(&designator.u)) { - if ((parser::Unwrap(ompObject)) || - (parser::Unwrap(ompObject))) { - context_.Say(GetContext().clauseSource, - "A variable that is part of another variable (as an " - "array or structure element)" - " cannot appear in a PRIVATE or SHARED clause."_err_en_US); - } - } - }, - [&](const parser::Name &name) {}, - }, - ompObject.u); + if ((parser::Unwrap(ompObject)) || + (parser::Unwrap(ompObject))) { + context_.Say(GetContext().clauseSource, + "A variable that is part of another variable (as an " + "array or structure element)" + " cannot appear in a PRIVATE or SHARED clause."_err_en_US); + } } } void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) { @@ -791,7 +914,8 @@ if (const auto *arr{ std::get_if>( &dataRef->u)}) { - CheckDependArraySection(*arr, GetLastName(*dataRef)); + CheckArraySection(arr->value(), GetLastName(*dataRef), + llvm::omp::Clause::OMPC_depend); } } } @@ -830,34 +954,55 @@ d.u); } -void OmpStructureChecker::CheckDependArraySection( - const common::Indirection &arr, - const parser::Name &name) { - for (const auto &subscript : arr.value().subscripts) { - if (const auto *triplet{ - std::get_if(&subscript.u)}) { - if (std::get<2>(triplet->t)) { - context_.Say(GetContext().clauseSource, - "Stride should not be specified for array section in DEPEND " - "clause"_err_en_US); - } - const auto &lower{std::get<0>(triplet->t)}; - const auto &upper{std::get<1>(triplet->t)}; - if (lower && upper) { - const auto lval{GetIntValue(lower)}; - const auto uval{GetIntValue(upper)}; - if (lval && uval && *uval < *lval) { - context_.Say(GetContext().clauseSource, - "'%s' in DEPEND clause is a zero size array section"_err_en_US, - name.ToString()); - break; +// Called from both Reduction and Depend clause. +void OmpStructureChecker::CheckArraySection( + const parser::ArrayElement &arrayElement, const parser::Name &name, + const llvm::omp::Clause clause) { + if (!arrayElement.subscripts.empty()) { + for (const auto &subscript : arrayElement.subscripts) { + if (const auto *triplet{ + std::get_if(&subscript.u)}) { + if (std::get<0>(triplet->t) && std::get<1>(triplet->t)) { + const auto &lower{std::get<0>(triplet->t)}; + const auto &upper{std::get<1>(triplet->t)}; + if (lower && upper) { + const auto lval{GetIntValue(lower)}; + const auto uval{GetIntValue(upper)}; + + if (lval && uval && *uval < *lval) { + context_.Say(GetContext().clauseSource, + "'%s' in %s clause" + " is a zero size array section"_err_en_US, + name.ToString(), + parser::ToUpperCaseLetters(getClauseName(clause).str())); + break; + } else if (std::get<2>(triplet->t)) { + const auto &strideExpr{std::get<2>(triplet->t)}; + if (strideExpr) { + if (clause == llvm::omp::Clause::OMPC_depend) { + context_.Say(GetContext().clauseSource, + "Stride should not be specified for array section in " + "DEPEND " + "clause"_err_en_US); + } + const auto stride{GetIntValue(strideExpr)}; + if ((stride && stride != 1)) { + context_.Say(GetContext().clauseSource, + "A list item that appears in a REDUCTION clause" + " should have a contiguos storage array section."_err_en_US, + ContextDirectiveAsFortran()); + break; + } + } + } + } } } } } } -void OmpStructureChecker::CheckIntentInPointer( +void OmpStructureChecker::CheckIntentInPointerAndDefinable( const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) { std::vector symbols; GetSymbolsInObjectList(objectList, symbols); @@ -869,6 +1014,12 @@ symbol->name(), parser::ToUpperCaseLetters(getClauseName(clause).str())); } + if (IsNamedConstant(*symbol)) { + context_.Say(GetContext().clauseSource, + "Variable '%s' on the %s clause is not definable"_err_en_US, + symbol->name(), + parser::ToUpperCaseLetters(getClauseName(clause).str())); + } } } 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 @@ -318,6 +318,40 @@ x.u); return false; } + + bool Pre(const parser::OmpClause::Reduction &x) { + const parser::OmpReductionOperator &opr{ + std::get(x.v.t)}; + + if (const auto *procD{parser::Unwrap(opr.u)}) { + if (const auto *name{parser::Unwrap(procD->u)}) { + if (!name->symbol) { + const auto namepair{currScope().try_emplace( + name->source, Attrs{}, ProcEntityDetails{})}; + auto &symbol{*namepair.first->second}; + name->symbol = &symbol; + name->symbol->set(Symbol::Flag::OmpReduction); + AddToContextObjectWithDSA(*name->symbol, Symbol::Flag::OmpReduction); + } + } + if (const auto *procRef{ + parser::Unwrap(procD->u)}) { + ResolveOmp(*procRef->v.thing.component.symbol, + Symbol::Flag::OmpReduction, currScope()); + } + } + + // To check Multiple appearances of a symbol on the same context. + const auto &objList{std::get(x.v.t)}; + for (const auto &ompObject : objList.v) { + if (const auto *name{parser::Unwrap(ompObject)}) { + CheckMultipleAppearances( + *name, *name->symbol, Symbol::Flag::OmpReduction); + } + } + return false; + } + bool Pre(const parser::OmpAlignedClause &x) { const auto &alignedNameList{std::get>(x.t)}; ResolveOmpNameList(alignedNameList, Symbol::Flag::OmpAligned); diff --git a/flang/test/Semantics/omp-reduction01.f90 b/flang/test/Semantics/omp-reduction01.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-reduction01.f90 @@ -0,0 +1,14 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.6 Reduction Clause +program omp_reduction + integer :: i + integer :: k = 10 + + !ERROR: Invalid reduction operator in REDUCTION clause. + !$omp parallel do reduction(**:k) + do i = 1, 10 + k = k ** 1 + end do + !$omp end parallel do +end program omp_reduction diff --git a/flang/test/Semantics/omp-reduction02.f90 b/flang/test/Semantics/omp-reduction02.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-reduction02.f90 @@ -0,0 +1,37 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.6 Reduction Clause +program omp_reduction + + integer :: i + integer :: k = 10 + integer :: j = 10 + + !ERROR: 'k' appears in more than one data-sharing clause on the same OpenMP directive + !$omp parallel do reduction(+:k), reduction(-:k) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do + + !ERROR: 'k' appears in more than one data-sharing clause on the same OpenMP directive + !$omp parallel do reduction(+:k), reduction(-:j), reduction(+:k) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do + + !ERROR: 'k' appears in more than one data-sharing clause on the same OpenMP directive + !$omp parallel do reduction(+:j), reduction(-:k), reduction(+:k) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do + + !ERROR: 'k' appears in more than one data-sharing clause on the same OpenMP directive + !$omp parallel do reduction(+:j), reduction(-:k), private(k) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do +end program omp_reduction diff --git a/flang/test/Semantics/omp-reduction03.f90 b/flang/test/Semantics/omp-reduction03.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-reduction03.f90 @@ -0,0 +1,18 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.6 Reduction Clause + +subroutine omp_target(p) + integer, pointer, intent(in) :: p + + integer :: i + integer :: k = 10 + + !ERROR: Pointer 'p' with the INTENT(IN) attribute may not appear in a REDUCTION clause + !$omp parallel do reduction(+:p) + do i = 1, 10 + k= k + 1 + end do + !$omp end parallel do + +end subroutine omp_target diff --git a/flang/test/Semantics/omp-reduction04.f90 b/flang/test/Semantics/omp-reduction04.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-reduction04.f90 @@ -0,0 +1,15 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.6 Reduction Clause +program omp_Reduction + integer :: i + integer, parameter :: k = 10 + + !ERROR: Variable 'k' on the REDUCTION clause is not definable + !$omp parallel do reduction(+:k) + do i = 1, 10 + l = k + 1 + end do + !$omp end parallel do + +end program omp_Reduction diff --git a/flang/test/Semantics/omp-reduction05.f90 b/flang/test/Semantics/omp-reduction05.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-reduction05.f90 @@ -0,0 +1,38 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.6 Reduction Clause + +program omp_reduction + + integer :: i + integer :: k = 10 + integer :: a(10),b(10,10,10) + + !ERROR: 'a' in REDUCTION clause is a zero size array section + !$omp parallel do reduction(+:a(1:0:2)) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do + + !ERROR: 'a' in REDUCTION clause is a zero size array section + !$omp parallel do reduction(+:a(1:0)) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do + + !ERROR: 'b' in REDUCTION clause is a zero size array section + !$omp parallel do reduction(+:b(1:6,5,1:0)) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do + + !ERROR: 'b' in REDUCTION clause is a zero size array section + !$omp parallel do reduction(+:b(1:6,1:0:5,1:10)) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do +end program omp_reduction diff --git a/flang/test/Semantics/omp-reduction06.f90 b/flang/test/Semantics/omp-reduction06.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-reduction06.f90 @@ -0,0 +1,31 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.6 Reduction Clause + +program omp_reduction + + integer :: i + integer :: k = 10 + integer :: a(10), b(10,10,10) + + !ERROR: A list item that appears in a REDUCTION clause should have a contiguos storage array section. + !$omp parallel do reduction(+:a(1:10:3)) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do + + !ERROR: A list item that appears in a REDUCTION clause should have a contiguos storage array section. + !$omp parallel do reduction(+:b(1:10:3,1:8:1,1:5:1)) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do + + !ERROR: A list item that appears in a REDUCTION clause should have a contiguos storage array section. + !$omp parallel do reduction(+:b(1:10:1,1:8:2,1:5:1)) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do +end program omp_reduction diff --git a/flang/test/Semantics/omp-reduction07.f90 b/flang/test/Semantics/omp-reduction07.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-reduction07.f90 @@ -0,0 +1,66 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.6 Reduction Clause +program omp_reduction + + integer :: i,j,l + integer :: k = 10 + !$omp parallel private(k) + !ERROR: REDUCTION variable 'k' is PRIVATE in outer context must be shared in the parallel regions to which any of the worksharing regions arising from the worksharing construct bind. + !$omp do reduction(+:k) + do i = 1, 10 + k = k + 1 + end do + !$omp end do + !$omp end parallel + + + !$omp parallel private(j),reduction(-:k) + !ERROR: REDUCTION variable 'k' is REDUCTION in outer context must be shared in the parallel regions to which any of the worksharing regions arising from the worksharing construct bind. + !$omp do reduction(+:k) + do i = 1, 10 + k = k + 1 + end do + !$omp end do + !$omp end parallel + + !$omp parallel private(j),firstprivate(k) + !ERROR: REDUCTION variable 'k' is FIRSTPRIVATE in outer context must be shared in the parallel regions to which any of the worksharing regions arising from the worksharing construct bind. + !$omp do reduction(+:k) + do i = 1, 10 + k = k + 1 + end do + !$omp end do + !$omp end parallel + + !$omp teams private(l,j),firstprivate(k) + !ERROR: REDUCTION variable 'k' is FIRSTPRIVATE in outer context must be shared in the parallel regions to which any of the worksharing regions arising from the worksharing construct bind. + !ERROR: REDUCTION variable 'j' is PRIVATE in outer context must be shared in the parallel regions to which any of the worksharing regions arising from the worksharing construct bind. + !$omp do reduction(+:k) reduction(-:j) + do i = 1, 10 + k = k + 1 + end do + !$omp end do + !$omp end teams + + !$omp parallel private(l,j),firstprivate(k) + !ERROR: REDUCTION variable 'k' is FIRSTPRIVATE in outer context must be shared in the parallel regions to which any of the worksharing regions arising from the worksharing construct bind. + !ERROR: REDUCTION variable 'j' is PRIVATE in outer context must be shared in the parallel regions to which any of the worksharing regions arising from the worksharing construct bind. + !$omp simd reduction(+:k) reduction(-:j) + do i = 1, 10 + k = k + 1 + end do + !!$omp end do + !$omp end parallel + + !$omp parallel private(l,j),firstprivate(k) + !ERROR: REDUCTION variable 'k' is FIRSTPRIVATE in outer context must be shared in the parallel regions to which any of the worksharing regions arising from the worksharing construct bind. + !ERROR: REDUCTION variable 'j' is PRIVATE in outer context must be shared in the parallel regions to which any of the worksharing regions arising from the worksharing construct bind. + !$omp sections reduction(+:k) reduction(-:j) + do i = 1, 10 + k = k + 1 + end do + !$omp end sections + !$omp end parallel + +end program omp_reduction diff --git a/flang/test/Semantics/omp-reduction08.f90 b/flang/test/Semantics/omp-reduction08.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-reduction08.f90 @@ -0,0 +1,63 @@ +! RUN: %S/test_symbols.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.6 Reduction Clause Positive cases + +!DEF: /omp_reduction MainProgram +program omp_reduction + !DEF: /omp_reduction/i ObjectEntity INTEGER(4) + integer i + !DEF: /omp_reduction/k ObjectEntity INTEGER(4) + integer :: k = 10 + !DEF: /omp_reduction/m ObjectEntity INTEGER(4) + integer :: m = 12 + !$omp parallel do reduction(max:k) + !DEF: /omp_reduction/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + !DEF: /omp_reduction/max INTRINSIC (Function) ProcEntity + !REF: /omp_reduction/m + k = max(k, m) + end do + !$omp end parallel do + + !$omp parallel do reduction(min:k) + !DEF: /omp_reduction/Block2/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + !DEF: /omp_reduction/min INTRINSIC (Function) ProcEntity + !REF: /omp_reduction/m + k = min(k, m) + end do + !$omp end parallel do + + !$omp parallel do reduction(iand:k) + !DEF: /omp_reduction/Block3/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + !DEF: /omp_reduction/iand INTRINSIC (Function) ProcEntity + !REF: /omp_reduction/m + k = iand(k, m) + end do + !$omp end parallel do + + !$omp parallel do reduction(ior:k) + !DEF: /omp_reduction/Block4/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + !DEF: /omp_reduction/ior INTRINSIC (Function) ProcEntity + !REF: /omp_reduction/m + k = ior(k, m) + end do + !$omp end parallel do + + !$omp parallel do reduction(ieor:k) + !DEF: /omp_reduction/Block5/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + !DEF: /omp_reduction/ieor INTRINSIC (Function) ProcEntity + !REF: /omp_reduction/m + k = ieor(k,m) + end do + !$omp end parallel do + +end program omp_reduction diff --git a/flang/test/Semantics/omp-reduction09.f90 b/flang/test/Semantics/omp-reduction09.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-reduction09.f90 @@ -0,0 +1,69 @@ +! RUN: %S/test_symbols.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.6 Reduction Clause Positive cases. +!DEF: /omp_reduction MainProgram +program omp_reduction + !DEF: /omp_reduction/i ObjectEntity INTEGER(4) + integer i + !DEF: /omp_reduction/k ObjectEntity INTEGER(4) + integer :: k = 10 + !DEF: /omp_reduction/a ObjectEntity INTEGER(4) + integer a(10) + !DEF: /omp_reduction/b ObjectEntity INTEGER(4) + integer b(10,10,10) + + !$omp parallel shared(k) + !$omp do reduction(+:k) + !DEF: /omp_reduction/Block1/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + k = k+1 + end do + !$omp end do + !$omp end parallel + + + !$omp parallel do reduction(+:a(10)) + !DEF: /omp_reduction/Block2/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + k = k+1 + end do + !$omp end parallel do + + + !$omp parallel do reduction(+:a(1:10:1)) + !DEF: /omp_reduction/Block3/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + k = k+1 + end do + !$omp end parallel do + + !$omp parallel do reduction(+:a(1:10:1,1:5,2)) + !DEF: /omp_reduction/Block4/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + k = k+1 + end do + !$omp end parallel do + + !$omp parallel do reduction(+:a(1:10:1,1:5,2:5:1)) + !DEF: /omp_reduction/Block5/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + k = k+1 + end do + !$omp end parallel do + + !$omp parallel private(i) + !$omp do reduction(+:k) reduction(+:j) + !DEF: /omp_reduction/Block6/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + k = k+1 + end do + !$omp end do + !$omp end parallel + +end program omp_reduction diff --git a/flang/test/Semantics/omp-reduction10.f90 b/flang/test/Semantics/omp-reduction10.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/omp-reduction10.f90 @@ -0,0 +1,15 @@ +! RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.6 Reduction Clause +program omp_reduction + + integer :: i + integer :: k = 10 + + !ERROR: Invalid reduction identifier in REDUCTION clause. + !$omp parallel do reduction(foo:k) + do i = 1, 10 + k = foo(k) + end do + !$omp end parallel do +end program omp_reduction