Skip to content

[Flang][OpenMP] Restrict certain loops not allowed in associated loops #91818

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 16, 2024

Conversation

kiranchandramohan
Copy link
Contributor

Extends the OmpCycleAndExitChecker to check that associated loops of a loop construct are not DO WHILE or DO without control.

OpenMP 5.0 standard clearly mentions this restriction. Later standards enforce this through the definition of associated loops and canonical loop forms.
https://www.openmp.org/spec-html/5.0/openmpsu41.html

Fixes #81949

Extends the OmpCycleAndExitChecker to check that associated loops of
a loop construct are not DO WHILE or DO without control.

OpenMP 5.0 standard clearly mentions this restriction. Later standards
enforce this through the definition of associated loops and canonical
loop forms.
https://www.openmp.org/spec-html/5.0/openmpsu41.html

Fixes llvm#81949
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:openmp flang:semantics labels May 10, 2024
@llvmbot
Copy link
Member

llvmbot commented May 10, 2024

@llvm/pr-subscribers-flang-semantics

@llvm/pr-subscribers-flang-openmp

Author: Kiran Chandramohan (kiranchandramohan)

Changes

Extends the OmpCycleAndExitChecker to check that associated loops of a loop construct are not DO WHILE or DO without control.

OpenMP 5.0 standard clearly mentions this restriction. Later standards enforce this through the definition of associated loops and canonical loop forms.
https://www.openmp.org/spec-html/5.0/openmpsu41.html

Fixes #81949


Full diff: https://github.com/llvm/llvm-project/pull/91818.diff

5 Files Affected:

  • (modified) flang/lib/Semantics/check-omp-structure.cpp (+21-24)
  • (modified) flang/lib/Semantics/check-omp-structure.h (+1-1)
  • (modified) flang/test/Semantics/OpenMP/clause-validity01.f90 (+1)
  • (modified) flang/test/Semantics/OpenMP/do-collapse.f90 (+1)
  • (modified) flang/test/Semantics/OpenMP/do09.f90 (+2-2)
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 2493eb3ed3676..dbf2862382e32 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -84,9 +84,9 @@ class OmpWorkshareBlockChecker {
   parser::CharBlock source_;
 };
 
