[llvm] 6fb01a9 - [flang][OpenMP] Add semantic checks for ordered construct

via llvm-commits llvm-commits at lists.llvm.org
Fri Sep 17 06:54:07 PDT 2021


Author: PeixinQiao
Date: 2021-09-17T21:53:07+08:00
New Revision: 6fb01a94708ffcd0aed63d0697d4ca08ed937dff

URL: https://github.com/llvm/llvm-project/commit/6fb01a94708ffcd0aed63d0697d4ca08ed937dff
DIFF: https://github.com/llvm/llvm-project/commit/6fb01a94708ffcd0aed63d0697d4ca08ed937dff.diff

LOG: [flang][OpenMP] Add semantic checks for ordered construct

This patch implements the following semantic checks according to
OpenMP Version 5.1 Ordered construct restriction:

```
At most one threads clause can appear on an ordered construct; At most
one simd clause can appear on an ordered construct; At most one
depend(source) clause can appear on an ordered construct; Either
depend(sink:vec) clauses or depend(source) clauses may appear on an
ordered construct, but not both.
```

This patch also implements the following semantic checks according to
the syntax and descriptions in OpenMP Version 5.1 Ordered construct:

```
The dependence types of sink or source are only allowed on an ordered
construct. The depend(*) clauses are not allowed when ordered construct
is a block construct with an ordered region. The threads or simd clauses
are not allowed when the ordered construct is a standalone construct
with no ordered region.
```

Co-authored-by: Sameeran Joshi <sameeranjayant.joshi at amd.com>

Reviewed By: kiranchandramohan

Differential Revision: https://reviews.llvm.org/D108512

Added: 
    flang/test/Semantics/omp-ordered01.f90

Modified: 
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/check-omp-structure.h
    flang/lib/Semantics/resolve-directives.cpp
    flang/test/Semantics/omp-clause-validity01.f90
    llvm/include/llvm/Frontend/OpenMP/OMP.td

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index bf166463997c1..3b58f97b2dba2 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -771,6 +771,25 @@ void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) {
   dirContext_.pop_back();
 }
 
+void OmpStructureChecker::ChecksOnOrderedAsBlock() {
+  if (FindClause(llvm::omp::Clause::OMPC_depend)) {
+    context_.Say(GetContext().clauseSource,
+        "DEPEND(*) clauses are not allowed when ORDERED construct is a block"
+        " construct with an ORDERED region"_err_en_US);
+  }
+}
+
+void OmpStructureChecker::Leave(const parser::OmpBeginBlockDirective &) {
+  switch (GetContext().directive) {
+  case llvm::omp::Directive::OMPD_ordered:
+    // [5.1] 2.19.9 Ordered Construct Restriction
+    ChecksOnOrderedAsBlock();
+    break;
+  default:
+    break;
+  }
+}
+
 void OmpStructureChecker::Enter(const parser::OpenMPSectionsConstruct &x) {
   const auto &beginSectionsDir{
       std::get<parser::OmpBeginSectionsDirective>(x.t)};
@@ -911,6 +930,48 @@ void OmpStructureChecker::CheckBarrierNesting(
   }
 }
 
