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 @@ -20,6 +20,8 @@ namespace Fortran::semantics { +using SymbolSourceMap = std::multimap; + template struct DirectiveClauses { const common::EnumSet allowed; const common::EnumSet allowedOnce; @@ -197,6 +199,25 @@ return nullptr; } + DirectiveContext *GetEnclosingDirContext() { + CHECK(!dirContext_.empty()); + auto it{dirContext_.rbegin()}; + if (++it != dirContext_.rend()) { + return &(*it); + } + return nullptr; + } + + const PC *FindClauseInContext(C type, DirectiveContext &dirContext) { + auto it{dirContext.clauseInfo.find(type)}; + if (it != dirContext.clauseInfo.end()) { + return it->second; + } + return nullptr; + } + + void GetSymbolsFromClause(C type, const PC *clause, SymbolSourceMap &symbols); + void PushContext(const parser::CharBlock &source, D dir) { dirContext_.emplace_back(source, dir); } @@ -266,6 +287,35 @@ std::string ClauseSetToString(const common::EnumSet set); }; +template +void DirectiveStructureChecker::GetSymbolsFromClause( + C type, const PC *clause, SymbolSourceMap &symbols) { + const parser::OmpObjectList *objList; + if (clause) { + 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; + } + for (const auto &ompObject : objList->v) { + if (const auto *name{parser::Unwrap(ompObject)}) { + if (const auto *symbol{name->symbol}) { + symbols.emplace(&symbol->GetUltimate(), name->source); + } + } + } + } +} template void DirectiveStructureChecker::CheckNoBranching( const parser::Block &block, D directive, 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 @@ -205,8 +205,20 @@ void CheckIsVarPartOfAnotherVar(const parser::OmpObjectList &objList); void CheckIntentInPointer( const parser::OmpObjectList &, const llvm::omp::Clause); - void GetSymbolsInObjectList( - const parser::OmpObjectList &, std::vector &); + void GetSymbolsInObjectList(const parser::OmpObjectList &, SymbolSourceMap &); + void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause); + void CheckCommonSymbolsInOuterCxt( + SymbolSourceMap &, const llvm::omp::Clause, const llvm::omp::Clause); + + 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( + SymbolSourceMap &symbols, const llvm::omp::Clause c); }; } // 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 @@ -419,7 +419,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) @@ -448,6 +447,103 @@ // 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)}; + SymbolSourceMap currSymbols, enclosingSymbols; + GetSymbolsFromClause(llvm::omp::Clause::OMPC_reduction,GetContext().clause, currSymbols); + CheckDefinableObjects(currSymbols, llvm::omp::Clause::OMPC_reduction); + CheckIntentInPointer(ompObjectList, llvm::omp::Clause::OMPC_reduction); + CheckReductionArraySection(ompObjectList); + CheckMultipleAppearanceAcrossContext( + currSymbols, llvm::omp::Clause::OMPC_reduction); +} + +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( + SymbolSourceMap &currSymbols, const llvm::omp::Clause currClause) { + + CheckCommonSymbolsInOuterCxt(currSymbols, llvm::omp::Clause::OMPC_reduction, + llvm::omp::Clause::OMPC_private); + CheckCommonSymbolsInOuterCxt(currSymbols, llvm::omp::Clause::OMPC_reduction, + llvm::omp::Clause::OMPC_firstprivate); + CheckCommonSymbolsInOuterCxt(currSymbols, llvm::omp::Clause::OMPC_reduction, + llvm::omp::Clause::OMPC_reduction); +} + void OmpStructureChecker::Enter(const parser::OmpClause::Ordered &x) { CheckAllowed(llvm::omp::Clause::OMPC_ordered); // the parameter of ordered clause is optional @@ -704,7 +800,8 @@ if (const auto *arr{ std::get_if>( &dataRef->u)}) { - CheckDependArraySection(*arr, GetLastName(*dataRef)); + CheckArraySection(arr->value(), GetLastName(*dataRef), + llvm::omp::Clause::OMPC_depend); } } } @@ -769,12 +866,61 @@ } } } +// 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" + " cannot have a zero-length 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( const parser::OmpObjectList &objectList, const llvm::omp::Clause clause) { - std::vector symbols; + SymbolSourceMap symbols; GetSymbolsInObjectList(objectList, symbols); - for (const auto *symbol : symbols) { + for (auto it{symbols.begin()}; it != symbols.end(); ++it) { + const auto *symbol{it->first}; + const auto source{it->second}; if (IsPointer(*symbol) && IsIntentIn(*symbol)) { context_.Say(GetContext().clauseSource, "Pointer '%s' with the INTENT(IN) attribute may not appear " @@ -786,22 +932,63 @@ } void OmpStructureChecker::GetSymbolsInObjectList( - const parser::OmpObjectList &objectList, - std::vector &symbols) { + const parser::OmpObjectList &objectList, SymbolSourceMap &symbols) { for (const auto &ompObject : objectList.v) { if (const auto *name{parser::Unwrap(ompObject)}) { if (const auto *symbol{name->symbol}) { if (const auto *commonBlockDetails{ symbol->detailsIf()}) { for (const auto &object : commonBlockDetails->objects()) { - symbols.emplace_back(&object->GetUltimate()); + symbols.emplace(&object->GetUltimate(), name->source); } } else { - symbols.emplace_back(&symbol->GetUltimate()); + symbols.emplace(&symbol->GetUltimate(), name->source); } } } } } +void OmpStructureChecker::CheckDefinableObjects( + SymbolSourceMap &symbols, const llvm::omp::Clause clause) { + for (auto it{symbols.begin()}; it != symbols.end(); ++it) { + const auto *symbol{it->first}; + const auto source{it->second}; + const auto msg{WhyNotModifiable(*symbol, context_.FindScope(source))}; + if (IsNamedConstant(*symbol) || msg) { + context_ + .Say(source, + "Variable '%s' on the %s clause is not definable"_err_en_US, + symbol->name(), + parser::ToUpperCaseLetters(getClauseName(clause).str())) + .Attach(source, std::move(*msg), symbol->name()); + } + } +} + +void OmpStructureChecker::CheckCommonSymbolsInOuterCxt( + SymbolSourceMap &currSymbols, const llvm::omp::Clause currClause, + const llvm::omp::Clause outerClause) { + SymbolSourceMap outerSymbols; + if (auto *enclosingContext{GetEnclosingDirContext()}) { + if (const auto *enclosingClause{FindClauseInContext(outerClause, *enclosingContext)}){ + GetSymbolsFromClause(outerClause, enclosingClause, outerSymbols); + + for (auto it{currSymbols.begin()}; it != currSymbols.end(); ++it) { + const auto *symbol{it->first}; + const auto source{it->second}; + if (outerSymbols.find(symbol) != outerSymbols.end()) { + context_.Say(source, + "%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(currClause).str()), + symbol->name(), + parser::ToUpperCaseLetters(getClauseName(outerClause).str())); + } + } + } + } +} } // namespace Fortran::semantics 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 @@ -316,6 +316,48 @@ x.u); return false; } + + bool Pre(const parser::OmpClause::Reduction &x) { + const parser::OmpReductionOperator &opr{ + std::get(x.v.t)}; + std::visit( + common::visitors{ + [&](const parser::DefinedOperator &dOP) {}, + [&](const parser::ProcedureDesignator &procD) { + std::visit( + common::visitors{ + [&](const parser::Name &name) { + 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); + } + }, + [&](const parser::ProcComponentRef &procRef) { + ResolveOmp(*procRef.v.thing.component.symbol, + Symbol::Flag::OmpReduction, currScope()); + }, + }, + procD.u); + }, + }, + opr.u); + + // 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-depend01.f90 b/flang/test/Semantics/omp-depend01.f90 --- a/flang/test/Semantics/omp-depend01.f90 +++ b/flang/test/Semantics/omp-depend01.f90 @@ -11,8 +11,8 @@ !$omp parallel !$omp single - !ERROR: 'a' in DEPEND clause is a zero size array section - !ERROR: 'b' in DEPEND clause is a zero size array section + !ERROR: 'a' in DEPEND clause cannot have a zero-length array section. + !ERROR: 'b' in DEPEND clause cannot have a zero-length array section. !$omp task shared(a,b) depend(out: a(2:1), b(3:1, 1:-1)) a(2:1) = b(2, 2) !$omp end task 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,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 :: 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 + +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,19 @@ +! 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 + !ERROR: Variable 'p' on the REDUCTION clause is not definable + !$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 cannot have a zero-length 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 cannot have a zero-length 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 cannot have a zero-length 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 cannot have a zero-length 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,35 @@ +! 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 + 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 +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