[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
Tue Nov 12 15:22:34 PST 2024
https://github.com/anchuraj updated https://github.com/llvm/llvm-project/pull/102792
>From c9942ccc492e2c31b4e8d8da7be1e961eba58cc7 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/8] 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 8b77f1ac6b4ff2..c887ae74cc8b08 100644
--- a/flang/lib/Lower/OpenMP/OpenMP.cpp
+++ b/flang/lib/Lower/OpenMP/OpenMP.cpp
@@ -2427,6 +2427,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 643b713b32e29d..fc0c61db2e599e 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);
}
}
@@ -2532,6 +2540,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 3b20d9e77e1cfe..a0d7d82de39b3b 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1590,9 +1590,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:
@@ -1603,6 +1605,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 e061e42798e78036b565b4b1f781a35fb7a0144c 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/8] 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 fc0c61db2e599e..372a28c1428fc0 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),
@@ -2537,15 +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.
- 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 a0d7d82de39b3b..fd71667264cc8e 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1611,8 +1611,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 d6873392ba0d69f7686851f3f3c4be7c990fe3f7 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/8] 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 372a28c1428fc0..f130b35a8359b2 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 7087dcf6c0ba92e75170cec6cfdd4a913c2e5a74 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/8] 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 fd71667264cc8e..12abf3ecc2c0b8 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1606,12 +1606,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 23fd9635590da7e898eca52347f5d5746386069a 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/8] 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 f130b35a8359b2..d8c37f8df37b49 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -2537,7 +2537,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 12abf3ecc2c0b8..c669bba9a40e24 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1611,7 +1611,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 "
>From d71e947022f3bcbdbce36fa8c145501054b9cc52 Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Mon, 9 Sep 2024 13:25:58 -0500
Subject: [PATCH 6/8] R6: Reworked to add a few more semantic checks and moved
checks to check-omp-structure
---
.../lib/Semantics/check-directive-structure.h | 4 +
flang/lib/Semantics/check-omp-structure.cpp | 148 ++++++++++++++++--
flang/lib/Semantics/check-omp-structure.h | 7 +-
flang/lib/Semantics/resolve-directives.cpp | 14 --
.../Lower/OpenMP/Todo/reduction-modifiers.f90 | 1 +
.../Semantics/OpenMP/reduction-modifiers.f90 | 3 +
flang/test/Semantics/OpenMP/scan.f90 | 14 +-
7 files changed, 156 insertions(+), 35 deletions(-)
diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index b32c10b0f3330b..9e16d4af832ae6 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -198,6 +198,10 @@ class DirectiveStructureChecker : public virtual BaseChecker {
ClauseMapTy clauseInfo;
std::list<C> actualClauses;
std::list<C> crtGroup;
+ std::set<std::string> usedInScanDirective;
+
+ using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
+ std::map<const std::string, ReductionModifier> reductionMod;
Symbol *loopIV{nullptr};
};
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index d8c37f8df37b49..cf981d7beb42f8 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -759,7 +759,43 @@ void OmpStructureChecker::CheckDistLinear(
}
}
-void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &) {
+void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
+ const auto &beginLoopDir = std::get<parser::OmpBeginLoopDirective>(x.t);
+ const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
+ for (const auto &clause : clauseList.v) {
+ if (const auto *reductionClause{
+ std::get_if<parser::OmpClause::Reduction>(&clause.u)}) {
+ using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
+ const auto &maybeModifier{
+ std::get<std::optional<ReductionModifier>>(reductionClause->v.t)};
+ if (maybeModifier && *maybeModifier == ReductionModifier::Inscan) {
+
+ const auto &objectList{
+ std::get<parser::OmpObjectList>(reductionClause->v.t)};
+ for (const auto &ompObj : objectList.v) {
+ common::visit(
+ common::visitors{
+ [&](const parser::Designator &designator) {
+ if (const auto *name{semantics::getDesignatorNameIfDataRef(
+ designator)}) {
+ std::string nameStr = name->symbol->name().ToString();
+ if (GetContext().usedInScanDirective.find(nameStr) ==
+ GetContext().usedInScanDirective.end()) {
+ context_.Say(name->source,
+ "List item %s must appear in 'inclusive' or "
+ "'exclusive' clause of an "
+ "enclosed scan directive"_err_en_US,
+ nameStr);
+ }
+ }
+ },
+ [&](const auto &name) {},
+ },
+ ompObj.u);
+ }
+ }
+ }
+ }
if (llvm::omp::allSimdSet.test(GetContext().directive)) {
ExitDirectiveNest(SIMDNest);
}
@@ -1391,19 +1427,32 @@ void OmpStructureChecker::Leave(const parser::OpenMPAllocatorsConstruct &x) {
dirContext_.pop_back();
}
+void OmpStructureChecker::CheckScan(
+ 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);
+ }
+ if (!CurrentDirectiveIsNested() ||
+ !llvm::omp::scanParentAllowedSet.test(GetContextParent().directive)) {
+ context_.Say(x.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);
+ }
+}
+
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) {
- if (IsCloselyNestedRegion(llvm::omp::nestedBarrierErrSet)) {
- context_.Say(parser::FindSourceLocation(x),
- "`BARRIER` region may not be closely nested inside of `WORKSHARING`, "
- "`LOOP`, `TASK`, `TASKLOOP`,"
- "`CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region."_err_en_US);
- }
+ if (IsCloselyNestedRegion(llvm::omp::nestedBarrierErrSet)) {
+ context_.Say(parser::FindSourceLocation(x),
+ "`BARRIER` region may not be closely nested inside of `WORKSHARING`, "
+ "`LOOP`, `TASK`, `TASKLOOP`,"
+ "`CRITICAL`, `ORDERED`, `ATOMIC` or `MASTER` region."_err_en_US);
}
}
@@ -1524,7 +1573,16 @@ void OmpStructureChecker::Enter(
const parser::OpenMPSimpleStandaloneConstruct &x) {
const auto &dir{std::get<parser::OmpSimpleStandaloneDirective>(x.t)};
PushContextAndClauseSets(dir.source, dir.v);
- CheckBarrierNesting(x);
+ switch (dir.v) {
+ case llvm::omp::Directive::OMPD_barrier:
+ CheckBarrierNesting(x);
+ break;
+ case llvm::omp::Directive::OMPD_scan:
+ CheckScan(x);
+ break;
+ default:
+ break;
+ }
}
void OmpStructureChecker::Leave(
@@ -2241,7 +2299,6 @@ CHECK_SIMPLE_CLAUSE(Destroy, OMPC_destroy)
CHECK_SIMPLE_CLAUSE(Detach, OMPC_detach)
CHECK_SIMPLE_CLAUSE(DeviceType, OMPC_device_type)
CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule)
-CHECK_SIMPLE_CLAUSE(Exclusive, OMPC_exclusive)
CHECK_SIMPLE_CLAUSE(Final, OMPC_final)
CHECK_SIMPLE_CLAUSE(Flush, OMPC_flush)
CHECK_SIMPLE_CLAUSE(From, OMPC_from)
@@ -2249,7 +2306,6 @@ CHECK_SIMPLE_CLAUSE(Full, OMPC_full)
CHECK_SIMPLE_CLAUSE(Hint, OMPC_hint)
CHECK_SIMPLE_CLAUSE(Holds, OMPC_holds)
CHECK_SIMPLE_CLAUSE(InReduction, OMPC_in_reduction)
-CHECK_SIMPLE_CLAUSE(Inclusive, OMPC_inclusive)
CHECK_SIMPLE_CLAUSE(Match, OMPC_match)
CHECK_SIMPLE_CLAUSE(Nontemporal, OMPC_nontemporal)
CHECK_SIMPLE_CLAUSE(Order, OMPC_order)
@@ -2322,7 +2378,24 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
if (CheckReductionOperators(x)) {
CheckReductionTypeList(x);
}
- CheckReductionModifier(x);
+ using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
+ if (const auto &maybeModifier{
+ std::get<std::optional<ReductionModifier>>(x.v.t)}) {
+ ReductionModifier modifier{*maybeModifier};
+ const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
+ addModifiertoMap(ompObjectList, modifier);
+ CheckReductionModifier(modifier);
+ }
+}
+
+void OmpStructureChecker::Enter(const parser::OmpClause::Inclusive &x) {
+ CheckAllowed(llvm::omp::Clause::OMPC_inclusive);
+ checkAndAddSymbolsToUsedInScanList(x.v);
+}
+
+void OmpStructureChecker::Enter(const parser::OmpClause::Exclusive &x) {
+ CheckAllowed(llvm::omp::Clause::OMPC_exclusive);
+ checkAndAddSymbolsToUsedInScanList(x.v);
}
bool OmpStructureChecker::CheckReductionOperators(
@@ -2365,6 +2438,49 @@ bool OmpStructureChecker::CheckReductionOperators(
return ok;
}
+
+void OmpStructureChecker::addModifiertoMap(const parser::OmpObjectList &x,
+ parser::OmpReductionClause::ReductionModifier &modifier) {
+ for (const auto &ompObject : x.v) {
+ if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
+ if (const auto *symbol{name->symbol}) {
+ GetContext().reductionMod[symbol->name().ToString()] = modifier;
+ }
+ }
+ }
+}
+
+void OmpStructureChecker::checkAndAddSymbolsToUsedInScanList(
+ const parser::OmpObjectList &x) {
+ for (const auto &ompObj : x.v) {
+ common::visit(
+ common::visitors{
+ [&](const parser::Designator &designator) {
+ if (const auto *name{
+ semantics::getDesignatorNameIfDataRef(designator)}) {
+ if (name->symbol) {
+ if (CurrentDirectiveIsNested()) {
+ std::string nameStr = name->symbol->name().ToString();
+ if (GetContextParent().reductionMod.find(nameStr) ==
+ GetContextParent().reductionMod.end()) {
+
+ context_.Say(name->source,
+ "List item %s must appear in 'reduction' clause "
+ "with the 'inscan' modifier of the parent "
+ "directive"_err_en_US,
+ nameStr);
+ }
+ GetContextParent().usedInScanDirective.insert(nameStr);
+ }
+ }
+ }
+ },
+ [&](const auto &name) {},
+ },
+ ompObj.u);
+ }
+}
+
bool OmpStructureChecker::CheckIntrinsicOperator(
const parser::DefinedOperator::IntrinsicOperator &op) {
@@ -2499,14 +2615,12 @@ void OmpStructureChecker::CheckReductionTypeList(
}
void OmpStructureChecker::CheckReductionModifier(
- const parser::OmpClause::Reduction &x) {
+ const parser::OmpReductionClause::ReductionModifier &modifier) {
using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
- const auto &maybeModifier{std::get<std::optional<ReductionModifier>>(x.v.t)};
- if (!maybeModifier || *maybeModifier == ReductionModifier::Default) {
- // No modifier, or the default one is always ok.
+ if (modifier == ReductionModifier::Default) {
+ // the default one is always ok.
return;
}
- ReductionModifier modifier{*maybeModifier};
const DirectiveContext &dirCtx{GetContext()};
if (dirCtx.directive == llvm::omp::Directive::OMPD_loop) {
// [5.2:257:33-34]
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 2cc1a78068f540..4319623f8ce0e6 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -205,10 +205,12 @@ class OmpStructureChecker
bool CheckIntrinsicOperator(
const parser::DefinedOperator::IntrinsicOperator &);
void CheckReductionTypeList(const parser::OmpClause::Reduction &);
- void CheckReductionModifier(const parser::OmpClause::Reduction &);
+ void CheckReductionModifier(
+ const parser::OmpReductionClause::ReductionModifier &);
void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
void ChecksOnOrderedAsBlock();
void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
+ void CheckScan(const parser::OpenMPSimpleStandaloneConstruct &x);
void ChecksOnOrderedAsStandalone();
void CheckOrderedDependClause(std::optional<std::int64_t> orderedValue);
void CheckReductionArraySection(const parser::OmpObjectList &ompObjectList);
@@ -223,6 +225,9 @@ class OmpStructureChecker
const parser::OmpObjectList &ompObjectList);
void CheckPredefinedAllocatorRestriction(
const parser::CharBlock &source, const parser::Name &name);
+ void checkAndAddSymbolsToUsedInScanList(const parser::OmpObjectList &x);
+ void addModifiertoMap(const parser::OmpObjectList &x,
+ parser::OmpReductionClause::ReductionModifier &modifier);
bool isPredefinedAllocator{false};
void CheckAllowedRequiresClause(llvmOmpClause clause);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index c669bba9a40e24..5cc570d579b6af 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -1590,7 +1590,6 @@ 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:
@@ -1605,19 +1604,6 @@ 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::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 "
- "loop simd or a simd directive."_err_en_US);
- }
- }
ClearDataSharingAttributeObjects();
return true;
}
diff --git a/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90 b/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
index 5e566466492ceb..82625ed8c5f31c 100644
--- a/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
+++ b/flang/test/Lower/OpenMP/Todo/reduction-modifiers.f90
@@ -8,6 +8,7 @@ subroutine foo()
j = 0
!$omp do reduction (inscan, *: j)
do i = 1, 10
+ !$omp scan inclusive(j)
j = j + 1
end do
end subroutine
diff --git a/flang/test/Semantics/OpenMP/reduction-modifiers.f90 b/flang/test/Semantics/OpenMP/reduction-modifiers.f90
index cf38200ba0a83e..31d21e9d4189cb 100644
--- a/flang/test/Semantics/OpenMP/reduction-modifiers.f90
+++ b/flang/test/Semantics/OpenMP/reduction-modifiers.f90
@@ -39,6 +39,7 @@ subroutine mod_inscan1(x)
!Correct: worksharing-loop directive
!$omp do reduction(inscan, +:x)
do i = 1, 100
+ !$omp scan inclusive(x)
x = foo(i)
enddo
!$omp end do
@@ -50,6 +51,7 @@ subroutine mod_inscan2(x)
!Correct: worksharing-loop simd directive
!$omp do simd reduction(inscan, +:x)
do i = 1, 100
+ !$omp scan inclusive(x)
x = foo(i)
enddo
!$omp end do simd
@@ -61,6 +63,7 @@ subroutine mod_inscan3(x)
!Correct: "simd" directive
!$omp simd reduction(inscan, +:x)
do i = 1, 100
+ !$omp scan inclusive(x)
x = foo(i)
enddo
!$omp end simd
diff --git a/flang/test/Semantics/OpenMP/scan.f90 b/flang/test/Semantics/OpenMP/scan.f90
index e82982f60b9021..c7526d31df4acb 100644
--- a/flang/test/Semantics/OpenMP/scan.f90
+++ b/flang/test/Semantics/OpenMP/scan.f90
@@ -1,17 +1,17 @@
! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
subroutine test_scan()
- integer x, y, k
+ integer x, y, k, z
!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)
+ !$omp parallel do simd
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)
+ !$omp parallel do simd
do k = 1, n
!ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
!$omp scan
@@ -22,4 +22,12 @@ subroutine test_scan()
!ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
!$omp scan inclusive(x) exclusive(y)
end do
+
+!ERROR: List item y must appear in 'inclusive' or 'exclusive' clause of an enclosed scan directive
+!$omp parallel do simd reduction(inscan,+: x, y)
+ do k = 1, n
+ !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
+ !ERROR: List item z must appear in 'reduction' clause with the 'inscan' modifier of the parent directive
+ !$omp scan inclusive(x) exclusive(z)
+ end do
end subroutine
>From 693760eeed647f6bf19ba007e553087d6b2d90a0 Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Fri, 20 Sep 2024 13:05:25 -0500
Subject: [PATCH 7/8] R7: Addressed a few review comments
---
.../flang/Semantics/openmp-directive-sets.h | 5 +-
flang/lib/Semantics/check-omp-structure.cpp | 83 ++++++++++---------
flang/lib/Semantics/check-omp-structure.h | 10 +--
3 files changed, 52 insertions(+), 46 deletions(-)
diff --git a/flang/include/flang/Semantics/openmp-directive-sets.h b/flang/include/flang/Semantics/openmp-directive-sets.h
index 271f4c4697c6d2..e1d0c43f5a16d6 100644
--- a/flang/include/flang/Semantics/openmp-directive-sets.h
+++ b/flang/include/flang/Semantics/openmp-directive-sets.h
@@ -186,7 +186,7 @@ static const OmpDirectiveSet allTeamsSet{
// Directive sets for groups of multiple directives
//===----------------------------------------------------------------------===//
-// Directive sets that form Composite constructs
+// Composite constructs
static const OmpDirectiveSet allDistributeParallelDoSet{
allDistributeSet & allParallelSet & allDoSet};
static const OmpDirectiveSet allDistributeParallelDoSimdSet{
@@ -288,9 +288,10 @@ static const OmpDirectiveSet workShareSet{
//===----------------------------------------------------------------------===//
// Directive sets for parent directives that do allow/not allow a construct
-static const OmpDirectiveSet scanParentAllowedSet{allDoSet | allSimdSet};
//===----------------------------------------------------------------------===//
+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 cf981d7beb42f8..1ccdecccb9c045 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -760,36 +760,40 @@ void OmpStructureChecker::CheckDistLinear(
}
void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
- const auto &beginLoopDir = std::get<parser::OmpBeginLoopDirective>(x.t);
+ const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
for (const auto &clause : clauseList.v) {
if (const auto *reductionClause{
std::get_if<parser::OmpClause::Reduction>(&clause.u)}) {
- using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
const auto &maybeModifier{
std::get<std::optional<ReductionModifier>>(reductionClause->v.t)};
if (maybeModifier && *maybeModifier == ReductionModifier::Inscan) {
const auto &objectList{
std::get<parser::OmpObjectList>(reductionClause->v.t)};
+ auto checkReductionSymbolInScan = [&](const parser::Name *name) {
+ if (name->symbol) {
+ std::string nameStr = name->symbol->name().ToString();
+ if (GetContext().usedInScanDirective.find(nameStr) ==
+ GetContext().usedInScanDirective.end()) {
+ context_.Say(name->source,
+ "List item %s must appear in 'inclusive' or "
+ "'exclusive' clause of an "
+ "enclosed scan directive"_err_en_US,
+ nameStr);
+ }
+ }
+ };
for (const auto &ompObj : objectList.v) {
common::visit(
common::visitors{
[&](const parser::Designator &designator) {
if (const auto *name{semantics::getDesignatorNameIfDataRef(
designator)}) {
- std::string nameStr = name->symbol->name().ToString();
- if (GetContext().usedInScanDirective.find(nameStr) ==
- GetContext().usedInScanDirective.end()) {
- context_.Say(name->source,
- "List item %s must appear in 'inclusive' or "
- "'exclusive' clause of an "
- "enclosed scan directive"_err_en_US,
- nameStr);
- }
+ checkReductionSymbolInScan(name);
}
},
- [&](const auto &name) {},
+ [&](const auto &name) { checkReductionSymbolInScan(&name); },
},
ompObj.u);
}
@@ -2378,24 +2382,23 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
if (CheckReductionOperators(x)) {
CheckReductionTypeList(x);
}
- using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
if (const auto &maybeModifier{
std::get<std::optional<ReductionModifier>>(x.v.t)}) {
- ReductionModifier modifier{*maybeModifier};
+ const ReductionModifier modifier{*maybeModifier};
const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
- addModifiertoMap(ompObjectList, modifier);
+ AddModifierToMap(ompObjectList, modifier);
CheckReductionModifier(modifier);
}
}
void OmpStructureChecker::Enter(const parser::OmpClause::Inclusive &x) {
CheckAllowed(llvm::omp::Clause::OMPC_inclusive);
- checkAndAddSymbolsToUsedInScanList(x.v);
+ CheckAndAddSymbolsToUsedInScanList(x.v);
}
void OmpStructureChecker::Enter(const parser::OmpClause::Exclusive &x) {
CheckAllowed(llvm::omp::Clause::OMPC_exclusive);
- checkAndAddSymbolsToUsedInScanList(x.v);
+ CheckAndAddSymbolsToUsedInScanList(x.v);
}
bool OmpStructureChecker::CheckReductionOperators(
@@ -2439,8 +2442,8 @@ bool OmpStructureChecker::CheckReductionOperators(
return ok;
}
-void OmpStructureChecker::addModifiertoMap(const parser::OmpObjectList &x,
- parser::OmpReductionClause::ReductionModifier &modifier) {
+void OmpStructureChecker::AddModifierToMap(
+ const parser::OmpObjectList &x, const ReductionModifier &modifier) {
for (const auto &ompObject : x.v) {
if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
if (const auto *symbol{name->symbol}) {
@@ -2450,32 +2453,35 @@ void OmpStructureChecker::addModifiertoMap(const parser::OmpObjectList &x,
}
}
-void OmpStructureChecker::checkAndAddSymbolsToUsedInScanList(
+void OmpStructureChecker::CheckAndAddSymbolsToUsedInScanList(
const parser::OmpObjectList &x) {
for (const auto &ompObj : x.v) {
+ auto checkScanSymbolInReduction = [&](const parser::Name *name) {
+ if (name->symbol) {
+ if (CurrentDirectiveIsNested()) {
+ std::string nameStr = name->symbol->name().ToString();
+ if (GetContextParent().reductionMod.find(nameStr) ==
+ GetContextParent().reductionMod.end()) {
+
+ context_.Say(name->source,
+ "List item %s must appear in 'reduction' clause "
+ "with the 'inscan' modifier of the parent "
+ "directive"_err_en_US,
+ nameStr);
+ }
+ GetContextParent().usedInScanDirective.insert(nameStr);
+ }
+ }
+ };
common::visit(
common::visitors{
[&](const parser::Designator &designator) {
if (const auto *name{
semantics::getDesignatorNameIfDataRef(designator)}) {
- if (name->symbol) {
- if (CurrentDirectiveIsNested()) {
- std::string nameStr = name->symbol->name().ToString();
- if (GetContextParent().reductionMod.find(nameStr) ==
- GetContextParent().reductionMod.end()) {
-
- context_.Say(name->source,
- "List item %s must appear in 'reduction' clause "
- "with the 'inscan' modifier of the parent "
- "directive"_err_en_US,
- nameStr);
- }
- GetContextParent().usedInScanDirective.insert(nameStr);
- }
- }
+ checkScanSymbolInReduction(name);
}
},
- [&](const auto &name) {},
+ [&](const auto &name) { checkScanSymbolInReduction(&name); },
},
ompObj.u);
}
@@ -2615,10 +2621,9 @@ void OmpStructureChecker::CheckReductionTypeList(
}
void OmpStructureChecker::CheckReductionModifier(
- const parser::OmpReductionClause::ReductionModifier &modifier) {
- using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
+ const ReductionModifier &modifier) {
if (modifier == ReductionModifier::Default) {
- // the default one is always ok.
+ // The default one is always ok.
return;
}
const DirectiveContext &dirCtx{GetContext()};
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 4319623f8ce0e6..dc3c6627a9e207 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -67,6 +67,7 @@ class OmpStructureChecker
) {
}
using llvmOmpClause = const llvm::omp::Clause;
+ using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
void Enter(const parser::OpenMPConstruct &);
void Enter(const parser::OpenMPLoopConstruct &);
@@ -205,8 +206,7 @@ class OmpStructureChecker
bool CheckIntrinsicOperator(
const parser::DefinedOperator::IntrinsicOperator &);
void CheckReductionTypeList(const parser::OmpClause::Reduction &);
- void CheckReductionModifier(
- const parser::OmpReductionClause::ReductionModifier &);
+ void CheckReductionModifier(const ReductionModifier &);
void CheckMasterNesting(const parser::OpenMPBlockConstruct &x);
void ChecksOnOrderedAsBlock();
void CheckBarrierNesting(const parser::OpenMPSimpleStandaloneConstruct &x);
@@ -225,9 +225,9 @@ class OmpStructureChecker
const parser::OmpObjectList &ompObjectList);
void CheckPredefinedAllocatorRestriction(
const parser::CharBlock &source, const parser::Name &name);
- void checkAndAddSymbolsToUsedInScanList(const parser::OmpObjectList &x);
- void addModifiertoMap(const parser::OmpObjectList &x,
- parser::OmpReductionClause::ReductionModifier &modifier);
+ void CheckAndAddSymbolsToUsedInScanList(const parser::OmpObjectList &x);
+ void AddModifierToMap(
+ const parser::OmpObjectList &x, const ReductionModifier &modifier);
bool isPredefinedAllocator{false};
void CheckAllowedRequiresClause(llvmOmpClause clause);
>From 9e4724c632d70c476ebf070f916d20a20aa6b04f Mon Sep 17 00:00:00 2001
From: Anchu Rajendran <asudhaku at amd.com>
Date: Thu, 7 Nov 2024 16:19:46 -0600
Subject: [PATCH 8/8] R8: converting string refs to symbol*
---
.../lib/Semantics/check-directive-structure.h | 4 -
flang/lib/Semantics/check-omp-structure.cpp | 78 +++++++++----------
flang/lib/Semantics/check-omp-structure.h | 43 +++++++++-
flang/lib/Semantics/resolve-directives.cpp | 28 +++++++
.../Semantics/OpenMP/reduction-modifiers.f90 | 4 +-
flang/test/Semantics/OpenMP/scan.f90 | 12 +--
6 files changed, 115 insertions(+), 54 deletions(-)
diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index 9e16d4af832ae6..b32c10b0f3330b 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -198,10 +198,6 @@ class DirectiveStructureChecker : public virtual BaseChecker {
ClauseMapTy clauseInfo;
std::list<C> actualClauses;
std::list<C> crtGroup;
- std::set<std::string> usedInScanDirective;
-
- using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
- std::map<const std::string, ReductionModifier> reductionMod;
Symbol *loopIV{nullptr};
};
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 1ccdecccb9c045..b68bee1a9aa933 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -762,6 +762,12 @@ void OmpStructureChecker::CheckDistLinear(
void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
+
+ // A few semantic checks for InScan reduction are performed below as SCAN
+ // constructs inside LOOP may add the relevant information. Scan reduction is
+ // supported only in loop constructs, so same checks are not applicable to
+ // other directives.
+
for (const auto &clause : clauseList.v) {
if (const auto *reductionClause{
std::get_if<parser::OmpClause::Reduction>(&clause.u)}) {
@@ -773,14 +779,13 @@ void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
std::get<parser::OmpObjectList>(reductionClause->v.t)};
auto checkReductionSymbolInScan = [&](const parser::Name *name) {
if (name->symbol) {
- std::string nameStr = name->symbol->name().ToString();
- if (GetContext().usedInScanDirective.find(nameStr) ==
- GetContext().usedInScanDirective.end()) {
+ if (!scanReductionInfoStack.top().findSymbolInScanConstruct(
+ name->symbol)) {
context_.Say(name->source,
- "List item %s must appear in 'inclusive' or "
- "'exclusive' clause of an "
- "enclosed scan directive"_err_en_US,
- nameStr);
+ "List item %s must appear in EXCLUSIVE or "
+ "INCLUSIVE clause of an "
+ "enclosed SCAN directive"_err_en_US,
+ name->ToString());
}
}
};
@@ -797,6 +802,7 @@ void OmpStructureChecker::Leave(const parser::OpenMPLoopConstruct &x) {
},
ompObj.u);
}
+ scanReductionInfoStack.pop();
}
}
}
@@ -1435,14 +1441,14 @@ void OmpStructureChecker::CheckScan(
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);
+ "Exactly one of EXCLUSIVE or INCLUSIVE clause is expected"_err_en_US);
}
if (!CurrentDirectiveIsNested() ||
!llvm::omp::scanParentAllowedSet.test(GetContextParent().directive)) {
context_.Say(x.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);
+ "Orphaned 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);
}
}
@@ -2385,20 +2391,24 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Reduction &x) {
if (const auto &maybeModifier{
std::get<std::optional<ReductionModifier>>(x.v.t)}) {
const ReductionModifier modifier{*maybeModifier};
- const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
- AddModifierToMap(ompObjectList, modifier);
+ if (modifier == ReductionModifier::Inscan) {
+ scanReductionInfoStack.emplace();
+ const auto &ompObjectList{std::get<parser::OmpObjectList>(x.v.t)};
+ scanReductionInfoStack.top().mapSymbolsToReductionModifiers(
+ ompObjectList, modifier);
+ }
CheckReductionModifier(modifier);
}
}
void OmpStructureChecker::Enter(const parser::OmpClause::Inclusive &x) {
CheckAllowed(llvm::omp::Clause::OMPC_inclusive);
- CheckAndAddSymbolsToUsedInScanList(x.v);
+ CheckAndMarkSymbolsUsedInScan(x.v);
}
void OmpStructureChecker::Enter(const parser::OmpClause::Exclusive &x) {
CheckAllowed(llvm::omp::Clause::OMPC_exclusive);
- CheckAndAddSymbolsToUsedInScanList(x.v);
+ CheckAndMarkSymbolsUsedInScan(x.v);
}
bool OmpStructureChecker::CheckReductionOperators(
@@ -2442,34 +2452,24 @@ bool OmpStructureChecker::CheckReductionOperators(
return ok;
}
-void OmpStructureChecker::AddModifierToMap(
- const parser::OmpObjectList &x, const ReductionModifier &modifier) {
- for (const auto &ompObject : x.v) {
- if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
- if (const auto *symbol{name->symbol}) {
- GetContext().reductionMod[symbol->name().ToString()] = modifier;
- }
- }
- }
-}
-
-void OmpStructureChecker::CheckAndAddSymbolsToUsedInScanList(
+void OmpStructureChecker::CheckAndMarkSymbolsUsedInScan(
const parser::OmpObjectList &x) {
for (const auto &ompObj : x.v) {
- auto checkScanSymbolInReduction = [&](const parser::Name *name) {
+ auto checkAndMark = [&](const parser::Name *name) {
if (name->symbol) {
if (CurrentDirectiveIsNested()) {
- std::string nameStr = name->symbol->name().ToString();
- if (GetContextParent().reductionMod.find(nameStr) ==
- GetContextParent().reductionMod.end()) {
-
+ ScanReductionInfo &scanReductionInfo = scanReductionInfoStack.top();
+ std::optional<ReductionModifier> reductionMod =
+ scanReductionInfo.findReductionModifier(name->symbol);
+ if (!reductionMod.has_value() ||
+ reductionMod.value() != ReductionModifier::Inscan) {
context_.Say(name->source,
- "List item %s must appear in 'reduction' clause "
- "with the 'inscan' modifier of the parent "
+ "List item %s must appear in REDUCTION clause "
+ "with the INSCAN modifier of the parent "
"directive"_err_en_US,
- nameStr);
+ name->ToString());
}
- GetContextParent().usedInScanDirective.insert(nameStr);
+ scanReductionInfo.markSymbolAsUsedInScanConstruct(name->symbol);
}
}
};
@@ -2478,10 +2478,10 @@ void OmpStructureChecker::CheckAndAddSymbolsToUsedInScanList(
[&](const parser::Designator &designator) {
if (const auto *name{
semantics::getDesignatorNameIfDataRef(designator)}) {
- checkScanSymbolInReduction(name);
+ checkAndMark(name);
}
},
- [&](const auto &name) { checkScanSymbolInReduction(&name); },
+ [&](const auto &name) { checkAndMark(&name); },
},
ompObj.u);
}
@@ -2659,7 +2659,7 @@ void OmpStructureChecker::CheckReductionModifier(
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, "
+ "WORKSHARING LOOP, WORKSHARING LOOP SIMD, "
"or SIMD directive"_err_en_US);
}
} else {
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index dc3c6627a9e207..ca4608e8fff3c0 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -20,6 +20,8 @@
#include "flang/Semantics/openmp-directive-sets.h"
#include "flang/Semantics/semantics.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
+#include <optional>
+#include <stack>
using OmpClauseSet =
Fortran::common::EnumSet<llvm::omp::Clause, llvm::omp::Clause_enumSize>;
@@ -68,6 +70,43 @@ class OmpStructureChecker
}
using llvmOmpClause = const llvm::omp::Clause;
using ReductionModifier = parser::OmpReductionClause::ReductionModifier;
+ using Symbol = Fortran::semantics::Symbol;
+ class ScanReductionInfo {
+
+ public:
+ std::set<Symbol *> usedInScanDirective;
+ std::map<Symbol *, ReductionModifier> reductionMod;
+
+ void mapSymbolsToReductionModifiers(
+ const parser::OmpObjectList &x, const ReductionModifier &modifier) {
+ for (const auto &ompObject : x.v) {
+ if (const auto *name{parser::Unwrap<parser::Name>(ompObject)}) {
+ if (const auto &symbol{name->symbol}) {
+ reductionMod[symbol] = modifier;
+ }
+ }
+ }
+ }
+
+ void markSymbolAsUsedInScanConstruct(Symbol *sym) {
+ usedInScanDirective.insert(sym);
+ }
+
+ bool findSymbolInScanConstruct(Symbol *sym) {
+ if (usedInScanDirective.find(sym) != usedInScanDirective.end()) {
+ return true;
+ }
+ return false;
+ }
+
+ std::optional<ReductionModifier> findReductionModifier(Symbol *sym) {
+ if (reductionMod.find(sym) != reductionMod.end()) {
+ return reductionMod[sym];
+ }
+ return std::nullopt;
+ }
+ };
+ std::stack<class ScanReductionInfo> scanReductionInfoStack;
void Enter(const parser::OpenMPConstruct &);
void Enter(const parser::OpenMPLoopConstruct &);
@@ -225,9 +264,7 @@ class OmpStructureChecker
const parser::OmpObjectList &ompObjectList);
void CheckPredefinedAllocatorRestriction(
const parser::CharBlock &source, const parser::Name &name);
- void CheckAndAddSymbolsToUsedInScanList(const parser::OmpObjectList &x);
- void AddModifierToMap(
- const parser::OmpObjectList &x, const ReductionModifier &modifier);
+ void CheckAndMarkSymbolsUsedInScan(const parser::OmpObjectList &x);
bool isPredefinedAllocator{false};
void CheckAllowedRequiresClause(llvmOmpClause clause);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 5cc570d579b6af..c2847c84cfb0b3 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -20,6 +20,7 @@
#include "flang/Parser/tools.h"
#include "flang/Semantics/expression.h"
#include "flang/Semantics/tools.h"
+#include <iostream>
#include <list>
#include <map>
#include <sstream>
@@ -435,6 +436,18 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
void Post(const parser::OpenMPAllocatorsConstruct &);
// 2.15.3 Data-Sharing Attribute Clauses
+ void ResolveNames(const parser::OmpObjectList &objList);
+
+ bool Pre(const parser::OmpClause::Inclusive &x) {
+ const auto &objectList{x.v};
+ ResolveNames(objectList);
+ return false;
+ }
+ bool Pre(const parser::OmpClause::Exclusive &x) {
+ const auto &objectList{x.v};
+ ResolveNames(objectList);
+ return false;
+ }
void Post(const parser::OmpDefaultClause &);
bool Pre(const parser::OmpClause::Shared &x) {
ResolveOmpObjectList(x.v, Symbol::Flag::OmpShared);
@@ -2866,4 +2879,19 @@ void OmpAttributeVisitor::IssueNonConformanceWarning(
context_.Say(source, "%s"_warn_en_US, warnStr);
}
}
+void OmpAttributeVisitor::ResolveNames(const parser::OmpObjectList &objList) {
+ for (const auto &ompObj : objList.v) {
+ common::visit(
+ common::visitors{
+ [&](const parser::Designator &designator) {
+ if (const auto *name{
+ semantics::getDesignatorNameIfDataRef(designator)}) {
+ ResolveName(name);
+ }
+ },
+ [&](const auto &name) { ResolveName(&name); },
+ },
+ ompObj.u);
+ }
+}
} // namespace Fortran::semantics
diff --git a/flang/test/Semantics/OpenMP/reduction-modifiers.f90 b/flang/test/Semantics/OpenMP/reduction-modifiers.f90
index 31d21e9d4189cb..e6238bb8cb7ffc 100644
--- a/flang/test/Semantics/OpenMP/reduction-modifiers.f90
+++ b/flang/test/Semantics/OpenMP/reduction-modifiers.f90
@@ -72,7 +72,7 @@ subroutine mod_inscan3(x)
subroutine mod_inscan4(x)
integer, intent(inout) :: x
- !ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with worksharing-loop, worksharing-loop simd, or SIMD directive
+ !ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with WORKSHARING LOOP, WORKSHARING LOOP SIMD, or SIMD directive
!$omp parallel reduction(inscan, +:x)
do i = 1, 100
x = foo(i)
@@ -83,7 +83,7 @@ subroutine mod_inscan4(x)
subroutine mod_inscan5(x)
integer, intent(inout) :: x
- !ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with worksharing-loop, worksharing-loop simd, or SIMD directive
+ !ERROR: Modifier 'INSCAN' on REDUCTION clause is only allowed with WORKSHARING LOOP, WORKSHARING LOOP SIMD, or SIMD directive
!$omp sections reduction(inscan, +:x)
do i = 1, 100
x = foo(i)
diff --git a/flang/test/Semantics/OpenMP/scan.f90 b/flang/test/Semantics/OpenMP/scan.f90
index c7526d31df4acb..4535a73650cf7d 100644
--- a/flang/test/Semantics/OpenMP/scan.f90
+++ b/flang/test/Semantics/OpenMP/scan.f90
@@ -3,7 +3,7 @@
subroutine test_scan()
integer x, y, k, z
- !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.
+ !ERROR: Orphaned 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
do k = 1, n
@@ -13,21 +13,21 @@ subroutine test_scan()
!$omp parallel do simd
do k = 1, n
- !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
+ !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
!$omp scan
end do
!$omp parallel do simd reduction(inscan,+: x, y)
do k = 1, n
- !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
+ !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
!$omp scan inclusive(x) exclusive(y)
end do
-!ERROR: List item y must appear in 'inclusive' or 'exclusive' clause of an enclosed scan directive
+!ERROR: List item y must appear in EXCLUSIVE or INCLUSIVE clause of an enclosed SCAN directive
!$omp parallel do simd reduction(inscan,+: x, y)
do k = 1, n
- !ERROR: Exactly one of `exclusive` or `inclusive` clause is expected
- !ERROR: List item z must appear in 'reduction' clause with the 'inscan' modifier of the parent directive
+ !ERROR: Exactly one of EXCLUSIVE or INCLUSIVE clause is expected
+ !ERROR: List item z must appear in REDUCTION clause with the INSCAN modifier of the parent directive
!$omp scan inclusive(x) exclusive(z)
end do
end subroutine
More information about the flang-commits
mailing list