[flang-commits] [flang] 42f5110 - [flang][OpenMP] Add semantic check for teams nesting

Arnamoy Bhattacharyya via flang-commits flang-commits at lists.llvm.org
Fri Aug 13 07:41:47 PDT 2021


Author: Peixin Qiao
Date: 2021-08-13T10:42:47-04:00
New Revision: 42f51107016ca869dc8d408c827bf61c2efcbc99

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

LOG: [flang][OpenMP] Add semantic check for teams nesting

This patch implements the following check for TEAMS construct:
```
OpenMP Version 5.0 Teams construct restriction: A teams region can
only be strictly nested within the implicit parallel region or a target
region. If a teams construct is nested within a target construct, that
target construct must contain no statements, declarations or directives
outside of the teams construct.
```

Also add one test case for the check.

Reviewed By: kiranchandramohan, clementval

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

Added: 
    flang/test/Semantics/omp-nested-teams.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-firstprivate01.f90
    flang/test/Semantics/omp-nested-master.f90
    flang/test/Semantics/omp-nested-simd.f90

Removed: 
    


################################################################################
diff  --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index 05b1a94a2d76..6ef60230cca5 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -203,12 +203,6 @@ 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)};
@@ -320,7 +314,6 @@ 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 34499e6d5f97..a5eefe2b3450 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -285,7 +285,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) {
   // called individually for each construct.  Therefore a
   // dirContext_ size `1` means the current construct is nested
   if (dirContext_.size() >= 1) {
-    if (GetSIMDNest() > 0) {
+    if (GetDirectiveNest(SIMDNest) > 0) {
       CheckSIMDNest(x);
     }
   }
@@ -306,7 +306,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
 
   PushContextAndClauseSets(beginDir.source, beginDir.v);
   if (llvm::omp::simdSet.test(GetContext().directive)) {
-    EnterSIMDNest();
+    EnterDirectiveNest(SIMDNest);
   }
 
   if (beginDir.v == llvm::omp::Directive::OMPD_do) {
@@ -585,7 +585,7 @@ void OmpStructureChecker::CheckDistLinear(
 
 void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) {
   if (llvm::omp::simdSet.test(GetContext().directive)) {
-    ExitSIMDNest();
+    ExitDirectiveNest(SIMDNest);
   }
   dirContext_.pop_back();
 }
@@ -625,11 +625,35 @@ void OmpStructureChecker::Enter(const parser::OpenMPBlockConstruct &x) {
     if (GetContext().directive == llvm::omp::Directive::OMPD_master) {
       CheckMasterNesting(x);
     }
+    // A teams region can only be strictly nested within the implicit parallel
+    // region or a target region.
+    if (GetContext().directive == llvm::omp::Directive::OMPD_teams &&
+        GetContextParent().directive != llvm::omp::Directive::OMPD_target) {
+      context_.Say(parser::FindSourceLocation(x),
+          "%s region can only be strictly nested within the implicit parallel "
+          "region or TARGET region"_err_en_US,
+          ContextDirectiveAsFortran());
+    }
+    // If a teams construct is nested within a target construct, that target
+    // construct must contain no statements, declarations or directives outside
+    // of the teams construct.
+    if (GetContext().directive == llvm::omp::Directive::OMPD_teams &&
+        GetContextParent().directive == llvm::omp::Directive::OMPD_target &&
+        !GetDirectiveNest(TargetBlockOnlyTeams)) {
+      context_.Say(GetContextParent().directiveSource,
+          "TARGET construct with nested TEAMS region contains statements or "
+          "directives outside of the TEAMS construct"_err_en_US);
+    }
   }
 
   CheckNoBranching(block, beginDir.v, beginDir.source);
 
   switch (beginDir.v) {
+  case llvm::omp::Directive::OMPD_target:
+    if (CheckTargetBlockOnlyTeams(block)) {
+      EnterDirectiveNest(TargetBlockOnlyTeams);
+    }
+    break;
   case llvm::omp::OMPD_workshare:
   case llvm::omp::OMPD_parallel_workshare:
     CheckWorkshareBlockStmts(block, beginDir.source);
@@ -683,6 +707,9 @@ void OmpStructureChecker::CheckIfDoOrderedClause(
 }
 
 void OmpStructureChecker::Leave(const parser::OpenMPBlockConstruct &) {
+  if (GetDirectiveNest(TargetBlockOnlyTeams)) {
+    ExitDirectiveNest(TargetBlockOnlyTeams);
+  }
   dirContext_.pop_back();
 }
 
@@ -1921,6 +1948,30 @@ void OmpStructureChecker::CheckPrivateSymbolsInOuterCxt(
   }
 }
 
+bool OmpStructureChecker::CheckTargetBlockOnlyTeams(
+    const parser::Block &block) {
+  bool nestedTeams{false};
+  auto it{block.begin()};
+
+  if (const auto *ompConstruct{parser::Unwrap<parser::OpenMPConstruct>(*it)}) {
+    if (const auto *ompBlockConstruct{
+            std::get_if<parser::OpenMPBlockConstruct>(&ompConstruct->u)}) {
+      const auto &beginBlockDir{
+          std::get<parser::OmpBeginBlockDirective>(ompBlockConstruct->t)};
+      const auto &beginDir{
+          std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
+      if (beginDir.v == llvm::omp::Directive::OMPD_teams) {
+        nestedTeams = true;
+      }
+    }
+  }
+
+  if (nestedTeams && ++it == block.end()) {
+    return true;
+  }
+  return false;
+}
+
 void OmpStructureChecker::CheckWorkshareBlockStmts(
     const parser::Block &block, parser::CharBlock source) {
   OmpWorkshareBlockChecker ompWorkshareBlockChecker{context_, source};

diff  --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 2eebb8f70508..03cd1f8d3f29 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -218,6 +218,7 @@ class OmpStructureChecker
   void SetLoopInfo(const parser::OpenMPLoopConstruct &x);
   void CheckIsLoopIvPartOfClause(
       llvmOmpClause clause, const parser::OmpObjectList &ompObjectList);
+  bool CheckTargetBlockOnlyTeams(const parser::Block &);
   void CheckWorkshareBlockStmts(const parser::Block &, parser::CharBlock);
 
   void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
@@ -248,6 +249,12 @@ class OmpStructureChecker
   void CheckPredefinedAllocatorRestriction(
       const parser::CharBlock &source, const parser::Name &name);
   bool isPredefinedAllocator{false};
+  void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
+  void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
+  int GetDirectiveNest(const int index) { return directiveNest_[index]; }
+
+  enum directiveNestType { SIMDNest, TargetBlockOnlyTeams, LastType };
+  int directiveNest_[LastType + 1] = {0};
 };
 } // namespace Fortran::semantics
 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_

diff  --git a/flang/test/Semantics/omp-firstprivate01.f90 b/flang/test/Semantics/omp-firstprivate01.f90
index d03cfc253c22..c461cefb54a5 100644
--- a/flang/test/Semantics/omp-firstprivate01.f90
+++ b/flang/test/Semantics/omp-firstprivate01.f90
@@ -12,6 +12,7 @@ program omp_firstprivate
   a = 10
   b = 20
 
+  !ERROR: TARGET construct with nested TEAMS region contains statements or directives outside of the TEAMS construct
   !$omp target
   !$omp teams private(a, b)
   !ERROR: FIRSTPRIVATE variable 'a' is PRIVATE in outer context

diff  --git a/flang/test/Semantics/omp-nested-master.f90 b/flang/test/Semantics/omp-nested-master.f90
index cb391d568ba2..9debac680fc1 100644
--- a/flang/test/Semantics/omp-nested-master.f90
+++ b/flang/test/Semantics/omp-nested-master.f90
@@ -87,6 +87,7 @@ program omp_nest_master
 
   !$omp ordered
   do i = 1, 10
+    !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
     !$omp teams
     !$omp distribute
     do k =1, 10
@@ -102,6 +103,7 @@ program omp_nest_master
 
   !$omp critical
   do i = 1, 10
+    !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
     !$omp teams
     !$omp distribute
     do k =1, 10
@@ -117,6 +119,7 @@ program omp_nest_master
 
   !$omp taskloop
   do i = 1, 10
+    !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
     !$omp teams
     !$omp distribute
     do k =1, 10
@@ -133,6 +136,7 @@ program omp_nest_master
 
   !$omp task
   do i = 1, 10
+    !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
     !$omp teams
     !$omp distribute
     do k =1, 10

diff  --git a/flang/test/Semantics/omp-nested-simd.f90 b/flang/test/Semantics/omp-nested-simd.f90
index 1b5bb9c5ccee..bb1a219771a4 100644
--- a/flang/test/Semantics/omp-nested-simd.f90
+++ b/flang/test/Semantics/omp-nested-simd.f90
@@ -42,6 +42,7 @@ SUBROUTINE NESTED_BAD(N)
       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.
+        !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
         !$omp teams 
          DO K = 1,N
         print *, 'Hello'
@@ -65,12 +66,6 @@ SUBROUTINE NESTED_BAD(N)
       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
@@ -104,12 +99,6 @@ SUBROUTINE NESTED_BAD(N)
       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
@@ -144,12 +133,6 @@ SUBROUTINE NESTED_BAD(N)
       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
@@ -184,12 +167,6 @@ SUBROUTINE NESTED_BAD(N)
       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

diff  --git a/flang/test/Semantics/omp-nested-teams.f90 b/flang/test/Semantics/omp-nested-teams.f90
new file mode 100644
index 000000000000..4a773b3b9454
--- /dev/null
+++ b/flang/test/Semantics/omp-nested-teams.f90
@@ -0,0 +1,113 @@
+! RUN: %S/test_errors.sh %s %t %flang -fopenmp
+! REQUIRES: shell
+
+! OpenMP Version 5.0
+! Check OpenMP construct validity for the following directives:
+! 2.7 Teams Construct
+
+program main
+  integer :: i, j, N = 10
+  real :: a, b, c
+
+  !$omp teams
+  a = 3.14
+  !$omp end teams
+
+  !$omp target
+  !$omp teams
+  a = 3.14
+  !$omp end teams
+  !$omp end target
+
+  !$omp target
+  !$omp parallel
+  !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
+  !$omp teams
+  a = 3.14
+  !$omp end teams
+  !$omp end parallel
+  !$omp end target
+
+  !$omp parallel
+  !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
+  !$omp teams
+  a = 3.14
+  !$omp end teams
+  !$omp end parallel
+
+  !$omp do
+  do i = 1, N
+  !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
+  !$omp teams
+  a = 3.14
+  !$omp end teams
+  end do
+
+  !$omp master
+  !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
+  !$omp teams
+  a = 3.14
+  !$omp end teams
+  !$omp end master
+
+  !$omp target parallel
+  !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
+  !$omp teams
+  a = 3.14
+  !$omp end teams
+  !$omp end target parallel
+
+  !$omp target
+  !$omp teams
+  !ERROR: Only `DISTRIBUTE` or `PARALLEL` regions are allowed to be strictly nested inside `TEAMS` region.
+  !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
+  !$omp teams
+  a = 3.14
+  !$omp end teams
+  !$omp end teams
+  !$omp end target
+
+  !$omp target teams
+  !ERROR: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
+  !$omp teams
+  a = 3.14
+  !$omp end teams
+  !$omp end target teams
+
+  !ERROR: TARGET construct with nested TEAMS region contains statements or directives outside of the TEAMS construct
+  !$omp target
+  do i = 1, N
+    !$omp teams
+    a = 3.14
+    !$omp end teams
+  enddo
+  !$omp end target
+
+  !ERROR: TARGET construct with nested TEAMS region contains statements or directives outside of the TEAMS construct
+  !$omp target
+  if (i .GT. 1) then
+    if (j .GT. 1) then
+      !$omp teams
+      a = 3.14
+      !$omp end teams
+    end if
+  end if
+  !$omp end target
+
+  !ERROR: TARGET construct with nested TEAMS region contains statements or directives outside of the TEAMS construct
+  !$omp target
+  b = 3.14
+  !$omp teams
+  a = 3.14
+  !$omp end teams
+  !$omp end target
+
+  !ERROR: TARGET construct with nested TEAMS region contains statements or directives outside of the TEAMS construct
+  !$omp target
+  !$omp teams
+  a = 3.14
+  !$omp end teams
+  c = 3.14
+  !$omp end target
+
+end program main


        


More information about the flang-commits mailing list