diff --git a/flang/lib/Semantics/check-acc-structure.h b/flang/lib/Semantics/check-acc-structure.h --- a/flang/lib/Semantics/check-acc-structure.h +++ b/flang/lib/Semantics/check-acc-structure.h @@ -59,6 +59,8 @@ void Leave(const parser::OpenACCWaitConstruct &); void Enter(const parser::OpenACCAtomicConstruct &); void Leave(const parser::OpenACCAtomicConstruct &); + void Enter(const parser::OpenACCCacheConstruct &); + void Leave(const parser::OpenACCCacheConstruct &); // Clauses void Leave(const parser::AccClauseList &); 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 @@ -238,6 +238,15 @@ dirContext_.pop_back(); } +void AccStructureChecker::Enter(const parser::OpenACCCacheConstruct &x) { + const auto &verbatim = std::get(x.t); + PushContextAndClauseSets(verbatim.source, llvm::acc::Directive::ACCD_cache); + SetContextDirectiveSource(verbatim.source); +} +void AccStructureChecker::Leave(const parser::OpenACCCacheConstruct &x) { + dirContext_.pop_back(); +} + // Clause checkers CHECK_REQ_SCALAR_INT_CONSTANT_CLAUSE(Collapse, ACCC_collapse) 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 @@ -140,6 +140,9 @@ GetContext().withinConstruct = true; } + bool Pre(const parser::OpenACCCacheConstruct &); + void Post(const parser::OpenACCCacheConstruct &) { PopContext(); } + void Post(const parser::AccDefaultClause &); bool Pre(const parser::AccClause::Copy &x) { @@ -209,6 +212,7 @@ Symbol *DeclareOrMarkOtherAccessEntity(Symbol &, Symbol::Flag); void CheckMultipleAppearances( const parser::Name &, const Symbol &, Symbol::Flag); + void AllowOnlyArrayAndSubArray(const parser::AccObjectList &objectList); }; // Data-sharing and Data-mapping attributes for data-refs in OpenMP construct @@ -450,7 +454,6 @@ bool AccAttributeVisitor::Pre(const parser::OpenACCStandaloneConstruct &x) { const auto &standaloneDir{std::get(x.t)}; switch (standaloneDir.v) { - case llvm::acc::Directive::ACCD_cache: case llvm::acc::Directive::ACCD_enter_data: case llvm::acc::Directive::ACCD_exit_data: case llvm::acc::Directive::ACCD_init: @@ -483,6 +486,64 @@ return true; } +static bool IsLastNameArray(const parser::Designator &designator) { + const auto &name{GetLastName(designator)}; + const evaluate::DataRef dataRef{*(name.symbol)}; + return std::visit( + common::visitors{ + [](const evaluate::SymbolRef &ref) { return ref->Rank() > 0; }, + [](const evaluate::ArrayRef &aref) { + return aref.base().IsSymbol() || + aref.base().GetComponent().base().Rank() == 0; + }, + [](const auto &) { return false; }, + }, + dataRef.u); +} + +void AccAttributeVisitor::AllowOnlyArrayAndSubArray( + const parser::AccObjectList &objectList) { + for (const auto &accObject : objectList.v) { + std::visit( + common::visitors{ + [&](const parser::Designator &designator) { + if (!IsLastNameArray(designator)) + context_.Say(designator.source, + "Only array element or subarray are allowed in %s directive"_err_en_US, + parser::ToUpperCaseLetters( + llvm::acc::getOpenACCDirectiveName( + GetContext().directive) + .str())); + }, + [&](const auto &name) { + context_.Say(name.source, + "Only array element or subarray are allowed in %s directive"_err_en_US, + parser::ToUpperCaseLetters( + llvm::acc::getOpenACCDirectiveName(GetContext().directive) + .str())); + }, + }, + accObject.u); + } +} + +bool AccAttributeVisitor::Pre(const parser::OpenACCCacheConstruct &x) { + const auto &verbatim{std::get(x.t)}; + PushContext(verbatim.source, llvm::acc::Directive::ACCD_cache); + ClearDataSharingAttributeObjects(); + + const auto &objectListWithModifier = + std::get(x.t); + const auto &objectList = + std::get(objectListWithModifier.t); + + // 2.10 Cache directive restriction: A var in a cache directive must be a + // single array element or a simple subarray. + AllowOnlyArrayAndSubArray(objectList); + + return true; +} + std::int64_t AccAttributeVisitor::GetAssociatedLoopLevelFromClauses( const parser::AccClauseList &x) { std::int64_t collapseLevel{0}; diff --git a/flang/test/Semantics/acc-clause-validity.f90 b/flang/test/Semantics/acc-clause-validity.f90 --- a/flang/test/Semantics/acc-clause-validity.f90 +++ b/flang/test/Semantics/acc-clause-validity.f90 @@ -11,6 +11,7 @@ ! 2.14.3 Set ! 2.14.4 Update ! 2.15.1 Routine +! 2.10 Cache ! 2.11 Parallel Loop ! 2.11 Kernels Loop ! 2.11 Serial Loop @@ -21,6 +22,11 @@ implicit none + type atype + real(8), dimension(10) :: arr + real(8) :: s + end type atype + integer :: i, j, b, gang_size, vector_size, worker_size integer, parameter :: N = 256 integer, dimension(N) :: c @@ -31,6 +37,8 @@ logical :: reduction_l real(8), dimension(N, N) :: aa, bb, cc logical :: ifCondition = .TRUE. + type(atype) :: t + type(atype), dimension(10) :: ta !ERROR: At least one clause is required on the DECLARE directive !$acc declare @@ -646,6 +654,28 @@ i = i + 1 !$acc end atomic !$acc end parallel + t%arr(i) = 2.0 + + !$acc cache(a(i)) + !$acc cache(a(1:2,3:4)) + !$acc cache(a) + !$acc cache(readonly: a, aa) + !$acc cache(readonly: a(i), aa(i, i)) + !$acc cache(t%arr) + !$acc cache(ta(1:2)%arr) + !$acc cache(ta(1:2)%arr(1:4)) + + !ERROR: Only array element or subarray are allowed in CACHE directive + !$acc cache(ta(1:2)%s) + + !ERROR: Only array element or subarray are allowed in CACHE directive + !$acc cache(i) + + !ERROR: Only array element or subarray are allowed in CACHE directive + !$acc cache(t%s) + + !ERROR: Only array element or subarray are allowed in CACHE directive + !$acc cache(/i/) contains