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 @@ -197,6 +197,23 @@ 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 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 @@ -78,6 +78,8 @@ namespace Fortran::semantics { +using SymbolSourceMap = std::multimap; + class OmpStructureChecker : public DirectiveStructureChecker { @@ -204,8 +206,25 @@ 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 GetSymbolsInDesignatorList( + const std::list &, SymbolSourceMap &); + void CheckDefinableObjects(SymbolSourceMap &, const llvm::omp::Clause); + void CheckCommonSymbolsInOuterCxt(SymbolSourceMap &, SymbolSourceMap &, + const llvm::omp::Clause, const llvm::omp::Clause); + + bool CheckReductionOperators(const parser::OmpReductionClause &); + bool CheckIntrinsicOperator( + const parser::DefinedOperator::IntrinsicOperator &); + void CheckReductionTypeList(const parser::OmpReductionClause &); + void CheckReductionArraySection( + const std::list &designatorList); + void CheckArraySection(const parser::ArrayElement &arrayElement, + const parser::Name &name, const llvm::omp::Clause clause); + void CheckMultipleAppearanceAcrossContext( + SymbolSourceMap &symbols, const llvm::omp::Clause c); + void CheckIntentInPointer(const std::list &designatorList, + const llvm::omp::Clause clause); }; } // 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 @@ -446,6 +446,126 @@ // Restrictions specific to each clause are implemented apart from the // generalized restrictions. +void OmpStructureChecker::Enter(const parser::OmpReductionClause &x) { + CheckAllowed(llvm::omp::Clause::OMPC_reduction); + if (CheckReductionOperators(x)) { + CheckReductionTypeList(x); + } +} +bool OmpStructureChecker::CheckReductionOperators( + const parser::OmpReductionClause &x) { + const auto &definedOp{std::get<0>(x.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::OmpReductionClause &x) { + + const auto &designatorList{std::get<1>(x.t)}; + SymbolSourceMap currSymbols, enclosingSymbols; + GetSymbolsInDesignatorList(designatorList, currSymbols); + CheckDefinableObjects(currSymbols, llvm::omp::Clause::OMPC_reduction); + CheckIntentInPointer(designatorList, llvm::omp::Clause::OMPC_reduction); + CheckReductionArraySection(designatorList); + CheckMultipleAppearanceAcrossContext( + currSymbols, llvm::omp::Clause::OMPC_reduction); +} + +void OmpStructureChecker::CheckReductionArraySection( + const std::list &designatorList) { + for (const auto &designator : designatorList) { + if (const auto *dataRef{std::get_if(&designator.u)}) { + if (const auto *arrayElement{ + parser::Unwrap(designator)}) { + if (arrayElement) { + CheckArraySection(*arrayElement, GetLastName(*dataRef), + llvm::omp::Clause::OMPC_reduction); + } + } + } + } +} + +void OmpStructureChecker::CheckMultipleAppearanceAcrossContext( + SymbolSourceMap &currSymbols, const llvm::omp::Clause currClause) { + SymbolSourceMap enclosingSymbols; + if (auto *enclosingContext{GetEnclosingDirContext()}) { + if (const auto *clause{FindClauseInContext( + llvm::omp::Clause::OMPC_private, *enclosingContext)}) { + const auto &privateClause{ + std::get(clause->u)}; + GetSymbolsInObjectList(privateClause.v, enclosingSymbols); + CheckCommonSymbolsInOuterCxt(currSymbols, enclosingSymbols, + llvm::omp::Clause::OMPC_reduction, llvm::omp::Clause::OMPC_private); + } + if (const auto *clause{FindClauseInContext( + llvm::omp::Clause::OMPC_firstprivate, *enclosingContext)}) { + const auto &firstprivateClause{ + std::get(clause->u)}; + GetSymbolsInObjectList(firstprivateClause.v, enclosingSymbols); + CheckCommonSymbolsInOuterCxt(currSymbols, enclosingSymbols, + llvm::omp::Clause::OMPC_reduction, + llvm::omp::Clause::OMPC_firstprivate); + } + if (const auto *clause{FindClauseInContext( + llvm::omp::Clause::OMPC_reduction, *enclosingContext)}) { + const auto &reductionClause{ + std::get(clause->u)}; + const auto &designators{ + std::get>(reductionClause.t)}; + GetSymbolsInDesignatorList(designators, enclosingSymbols); + CheckCommonSymbolsInOuterCxt(currSymbols, enclosingSymbols, + 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 @@ -493,8 +613,7 @@ ompObject.u); } } -// Following clauses have a seperate node in parse-tree.h. -CHECK_SIMPLE_PARSER_CLAUSE(OmpReductionClause, OMPC_reduction) + // Atomic-clause CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicRead, OMPC_read) CHECK_SIMPLE_PARSER_CLAUSE(OmpAtomicWrite, OMPC_write) @@ -703,7 +822,8 @@ if (const auto *arr{ std::get_if>( &dataRef->u)}) { - CheckDependArraySection(*arr, GetLastName(*dataRef)); + CheckArraySection(arr->value(), GetLastName(*dataRef), + llvm::omp::Clause::OMPC_depend); } } } @@ -768,12 +888,80 @@ } } } +// 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 " + "in a %s clause"_err_en_US, + symbol->name(), + parser::ToUpperCaseLetters(getClauseName(clause).str())); + } + } +} + +void OmpStructureChecker::CheckIntentInPointer( + const std::list &designatorList, + const llvm::omp::Clause clause) { + SymbolSourceMap symbols; + GetSymbolsInDesignatorList(designatorList, 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 " @@ -785,22 +973,66 @@ } 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::GetSymbolsInDesignatorList( + const std::list &designatorList, + SymbolSourceMap &symbols) { + for (const auto &designator : designatorList) { + if (const auto *name{parser::Unwrap(designator)}) { + if (const auto *symbol{name->symbol}) { + 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, SymbolSourceMap &outerSymbols, + const llvm::omp::Clause currClause, const llvm::omp::Clause outerClause) { + 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,49 @@ x.u); return false; } + + bool Pre(const parser::OmpReductionClause &x) { + const parser::OmpReductionOperator &opr{ + std::get(x.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. + // ResolveObjectList() + const auto &designatorList{std::get>(x.t)}; + for (const auto &designator : designatorList) { + if (const auto *name{GetDesignatorNameIfDataRef(designator)}) { + 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,16 @@ +! 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,70 @@ +! 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