Skip to content

[Flang][OpenMP][Sema] Adding parsing and semantic support for scan directive. #102792

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 10 commits into from
Nov 15, 2024

Conversation

anchuraj
Copy link
Contributor

@anchuraj anchuraj commented Aug 11, 2024

Scan directive specifies the scan computations. This PR adds the initial parsing and semantic support in flang.

scan is parsed as a stand alone directive as done in clang.

@anchuraj anchuraj requested review from shraiysh and kparzysz August 11, 2024 06:01
@llvmbot llvmbot added flang Flang issues not falling into any other category flang:fir-hlfir flang:openmp flang:semantics flang:parser clang:openmp OpenMP related changes to Clang labels Aug 11, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 11, 2024

@llvm/pr-subscribers-flang-parser
@llvm/pr-subscribers-flang-semantics
@llvm/pr-subscribers-flang-openmp

@llvm/pr-subscribers-flang-fir-hlfir

Author: Anchu Rajendran S (anchuraj)

Changes

Scan directive specifies the scan computations. This PR adds the initial parsing and semantic support in flang.


Patch is 28.78 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/102792.diff

13 Files Affected:

  • (modified) flang/lib/Lower/OpenMP/OpenMP.cpp (+3)
  • (modified) flang/lib/Parser/openmp-parsers.cpp (+5)
  • (modified) flang/lib/Parser/unparse.cpp (+3)
  • (modified) flang/lib/Semantics/check-omp-structure.cpp (+20-12)
  • (modified) flang/lib/Semantics/resolve-directives.cpp (+16)
  • (added) flang/test/Parser/OpenMP/scan.f90 (+40)
  • (modified) flang/test/Semantics/OpenMP/do05.f90 (+4-4)
  • (modified) flang/test/Semantics/OpenMP/nested-barrier.f90 (+2-2)
  • (modified) flang/test/Semantics/OpenMP/nested-master.f90 (+1-1)
  • (modified) flang/test/Semantics/OpenMP/nested-simd.f90 (+17-17)
  • (modified) flang/test/Semantics/OpenMP/ordered-simd.f90 (+1-1)
  • (added) flang/test/Semantics/OpenMP/scan.f90 (+19)
  • (modified) llvm/include/llvm/Frontend/OpenMP/OMP.td (+2)
diff --git a/flang/lib/Lower/OpenMP/OpenMP.cpp b/flang/lib/Lower/OpenMP/OpenMP.cpp
index bbde77c14f36a1..52cc15d4ac6946 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2189,6 +2189,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..7c10099fe0da8b 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..f38b929fb78b3d 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -550,17 +550,21 @@ void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
                         }
                       }
                     },
-                    [&](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;
+                    [&](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;
                         }
                       }
                     },
@@ -571,6 +575,7 @@ void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
                       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;
                       }