+void OmpStructureChecker::ChecksOnOrderedAsStandalone() {
+  if (FindClause(llvm::omp::Clause::OMPC_threads) ||
+      FindClause(llvm::omp::Clause::OMPC_simd)) {
+    context_.Say(GetContext().clauseSource,
+        "THREADS, SIMD clauses are not allowed when ORDERED construct is a "
+        "standalone construct with no ORDERED region"_err_en_US);
+  }
+
+  bool isSinkPresent{false};
+  int dependSourceCount{0};
+  auto clauseAll = FindClauses(llvm::omp::Clause::OMPC_depend);
+  for (auto itr = clauseAll.first; itr != clauseAll.second; ++itr) {
+    const auto &dependClause{
+        std::get<parser::OmpClause::Depend>(itr->second->u)};
+    if (std::get_if<parser::OmpDependClause::Source>(&dependClause.v.u)) {
+      dependSourceCount++;
+      if (isSinkPresent) {
+        context_.Say(itr->second->source,
+            "DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present "
+            "on ORDERED directive"_err_en_US);
+      }
+      if (dependSourceCount > 1) {
+        context_.Say(itr->second->source,
+            "At most one DEPEND(SOURCE) clause can appear on the ORDERED "
+            "directive"_err_en_US);
+      }
+    } else if (std::get_if<parser::OmpDependClause::Sink>(&dependClause.v.u)) {
+      isSinkPresent = true;
+      if (dependSourceCount > 0) {
+        context_.Say(itr->second->source,
+            "DEPEND(SINK: vec) is not allowed when DEPEND(SOURCE) is present "
+            "on ORDERED directive"_err_en_US);
+      }
+    } else {
+      context_.Say(itr->second->source,
+          "Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED "
+          "construct is a standalone construct with no ORDERED "
+          "region"_err_en_US);
+    }
+  }
+}
+
 void OmpStructureChecker::Enter(
     const parser::OpenMPSimpleStandaloneConstruct &x) {
   const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
@@ -920,6 +981,14 @@ void OmpStructureChecker::Enter(
 
 void OmpStructureChecker::Leave(
     const parser::OpenMPSimpleStandaloneConstruct &) {
+  switch (GetContext().directive) {
+  case llvm::omp::Directive::OMPD_ordered:
+    // [5.1] 2.19.9 Ordered Construct Restriction
+    ChecksOnOrderedAsStandalone();
+    break;
+  default:
+    break;
+  }
   dirContext_.pop_back();
 }
 

diff  --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index a610a531f8c9b..d82bf0032a243 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -135,6 +135,7 @@ class OmpStructureChecker
 
   void Enter(const parser::OpenMPBlockConstruct &);
   void Leave(const parser::OpenMPBlockConstruct &);
+  void Leave(const parser::OmpBeginBlockDirective &);
   void Enter(const parser::OmpEndBlockDirective &);
   void Leave(const parser::OmpEndBlockDirective &);
 
@@ -238,7 +239,9 @@ class OmpStructureChecker
       const parser::DefinedOperator::IntrinsicOperator &);
   void CheckReductionTypeList(const parser::OmpClause::Reduction &);
   void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
+  void ChecksOnOrderedAsBlock();
   void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
+  void ChecksOnOrderedAsStandalone();
   void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
   void CheckIntentInPointerAndDefinable(
       const parser::OmpObjectList &, const llvm::omp::Clause);

diff  --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 120f4db423e4b..6df35af6e78c2 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -298,6 +298,9 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
     GetContext().withinConstruct = true;
   }
 
+  bool Pre(const parser::OpenMPSimpleStandaloneConstruct &);
+  void Post(const parser::OpenMPSimpleStandaloneConstruct &) { PopContext(); }
+
   bool Pre(const parser::OpenMPLoopConstruct &);
   void Post(const parser::OpenMPLoopConstruct &) { PopContext(); }
   void Post(const parser::OmpBeginLoopDirective &) {
@@ -414,6 +417,18 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
     return false;
   }
 
+  bool Pre(const parser::OmpDependClause &x) {
+    if (const auto *dependSink{
+            std::get_if<parser::OmpDependClause::Sink>(&x.u)}) {
+      const auto &dependSinkVec{dependSink->v};
+      for (const auto &dependSinkElement : dependSinkVec) {
+        const auto &name{std::get<parser::Name>(dependSinkElement.t)};
+        ResolveName(&name);
+      }
+    }
+    return false;
+  }
+
   void Post(const parser::Name &);
 
   // Keep track of labels in the statements that causes jumps to target labels
@@ -1132,6 +1147,27 @@ void OmpAttributeVisitor::Post(const parser::OpenMPBlockConstruct &x) {
   PopContext();
 }
 
+bool OmpAttributeVisitor::Pre(
+    const parser::OpenMPSimpleStandaloneConstruct &x) {
+  const auto &standaloneDir{
+      std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
+  switch (standaloneDir.v) {
+  case llvm::omp::Directive::OMPD_barrier:
+  case llvm::omp::Directive::OMPD_ordered:
+  case llvm::omp::Directive::OMPD_target_enter_data:
+  case llvm::omp::Directive::OMPD_target_exit_data:
+  case llvm::omp::Directive::OMPD_target_update:
+  case llvm::omp::Directive::OMPD_taskwait:
+  case llvm::omp::Directive::OMPD_taskyield:
+    PushContext(standaloneDir.source, standaloneDir.v);
+    break;
+  default:
+    break;
+  }
+  ClearDataSharingAttributeObjects();
+  return true;
+}
+
 bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) {
   const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
   const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};

diff  --git a/flang/test/Semantics/omp-clause-validity01.f90 b/flang/test/Semantics/omp-clause-validity01.f90
index f6150a2901b2b..a4712a27c4400 100644
--- a/flang/test/Semantics/omp-clause-validity01.f90
+++ b/flang/test/Semantics/omp-clause-validity01.f90
@@ -480,8 +480,6 @@
   ! !$omp target enter data map(to:arrayA) map(alloc:arrayB)
   ! !$omp target update from(arrayA) to(arrayB)
   ! !$omp target exit data map(from:arrayA) map(delete:arrayB)
