[flang-commits] [flang] [llvm] [Flang][OpenMP][Sema] Adding parsing and semantic support for scan directive. (PR #102792)

Anchu Rajendran S via flang-commits flang-commits at lists.llvm.org
Thu Aug 29 12:54:51 PDT 2024


https://github.com/anchuraj updated https://github.com/llvm/llvm-project/pull/102792

>From 5bf0f84e8133cc7c50dd5ad58ebcffb3be04d959 Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Thu, 8 Aug 2024 15:28:26 -0500
Subject: [PATCH 1/5] Adding parsing support for scan directive.

---
 flang/lib/Lower/OpenMP/OpenMP.cpp             |   3 +
 flang/lib/Parser/openmp-parsers.cpp           |   5 +
 flang/lib/Parser/unparse.cpp                  |   3 +
 flang/lib/Semantics/check-omp-structure.cpp   | 113 ++++++++++--------
 flang/lib/Semantics/resolve-directives.cpp    |  16 +++
 flang/test/Parser/OpenMP/scan.f90             |  40 +++++++
 flang/test/Semantics/OpenMP/do05.f90          |   8 +-
 .../test/Semantics/OpenMP/nested-barrier.f90  |   4 +-
 flang/test/Semantics/OpenMP/nested-master.f90 |   2 +-
 flang/test/Semantics/OpenMP/nested-simd.f90   |  34 +++---
 flang/test/Semantics/OpenMP/ordered-simd.f90  |   2 +-
 flang/test/Semantics/OpenMP/scan.f90          |  19 +++
 llvm/include/llvm/Frontend/OpenMP/OMP.td      |   2 +
 13 files changed, 175 insertions(+), 76 deletions(-)
 create mode 100644 flang/test/Parser/OpenMP/scan.f90
 create mode 100644 flang/test/Semantics/OpenMP/scan.f90

diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index 26825468df9b1d..fa8c508d1434fb 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2199,6 +2199,9 @@ static void genOMPDispatch(lower::AbstractConverter &converter,
   case llvm::omp::Directive::OMPD_parallel:
     genStandaloneParallel(converter, symTable, semaCtx, eval, loc, queue, item);
     break;
+  case llvm::omp::Directive::OMPD_scan:
+    TODO(loc, "Unhandled directive " + llvm::omp::getOpenMPDirectiveName(dir));
+    break;
   case llvm::omp::Directive::OMPD_section:
     llvm_unreachable("genOMPDispatch: OMPD_section");
     // Lowered in the enclosing genSectionsOp.
diff --git a/flang/lib/Parser/openmp-parsers.cpp b/flang/lib/Parser/openmp-parsers.cpp
index 52789d6e5f0f6b..5951be846762ab 100644
--- a/flang/lib/Parser/openmp-parsers.cpp
+++ b/flang/lib/Parser/openmp-parsers.cpp
@@ -267,6 +267,8 @@ TYPE_PARSER(
         construct<OmpClause>(construct<OmpClause::DynamicAllocators>()) ||
     "ENTER" >> construct<OmpClause>(construct<OmpClause::Enter>(
                    parenthesized(Parser<OmpObjectList>{}))) ||
+    "EXCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Exclusive>(
+                       parenthesized(Parser<OmpObjectList>{}))) ||
     "FILTER" >> construct<OmpClause>(construct<OmpClause::Filter>(
                     parenthesized(scalarIntExpr))) ||
     "FINAL" >> construct<OmpClause>(construct<OmpClause::Final>(
@@ -286,6 +288,8 @@ TYPE_PARSER(
     "IF" >> construct<OmpClause>(construct<OmpClause::If>(
                 parenthesized(Parser<OmpIfClause>{}))) ||
     "INBRANCH" >> construct<OmpClause>(construct<OmpClause::Inbranch>()) ||
+    "INCLUSIVE" >> construct<OmpClause>(construct<OmpClause::Inclusive>(
+                       parenthesized(Parser<OmpObjectList>{}))) ||
     "IS_DEVICE_PTR" >> construct<OmpClause>(construct<OmpClause::IsDevicePtr>(
                            parenthesized(Parser<OmpObjectList>{}))) ||
     "LASTPRIVATE" >> construct<OmpClause>(construct<OmpClause::Lastprivate>(
@@ -481,6 +485,7 @@ TYPE_PARSER(sourced(construct<OpenMPFlushConstruct>(verbatim("FLUSH"_tok),
 TYPE_PARSER(sourced(construct<OmpSimpleStandaloneDirective>(first(
     "BARRIER" >> pure(llvm::omp::Directive::OMPD_barrier),
     "ORDERED" >> pure(llvm::omp::Directive::OMPD_ordered),
+    "SCAN" >> pure(llvm::omp::Directive::OMPD_scan),
     "TARGET ENTER DATA" >> pure(llvm::omp::Directive::OMPD_target_enter_data),
     "TARGET EXIT DATA" >> pure(llvm::omp::Directive::OMPD_target_exit_data),
     "TARGET UPDATE" >> pure(llvm::omp::Directive::OMPD_target_update),
diff --git a/flang/lib/Parser/unparse.cpp b/flang/lib/Parser/unparse.cpp
index 2511a5dda9d095..f252512a41f655 100644
--- a/flang/lib/Parser/unparse.cpp
+++ b/flang/lib/Parser/unparse.cpp
@@ -2295,6 +2295,9 @@ class UnparseVisitor {
     case llvm::omp::Directive::OMPD_barrier:
       Word("BARRIER ");
       break;
+    case llvm::omp::Directive::OMPD_scan:
+      Word("SCAN ");
+      break;
     case llvm::omp::Directive::OMPD_taskwait:
       Word("TASKWAIT ");
       break;
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 50840898438c78..9ba5a3c1288e10 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -532,62 +532,70 @@ void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
   // current context yet.
   // TODO: Check for declare simd regions.
   bool eligibleSIMD{false};
-  common::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) {},
-                },
+  common::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::OpenMPStandaloneConstruct &c) {
+            if (const auto &simpleConstruct =
+                    std::get_if<parser::OpenMPSimpleStandaloneConstruct>(
+                        &c.u)) {
+              const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(
+                  simpleConstruct->t)};
+              if (dir.v == llvm::omp::Directive::OMPD_ordered) {
+                const auto &clauses{
+                    std::get<parser::OmpClauseList>(simpleConstruct->t)};
+                for (const auto &clause : clauses.v) {
+                  if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
+                    eligibleSIMD = true;
+                    break;
+                  }
+                }
+              } else if (dir.v == llvm::omp::Directive::OMPD_scan) {
+                eligibleSIMD = true;
+              }
+            }
+          },
+          // 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_parallel_do_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);
+        "the `SIMD` construct, the `SCAN` construct and the `ORDERED` "
+        "construct with the `SIMD` clause."_err_en_US);
   }
 }
 
@@ -2531,6 +2539,9 @@ void OmpStructureChecker::CheckReductionModifier(
     switch (dirCtx.directive) {
     case llvm::omp::Directive::OMPD_do: // worksharing-loop
     case llvm::omp::Directive::OMPD_do_simd: // worksharing-loop simd
+    case llvm::omp::Directive::
+        OMPD_parallel_do_simd: // worksharing-parallel-loop
+                               // simd
     case llvm::omp::Directive::OMPD_simd: // "simd"
       break;
     default:
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index d635a7b8b7874f..131e2a74292426 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1578,9 +1578,11 @@ bool OmpAttributeVisitor::Pre(
     const parser::OpenMPSimpleStandaloneConstruct &x) {
   const auto &standaloneDir{
       std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
+  const auto &parentContext{GetContextIf()};
   switch (standaloneDir.v) {
   case llvm::omp::Directive::OMPD_barrier:
   case llvm::omp::Directive::OMPD_ordered:
+  case llvm::omp::Directive::OMPD_scan:
   case llvm::omp::Directive::OMPD_target_enter_data:
   case llvm::omp::Directive::OMPD_target_exit_data:
   case llvm::omp::Directive::OMPD_target_update:
@@ -1591,6 +1593,20 @@ bool OmpAttributeVisitor::Pre(
   default:
     break;
   }
+  if (standaloneDir.v == llvm::omp::Directive::OMPD_scan) {
+    if ((std::get<parser::OmpClauseList>(x.t).v.size() != 1)) {
+      context_.Say(standaloneDir.source,
+          "Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
+    }
+    if (!parentContext ||
+        (llvm::omp::getDirectiveAssociation(parentContext->directive) !=
+            llvm::omp::Association::Loop)) {
+      context_.Say(standaloneDir.source,
+          "Orphaned `omp scan` directives are prohibited; perhaps you forgot "
+          "to enclose the directive in to a worksharing loop, a worksharing "
+          "loop simd or a simd directive."_err_en_US);
+    }
+  }
   ClearDataSharingAttributeObjects();
   return true;
 }
diff --git a/flang/test/Parser/OpenMP/scan.f90 b/flang/test/Parser/OpenMP/scan.f90
new file mode 100644
index 00000000000000..a6e23ac9404882
--- /dev/null
+++ b/flang/test/Parser/OpenMP/scan.f90
@@ -0,0 +1,40 @@
+! RUN: %flang_fc1 -fdebug-unparse -fopenmp %s | FileCheck --ignore-case %s
+! RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s
+
+! Check for parsing scan directive
+subroutine test_scan_inclusive()
+  implicit none
+  integer, parameter :: n = 100
+  integer a(n), b(n)
+  integer x, k
+
+  ! initialization
+  x = 0
+  do k = 1, n
+   a(k) = k
+  end do
+
+  ! a(k) is included in the computation of producing results in b(k)
+  !$omp parallel do simd reduction(inscan,+: x)
+  do k = 1, n
+    x = x + a(k)
+    !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+    !PARSE-TREE-NEXT: OmpSimpleStandaloneDirective -> llvm::omp::Directive = scan
+    !PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Inclusive -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+    !CHECK: !$omp scan inclusive(x)
+    !$omp scan inclusive(x)
+      b(k) = x
+  end do
+
+  ! a(k) is not included in the computation of producing results in b(k)
+  !$omp parallel do simd reduction(inscan,+: x)
+  do k = 1, n
+    b(k) = x
+    !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+    !PARSE-TREE-NEXT: OmpSimpleStandaloneDirective -> llvm::omp::Directive = scan
+    !PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Exclusive -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+    !CHECK: !$omp scan exclusive(x)
+    !$omp scan exclusive(x)
+    x = x + a(k)
+  end do
+end subroutine
diff --git a/flang/test/Semantics/OpenMP/do05.f90 b/flang/test/Semantics/OpenMP/do05.f90
index c0f240db57b65b..24844f9fe4f62a 100644
--- a/flang/test/Semantics/OpenMP/do05.f90
+++ b/flang/test/Semantics/OpenMP/do05.f90
@@ -39,7 +39,7 @@ program omp_do
     if( i == 5 ) then
         cycle
     end if
-    !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 only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` 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
@@ -70,7 +70,7 @@ program omp_do
     if( i == 3 ) then
         cycle
     end if
-    !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 only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` 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
@@ -93,7 +93,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: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` 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
@@ -116,7 +116,7 @@ program omp_do
 
   !$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: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` 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/OpenMP/nested-barrier.f90 b/flang/test/Semantics/OpenMP/nested-barrier.f90
index aae283229e330d..ed13c98539c93c 100644
--- a/flang/test/Semantics/OpenMP/nested-barrier.f90
+++ b/flang/test/Semantics/OpenMP/nested-barrier.f90
@@ -17,7 +17,7 @@ program omp_nest_barrier
   !$omp do simd
   do i = 1, 10
     k = k + 1
-    !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 only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: `BARRIER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`,`CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region.
     !$omp barrier
     j = j -1
@@ -34,7 +34,7 @@ program omp_nest_barrier
   !$omp parallel do simd
   do i = 1, 10
     k = k + 1
-    !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 only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: `BARRIER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`,`CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region.
     !$omp barrier
     j = j -1
diff --git a/flang/test/Semantics/OpenMP/nested-master.f90 b/flang/test/Semantics/OpenMP/nested-master.f90
index 069de67cafae28..0a5118bb947550 100644
--- a/flang/test/Semantics/OpenMP/nested-master.f90
+++ b/flang/test/Semantics/OpenMP/nested-master.f90
@@ -64,7 +64,7 @@ program omp_nest_master
   do i = 1, 10
     k = k + 1
     !WARNING: OpenMP directive 'master' has been deprecated, please use 'masked' instead.
-    !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 only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
     !ERROR: `MASTER` region may not be closely nested inside of `WORKSHARING`, `LOOP`, `TASK`, `TASKLOOP`, or `ATOMIC` region.
     !$omp master
     j = j -1
diff --git a/flang/test/Semantics/OpenMP/nested-simd.f90 b/flang/test/Semantics/OpenMP/nested-simd.f90
index 4149b6d97e9dc7..c9fb90cdeceb25 100644
--- a/flang/test/Semantics/OpenMP/nested-simd.f90
+++ b/flang/test/Semantics/OpenMP/nested-simd.f90
@@ -40,7 +40,7 @@ SUBROUTINE NESTED_BAD(N)
       !$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.
+        !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, the `SCAN` 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
@@ -58,25 +58,25 @@ SUBROUTINE NESTED_BAD(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.
+      !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, the `SCAN` 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.
+      !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, the `SCAN` 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: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` 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.
+      !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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$OMP PARALLEL DO
       DO J = 1,N
         A(J) = J
@@ -91,26 +91,26 @@ SUBROUTINE NESTED_BAD(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.
+      !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, the `SCAN` 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.
+      !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, the `SCAN` 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: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` 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.
+      !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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$OMP PARALLEL DO
       DO J = 1,N
         A(J) = J
@@ -125,26 +125,26 @@ SUBROUTINE NESTED_BAD(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.
+      !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, the `SCAN` 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.
+      !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, the `SCAN` 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: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` 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.
+      !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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$OMP PARALLEL DO
       DO J = 1,N
         A(J) = J
@@ -159,25 +159,25 @@ SUBROUTINE NESTED_BAD(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.
+      !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, the `SCAN` 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.
+      !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, the `SCAN` 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: The only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` 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.
+      !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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !$OMP PARALLEL DO
       DO J = 1,N
         A(J) = J
diff --git a/flang/test/Semantics/OpenMP/ordered-simd.f90 b/flang/test/Semantics/OpenMP/ordered-simd.f90
index ed52b759491002..0df0471f3db60e 100644
--- a/flang/test/Semantics/OpenMP/ordered-simd.f90
+++ b/flang/test/Semantics/OpenMP/ordered-simd.f90
@@ -25,7 +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 only OpenMP constructs that can be encountered during execution of a 'SIMD' region are the `ATOMIC` construct, the `LOOP` construct, the `SIMD` construct, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
       !ERROR: An ORDERED directive without the DEPEND clause must be closely nested in a worksharing-loop (or worksharing-loop SIMD) region with ORDERED clause without the parameter
       !$OMP ORDERED 
       CALL WORK(I)
diff --git a/flang/test/Semantics/OpenMP/scan.f90 b/flang/test/Semantics/OpenMP/scan.f90
new file mode 100644
index 00000000000000..76a0379dfec55c
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/scan.f90
@@ -0,0 +1,19 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+
+subroutine test_scan()
+ integer x, k
+ 
+ !ERROR: Orphaned `omp scan` directives are prohibited; perhaps you forgot to enclose the directive in to a worksharing loop, a worksharing loop simd or a simd directive.
+ !$omp scan inclusive(x)
+ !$omp parallel do simd reduction(inscan,+: x)
+ do k = 1, n
+ !ERROR: UNTIED clause is not allowed on the SCAN directive
+   !$omp scan untied
+ end do
+ 
+ !$omp parallel do simd reduction(inscan,+: x)
+ do k = 1, n
+ !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
+   !$omp scan
+ end do
+end subroutine
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 2cbcbd883fb2e3..6a96fe1d82abef 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -156,6 +156,7 @@ def OMPC_Enter : Clause<"enter"> {
 }
 def OMPC_Exclusive : Clause<"exclusive"> {
   let clangClass = "OMPExclusiveClause";
+  let flangClass = "OmpObjectList";
 }
 def OMPC_Fail : Clause<"fail"> {
   let clangClass = "OMPFailClause";
@@ -213,6 +214,7 @@ def OMPC_Inbranch : Clause<"inbranch"> {
 }
 def OMPC_Inclusive : Clause<"inclusive"> {
   let clangClass = "OMPInclusiveClause";
+  let flangClass = "OmpObjectList";
 }
 def OMPC_Indirect : Clause<"indirect"> {
 }

>From 4442fc87517c0785851ceea8ba302a54dbd6da20 Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Wed, 28 Aug 2024 17:17:14 -0500
Subject: [PATCH 2/5] R2: Addressing review comments

---
 .../flang/Semantics/openmp-directive-sets.h   |   1 +
 flang/lib/Semantics/check-omp-structure.cpp   | 123 ++++++++----------
 flang/lib/Semantics/resolve-directives.cpp    |   3 +-
 flang/test/Parser/OpenMP/scan.f90             |  36 +++--
 flang/test/Semantics/OpenMP/out               |  37 ++++++
 flang/test/Semantics/OpenMP/scan.f90          |   8 +-
 6 files changed, 130 insertions(+), 78 deletions(-)
 create mode 100644 flang/test/Semantics/OpenMP/out

diff --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h
index 8eb736bb098fe4..0df4e992d793bc 100644
--- a/flang/include/flang/Semantics/openmp-directive-sets.h
+++ b/flang/include/flang/Semantics/openmp-directive-sets.h
@@ -194,6 +194,7 @@ static const OmpDirectiveSet allDistributeParallelDoSimdSet{
 static const OmpDirectiveSet allDistributeSimdSet{
     allDistributeSet & allSimdSet};
 static const OmpDirectiveSet allDoSimdSet{allDoSet & allSimdSet};
+static const OmpDirectiveSet scanAllowedSet{allDoSet | allSimdSet};
 static const OmpDirectiveSet allTaskloopSimdSet{allTaskloopSet & allSimdSet};
 
 static const OmpDirectiveSet compositeConstructSet{
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 9ba5a3c1288e10..0cbfdb4516a300 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -10,6 +10,7 @@
 #include "definable.h"
 #include "flang/Parser/parse-tree.h"
 #include "flang/Semantics/tools.h"
+#include <variant>
 
 namespace Fortran::semantics {
 
@@ -532,63 +533,61 @@ void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
   // current context yet.
   // TODO: Check for declare simd regions.
   bool eligibleSIMD{false};
-  common::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::OpenMPStandaloneConstruct &c) {
-            if (const auto &simpleConstruct =
-                    std::get_if<parser::OpenMPSimpleStandaloneConstruct>(
-                        &c.u)) {
-              const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(
-                  simpleConstruct->t)};
-              if (dir.v == llvm::omp::Directive::OMPD_ordered) {
-                const auto &clauses{
-                    std::get<parser::OmpClauseList>(simpleConstruct->t)};
-                for (const auto &clause : clauses.v) {
-                  if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
-                    eligibleSIMD = true;
-                    break;
-                  }
-                }
-              } else if (dir.v == llvm::omp::Directive::OMPD_scan) {
-                eligibleSIMD = true;
-              }
-            }
-          },
-          // 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_parallel_do_simd) ||
-                (beginDir.v == llvm::omp::Directive::OMPD_do_simd)) {
-              eligibleSIMD = true;
-            }
-          },
-          [&](const parser::OpenMPAtomicConstruct &c) {
-            // Allow `!$OMP ATOMIC`
-            eligibleSIMD = true;
-          },
-          [&](const auto &c) {},
-      },
+  common::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::OpenMPStandaloneConstruct &c) {
+                      if (const auto &simpleConstruct =
+                              std::get_if<parser::OpenMPSimpleStandaloneConstruct>(
+                                  &c.u)) {
+                        const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(
+                            simpleConstruct->t)};
+                        if (dir.v == llvm::omp::Directive::OMPD_ordered) {
+                          const auto &clauses{
+                              std::get<parser::OmpClauseList>(simpleConstruct->t)};
+                          for (const auto &clause : clauses.v) {
+                            if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
+                              eligibleSIMD = true;
+                              break;
+                            }
+                          }
+                        } else if (dir.v == llvm::omp::Directive::OMPD_scan) {
+                          eligibleSIMD = true;
+                        }
+                      }
+                    },
+                    // 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),
@@ -2536,15 +2535,7 @@ void OmpStructureChecker::CheckReductionModifier(
     // or "simd" directive.
     // The worksharing-loop directives are OMPD_do and OMPD_for. Only the
     // former is allowed in Fortran.
-    switch (dirCtx.directive) {
-    case llvm::omp::Directive::OMPD_do: // worksharing-loop
-    case llvm::omp::Directive::OMPD_do_simd: // worksharing-loop simd
-    case llvm::omp::Directive::
-        OMPD_parallel_do_simd: // worksharing-parallel-loop
-                               // simd
-    case llvm::omp::Directive::OMPD_simd: // "simd"
-      break;
-    default:
+    if (!llvm::omp::scanAllowedSet.test(dirCtx.directive)) {
       context_.Say(GetContext().clauseSource,
           "Modifier 'INSCAN' on REDUCTION clause is only allowed with "
           "worksharing-loop, worksharing-loop simd, "
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 131e2a74292426..f1a956adff645b 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1599,8 +1599,7 @@ bool OmpAttributeVisitor::Pre(
           "Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
     }
     if (!parentContext ||
-        (llvm::omp::getDirectiveAssociation(parentContext->directive) !=
-            llvm::omp::Association::Loop)) {
+        (!llvm::omp::scanAllowedSet.test(parentContext->directive))) {
       context_.Say(standaloneDir.source,
           "Orphaned `omp scan` directives are prohibited; perhaps you forgot "
           "to enclose the directive in to a worksharing loop, a worksharing "
diff --git a/flang/test/Parser/OpenMP/scan.f90 b/flang/test/Parser/OpenMP/scan.f90
index a6e23ac9404882..6bc970c922160f 100644
--- a/flang/test/Parser/OpenMP/scan.f90
+++ b/flang/test/Parser/OpenMP/scan.f90
@@ -2,17 +2,11 @@
 ! RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s
 
 ! Check for parsing scan directive
-subroutine test_scan_inclusive()
+subroutine test_scan(n, a, b)
   implicit none
-  integer, parameter :: n = 100
+  integer n
   integer a(n), b(n)
-  integer x, k
-
-  ! initialization
-  x = 0
-  do k = 1, n
-   a(k) = k
-  end do
+  integer x,y,k
 
   ! a(k) is included in the computation of producing results in b(k)
   !$omp parallel do simd reduction(inscan,+: x)
@@ -37,4 +31,28 @@ subroutine test_scan_inclusive()
     !$omp scan exclusive(x)
     x = x + a(k)
   end do
+
+  !$omp parallel do simd reduction(inscan,+: x)
+  do k = 1, n
+    x = x + a(k)
+    !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+    !PARSE-TREE-NEXT: OmpSimpleStandaloneDirective -> llvm::omp::Directive = scan
+    !PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Inclusive -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+    !PARSE-TREE-NEXT: OmpObject -> Designator -> DataRef -> Name = 'y'
+    !CHECK: !$omp scan inclusive(x,y)
+    !$omp scan inclusive(x, y)
+      b(k) = x
+  end do
+
+  !$omp parallel do simd reduction(inscan,+: x)
+  do k = 1, n
+    x = x + a(k)
+    !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
+    !PARSE-TREE-NEXT: OmpSimpleStandaloneDirective -> llvm::omp::Directive = scan
+    !PARSE-TREE-NEXT: OmpClauseList -> OmpClause -> Exclusive -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
+    !PARSE-TREE-NEXT: OmpObject -> Designator -> DataRef -> Name = 'y'
+    !CHECK: !$omp scan exclusive(x,y)
+    !$omp scan exclusive(x, y)
+      b(k) = x
+  end do
 end subroutine
diff --git a/flang/test/Semantics/OpenMP/out b/flang/test/Semantics/OpenMP/out
new file mode 100644
index 00000000000000..d63b909cdd6c6c
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/out
@@ -0,0 +1,37 @@
+error: Semantic errors in nested-simd.f90
+./nested-simd.f90:45:15: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+          !$omp teams 
+                ^
+./nested-simd.f90:45:15: error: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
+          !$omp teams 
+                ^
+./nested-simd.f90:62:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp task 
+              ^
+./nested-simd.f90:68:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp target 
+              ^
+./nested-simd.f90:95:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp task 
+              ^
+./nested-simd.f90:101:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp target 
+              ^
+./nested-simd.f90:108:13: error: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
+        !$OMP DO
+              ^^
+./nested-simd.f90:129:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp task 
+              ^
+./nested-simd.f90:135:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp target 
+              ^
+./nested-simd.f90:142:13: error: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
+        !$OMP DO
+              ^^
+./nested-simd.f90:163:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp task 
+              ^
+./nested-simd.f90:169:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
+        !$omp target 
+              ^
diff --git a/flang/test/Semantics/OpenMP/scan.f90 b/flang/test/Semantics/OpenMP/scan.f90
index 76a0379dfec55c..fe154c2fa74cd3 100644
--- a/flang/test/Semantics/OpenMP/scan.f90
+++ b/flang/test/Semantics/OpenMP/scan.f90
@@ -1,7 +1,7 @@
 ! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
 
 subroutine test_scan()
- integer x, k
+ integer x, y, k
  
  !ERROR: Orphaned `omp scan` directives are prohibited; perhaps you forgot to enclose the directive in to a worksharing loop, a worksharing loop simd or a simd directive.
  !$omp scan inclusive(x)
@@ -16,4 +16,10 @@ subroutine test_scan()
  !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
    !$omp scan
  end do
+
+!$omp parallel do simd reduction(inscan,+: x)
+ do k = 1, n
+ !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
+   !$omp scan inclusive(x) exclusive(y)
+ end do
 end subroutine

>From 747ea634a2aab434d41722989078085017dcebb6 Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Wed, 28 Aug 2024 18:54:32 -0500
Subject: [PATCH 3/5] R3: Adding formatted file

---
 flang/lib/Semantics/check-omp-structure.cpp | 111 ++++++++++----------
 1 file changed, 56 insertions(+), 55 deletions(-)

diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 0cbfdb4516a300..66149d04952dc5 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -533,61 +533,62 @@ void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
   // current context yet.
   // TODO: Check for declare simd regions.
   bool eligibleSIMD{false};
-  common::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::OpenMPStandaloneConstruct &c) {
-                      if (const auto &simpleConstruct =
-                              std::get_if<parser::OpenMPSimpleStandaloneConstruct>(
-                                  &c.u)) {
-                        const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(
-                            simpleConstruct->t)};
-                        if (dir.v == llvm::omp::Directive::OMPD_ordered) {
-                          const auto &clauses{
-                              std::get<parser::OmpClauseList>(simpleConstruct->t)};
-                          for (const auto &clause : clauses.v) {
-                            if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
-                              eligibleSIMD = true;
-                              break;
-                            }
-                          }
-                        } else if (dir.v == llvm::omp::Directive::OMPD_scan) {
-                          eligibleSIMD = true;
-                        }
-                      }
-                    },
-                    // 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) {},
-                },
+  common::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::OpenMPStandaloneConstruct &c) {
+            if (const auto &simpleConstruct =
+                    std::get_if<parser::OpenMPSimpleStandaloneConstruct>(
+                        &c.u)) {
+              const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(
+                  simpleConstruct->t)};
+              if (dir.v == llvm::omp::Directive::OMPD_ordered) {
+                const auto &clauses{
+                    std::get<parser::OmpClauseList>(simpleConstruct->t)};
+                for (const auto &clause : clauses.v) {
+                  if (std::get_if<parser::OmpClause::Simd>(&clause.u)) {
+                    eligibleSIMD = true;
+                    break;
+                  }
+                }
+              } else if (dir.v == llvm::omp::Directive::OMPD_scan) {
+                eligibleSIMD = true;
+              }
+            }
+          },
+          // 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),

>From 2fc5c3e18104b6417f292eb789236336fa1be3fb Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Thu, 29 Aug 2024 13:19:04 -0500
Subject: [PATCH 4/5] R4: Addressing review comments

---
 .../flang/Semantics/openmp-directive-sets.h   |  6 ++-
 flang/lib/Semantics/resolve-directives.cpp    |  4 +-
 flang/test/Parser/OpenMP/scan.f90             |  4 +-
 flang/test/Semantics/OpenMP/out               | 37 -------------------
 flang/test/Semantics/OpenMP/scan.f90          |  2 +-
 5 files changed, 9 insertions(+), 44 deletions(-)
 delete mode 100644 flang/test/Semantics/OpenMP/out

diff --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h
index 0df4e992d793bc..90ce28e450ea46 100644
--- a/flang/include/flang/Semantics/openmp-directive-sets.h
+++ b/flang/include/flang/Semantics/openmp-directive-sets.h
@@ -186,7 +186,10 @@ static const OmpDirectiveSet allTeamsSet{
 // Directive sets for groups of multiple directives
 //===----------------------------------------------------------------------===//
 
-// Composite constructs
+// Directive sets for parent directives that do allow/not allow a construct
+static const OmpDirectiveSet scanAllowedSet{allDoSet | allSimdSet};
+
+// Directive sets that form Composite constructs
 static const OmpDirectiveSet allDistributeParallelDoSet{
     allDistributeSet & allParallelSet & allDoSet};
 static const OmpDirectiveSet allDistributeParallelDoSimdSet{
@@ -194,7 +197,6 @@ static const OmpDirectiveSet allDistributeParallelDoSimdSet{
 static const OmpDirectiveSet allDistributeSimdSet{
     allDistributeSet & allSimdSet};
 static const OmpDirectiveSet allDoSimdSet{allDoSet & allSimdSet};
-static const OmpDirectiveSet scanAllowedSet{allDoSet | allSimdSet};
 static const OmpDirectiveSet allTaskloopSimdSet{allTaskloopSet & allSimdSet};
 
 static const OmpDirectiveSet compositeConstructSet{
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index f1a956adff645b..9cd0046fb76dca 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1594,12 +1594,12 @@ bool OmpAttributeVisitor::Pre(
     break;
   }
   if (standaloneDir.v == llvm::omp::Directive::OMPD_scan) {
-    if ((std::get<parser::OmpClauseList>(x.t).v.size() != 1)) {
+    if (std::get<parser::OmpClauseList>(x.t).v.size() != 1) {
       context_.Say(standaloneDir.source,
           "Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
     }
     if (!parentContext ||
-        (!llvm::omp::scanAllowedSet.test(parentContext->directive))) {
+        !llvm::omp::scanAllowedSet.test(parentContext->directive)) {
       context_.Say(standaloneDir.source,
           "Orphaned `omp scan` directives are prohibited; perhaps you forgot "
           "to enclose the directive in to a worksharing loop, a worksharing "
diff --git a/flang/test/Parser/OpenMP/scan.f90 b/flang/test/Parser/OpenMP/scan.f90
index 6bc970c922160f..02fa09b6ef3505 100644
--- a/flang/test/Parser/OpenMP/scan.f90
+++ b/flang/test/Parser/OpenMP/scan.f90
@@ -32,7 +32,7 @@ subroutine test_scan(n, a, b)
     x = x + a(k)
   end do
 
-  !$omp parallel do simd reduction(inscan,+: x)
+  !$omp parallel do simd reduction(inscan,+: x, y)
   do k = 1, n
     x = x + a(k)
     !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
@@ -44,7 +44,7 @@ subroutine test_scan(n, a, b)
       b(k) = x
   end do
 
-  !$omp parallel do simd reduction(inscan,+: x)
+  !$omp parallel do simd reduction(inscan,+: x, y)
   do k = 1, n
     x = x + a(k)
     !PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPStandaloneConstruct -> OpenMPSimpleStandaloneConstruct
diff --git a/flang/test/Semantics/OpenMP/out b/flang/test/Semantics/OpenMP/out
deleted file mode 100644
index d63b909cdd6c6c..00000000000000
--- a/flang/test/Semantics/OpenMP/out
+++ /dev/null
@@ -1,37 +0,0 @@
-error: Semantic errors in nested-simd.f90
-./nested-simd.f90:45:15: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-          !$omp teams 
-                ^
-./nested-simd.f90:45:15: error: TEAMS region can only be strictly nested within the implicit parallel region or TARGET region
-          !$omp teams 
-                ^
-./nested-simd.f90:62:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp task 
-              ^
-./nested-simd.f90:68:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp target 
-              ^
-./nested-simd.f90:95:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp task 
-              ^
-./nested-simd.f90:101:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp target 
-              ^
-./nested-simd.f90:108:13: error: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
-        !$OMP DO
-              ^^
-./nested-simd.f90:129:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp task 
-              ^
-./nested-simd.f90:135:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp target 
-              ^
-./nested-simd.f90:142:13: error: A worksharing region may not be closely nested inside a worksharing, explicit task, taskloop, critical, ordered, atomic, or master region
-        !$OMP DO
-              ^^
-./nested-simd.f90:163:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp task 
-              ^
-./nested-simd.f90:169:13: 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, the `SCAN` construct and the `ORDERED` construct with the `SIMD` clause.
-        !$omp target 
-              ^
diff --git a/flang/test/Semantics/OpenMP/scan.f90 b/flang/test/Semantics/OpenMP/scan.f90
index fe154c2fa74cd3..e82982f60b9021 100644
--- a/flang/test/Semantics/OpenMP/scan.f90
+++ b/flang/test/Semantics/OpenMP/scan.f90
@@ -17,7 +17,7 @@ subroutine test_scan()
    !$omp scan
  end do
 
-!$omp parallel do simd reduction(inscan,+: x)
+!$omp parallel do simd reduction(inscan,+: x, y)
  do k = 1, n
  !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
    !$omp scan inclusive(x) exclusive(y)

>From 945fd5db7ef50446887776d8fbd5e2c973ec0a79 Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Thu, 29 Aug 2024 14:43:18 -0500
Subject: [PATCH 5/5] R5: Addressing a few more review comments

---
 flang/include/flang/Semantics/openmp-directive-sets.h | 8 +++++---
 flang/lib/Semantics/check-omp-structure.cpp           | 2 +-
 flang/lib/Semantics/resolve-directives.cpp            | 2 +-
 3 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h
index 90ce28e450ea46..271f4c4697c6d2 100644
--- a/flang/include/flang/Semantics/openmp-directive-sets.h
+++ b/flang/include/flang/Semantics/openmp-directive-sets.h
@@ -186,9 +186,6 @@ static const OmpDirectiveSet allTeamsSet{
 // Directive sets for groups of multiple directives
 //===----------------------------------------------------------------------===//
 
-// Directive sets for parent directives that do allow/not allow a construct
-static const OmpDirectiveSet scanAllowedSet{allDoSet | allSimdSet};
-
 // Directive sets that form Composite constructs
 static const OmpDirectiveSet allDistributeParallelDoSet{
     allDistributeSet & allParallelSet & allDoSet};
@@ -289,6 +286,11 @@ static const OmpDirectiveSet workShareSet{
     } | allDoSet,
 };
 
+//===----------------------------------------------------------------------===//
+// Directive sets for parent directives that do allow/not allow a construct
+static const OmpDirectiveSet scanParentAllowedSet{allDoSet | allSimdSet};
+//===----------------------------------------------------------------------===//
+
 //===----------------------------------------------------------------------===//
 // Directive sets for allowed/not allowed nested directives
 //===----------------------------------------------------------------------===//
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 66149d04952dc5..14091759cebb9c 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -2536,7 +2536,7 @@ void OmpStructureChecker::CheckReductionModifier(
     // or "simd" directive.
     // The worksharing-loop directives are OMPD_do and OMPD_for. Only the
     // former is allowed in Fortran.
-    if (!llvm::omp::scanAllowedSet.test(dirCtx.directive)) {
+    if (!llvm::omp::scanParentAllowedSet.test(dirCtx.directive)) {
       context_.Say(GetContext().clauseSource,
           "Modifier 'INSCAN' on REDUCTION clause is only allowed with "
           "worksharing-loop, worksharing-loop simd, "
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 9cd0046fb76dca..76a6a39b5dd047 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1599,7 +1599,7 @@ bool OmpAttributeVisitor::Pre(
           "Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
     }
     if (!parentContext ||
-        !llvm::omp::scanAllowedSet.test(parentContext->directive)) {
+        !llvm::omp::scanParentAllowedSet.test(parentContext->directive)) {
       context_.Say(standaloneDir.source,
           "Orphaned `omp scan` directives are prohibited; perhaps you forgot "
           "to enclose the directive in to a worksharing loop, a worksharing "



More information about the flang-commits mailing list