-class OmpCycleAndExitChecker {
+class AssociatedLoopChecker {
 public:
-  OmpCycleAndExitChecker(SemanticsContext &context, std::int64_t level)
+  AssociatedLoopChecker(SemanticsContext &context, std::int64_t level)
       : context_{context}, level_{level} {}
 
   template <typename T> bool Pre(const T &) { return true; }
@@ -94,11 +94,24 @@ class OmpCycleAndExitChecker {
 
   bool Pre(const parser::DoConstruct &dc) {
     level_--;
-    const auto &constructName{std::get<0>(std::get<0>(dc.t).statement.t)};
+    const auto &doStmt{
+        std::get<parser::Statement<parser::NonLabelDoStmt>>(dc.t)};
+    const auto &constructName{
+        std::get<std::optional<parser::Name>>(doStmt.statement.t)};
     if (constructName) {
       constructNamesAndLevels_.emplace(
           constructName.value().ToString(), level_);
     }
+    if (level_ >= 0) {
+      if (dc.IsDoWhile()) {
+        context_.Say(doStmt.source,
+            "The associated loop of a loop-associated directive cannot be a DO WHILE."_err_en_US);
+      }
+      if (!dc.GetLoopControl()) {
+        context_.Say(doStmt.source,
+            "The associated loop of a loop-associated directive cannot be a DO without control."_err_en_US);
+      }
+    }
     return true;
   }
 
@@ -449,9 +462,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPLoopConstruct &x) {
     const auto &doBlock{std::get<parser::Block>(doConstruct->t)};
     CheckNoBranching(doBlock, beginDir.v, beginDir.source);
   }
-  CheckDoWhile(x);
   CheckLoopItrVariableIsInt(x);
-  CheckCycleConstraints(x);
+  CheckAssociatedLoopConstraints(x);
   HasInvalidDistributeNesting(x);
   if (CurrentDirectiveIsNested() &&
       llvm::omp::topTeamsSet.test(GetContextParent().directive)) {
@@ -477,21 +489,6 @@ void OmpStructureChecker::SetLoopInfo(const parser::OpenMPLoopConstruct &x) {
     }
   }
 }
-void OmpStructureChecker::CheckDoWhile(const parser::OpenMPLoopConstruct &x) {
-  const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
-  const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
-  if (beginDir.v == llvm::omp::Directive::OMPD_do) {
-    if (const auto &doConstruct{
-            std::get<std::optional<parser::DoConstruct>>(x.t)}) {
-      if (doConstruct.value().IsDoWhile()) {
-        const auto &doStmt{std::get<parser::Statement<parser::NonLabelDoStmt>>(
-            doConstruct.value().t)};
-        context_.Say(doStmt.source,
-            "The DO loop cannot be a DO WHILE with DO directive."_err_en_US);
-      }
-    }
-  }
-}
 
 void OmpStructureChecker::CheckLoopItrVariableIsInt(
     const parser::OpenMPLoopConstruct &x) {
@@ -646,8 +643,8 @@ std::int64_t OmpStructureChecker::GetOrdCollapseLevel(
   const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
   const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
   std::int64_t orderedCollapseLevel{1};
-  std::int64_t orderedLevel{0};
-  std::int64_t collapseLevel{0};
+  std::int64_t orderedLevel{1};
+  std::int64_t collapseLevel{1};
 
   for (const auto &clause : clauseList.v) {
     if (const auto *collapseClause{
@@ -671,10 +668,10 @@ std::int64_t OmpStructureChecker::GetOrdCollapseLevel(
   return orderedCollapseLevel;
 }
 
-void OmpStructureChecker::CheckCycleConstraints(
+void OmpStructureChecker::CheckAssociatedLoopConstraints(
     const parser::OpenMPLoopConstruct &x) {
   std::int64_t ordCollapseLevel{GetOrdCollapseLevel(x)};
-  OmpCycleAndExitChecker checker{context_, ordCollapseLevel};
+  AssociatedLoopChecker checker{context_, ordCollapseLevel};
   parser::Walk(x, checker);
 }
 
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 1f7284307703b..200a89909a73d 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -186,7 +186,7 @@ class OmpStructureChecker
 
   void CheckLoopItrVariableIsInt(const parser::OpenMPLoopConstruct &x);
   void CheckDoWhile(const parser::OpenMPLoopConstruct &x);
-  void CheckCycleConstraints(const parser::OpenMPLoopConstruct &x);
+  void CheckAssociatedLoopConstraints(const parser::OpenMPLoopConstruct &x);
   template <typename T, typename D> bool IsOperatorValid(const T &, const D &);
   void CheckAtomicMemoryOrderClause(
       const parser::OmpAtomicClauseList *, const parser::OmpAtomicClauseList *);
diff --git a/flang/test/Semantics/OpenMP/clause-validity01.f90 b/flang/test/Semantics/OpenMP/clause-validity01.f90
index 21b99cb82549a..f8453e11d0a9a 100644
--- a/flang/test/Semantics/OpenMP/clause-validity01.f90
+++ b/flang/test/Semantics/OpenMP/clause-validity01.f90
@@ -173,6 +173,7 @@
   outer: do i=0, 10
     inner: do j=1, 10
       exit
+      !ERROR: EXIT statement terminates associated loop of an OpenMP DO construct
       exit outer
       !ERROR: EXIT to construct 'outofparallel' outside of PARALLEL construct is not allowed
       !ERROR: EXIT to construct 'outofparallel' outside of DO construct is not allowed
diff --git a/flang/test/Semantics/OpenMP/do-collapse.f90 b/flang/test/Semantics/OpenMP/do-collapse.f90
index 145b7b75d28df..4f2512937ace4 100644
--- a/flang/test/Semantics/OpenMP/do-collapse.f90
+++ b/flang/test/Semantics/OpenMP/do-collapse.f90
@@ -26,6 +26,7 @@ program omp_doCollapse
   !$omp parallel do collapse(2)
     do i = 1, 3
       !ERROR: Loop control is not present in the DO LOOP
+      !ERROR: The associated loop of a loop-associated directive cannot be a DO without control.
       do
       end do
     end do
diff --git a/flang/test/Semantics/OpenMP/do09.f90 b/flang/test/Semantics/OpenMP/do09.f90
index af9f2e294ace9..624a11555f105 100644
--- a/flang/test/Semantics/OpenMP/do09.f90
+++ b/flang/test/Semantics/OpenMP/do09.f90
@@ -6,7 +6,7 @@
 program omp_do
   integer ::  i = 0,k
   !$omp do
-  !ERROR: The DO loop cannot be a DO WHILE with DO directive.
+  !ERROR: The associated loop of a loop-associated directive cannot be a DO WHILE.
   do while (i <= 10)
     print *, "it",i
     i = i+1
@@ -14,7 +14,7 @@ program omp_do
   !$omp end do
 
   !$omp do
-  !ERROR: The DO loop cannot be a DO WHILE with DO directive.
+  !ERROR: The associated loop of a loop-associated directive cannot be a DO WHILE.
   do while (i <= 10)
     do while (j <= 10)
       print *, "it",k

Copy link
Contributor

@luporl luporl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@kiranchandramohan kiranchandramohan merged commit 977cb5d into llvm:main Jul 16, 2024
7 checks passed
yuxuanchen1997 pushed a commit that referenced this pull request Jul 25, 2024
#91818)

Summary:
Extends the OmpCycleAndExitChecker to check that associated loops of a
loop construct are not DO WHILE or DO without control.

OpenMP 5.0 standard clearly mentions this restriction. Later standards
enforce this through the definition of associated loops and canonical
loop forms.
https://www.openmp.org/spec-html/5.0/openmpsu41.html

Fixes #81949

Test Plan: 

Reviewers: 

Subscribers: 

Tasks: 

Tags: 


Differential Revision: https://phabricator.intern.facebook.com/D60251623
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:openmp flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[Flang][OpenMP] Compilation error of a collapse clause with DO WHILE loops
3 participants