@@ -586,8 +591,9 @@ void OmpStructureChecker::CheckSIMDNest(const parser::OpenMPConstruct &c) {
     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 +2537,8 @@ 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..018352f072a112 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:...
[truncated]

Copy link

github-actions bot commented Aug 11, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@anchuraj anchuraj force-pushed the scan-parse branch 4 times, most recently from 9a045a6 to 5bf0f84 Compare August 13, 2024 19:30
@anchuraj anchuraj requested review from skatrak, mjklemm, klausler, shraiysh and kparzysz and removed request for skatrak August 14, 2024 16:37
@klausler klausler removed their request for review August 17, 2024 19:58
Copy link
Member

@skatrak skatrak left a comment

Choose a reason for hiding this comment

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

Thank you Anchu, I just have one remaining concern. I hope someone else can share their thoughts on it and get this work merged soon.

@@ -198,6 +198,10 @@ class DirectiveStructureChecker : public virtual BaseChecker {
ClauseMapTy clauseInfo;
std::list<C> actualClauses;
std::list<C> crtGroup;
std::set<std::string> usedInScanDirective;
Copy link
Member

Choose a reason for hiding this comment

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

After our private discussion, I'm not against representing symbols as strings as part of this PR and address not matching symbols as part of a separate PR, if there's actually a semantics bug causing this mismatch.

What I'm still not sure about is having these new OpenMP-specific properties added to the generic DirectiveContext. Perhaps someone from the OpenACC side can chime in on this (@clementval, @jeanPerier).

std::get_if<parser::OmpClause::Reduction>(&clause.u)}) {
const auto &maybeModifier{
std::get<std::optional<ReductionModifier>>(reductionClause->v.t)};
if (maybeModifier && *maybeModifier == ReductionModifier::Inscan) {
Copy link
Member

Choose a reason for hiding this comment

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

Nit: Reduce the nesting level to make code easier to follow.

Suggested change
if (maybeModifier && *maybeModifier == ReductionModifier::Inscan) {
if (!maybeModifier || *maybeModifier != ReductionModifier::Inscan)
continue;

Copy link
Contributor

Choose a reason for hiding this comment

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

Generally frontend code in flang is more nested.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I prefer to go with the existing approach as personally I feel it more readable. Please let me know if there are suggestions otherwise.

const parser::OmpObjectList &x) {
for (const auto &ompObj : x.v) {
auto checkScanSymbolInReduction = [&](const parser::Name *name) {
if (name->symbol) {
Copy link
Member

Choose a reason for hiding this comment

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

Nit: I think an early return here instead of adding a nesting level helps readability.

Suggested change
if (name->symbol) {
if (!name->symbol)
return;

Copy link
Contributor

Choose a reason for hiding this comment

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

Generally frontend code in flang is nested.

Copy link
Contributor

@kiranchandramohan kiranchandramohan left a comment

Choose a reason for hiding this comment

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

A few comments.

Comment on lines 1443 to 1445
"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);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"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);
"Orphaned SCAN directives are prohibited, perhaps you forgot "
"to enclose the directive in a WORKSHARING LOOP, a WORKSHARING "
"LOOP SIMD or a SIMD directive."_err_en_US);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

const parser::OpenMPSimpleStandaloneConstruct &x) {
if (std::get<parser::OmpClauseList>(x.t).v.size() != 1) {
context_.Say(x.source,
"Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"Exactly one of `exclusive` or `inclusive` clause is expected"_err_en_US);
"Exactly one of EXCLUSIVE or INCLUSIVE clause is expected"_err_en_US);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

Comment on lines 780 to 782
"List item %s must appear in 'inclusive' or "
"'exclusive' clause of an "
"enclosed scan directive"_err_en_US,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"List item %s must appear in 'inclusive' or "
"'exclusive' clause of an "
"enclosed scan directive"_err_en_US,
"List item %s must appear in INCLUSIVE or "
"EXCLUSIVE clause of an "
"enclosed SCAN directive"_err_en_US,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

std::get_if<parser::OmpClause::Reduction>(&clause.u)}) {
const auto &maybeModifier{
std::get<std::optional<ReductionModifier>>(reductionClause->v.t)};
if (maybeModifier && *maybeModifier == ReductionModifier::Inscan) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Generally frontend code in flang is more nested.

const parser::OmpObjectList &x) {
for (const auto &ompObj : x.v) {
auto checkScanSymbolInReduction = [&](const parser::Name *name) {
if (name->symbol) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Generally frontend code in flang is nested.

Comment on lines 2467 to 2922
"List item %s must appear in 'reduction' clause "
"with the 'inscan' modifier of the parent "
"directive"_err_en_US,
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
"List item %s must appear in 'reduction' clause "
"with the 'inscan' modifier of the parent "
"directive"_err_en_US,
"List item %s must appear in a REDUCTION clause "
"with the INSCAN modifier of the parent "
"directive"_err_en_US,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Changed

@@ -198,6 +198,10 @@ class DirectiveStructureChecker : public virtual BaseChecker {
ClauseMapTy clauseInfo;
std::list<C> actualClauses;
std::list<C> crtGroup;
std::set<std::string> usedInScanDirective;
Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with @skatrak's initial comments. We should try to keep the OpenMP specific data-structures in the OpenMP specific checkers. And if we can use the symbol that would be great. If the reduction creates a new private symbol, that should be the symbol bound to the inclusive or exclusive clause of the SCAN directive.

@anchuraj anchuraj force-pushed the scan-parse branch 2 times, most recently from 81f37c2 to 9e4724c Compare November 12, 2024 23:22

bool Pre(const parser::OmpClause::Inclusive &x) {
const auto &objectList{x.v};
ResolveNames(objectList);
Copy link
Contributor

Choose a reason for hiding this comment

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

Can you add a debug-dump-symbols test?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have added a new flag and dumped the symbols in a new test.

void OmpStructureChecker::CheckBarrierNesting(
const parser::OpenMPSimpleStandaloneConstruct &x) {
// A barrier region may not be `closely nested` inside a worksharing, loop,
// task, taskloop, critical, ordered, atomic, or master region.
// TODO: Expand the check to include `LOOP` construct as well when it is
// supported.
if (GetContext().directive == llvm::omp::Directive::OMPD_barrier) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Was this check for barrier not required?

Copy link
Contributor Author

@anchuraj anchuraj Nov 13, 2024

Choose a reason for hiding this comment

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

I moved the check to the caller (@line 1906) since I needed a function for scan as well.

@@ -2865,4 +2879,19 @@ void OmpAttributeVisitor::IssueNonConformanceWarning(
context_.Say(source, "%s"_warn_en_US, warnStr);
}
}
void OmpAttributeVisitor::ResolveNames(const parser::OmpObjectList &objList) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I am a bit surprised that we needed to define this function. Was the resolution of names not handled anywhere else?

Copy link
Contributor Author

@anchuraj anchuraj Nov 13, 2024

Choose a reason for hiding this comment

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

Thank you for pointing this out. I believe I was not understanding the existing code well. I made use of ResolveOmpObjList function now.

Copy link
Contributor

@kiranchandramohan kiranchandramohan left a comment

Choose a reason for hiding this comment

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

LGTM. Nice work.

Copy link
Member

@skatrak skatrak left a comment

Choose a reason for hiding this comment

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

LGTM, thanks!

@anchuraj anchuraj merged commit e67e09a into llvm:main Nov 15, 2024
8 checks passed
anchuraj added a commit that referenced this pull request Jan 22, 2025
…114737)

Scan directive allows to specify scan reductions within an worksharing
loop, worksharing loop simd or simd directive which should have an
`InScan` modifier associated with it. This change adds the mlir support
for the same.

Related PR: [Parsing and Semantic Support for
scan](#102792)
github-actions bot pushed a commit to arm/arm-toolchain that referenced this pull request Jan 22, 2025
…support (#114737)

Scan directive allows to specify scan reductions within an worksharing
loop, worksharing loop simd or simd directive which should have an
`InScan` modifier associated with it. This change adds the mlir support
for the same.

Related PR: [Parsing and Semantic Support for
scan](llvm/llvm-project#102792)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:openmp OpenMP related changes to Clang flang:fir-hlfir flang:openmp flang:parser flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants