[flang-commits] [flang] a40b609 - [flang][OpenMP] Add semantic check for occurrence of constructs nested inside a SIMD region

Arnamoy Bhattacharyya via flang-commits flang-commits at lists.llvm.org
Thu May 6 12:08:02 PDT 2021


Author: Arnamoy Bhattacharyya
Date: 2021-05-06T15:09:51-04:00
New Revision: a40b609958828960ce55a5e266c157491772a67e

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

LOG: [flang][OpenMP] Add semantic check for occurrence of constructs nested inside a SIMD region

Reviewed By: kiranchandramohan

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

Added: 
    flang/test/Semantics/omp-nested-simd.f90

Modified: 
    flang/lib/Semantics/check-directive-structure.h
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/check-omp-structure.h
    flang/test/Semantics/omp-do05.f90
    flang/test/Semantics/omp-ordered-simd.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index 6ef60230cca5..05b1a94a2d76 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -203,6 +203,12 @@ class DirectiveStructureChecker : public virtual BaseChecker {
     GetContext().actualClauses.push_back(type);
   }
 
+  void EnterSIMDNest() { simdNest_++; }
+
+  void ExitSIMDNest() { simdNest_--; }
+
+  int GetSIMDNest() { return simdNest_; }
+
   // Check if the given clause is present in the current context
   const PC *FindClause(C type) {
     auto it{GetContext().clauseInfo.find(type)};
@@ -314,6 +320,7 @@ class DirectiveStructureChecker : public virtual BaseChecker {
       directiveClausesMap_;
 
   std::string ClauseSetToString(const common::EnumSet<C, ClauseEnumSize> set);
+  int simdNest_{0};
 };
 
 template <typename D, typename C, typename PC, std::size_t ClauseEnumSize>

diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 868c64651bc3..2903a4105961 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -238,7 +238,16 @@ void OmpStructureChecker::HasInvalidTeamsNesting(
 }
 
 void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) {
-  // 2.8.1 TODO: Simd Construct with Ordered Construct Nesting check
+  // Simd Construct with Ordered Construct Nesting check
+  // We cannot use CurrentDirectiveIsNested() here because
+  // PushContextAndClauseSets() has not been called yet, it is
+  // called individually for each construct.  Therefore a
+  // dirContext_ size `1` means the current construct is nested
+  if (dirContext_.size() >= 1) {
+    if (GetSIMDNest() > 0) {
+      CheckSIMDNest(x);
+    }
+  }
 }
 
 void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
@@ -255,6 +264,9 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
   }
 
   PushContextAndClauseSets(beginDir.source, beginDir.v);
+  if (llvm::omp::simdSet.test(GetContext().directive)) {
+    EnterSIMDNest();
+  }
 
   if (beginDir.v == llvm::omp::Directive::OMPD_do) {
     // 2.7.1 do-clause -> private-clause |
@@ -344,6 +356,78 @@ void OmpStructureChecker::CheckLoopItrVariableIsInt(
   }
 }
 
