diff --git a/flang/include/flang/Parser/dump-parse-tree.h b/flang/include/flang/Parser/dump-parse-tree.h --- a/flang/include/flang/Parser/dump-parse-tree.h +++ b/flang/include/flang/Parser/dump-parse-tree.h @@ -231,6 +231,7 @@ NODE(parser, DefinedOpName) NODE(parser, DefinedOperator) NODE_ENUM(DefinedOperator, IntrinsicOperator) + NODE_ENUM(DefinedOperator, IntrinsicProcedure) NODE(parser, DerivedTypeDef) NODE(parser, DerivedTypeSpec) NODE(parser, DerivedTypeStmt) diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h --- a/flang/include/flang/Parser/parse-tree.h +++ b/flang/include/flang/Parser/parse-tree.h @@ -586,7 +586,8 @@ UNION_CLASS_BOILERPLATE(DefinedOperator); ENUM_CLASS(IntrinsicOperator, Power, Multiply, Divide, Add, Subtract, Concat, LT, LE, EQ, NE, GE, GT, NOT, AND, OR, EQV, NEQV) - std::variant u; + ENUM_CLASS(IntrinsicProcedure, MAX, MIN, IAND, IOR, IEOR); + std::variant u; }; // R804 object-name -> name diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h --- a/flang/include/flang/Semantics/symbol.h +++ b/flang/include/flang/Semantics/symbol.h @@ -399,7 +399,8 @@ // A GenericKind is one of: generic name, defined operator, // defined assignment, intrinsic operator, or defined I/O. struct GenericKind { - ENUM_CLASS(OtherKind, Name, DefinedOp, Assignment, Concat) + ENUM_CLASS( + OtherKind, Name, DefinedOp, Assignment, Concat, MAX, MIN, IAND, IOR, IEOR) ENUM_CLASS(DefinedIo, // defined io ReadFormatted, ReadUnformatted, WriteFormatted, WriteUnformatted) GenericKind() : u{OtherKind::Name} {} diff --git a/flang/lib/Parser/Fortran-parsers.cpp b/flang/lib/Parser/Fortran-parsers.cpp --- a/flang/lib/Parser/Fortran-parsers.cpp +++ b/flang/lib/Parser/Fortran-parsers.cpp @@ -97,10 +97,17 @@ ">" >> pure(DefinedOperator::IntrinsicOperator::GT) || namedIntrinsicOperator}; +constexpr auto intrinsicProcedure{ + "MAX" >> pure(DefinedOperator::IntrinsicProcedure::MAX) || + "MIN" >> pure(DefinedOperator::IntrinsicProcedure::MIN) || + "IAND" >> pure(DefinedOperator::IntrinsicProcedure::IAND) || + "IOR" >> pure(DefinedOperator::IntrinsicProcedure::IOR) || + "IEOR" >> pure(DefinedOperator::IntrinsicProcedure::IEOR)}; // R609 defined-operator -> // defined-unary-op | defined-binary-op | extended-intrinsic-op TYPE_PARSER(construct(intrinsicOperator) || - construct(definedOpName)) + construct(definedOpName) || + construct(intrinsicProcedure)) // R505 implicit-part -> [implicit-part-stmt]... implicit-stmt // TODO: Can overshoot; any trailing PARAMETER, FORMAT, & ENTRY 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 @@ -134,8 +134,11 @@ const PC *clause{nullptr}; std::multimap clauseInfo; std::list actualClauses; + std::list reductionSymbols; }; + bool FindReductionVariable(Symbol *symbol); + bool CheckPrivateReductionVariable(Symbol *symbol); // back() is the top of the stack DirectiveContext &GetContext() { CHECK(!dirContext_.empty()); @@ -155,6 +158,7 @@ GetContext().allowedExclusiveClauses = {}; GetContext().requiredClauses = {}; GetContext().clauseInfo = {}; + GetContext().reductionSymbols.clear(); } void SetContextDirectiveSource(const parser::CharBlock &directive) { @@ -266,6 +270,29 @@ std::string ClauseSetToString(const common::EnumSet set); }; +template +bool DirectiveStructureChecker::FindReductionVariable( + Symbol *symbol) { + if (std::find(GetContext().reductionSymbols.begin(), + GetContext().reductionSymbols.end(), + symbol) != GetContext().reductionSymbols.end()) { + return true; + } + GetContext().reductionSymbols.push_back(symbol); + return false; +} +template +bool DirectiveStructureChecker::CheckPrivateReductionVariable(Symbol *symbol) { + if (!GetContext().reductionSymbols.empty()) { + for (auto rs : GetContext().reductionSymbols) { + if (rs && rs->name() == symbol->name()) { + return true; + } + } + } + return false; +} 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 @@ -175,6 +175,18 @@ llvm::StringRef getClauseName(llvm::omp::Clause clause) override; llvm::StringRef getDirectiveName(llvm::omp::Directive directive) override; + + void CheckPrivateClauseRestrictions(const parser::OmpObjectList &); + bool CheckReductionOperators(const parser::OmpReductionClause &); + bool CheckIntrinsicOperator( + const parser::DefinedOperator::IntrinsicOperator &); + bool CheckIntrinsicProcedure( + const parser::DefinedOperator::IntrinsicProcedure &); + void CheckReductionTypeList(const parser::OmpReductionClause &); + void CheckReductionVariableDefinable(Symbol &); + void CheckReductionVariableIntentIn(Symbol &); + void CheckMultipleReductionVariable(Symbol *); + void CheckReductionArrayVariable(const parser::ArrayElement &); }; } // 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 @@ -385,7 +385,6 @@ CHECK_SIMPLE_CLAUSE(Mergeable, OMPC_mergeable) CHECK_SIMPLE_CLAUSE(Nogroup, OMPC_nogroup) CHECK_SIMPLE_CLAUSE(Notinbranch, OMPC_notinbranch) -CHECK_SIMPLE_CLAUSE(Private, OMPC_private) CHECK_SIMPLE_CLAUSE(Shared, OMPC_shared) CHECK_SIMPLE_CLAUSE(To, OMPC_to) CHECK_SIMPLE_CLAUSE(Uniform, OMPC_uniform) @@ -405,6 +404,187 @@ // Restrictions specific to each clause are implemented apart from the // generalized restrictions. +void OmpStructureChecker::Enter(const parser::OmpClause::Private &x) { + CheckAllowed(llvm::omp::Clause::OMPC_private); + CheckPrivateClauseRestrictions(x.v); +} +void OmpStructureChecker::CheckPrivateClauseRestrictions( + 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 (const auto *name{parser::Unwrap(ompObject)}) { + Symbol *symbol = name->symbol; + if (symbol) { + if (CheckPrivateReductionVariable(symbol)) { + context_.Say(GetContext().clauseSource, + "A list item that appears in a REDUCTION clause" + " of a worksharing construct must be shared in" + " the parallel regions to which any of the " + "worksharing" + " regions arising from the worksharing construct bind."_err_en_US, + ContextDirectiveAsFortran()); + } + } + } + } + }, + [&](const parser::Name &name) {}, + }, + ompObject.u); + } +} +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)}; + const auto &opr{std::get(definedOp.u)}; + bool ok = false; + std::visit(common::visitors{ + [&](const parser::DefinedOpName &defName) {}, + [&](const parser::DefinedOperator::IntrinsicOperator &op) { + ok = CheckIntrinsicOperator(op); + }, + [&](const parser::DefinedOperator::IntrinsicProcedure &proc) { + ok = CheckIntrinsicProcedure(proc); + }, + }, + opr.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; +} +bool OmpStructureChecker::CheckIntrinsicProcedure( + const parser::DefinedOperator::IntrinsicProcedure &proc) { + switch (proc) { + case parser::DefinedOperator::IntrinsicProcedure::MAX: + case parser::DefinedOperator::IntrinsicProcedure::MIN: + case parser::DefinedOperator::IntrinsicProcedure::IAND: + case parser::DefinedOperator::IntrinsicProcedure::IOR: + case parser::DefinedOperator::IntrinsicProcedure::IEOR: + return true; + default: + context_.Say(GetContext().clauseSource, + "Invalid Intrinsic Procedure in REDUCTION clause."_err_en_US, + ContextDirectiveAsFortran()); + } + return false; +} +void OmpStructureChecker::CheckReductionTypeList( + const parser::OmpReductionClause &x) { + + const auto &objList{std::get<1>(x.t)}; + for (const auto &ompObject : objList) { + std::visit( + common::visitors{ + [&](const parser::DataRef &dataRef) { + if (const auto *name{parser::Unwrap(ompObject)}) { + Symbol *symbol = name->symbol; + if (symbol) { + CheckReductionVariableDefinable(*symbol); + CheckReductionVariableIntentIn(*symbol); + CheckMultipleReductionVariable(symbol); + } + } + if (const auto *arrayElement{ + parser::Unwrap(ompObject)}) { + if (arrayElement) { + CheckReductionArrayVariable(*arrayElement); + } + } + }, + [&](const parser::Substring &ss) {}, + + }, + ompObject.u); + } +} +void OmpStructureChecker::CheckMultipleReductionVariable( + Symbol *reductionSymbol) { + + if (FindReductionVariable(reductionSymbol)) { + context_.Say(GetContext().clauseSource, + "A list item can appear only once in the" + " REDUCTION clause."_err_en_US, + ContextDirectiveAsFortran()); + } +} +void OmpStructureChecker::CheckReductionVariableIntentIn(Symbol &symbol) { + if (IsPointer(symbol) && IsIntentIn(symbol)) { + context_.Say(GetContext().clauseSource, + "A pointer with the INTENT(IN) attribute may not appear" + " in the REDUCTION clause."_err_en_US, + ContextDirectiveAsFortran()); + } +} +void OmpStructureChecker::CheckReductionVariableDefinable(Symbol &symbol) { + if (IsNamedConstant(symbol)) { + context_.Say(GetContext().clauseSource, + "A list item that appears in a REDUCTION clause" + " must be definable."_err_en_US, + ContextDirectiveAsFortran()); + } +} +void OmpStructureChecker::CheckReductionArrayVariable( + const parser::ArrayElement &arrayElement) { + if (!arrayElement.subscripts.empty()) { + auto iter{arrayElement.subscripts.begin()}; + if (auto *triplet{std::get_if(&iter->u)}) { + if (std::get<0>(triplet->t) && std::get<1>(triplet->t)) { + const auto &lowerExpr{std::get<0>(triplet->t).value()}; + const auto *lb{semantics::GetExpr(lowerExpr.thing.thing)}; + auto lower{evaluate::ToInt64(*lb)}; + const auto &upperExpr{std::get<1>(triplet->t).value()}; + const auto *ub{semantics::GetExpr(upperExpr.thing.thing)}; + auto upper{evaluate::ToInt64(*ub)}; + if (lower && upper) { + if (lower > upper) { + context_.Say(GetContext().clauseSource, + "A list item that appears in a REDUCTION clause" + " cannot have a zero-length array section."_err_en_US, + ContextDirectiveAsFortran()); + } else if (std::get<2>(triplet->t)) { + const auto &strideExpr{std::get<2>(triplet->t).value()}; + const auto *st{semantics::GetExpr(strideExpr.thing.thing)}; + auto stride{evaluate::ToInt64(*st)}; + if ((stride && stride != 1)) { + context_.Say(GetContext().clauseSource, + "A list item that appears in a REDUCTION clause" + " should have a continuous storage array section."_err_en_US, + ContextDirectiveAsFortran()); + } + } + } + } + } + } +} + void OmpStructureChecker::Enter(const parser::OmpClause::Ordered &x) { CheckAllowed(llvm::omp::Clause::OMPC_ordered); // the parameter of ordered clause is optional @@ -428,7 +608,6 @@ CHECK_SIMPLE_PARSER_CLAUSE(OmpDistScheduleClause, OMPC_dist_schedule) CHECK_SIMPLE_PARSER_CLAUSE(OmpNowait, OMPC_nowait) CHECK_SIMPLE_PARSER_CLAUSE(OmpProcBindClause, OMPC_proc_bind) -CHECK_SIMPLE_PARSER_CLAUSE(OmpReductionClause, OMPC_reduction) // Restrictions specific to each clause are implemented apart from the // generalized restrictions. diff --git a/flang/lib/Semantics/resolve-names-utils.cpp b/flang/lib/Semantics/resolve-names-utils.cpp --- a/flang/lib/Semantics/resolve-names-utils.cpp +++ b/flang/lib/Semantics/resolve-names-utils.cpp @@ -28,8 +28,10 @@ using common::NumericOperator; using common::RelationalOperator; using IntrinsicOperator = parser::DefinedOperator::IntrinsicOperator; +using IntrinsicProcedure = parser::DefinedOperator::IntrinsicProcedure; static GenericKind MapIntrinsicOperator(IntrinsicOperator); +static GenericKind MapIntrinsicProcedure(IntrinsicProcedure); Symbol *Resolve(const parser::Name &name, Symbol *symbol) { if (symbol && !name.symbol) { @@ -140,6 +142,9 @@ [&](const IntrinsicOperator &z) { return MapIntrinsicOperator(z); }, + [&](const IntrinsicProcedure &z) { + return MapIntrinsicProcedure(z); + }, }, y.u); }, @@ -203,6 +208,22 @@ } } +static GenericKind MapIntrinsicProcedure(IntrinsicProcedure op) { + switch (op) { + SWITCH_COVERS_ALL_CASES + case IntrinsicProcedure::MAX: + return GenericKind::OtherKind::MAX; + case IntrinsicProcedure::MIN: + return GenericKind::OtherKind::MIN; + case IntrinsicProcedure::IAND: + return GenericKind::OtherKind::IAND; + case IntrinsicProcedure::IOR: + return GenericKind::OtherKind::IOR; + case IntrinsicProcedure::IEOR: + return GenericKind::OtherKind::IEOR; + } +} + class ArraySpecAnalyzer { public: ArraySpecAnalyzer(SemanticsContext &context) : context_{context} {} 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,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 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: A list item can appear only once in the REDUCTION clause. + !$omp parallel do reduction(+:k), reduction(-:k) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do + + !ERROR: A list item can appear only once in the REDUCTION clause. + !$omp parallel do reduction(+:k), reduction(-:j), reduction(+:k) + do i = 1, 10 + k = k + 1 + end do + !$omp end parallel do + + !ERROR: A list item can appear only once in the REDUCTION clause. + !$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,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: A pointer with the INTENT(IN) attribute may not appear in the 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,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: A list item that appears in a REDUCTION clause must be 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,25 @@ +!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) + + !ERROR: A list item that appears in a 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 list item that appears in a 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 + +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,18 @@ +!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) + + !ERROR: A list item that appears in a REDUCTION clause should have a continuous storage array section. + !$omp parallel do reduction(+:a(1:10:3)) + 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,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: A list item that appears in a REDUCTION clause of a worksharing construct must be shared in the parallel regions to which any of the worksharing regions arising from the worksharing construct bind. + !$omp parallel do 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-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,62 @@ +!RUN: %S/test_errors.sh %s %t %f18 -fopenmp +! OpenMP Version 4.5 +! 2.15.3.6 Reduction Clause Positive cases + +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/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 = min(k, m) + end do + !$omp end parallel do + + !$omp parallel do reduction(IAND: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 = k + m + end do + !$omp end parallel do + + !$omp parallel do reduction(IOR: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 = k + m + end do + !$omp end parallel do + + !$omp parallel do reduction(IEOR: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 = 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,58 @@ +!RUN: %S/test_errors.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) + + !$omp parallel do reduction(+:k) shared(k) + !DEF: /omp_reduction/Block1/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) + !DEF: /omp_reduction/Block1/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(10)) + !DEF: /omp_reduction/Block1/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/Block1/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 private(i) shared(k) reduction(+:k) + !$omp& reduction(+:j) + !DEF: /omp_reduction/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4) + do i=1,10 + !REF: /omp_reduction/k + k = k+1 + end do + +end program omp_reduction