Commit e73d8c79 authored by Valentin Clement's avatar Valentin Clement Committed by clementval
Browse files

[flang][openacc] Semantic check for cache directive

Add semantic check for the cache directive. According to section 2.10 from the specification:
A var in a cache directive must be a single array element or a simple subarray.

Reviewed By: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D90184
parent 0637dfe8
Loading
Loading
Loading
Loading
+9 −0
Original line number Diff line number Diff line
@@ -238,6 +238,15 @@ void AccStructureChecker::Leave(const parser::OpenACCAtomicConstruct &x) {
  dirContext_.pop_back();
}

void AccStructureChecker::Enter(const parser::OpenACCCacheConstruct &x) {
  const auto &verbatim = std::get<parser::Verbatim>(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)

+2 −0
Original line number Diff line number Diff line
@@ -59,6 +59,8 @@ public:
  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 &);
+62 −1
Original line number Diff line number Diff line
@@ -140,6 +140,9 @@ public:
    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 @@ private:
  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::OpenACCLoopConstruct &x) {
bool AccAttributeVisitor::Pre(const parser::OpenACCStandaloneConstruct &x) {
  const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(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 @@ bool AccAttributeVisitor::Pre(const parser::OpenACCCombinedConstruct &x) {
  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<parser::Verbatim>(x.t)};
  PushContext(verbatim.source, llvm::acc::Directive::ACCD_cache);
  ClearDataSharingAttributeObjects();

  const auto &objectListWithModifier =
      std::get<parser::AccObjectListWithModifier>(x.t);
  const auto &objectList =
      std::get<Fortran::parser::AccObjectList>(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};
+30 −0
Original line number Diff line number Diff line
@@ -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 @@ program openacc_clause_validity

  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 @@ program openacc_clause_validity
  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 @@ program openacc_clause_validity
  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