+void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
+  // Check the following:
+  //  The only OpenMP constructs that can be encountered during execution of
+  // a simd region are the `atomic` construct, the `loop` construct, the `simd`
+  // construct and the `ordered` construct with the `simd` clause.
+  // TODO:  Expand the check to include `LOOP` construct as well when it is
+  // supported.
+
+  // Check if the parent context has the SIMD clause
+  // Please note that we use GetContext() instead of GetContextParent()
+  // because PushContextAndClauseSets() has not been called on the
+  // current context yet.
+  // TODO: Check for declare simd regions.
+  bool eligibleSIMD{false};
+  std::visit(Fortran::common::visitors{
+                 // Allow `!$OMP ORDERED SIMD`
+                 [&](const parser::OpenMPBlockConstruct &c) {
+                   const auto &beginBlockDir{
+                       std::get<parser::OmpBeginBlockDirective>(c.t)};
+                   const auto &beginDir{
+                       std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
+                   if (beginDir.v == llvm::omp::Directive::OMPD_ordered) {
+                     const auto &clauses{
+                         std::get<parser::OmpClauseList>(beginBlockDir.t)};
+                     for (const auto &clause : clauses.v) {
+                       if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
+                         eligibleSIMD = true;
+                         break;
+                       }
+                     }
+                   }
+                 },
+                 [&](const parser::OpenMPSimpleStandaloneConstruct &c) {
+                   const auto &dir{
+                       std::get<parser::OmpSimpleStandaloneDirective>(c.t)};
+                   if (dir.v == llvm::omp::Directive::OMPD_ordered) {
+                     const auto &clauses{std::get<parser::OmpClauseList>(c.t)};
+                     for (const auto &clause : clauses.v) {
+                       if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
+                         eligibleSIMD = true;
+                         break;
+                       }
+                     }
+                   }
+                 },
+                 // Allowing SIMD construct
+                 [&](const parser::OpenMPLoopConstruct &c) {
+                   const auto &beginLoopDir{
+                       std::get<parser::OmpBeginLoopDirective>(c.t)};
+                   const auto &beginDir{
+                       std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
+                   if ((beginDir.v == llvm::omp::Directive::OMPD_simd) ||
+                       (beginDir.v == llvm::omp::Directive::OMPD_do_simd)) {
+                     eligibleSIMD = true;
+                   }
+                 },
+                 [&](const parser::OpenMPAtomicConstruct &c) {
+                   // Allow `!$OMP ATOMIC`
+                   eligibleSIMD = true;
+                 },
+                 [&](const auto &c) {},
+             },
+      c.u);
+  if (!eligibleSIMD) {
+    context_.Say(parser::FindSourceLocation(c),
+        "The only OpenMP constructs that can be encountered during execution "
+        "of a 'SIMD'"
+        " region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD`"
+        " construct and the `ORDERED` construct with the `SIMD` clause."_err_en_US);
+  }
+}
+
 std::int64_t OmpStructureChecker::GetOrdCollapseLevel(
     const parser::OpenMPLoopConstruct &x) {
   const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
@@ -382,6 +466,9 @@ void OmpStructureChecker::CheckCycleConstraints(
 }
 
 void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) {
+  if (llvm::omp::simdSet.test(GetContext().directive)) {
+    ExitSIMDNest();
+  }
   dirContext_.pop_back();
 }
 

diff  --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 8c76530551a3..fbbe8ae35f7d 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -215,6 +215,7 @@ class OmpStructureChecker
   void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
   void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
   void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x);
+  void CheckSIMDNest(const parser::OpenMPConstruct &x);
   std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
   void CheckIfDoOrderedClause(const parser::OmpBlockDirective &blkDirectiv);
   bool CheckReductionOperators(const parser::OmpClause::Reduction &);

diff  --git a/flang/test/Semantics/omp-do05.f90 b/flang/test/Semantics/omp-do05.f90
index e2e899959d6f..fb9281c4d946 100644
--- a/flang/test/Semantics/omp-do05.f90
+++ b/flang/test/Semantics/omp-do05.f90
@@ -31,6 +31,7 @@ program omp_do
 
   !$omp parallel do simd
   do i=1,10
+    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
     !$omp single
     do j=1,10
@@ -55,6 +56,7 @@ program omp_do
   !ERROR: `DISTRIBUTE` region has to be strictly nested inside `TEAMS` region.
   !$omp distribute parallel do simd
   do i=1,10
+    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
     !$omp single
     do j=1,10
@@ -77,6 +79,7 @@ program omp_do
 
   !$omp target parallel do simd
   do i=1,10
+    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
     !$omp single
     do j=1,10
@@ -97,8 +100,9 @@ program omp_do
   end do
   !$omp end target teams distribute parallel do
 
-    !$omp target teams distribute parallel do simd
+  !$omp target teams distribute parallel do simd
   do i=1,10
+    !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
     !$omp single
     do j=1,10

