llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-flang-semantics

Author: Krzysztof Parzyszek (kparzysz)

<details>
<summary>Changes</summary>

In a label-DO construct where two or more loops share the same teminator, an 
OpenMP construct must enclose all the loops if an end-directive is present. E.g.

```
  do 100 i = 1,10
!$omp do
    do 100 j = 1,10
    100 continue
!$omp end do    ! Error, but ok if this line is removed
```

OpenMP 5.1 and later no longer has this restriction.

Fixes https://github.com/llvm/llvm-project/issues/169536.

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


6 Files Affected:

- (modified) flang/include/flang/Parser/parse-tree.h (+1-1) 
- (modified) flang/lib/Semantics/canonicalize-do.cpp (+27-5) 
- (modified) flang/lib/Semantics/check-omp-loop.cpp (+17) 
- (modified) flang/test/Parser/OpenMP/atomic-label-do.f90 (+1-1) 
- (modified) flang/test/Parser/OpenMP/cross-label-do.f90 (+4-3) 
- (modified) flang/test/Semantics/OpenMP/loop-association.f90 (+2) 


``````````diff
diff --git a/flang/include/flang/Parser/parse-tree.h 
b/flang/include/flang/Parser/parse-tree.h
index dd928e1244a2f..e5d3d3f2a7d5b 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -4976,7 +4976,7 @@ struct OmpClauseList {
 // --- Directives and constructs
 
 struct OmpDirectiveSpecification {
-  ENUM_CLASS(Flag, DeprecatedSyntax)
+  ENUM_CLASS(Flag, DeprecatedSyntax, CrossesLabelDo)
   using Flags = common::EnumSet<Flag, Flag_enumSize>;
 
   TUPLE_CLASS_BOILERPLATE(OmpDirectiveSpecification);
diff --git a/flang/lib/Semantics/canonicalize-do.cpp 
b/flang/lib/Semantics/canonicalize-do.cpp
index 409195d5960b4..a0a6f8d870f6e 100644
--- a/flang/lib/Semantics/canonicalize-do.cpp
+++ b/flang/lib/Semantics/canonicalize-do.cpp
@@ -92,8 +92,11 @@ class CanonicalizationOfDoLoops {
                 [&](common::Indirection<OpenMPConstruct> &construct) {
                   // If the body of the OpenMP construct ends with a label,
                   // treat the label as ending the construct itself.
-                  CanonicalizeIfMatch(
-                      block, stack, i, omp::GetFinalLabel(construct.value()));
+                  OpenMPConstruct &omp{construct.value()};
+                  if (CanonicalizeIfMatch(
+                          block, stack, i, omp::GetFinalLabel(omp))) {
+                    MarkOpenMPConstruct(omp);
+                  }
                 },
             },
             executableConstruct->u);
@@ -103,12 +106,12 @@ class CanonicalizationOfDoLoops {
 
 private:
   template <typename T>
-  void CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
+  bool CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
       Block::iterator &i, Statement<T> &statement) {
-    CanonicalizeIfMatch(originalBlock, stack, i, statement.label);
+    return CanonicalizeIfMatch(originalBlock, stack, i, statement.label);
   }
 
-  void CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
+  bool CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
       Block::iterator &i, std::optional<Label> label) {
     if (!stack.empty() && label && stack.back().label == *label) {
       auto currentLabel{stack.back().label};
@@ -141,8 +144,27 @@ class CanonicalizationOfDoLoops {
         stack.pop_back();
       } while (!stack.empty() && stack.back().label == currentLabel);
       i = --next;
+      return true;
+    } else {
+      return false;
     }
   }
