diff --git a/flang/examples/FeatureList/FeatureList.cpp b/flang/examples/FeatureList/FeatureList.cpp --- a/flang/examples/FeatureList/FeatureList.cpp +++ b/flang/examples/FeatureList/FeatureList.cpp @@ -80,7 +80,7 @@ READ_FEATURE(AccEndAtomic) READ_FEATURE(AccEndBlockDirective) READ_FEATURE(AccEndCombinedDirective) - READ_FEATURE(AccGangArgument) + READ_FEATURE(AccGangArg) READ_FEATURE(AccObject) READ_FEATURE(AccObjectList) READ_FEATURE(AccObjectListWithModifier) 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 @@ -84,8 +84,12 @@ NODE(parser, AccEndAtomic) NODE(parser, AccEndBlockDirective) NODE(parser, AccEndCombinedDirective) - NODE(parser, AccGangArgument) NODE(parser, AccCollapseArg) + NODE(parser, AccGangArg) + NODE(AccGangArg, Num) + NODE(AccGangArg, Dim) + NODE(AccGangArg, Static) + NODE(parser, AccGangArgList) NODE(parser, AccObject) NODE(parser, AccObjectList) NODE(parser, AccObjectListWithModifier) 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 @@ -4077,9 +4077,7 @@ }; struct AccSizeExpr { - TUPLE_CLASS_BOILERPLATE(AccSizeExpr); - CharBlock source; - std::tuple> t; // if null then * + WRAPPER_CLASS_BOILERPLATE(AccSizeExpr, std::optional); }; struct AccSizeExprList { @@ -4092,9 +4090,18 @@ CharBlock source; }; -struct AccGangArgument { - TUPLE_CLASS_BOILERPLATE(AccGangArgument); - std::tuple, std::optional> t; +// num, dim, static +struct AccGangArg { + UNION_CLASS_BOILERPLATE(AccGangArg); + WRAPPER_CLASS(Num, ScalarIntExpr); + WRAPPER_CLASS(Dim, ScalarIntExpr); + WRAPPER_CLASS(Static, AccSizeExpr); + std::variant u; + CharBlock source; +}; + +struct AccGangArgList { + WRAPPER_CLASS_BOILERPLATE(AccGangArgList, std::list); }; struct AccCollapseArg { diff --git a/flang/lib/Lower/OpenACC.cpp b/flang/lib/Lower/OpenACC.cpp --- a/flang/lib/Lower/OpenACC.cpp +++ b/flang/lib/Lower/OpenACC.cpp @@ -811,25 +811,26 @@ if (const auto *gangClause = std::get_if(&clause.u)) { if (gangClause->v) { - const Fortran::parser::AccGangArgument &x = *gangClause->v; - if (const auto &gangNumValue = - std::get>(x.t)) { - gangNum = fir::getBase(converter.genExprValue( - *Fortran::semantics::GetExpr(gangNumValue.value()), stmtCtx)); - } - if (const auto &gangStaticValue = - std::get>(x.t)) { - const auto &expr = - std::get>( - gangStaticValue.value().t); - if (expr) { - gangStatic = fir::getBase(converter.genExprValue( - *Fortran::semantics::GetExpr(*expr), stmtCtx)); - } else { - // * was passed as value and will be represented as a special - // constant. - gangStatic = builder.createIntegerConstant( - clauseLocation, builder.getIndexType(), starCst); + const Fortran::parser::AccGangArgList &x = *gangClause->v; + for (const Fortran::parser::AccGangArg &gangArg : x.v) { + if (const auto *num = + std::get_if(&gangArg.u)) { + gangNum = fir::getBase(converter.genExprValue( + *Fortran::semantics::GetExpr(num->v), stmtCtx)); + } else if (const auto *staticArg = + std::get_if( + &gangArg.u)) { + + const Fortran::parser::AccSizeExpr &sizeExpr = staticArg->v; + if (sizeExpr.v) { + gangStatic = fir::getBase(converter.genExprValue( + *Fortran::semantics::GetExpr(*sizeExpr.v), stmtCtx)); + } else { + // * was passed as value and will be represented as a special + // constant. + gangStatic = builder.createIntegerConstant( + clauseLocation, builder.getIndexType(), starCst); + } } } } diff --git a/flang/lib/Parser/openacc-parsers.cpp b/flang/lib/Parser/openacc-parsers.cpp --- a/flang/lib/Parser/openacc-parsers.cpp +++ b/flang/lib/Parser/openacc-parsers.cpp @@ -66,11 +66,20 @@ "*" >> construct>())) TYPE_PARSER(construct(nonemptyList(Parser{}))) -// 2.9 (1607) gang-arg is: -// [[num:]int-expr][[,]static:size-expr] -TYPE_PARSER(construct( - maybe(("NUM:"_tok >> scalarIntExpr || scalarIntExpr)), - maybe(", STATIC:" >> Parser{}))) +// 2.9 gang-arg is one of : +// [num:]int-expr +// dim:int-expr +// static:size-expr +TYPE_PARSER(construct(construct( + "STATIC: " >> Parser{})) || + construct( + construct("DIM: " >> scalarIntExpr)) || + construct( + construct(maybe("NUM: "_tok) >> scalarIntExpr))) + +// 2.9 gang-arg-list +TYPE_PARSER( + construct(many(maybe(","_tok) >> Parser{}))) // 2.9.1 collapse TYPE_PARSER(construct( diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp --- a/flang/lib/Parser/unparse.cpp +++ b/flang/lib/Parser/unparse.cpp @@ -1908,9 +1908,19 @@ } } void Unparse(const AccClauseList &x) { Walk(" ", x.v, " "); } - void Unparse(const AccGangArgument &x) { - Walk("NUM:", std::get>(x.t)); - Walk(", STATIC:", std::get>(x.t)); + void Unparse(const AccGangArgList &x) { Walk(x.v, ","); } + void Before(const AccSizeExpr &x) { + if (!x.v) + Put("*"); + } + void Before(const AccGangArg &x) { + common::visit(common::visitors{ + [&](const AccGangArg::Num &) { Word("NUM:"); }, + [&](const AccGangArg::Dim &) { Word("DIM:"); }, + [&](const AccGangArg::Static &) { Word("STATIC:"); }, + [](const StatOrErrmsg &) {}, + }, + x.u); } void Unparse(const AccCollapseArg &x) { const auto &force{std::get(x.t)}; 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 @@ -324,7 +324,6 @@ CHECK_SIMPLE_CLAUSE(DeviceType, ACCC_device_type) CHECK_SIMPLE_CLAUSE(Finalize, ACCC_finalize) CHECK_SIMPLE_CLAUSE(Firstprivate, ACCC_firstprivate) -CHECK_SIMPLE_CLAUSE(Gang, ACCC_gang) CHECK_SIMPLE_CLAUSE(Host, ACCC_host) CHECK_SIMPLE_CLAUSE(If, ACCC_if) CHECK_SIMPLE_CLAUSE(IfPresent, ACCC_if_present) @@ -405,6 +404,26 @@ } } +void AccStructureChecker::Enter(const parser::AccClause::Gang &g) { + CheckAllowed(llvm::acc::Clause::ACCC_gang); + + if (g.v) { + bool hasNum = false; + bool hasDim = false; + const Fortran::parser::AccGangArgList &x = *g.v; + for (const Fortran::parser::AccGangArg &gangArg : x.v) { + if (std::get_if(&gangArg.u)) + hasNum = true; + else if (std::get_if(&gangArg.u)) + hasDim = true; + } + + if (hasDim && hasNum) + context_.Say(GetContext().clauseSource, + "The num argument is not allowed when dim is specified"_err_en_US); + } +} + 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/Parser/acc-unparse.f90 b/flang/test/Parser/acc-unparse.f90 --- a/flang/test/Parser/acc-unparse.f90 +++ b/flang/test/Parser/acc-unparse.f90 @@ -21,13 +21,58 @@ subroutine acc_loop() integer :: i, j + real :: a(10) + integer :: gangNum, gangDim, gangStatic + +!CHECK-LABEL: SUBROUTINE acc_loop !$acc loop collapse(force: 2) do i = 1, 10 do j = 1, 10 end do end do -end subroutine - -!CHECK-LABEL: SUBROUTINE acc_loop !CHECK: !$ACC LOOP COLLAPSE(FORCE:2_4) + + !$acc loop gang + do i = 1, 10 + a(i) = i + end do +! CHECK: !$ACC LOOP GANG + + !$acc loop gang(gangNum) + do i = 1, 10 + a(i) = i + end do +! CHECK: !$ACC LOOP GANG(NUM:gangnum) + + !$acc loop gang(num: gangNum) + do i = 1, 10 + a(i) = i + end do +! CHECK: !$ACC LOOP GANG(NUM:gangnum) + + !$acc loop gang(dim: gangDim) + do i = 1, 10 + a(i) = i + end do +! CHECK: !$ACC LOOP GANG(DIM:gangdim) + + !$acc loop gang(static:gangStatic) + do i = 1, 10 + a(i) = i + end do +! CHECK: !$ACC LOOP GANG(STATIC:gangstatic) + + !$acc loop gang(static:*) + do i = 1, 10 + a(i) = i + end do +! CHECK: !$ACC LOOP GANG(STATIC:*) + + !$acc loop gang(static:gangStatic, dim: gangDim) + do i = 1, 10 + a(i) = i + end do +! CHECK: !$ACC LOOP GANG(STATIC:gangstatic,DIM:gangdim) + +end subroutine diff --git a/flang/test/Semantics/OpenACC/acc-loop.f90 b/flang/test/Semantics/OpenACC/acc-loop.f90 --- a/flang/test/Semantics/OpenACC/acc-loop.f90 +++ b/flang/test/Semantics/OpenACC/acc-loop.f90 @@ -257,4 +257,10 @@ a(i) = 3.14 end do end do + + !ERROR: The num argument is not allowed when dim is specified + !$acc loop gang(1, dim: 2) + do i = 1, N + end do + end program openacc_loop_validity diff --git a/llvm/include/llvm/Frontend/OpenACC/ACC.td b/llvm/include/llvm/Frontend/OpenACC/ACC.td --- a/llvm/include/llvm/Frontend/OpenACC/ACC.td +++ b/llvm/include/llvm/Frontend/OpenACC/ACC.td @@ -147,7 +147,7 @@ // 2.9.2 def ACCC_Gang : Clause<"gang"> { - let flangClass = "AccGangArgument"; + let flangClass = "AccGangArgList"; let isValueOptional = true; }