diff  --git a/flang/test/Semantics/omp-nested-simd.f90 b/flang/test/Semantics/omp-nested-simd.f90
new file mode 100644
index 000000000000..b17614cce45f
--- /dev/null
+++ b/flang/test/Semantics/omp-nested-simd.f90
@@ -0,0 +1,214 @@
+! RUN: %S/test_errors.sh %s %t %flang_fc1 -fopenmp
+! OpenMP Version 4.5
+! Various checks with the nesting of SIMD construct
+
+SUBROUTINE NESTED_GOOD(N)
+  INTEGER N, I, J, K, A(10), B(10)
+  !$OMP SIMD
+  DO I = 1,N
+    !$OMP ATOMIC
+    K =  K + 1
+    IF (I <= 10) THEN
+      !$OMP ORDERED SIMD
+      DO J = 1,N
+        A(J) = J
+      END DO
+      !$OMP END ORDERED
+    ENDIF
+  END DO
+  !$OMP END SIMD
+
+  !$OMP SIMD
+  DO I = 1,N
+    IF (I <= 10) THEN
+      !$OMP SIMD
+      DO J = 1,N
+        A(J) = J
+      END DO
+      !$OMP END SIMD
+    ENDIF
+  END DO
+  !$OMP END SIMD
+END SUBROUTINE NESTED_GOOD
+
+SUBROUTINE NESTED_BAD(N)
+  INTEGER N, I, J, K, A(10), B(10)
+
+  !$OMP SIMD
+  DO I = 1,N
+    IF (I <= 10) THEN
+      !$OMP ORDERED SIMD
+      DO J = 1,N
+        print *, "Hi"
+        !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp teams 
+         DO K = 1,N
+        print *, 'Hello'
+        END DO
+        !$omp end teams
+      END DO
+      !$OMP END ORDERED
+    ENDIF
+  END DO
+  !$OMP END SIMD
+
+  !$OMP SIMD
+  DO I = 1,N
+    !$OMP ATOMIC
+    K =  K + 1
+    IF (I <= 10) THEN
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp task 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end task
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp teams 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end teams
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp target 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end target
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$OMP DO
+      DO J = 1,N
+        A(J) = J
+      END DO
+      !$OMP END DO
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$OMP PARALLEL DO
+      DO J = 1,N
+        A(J) = J
+      END DO
+      !$OMP END PARALLEL DO
+    ENDIF
+  END DO
+  !$OMP END SIMD
+
+  !$OMP DO SIMD
+  DO I = 1,N
+    !$OMP ATOMIC
+    K =  K + 1
+    IF (I <= 10) THEN
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp task 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end task
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp teams 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end teams
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp target 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end target
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
+      !$OMP DO
+      DO J = 1,N
+        A(J) = J
+      END DO
+      !$OMP END DO
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$OMP PARALLEL DO
+      DO J = 1,N
+        A(J) = J
+      END DO
+      !$OMP END PARALLEL DO
+    ENDIF
+  END DO
+  !$OMP END DO SIMD
+
+  !$OMP PARALLEL DO SIMD
+  DO I = 1,N
+    !$OMP ATOMIC
+    K =  K + 1
+    IF (I <= 10) THEN
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp task 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end task
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp teams 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end teams
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp target 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end target
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !ERROR: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
+      !$OMP DO
+      DO J = 1,N
+        A(J) = J
+      END DO
+      !$OMP END DO
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$OMP PARALLEL DO
+      DO J = 1,N
+        A(J) = J
+      END DO
+      !$OMP END PARALLEL DO
+    ENDIF
+  END DO
+  !$OMP END PARALLEL DO SIMD
+
+  !$OMP TARGET SIMD
+  DO I = 1,N
+    !$OMP ATOMIC
+    K =  K + 1
+    IF (I <= 10) THEN
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp task 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end task
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp teams 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end teams
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$omp target 
+      do J = 1, N
+        K = 2
+      end do
+      !$omp end target
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$OMP DO
+      DO J = 1,N
+        A(J) = J
+      END DO
+      !$OMP END DO
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
+      !$OMP PARALLEL DO
+      DO J = 1,N
+        A(J) = J
+      END DO
+      !$OMP END PARALLEL DO
+    ENDIF
+  END DO
+  !$OMP END TARGET SIMD
+
+
+END SUBROUTINE NESTED_BAD

diff  --git a/flang/test/Semantics/omp-ordered-simd.f90 b/flang/test/Semantics/omp-ordered-simd.f90
index 5a3760ea604c..8350a9e13891 100644
--- a/flang/test/Semantics/omp-ordered-simd.f90
+++ b/flang/test/Semantics/omp-ordered-simd.f90
@@ -25,6 +25,7 @@ SUBROUTINE ORDERED_BAD(N)
   !$OMP DO SIMD
   DO I = 1,N
     IF (I <= 10) THEN
+      !ERROR: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct and the `ORDERED` construct with the `SIMD` clause.
       !ERROR: The ORDERED clause must be present on the loop construct if any ORDERED region ever binds to a loop region arising from the loop construct.
       !$OMP ORDERED 
       CALL WORK(I)


        


More information about the flang-commits mailing list