+
+  void MarkOpenMPConstruct(OpenMPConstruct &omp) {
+    common::visit(
+        [](const auto &s) {
+          using S = std::decay_t<decltype(s)>;
+          if constexpr (std::is_base_of_v<OmpBlockConstruct, S> ||
+              std::is_same_v<OpenMPLoopConstruct, S>) {
+            const OmpDirectiveSpecification &beginSpec{s.BeginDir()};
+            auto &flags{
+                std::get<OmpDirectiveSpecification::Flags>(beginSpec.t)};
+            const_cast<OmpDirectiveSpecification::Flags &>(flags).set(
+                OmpDirectiveSpecification::Flag::CrossesLabelDo);
+          }
+        },
+        omp.u);
+  }
 };
 
 bool CanonicalizeDo(Program &program) {
diff --git a/flang/lib/Semantics/check-omp-loop.cpp 
b/flang/lib/Semantics/check-omp-loop.cpp
index 9a78209369949..5830bff1596b3 100644
--- a/flang/lib/Semantics/check-omp-loop.cpp
+++ b/flang/lib/Semantics/check-omp-loop.cpp
@@ -289,6 +289,23 @@ void OmpStructureChecker::CheckNestedBlock(const 
parser::OpenMPLoopConstruct &x,
 void OmpStructureChecker::CheckNestedConstruct(
     const parser::OpenMPLoopConstruct &x) {
   size_t nestedCount{0};
+  unsigned version{context_.langOptions().OpenMPVersion};
+
+  if (version <= 50) {
+    const parser::OmpDirectiveSpecification &beginSpec{x.BeginDir()};
+    auto &flags{
+        std::get<parser::OmpDirectiveSpecification::Flags>(beginSpec.t)};
+    if (flags.test(parser::OmpDirectiveSpecification::Flag::CrossesLabelDo)) {
+      if (auto &endSpec{x.EndDir()}) {
+        parser::CharBlock beginSource{beginSpec.DirName().source};
+        context_
+            .Say(endSpec->DirName().source,
+                "END %s directive is not allowed when the construct does not 
contain all loops that shares a loop-terminating statement"_err_en_US,
+                parser::ToUpperCaseLetters(beginSource.ToString()))
+            .Attach(beginSource, "The construct starts here"_en_US);
+      }
+    }
+  }
 
   auto &body{std::get<parser::Block>(x.t)};
   if (body.empty()) {
diff --git a/flang/test/Parser/OpenMP/atomic-label-do.f90 
b/flang/test/Parser/OpenMP/atomic-label-do.f90
index f0c83c01f7a21..1c7037f239191 100644
--- a/flang/test/Parser/OpenMP/atomic-label-do.f90
+++ b/flang/test/Parser/OpenMP/atomic-label-do.f90
@@ -29,7 +29,7 @@ subroutine f
 !PARSE-TREE: | | | OmpBeginDirective
 !PARSE-TREE: | | | | OmpDirectiveName -> llvm::omp::Directive = atomic
 !PARSE-TREE: | | | | OmpClauseList -> OmpClause -> Write
-!PARSE-TREE: | | | | Flags = {}
+!PARSE-TREE: | | | | Flags = {CrossesLabelDo}
 !PARSE-TREE: | | | Block
 !PARSE-TREE: | | | | ExecutionPartConstruct -> ExecutableConstruct -> 
ActionStmt -> AssignmentStmt = 'x=i'
 !PARSE-TREE: | | | | | Variable = 'x'
diff --git a/flang/test/Parser/OpenMP/cross-label-do.f90 
b/flang/test/Parser/OpenMP/cross-label-do.f90
index fd648e0248258..c3768f8551c26 100644
--- a/flang/test/Parser/OpenMP/cross-label-do.f90
+++ b/flang/test/Parser/OpenMP/cross-label-do.f90
@@ -1,5 +1,5 @@
-!RUN: %flang_fc1 -fdebug-unparse -fopenmp %s | FileCheck --ignore-case 
--check-prefix="UNPARSE" %s
-!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp %s | FileCheck 
--check-prefix="PARSE-TREE" %s
+!RUN: %flang_fc1 -fdebug-unparse -fopenmp -fopenmp-version=51 %s | FileCheck 
--ignore-case --check-prefix="UNPARSE" %s
+!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp -fopenmp-version=51 %s | 
FileCheck --check-prefix="PARSE-TREE" %s
 
 subroutine f00
   integer :: i, j
@@ -7,6 +7,7 @@ subroutine f00
 !$omp do
     do 100 j = 1,10
     100 continue
+!$omp end do    ! This is legal in OpenMP 5.1+
 end
 
 !UNPARSE:  SUBROUTINE f00
@@ -32,7 +33,7 @@ subroutine f00
 !PARSE-TREE: | | | OmpBeginLoopDirective
 !PARSE-TREE: | | | | OmpDirectiveName -> llvm::omp::Directive = do
 !PARSE-TREE: | | | | OmpClauseList ->
-!PARSE-TREE: | | | | Flags = {}
+!PARSE-TREE: | | | | Flags = {CrossesLabelDo}
 !PARSE-TREE: | | | Block
 !PARSE-TREE: | | | | ExecutionPartConstruct -> ExecutableConstruct -> 
DoConstruct
 !PARSE-TREE: | | | | | NonLabelDoStmt
diff --git a/flang/test/Semantics/OpenMP/loop-association.f90 
b/flang/test/Semantics/OpenMP/loop-association.f90
index 4e63cafb3fda1..d39b9ed7b82c2 100644
--- a/flang/test/Semantics/OpenMP/loop-association.f90
+++ b/flang/test/Semantics/OpenMP/loop-association.f90
@@ -64,6 +64,8 @@
      do 100 j=1, N
         a = 3.14
 100     continue
+    !This is only an error in OpenMP 5.0-.
+    !ERROR: END DO directive is not allowed when the construct does not 
contain all loops that shares a loop-terminating statement
     !$omp enddo
 
   !ERROR: Non-THREADPRIVATE object 'a' in COPYIN clause

``````````

</details>


https://github.com/llvm/llvm-project/pull/169714
_______________________________________________
llvm-branch-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits

Reply via email to