diff --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp --- a/flang/lib/Semantics/check-acc-structure.cpp +++ b/flang/lib/Semantics/check-acc-structure.cpp @@ -6,6 +6,7 @@ // //===----------------------------------------------------------------------===// #include "check-acc-structure.h" +#include "flang/Common/enum-set.h" #include "flang/Parser/parse-tree.h" #include "flang/Semantics/tools.h" @@ -20,6 +21,35 @@ RequiresConstantPositiveParameter(llvm::acc::Clause::Y, c.v); \ } +using ReductionOpsSet = + Fortran::common::EnumSet; + +static ReductionOpsSet reductionIntegerSet{ + Fortran::parser::AccReductionOperator::Operator::Plus, + Fortran::parser::AccReductionOperator::Operator::Multiply, + Fortran::parser::AccReductionOperator::Operator::Max, + Fortran::parser::AccReductionOperator::Operator::Min, + Fortran::parser::AccReductionOperator::Operator::Iand, + Fortran::parser::AccReductionOperator::Operator::Ior, + Fortran::parser::AccReductionOperator::Operator::Ieor}; + +static ReductionOpsSet reductionRealSet{ + Fortran::parser::AccReductionOperator::Operator::Plus, + Fortran::parser::AccReductionOperator::Operator::Multiply, + Fortran::parser::AccReductionOperator::Operator::Max, + Fortran::parser::AccReductionOperator::Operator::Min}; + +static ReductionOpsSet reductionComplexSet{ + Fortran::parser::AccReductionOperator::Operator::Plus, + Fortran::parser::AccReductionOperator::Operator::Multiply}; + +static ReductionOpsSet reductionLogicalSet{ + Fortran::parser::AccReductionOperator::Operator::And, + Fortran::parser::AccReductionOperator::Operator::Or, + Fortran::parser::AccReductionOperator::Operator::Eqv, + Fortran::parser::AccReductionOperator::Operator::Neqv}; + namespace Fortran::semantics { static constexpr inline AccClauseSet @@ -335,7 +365,6 @@ CHECK_SIMPLE_CLAUSE(Present, ACCC_present) CHECK_SIMPLE_CLAUSE(Private, ACCC_private) CHECK_SIMPLE_CLAUSE(Read, ACCC_read) -CHECK_SIMPLE_CLAUSE(Reduction, ACCC_reduction) CHECK_SIMPLE_CLAUSE(Seq, ACCC_seq) CHECK_SIMPLE_CLAUSE(Tile, ACCC_tile) CHECK_SIMPLE_CLAUSE(UseDevice, ACCC_use_device) @@ -431,6 +460,57 @@ "NUM_GANGS clause accepts a maximum of 3 arguments"_err_en_US); } +void AccStructureChecker::Enter(const parser::AccClause::Reduction &reduction) { + CheckAllowed(llvm::acc::Clause::ACCC_reduction); + + // From OpenACC 3.3 + // At a minimum, the supported data types include Fortran logical as well as + // the numerical data types (e.g. integer, real, double precision, complex). + // However, for each reduction operator, the supported data types include only + // the types permitted as operands to the corresponding operator in the base + // language where (1) for max and min, the corresponding operator is less-than + // and (2) for other operators, the operands and the result are the same type. + // + // The following check that the reduction operator is supported with the given + // type. + const parser::AccObjectListWithReduction &list{reduction.v}; + const auto &op{std::get(list.t)}; + const auto &objects{std::get(list.t)}; + + for (const auto &object : objects.v) { + std::visit( + Fortran::common::visitors{ + [&](const Fortran::parser::Designator &designator) { + if (const auto *name = getDesignatorNameIfDataRef(designator)) { + const auto *type{name->symbol->GetType()}; + if (type->IsNumeric(TypeCategory::Integer) && + !reductionIntegerSet.test(op.v)) { + context_.Say(GetContext().clauseSource, + "reduction operator not supported for integer type"_err_en_US); + } else if (type->IsNumeric(TypeCategory::Real) && + !reductionRealSet.test(op.v)) { + context_.Say(GetContext().clauseSource, + "reduction operator not supported for real type"_err_en_US); + } else if (type->IsNumeric(TypeCategory::Complex) && + !reductionComplexSet.test(op.v)) { + context_.Say(GetContext().clauseSource, + "reduction operator not supported for complex type"_err_en_US); + } else if (type->category() == + Fortran::semantics::DeclTypeSpec::Category::Logical && + !reductionLogicalSet.test(op.v)) { + context_.Say(GetContext().clauseSource, + "reduction operator not supported for logical type"_err_en_US); + } + // TODO: check composite type. + } + }, + [&](const Fortran::parser::Name &name) { + // TODO: check common block + }}, + object.u); + } +} + void AccStructureChecker::Enter(const parser::AccClause::Self &x) { CheckAllowed(llvm::acc::Clause::ACCC_self); const std::optional &accSelfClause = x.v; diff --git a/flang/test/Semantics/OpenACC/acc-reduction-validity.f90 b/flang/test/Semantics/OpenACC/acc-reduction-validity.f90 new file mode 100644 --- /dev/null +++ b/flang/test/Semantics/OpenACC/acc-reduction-validity.f90 @@ -0,0 +1,172 @@ +! RUN: %python %S/../test_errors.py %s %flang -fopenacc + +! Check OpenACC reduction validity. + +program openacc_reduction_validity + + integer :: i + real :: r + complex :: c + logical :: l + + !$acc parallel reduction(+:i) + !$acc end parallel + + !$acc parallel reduction(*:i) + !$acc end parallel + + !$acc parallel reduction(min:i) + !$acc end parallel + + !$acc parallel reduction(max:i) + !$acc end parallel + + !$acc parallel reduction(iand:i) + !$acc end parallel + + !$acc parallel reduction(ior:i) + !$acc end parallel + + !$acc parallel reduction(ieor:i) + !$acc end parallel + + !ERROR: reduction operator not supported for integer type + !$acc parallel reduction(.and.:i) + !$acc end parallel + + !ERROR: reduction operator not supported for integer type + !$acc parallel reduction(.or.:i) + !$acc end parallel + + !ERROR: reduction operator not supported for integer type + !$acc parallel reduction(.eqv.:i) + !$acc end parallel + + !ERROR: reduction operator not supported for integer type + !$acc parallel reduction(.neqv.:i) + !$acc end parallel + + !$acc parallel reduction(+:r) + !$acc end parallel + + !$acc parallel reduction(*:r) + !$acc end parallel + + !$acc parallel reduction(min:r) + !$acc end parallel + + !$acc parallel reduction(max:r) + !$acc end parallel + + !ERROR: reduction operator not supported for real type + !$acc parallel reduction(iand:r) + !$acc end parallel + + !ERROR: reduction operator not supported for real type + !$acc parallel reduction(ior:r) + !$acc end parallel + + !ERROR: reduction operator not supported for real type + !$acc parallel reduction(ieor:r) + !$acc end parallel + + !ERROR: reduction operator not supported for real type + !$acc parallel reduction(.and.:r) + !$acc end parallel + + !ERROR: reduction operator not supported for real type + !$acc parallel reduction(.or.:r) + !$acc end parallel + + !ERROR: reduction operator not supported for real type + !$acc parallel reduction(.eqv.:r) + !$acc end parallel + + !ERROR: reduction operator not supported for real type + !$acc parallel reduction(.neqv.:r) + !$acc end parallel + + !$acc parallel reduction(+:c) + !$acc end parallel + + !$acc parallel reduction(*:c) + !$acc end parallel + + !ERROR: reduction operator not supported for complex type + !$acc parallel reduction(min:c) + !$acc end parallel + + !ERROR: reduction operator not supported for complex type + !$acc parallel reduction(max:c) + !$acc end parallel + + !ERROR: reduction operator not supported for complex type + !$acc parallel reduction(iand:c) + !$acc end parallel + + !ERROR: reduction operator not supported for complex type + !$acc parallel reduction(ior:c) + !$acc end parallel + + !ERROR: reduction operator not supported for complex type + !$acc parallel reduction(ieor:c) + !$acc end parallel + + !ERROR: reduction operator not supported for complex type + !$acc parallel reduction(.and.:c) + !$acc end parallel + + !ERROR: reduction operator not supported for complex type + !$acc parallel reduction(.or.:c) + !$acc end parallel + + !ERROR: reduction operator not supported for complex type + !$acc parallel reduction(.eqv.:c) + !$acc end parallel + + !ERROR: reduction operator not supported for complex type + !$acc parallel reduction(.neqv.:c) + !$acc end parallel + + !$acc parallel reduction(.and.:l) + !$acc end parallel + + !$acc parallel reduction(.or.:l) + !$acc end parallel + + !$acc parallel reduction(.eqv.:l) + !$acc end parallel + + !$acc parallel reduction(.neqv.:l) + !$acc end parallel + + !ERROR: reduction operator not supported for logical type + !$acc parallel reduction(+:l) + !$acc end parallel + + !ERROR: reduction operator not supported for logical type + !$acc parallel reduction(*:l) + !$acc end parallel + + !ERROR: reduction operator not supported for logical type + !$acc parallel reduction(min:l) + !$acc end parallel + + !ERROR: reduction operator not supported for logical type + !$acc parallel reduction(max:l) + !$acc end parallel + + !ERROR: reduction operator not supported for logical type + !$acc parallel reduction(iand:l) + !$acc end parallel + + !ERROR: reduction operator not supported for logical type + !$acc parallel reduction(ior:l) + !$acc end parallel + + !ERROR: reduction operator not supported for logical type + !$acc parallel reduction(ieor:l) + !$acc end parallel + + +end program