-  !$omp ordered depend(source)
-  ! !$omp ordered depend(sink:i-1)
   !$omp flush (c)
   !$omp flush acq_rel
   !$omp flush release

diff  --git a/flang/test/Semantics/omp-ordered01.f90 b/flang/test/Semantics/omp-ordered01.f90
new file mode 100644
index 0000000000000..948ad41de1a76
--- /dev/null
+++ b/flang/test/Semantics/omp-ordered01.f90
@@ -0,0 +1,80 @@
+! RUN: %python %S/test_errors.py %s %flang -fopenmp
+! OpenMP Version 5.1
+! Check OpenMP construct validity for the following directives:
+! 2.19.9 Ordered Construct
+
+program main
+  integer :: i, N = 10
+  real :: a, arrayA(10), arrayB(10), arrayC(10)
+  real, external :: foo, bar, baz
+
+  !$omp do ordered
+  do i = 1, N
+    !ERROR: At most one THREADS clause can appear on the ORDERED directive
+    !$omp ordered threads threads
+    arrayA(i) = i
+    !$omp end ordered
+  end do
+  !$omp end do
+
+  !$omp simd
+  do i = 1, N
+    !ERROR: At most one SIMD clause can appear on the ORDERED directive
+    !$omp ordered simd simd
+    arrayA(i) = i
+    !$omp end ordered
+  end do
+  !$omp end simd
+
+  !$omp do simd ordered
+  do i = 1, N
+    !ERROR: At most one SIMD clause can appear on the ORDERED directive
+    !$omp ordered simd simd
+    arrayA(i) = i
+    !$omp end ordered
+  end do
+  !$omp end do simd
+
+  !$omp do ordered(1)
+  do i = 2, N
+    !ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
+    !ERROR: At most one DEPEND(SOURCE) clause can appear on the ORDERED directive
+    !$omp ordered depend(source) depend(inout: arrayA) depend(source)
+    arrayA(i) = foo(i)
+    !ERROR: DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present on ORDERED directive
+    !ERROR: DEPEND(SOURCE) is not allowed when DEPEND(SINK: vec) is present on ORDERED directive
+    !ERROR: At most one DEPEND(SOURCE) clause can appear on the ORDERED directive
+    !$omp ordered depend(sink: i - 1) depend(source) depend(source)
+    arrayB(i) = bar(arrayA(i), arrayB(i-1))
+    !ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
+    !ERROR: Only DEPEND(SOURCE) or DEPEND(SINK: vec) are allowed when ORDERED construct is a standalone construct with no ORDERED region
+    !$omp ordered depend(out: arrayC) depend(in: arrayB)
+    arrayC(i) = baz(arrayB(i-1))
+  end do
+  !$omp end do
+
+  !$omp do ordered(1)
+  do i = 2, N
+    !ERROR: DEPEND(*) clauses are not allowed when ORDERED construct is a block construct with an ORDERED region
+    !$omp ordered depend(source)
+    arrayA(i) = foo(i)
+    !$omp end ordered
+    !ERROR: DEPEND(*) clauses are not allowed when ORDERED construct is a block construct with an ORDERED region
+    !$omp ordered depend(sink: i - 1)
+    arrayB(i) = bar(arrayA(i), arrayB(i-1))
+    !$omp end ordered
+  end do
+  !$omp end do
+
+contains
+  subroutine work1()
+    !ERROR: THREADS, SIMD clauses are not allowed when ORDERED construct is a standalone construct with no ORDERED region
+    !$omp ordered simd
+  end subroutine work1
+
+  subroutine work2()
+    !ERROR: THREADS, SIMD clauses are not allowed when ORDERED construct is a standalone construct with no ORDERED region
+    !$omp ordered threads
+  end subroutine work2
+
+end program main

diff  --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 5ed279c2d1526..010a35b60c52e 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -491,10 +491,12 @@ def OMP_Flush : Directive<"flush"> {
 }
 def OMP_Ordered : Directive<"ordered"> {
   let allowedClauses = [
-    VersionedClause<OMPC_Threads>,
-    VersionedClause<OMPC_Simd>,
     VersionedClause<OMPC_Depend>
   ];
+  let allowedOnceClauses = [
+    VersionedClause<OMPC_Threads>,
+    VersionedClause<OMPC_Simd>
+  ];
 }
 def OMP_Atomic : Directive<"atomic"> {
   let allowedClauses = [


        


More information about the llvm-commits mailing list