[flang-commits] [flang] [flang][openacc] bug fix in semantic checking (PR #155659)
Andre Kuhlenschmidt via flang-commits
flang-commits at lists.llvm.org
Wed Aug 27 14:58:00 PDT 2025
https://github.com/akuhlens updated https://github.com/llvm/llvm-project/pull/155659
>From 3e276d91c1df923acc3eb52f2e998d68d46c9200 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Mon, 25 Aug 2025 10:49:13 -0700
Subject: [PATCH 1/2] initial commit
---
flang/lib/Semantics/resolve-directives.cpp | 47 +++++++++++++++----
flang/test/Semantics/OpenACC/acc-parallel.f90 | 22 +++++++++
2 files changed, 60 insertions(+), 9 deletions(-)
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 3c59085812989..05efc4f1da910 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -29,7 +29,6 @@
#include "llvm/Support/Debug.h"
#include <list>
#include <map>
-#include <sstream>
template <typename T>
static Fortran::semantics::Scope *GetScope(
@@ -61,6 +60,14 @@ template <typename T> class DirectiveAttributeVisitor {
parser::OmpDefaultmapClause::ImplicitBehavior>
defaultMap;
+ std::optional<Symbol::Flag> FindSymbolWithDSA(const Symbol &symbol) {
+ auto it{objectWithDSA.find(&symbol)};
+ if (it != objectWithDSA.end()) {
+ return std::make_optional(it->second);
+ }
+ return std::nullopt;
+ }
+
bool withinConstruct{false};
std::int64_t associatedLoopLevel{0};
};
@@ -75,10 +82,20 @@ template <typename T> class DirectiveAttributeVisitor {
: std::make_optional<DirContext>(dirContext_.back());
}
void PushContext(const parser::CharBlock &source, T dir, Scope &scope) {
- dirContext_.emplace_back(source, dir, scope);
+ if constexpr (std::is_same_v<T, llvm::acc::Directive>) {
+ bool wasEmpty{dirContext_.empty()};
+ dirContext_.emplace_back(source, dir, scope);
+ if (!wasEmpty) {
+ std::size_t lastIndex{dirContext_.size() - 1};
+ dirContext_[lastIndex].defaultDSA =
+ dirContext_[lastIndex - 1].defaultDSA;
+ }
+ } else {
+ dirContext_.emplace_back(source, dir, scope);
+ }
}
void PushContext(const parser::CharBlock &source, T dir) {
- dirContext_.emplace_back(source, dir, context_.FindScope(source));
+ PushContext(source, dir, context_.FindScope(source));
}
void PopContext() { dirContext_.pop_back(); }
void SetContextDirectiveSource(parser::CharBlock &dir) {
@@ -100,9 +117,21 @@ template <typename T> class DirectiveAttributeVisitor {
AddToContextObjectWithDSA(symbol, flag, GetContext());
}
bool IsObjectWithDSA(const Symbol &symbol) {
- auto it{GetContext().objectWithDSA.find(&symbol)};
- return it != GetContext().objectWithDSA.end();
+ return GetContext().FindSymbolWithDSA(symbol).has_value();
+ }
+ bool IsObjectWithVisibleDSA(const Symbol &symbol) {
+ for (std::size_t i{dirContext_.size()}; i != 0; i--) {
+ if (dirContext_[i - 1].FindSymbolWithDSA(symbol).has_value()) {
+ return true;
+ }
+ }
+ return false;
}
+
+ bool WithinContstruct() {
+ return !dirContext_.empty() && GetContext().withinConstruct;
+ }
+
void SetContextAssociatedLoopLevel(std::int64_t level) {
GetContext().associatedLoopLevel = level;
}
@@ -1573,10 +1602,10 @@ void AccAttributeVisitor::Post(const parser::AccDefaultClause &x) {
// and adjust the symbol for each Name if necessary
void AccAttributeVisitor::Post(const parser::Name &name) {
auto *symbol{name.symbol};
- if (symbol && !dirContext_.empty() && GetContext().withinConstruct) {
+ if (symbol && WithinContstruct()) {
symbol = &symbol->GetUltimate();
if (!symbol->owner().IsDerivedType() && !symbol->has<ProcEntityDetails>() &&
- !symbol->has<SubprogramDetails>() && !IsObjectWithDSA(*symbol)) {
+ !symbol->has<SubprogramDetails>() && !IsObjectWithVisibleDSA(*symbol)) {
if (Symbol * found{currScope().FindSymbol(name.source)}) {
if (symbol != found) {
name.symbol = found; // adjust the symbol within region
@@ -1959,7 +1988,7 @@ void OmpAttributeVisitor::ResolveSeqLoopIndexInParallelOrTaskConstruct(
// till OpenMP-5.0 standard.
// In above both cases we skip the privatization of iteration variables.
bool OmpAttributeVisitor::Pre(const parser::DoConstruct &x) {
- if (!dirContext_.empty() && GetContext().withinConstruct) {
+ if (WithinContstruct()) {
llvm::SmallVector<const parser::Name *> ivs;
if (x.IsDoNormal()) {
const parser::Name *iv{GetLoopIndex(x)};
@@ -2685,7 +2714,7 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
void OmpAttributeVisitor::Post(const parser::Name &name) {
auto *symbol{name.symbol};
- if (symbol && !dirContext_.empty() && GetContext().withinConstruct) {
+ if (symbol && WithinContstruct()) {
if (IsPrivatizable(symbol) && !IsObjectWithDSA(*symbol)) {
// TODO: create a separate function to go through the rules for
// predetermined, explicitly determined, and implicitly
diff --git a/flang/test/Semantics/OpenACC/acc-parallel.f90 b/flang/test/Semantics/OpenACC/acc-parallel.f90
index 635c547f744c8..52e267f6910da 100644
--- a/flang/test/Semantics/OpenACC/acc-parallel.f90
+++ b/flang/test/Semantics/OpenACC/acc-parallel.f90
@@ -200,3 +200,25 @@ program openacc_parallel_validity
!$acc end parallel
end program openacc_parallel_validity
+
+subroutine acc_parallel_default_none
+ integer :: i, l
+ real :: a(10,10)
+ l = 10
+ !$acc parallel default(none)
+ !$acc loop
+ !ERROR: The DEFAULT(NONE) clause requires that 'l' must be listed in a data-mapping clause
+ do i = 1, l
+ !ERROR: The DEFAULT(NONE) clause requires that 'a' must be listed in a data-mapping clause
+ a(1,i) = 1
+ end do
+ !$acc end parallel
+
+ !$acc data copy(a)
+ !$acc parallel loop firstprivate(l) default(none)
+ do i = 1, l
+ a(1,i) = 1
+ end do
+ !$acc end parallel
+ !$acc end data
+end subroutine acc_parallel_default_none
\ No newline at end of file
>From 7672b0fe65e956dbd3488dfe4ffabe2ab3c6e829 Mon Sep 17 00:00:00 2001
From: Andre Kuhlenschmidt <akuhlenschmi at nvidia.com>
Date: Wed, 27 Aug 2025 14:57:18 -0700
Subject: [PATCH 2/2] address feedback
---
flang/lib/Semantics/resolve-directives.cpp | 18 ++++++++----------
flang/test/Semantics/OpenACC/acc-parallel.f90 | 2 +-
2 files changed, 9 insertions(+), 11 deletions(-)
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 05efc4f1da910..c3568799c2159 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -61,9 +61,8 @@ template <typename T> class DirectiveAttributeVisitor {
defaultMap;
std::optional<Symbol::Flag> FindSymbolWithDSA(const Symbol &symbol) {
- auto it{objectWithDSA.find(&symbol)};
- if (it != objectWithDSA.end()) {
- return std::make_optional(it->second);
+ if (auto it{objectWithDSA.find(&symbol)}; it != objectWithDSA.end()) {
+ return it->second;
}
return std::nullopt;
}
@@ -83,10 +82,9 @@ template <typename T> class DirectiveAttributeVisitor {
}
void PushContext(const parser::CharBlock &source, T dir, Scope &scope) {
if constexpr (std::is_same_v<T, llvm::acc::Directive>) {
- bool wasEmpty{dirContext_.empty()};
dirContext_.emplace_back(source, dir, scope);
- if (!wasEmpty) {
- std::size_t lastIndex{dirContext_.size() - 1};
+ if (std::size_t size{dirContext_.size()}; size > 1) {
+ std::size_t lastIndex{size - 1};
dirContext_[lastIndex].defaultDSA =
dirContext_[lastIndex - 1].defaultDSA;
}
@@ -128,7 +126,7 @@ template <typename T> class DirectiveAttributeVisitor {
return false;
}
- bool WithinContstruct() {
+ bool WithinConstruct() {
return !dirContext_.empty() && GetContext().withinConstruct;
}
@@ -1602,7 +1600,7 @@ void AccAttributeVisitor::Post(const parser::AccDefaultClause &x) {
// and adjust the symbol for each Name if necessary
void AccAttributeVisitor::Post(const parser::Name &name) {
auto *symbol{name.symbol};
- if (symbol && WithinContstruct()) {
+ if (symbol && WithinConstruct()) {
symbol = &symbol->GetUltimate();
if (!symbol->owner().IsDerivedType() && !symbol->has<ProcEntityDetails>() &&
!symbol->has<SubprogramDetails>() && !IsObjectWithVisibleDSA(*symbol)) {
@@ -1988,7 +1986,7 @@ void OmpAttributeVisitor::ResolveSeqLoopIndexInParallelOrTaskConstruct(
// till OpenMP-5.0 standard.
// In above both cases we skip the privatization of iteration variables.
bool OmpAttributeVisitor::Pre(const parser::DoConstruct &x) {
- if (WithinContstruct()) {
+ if (WithinConstruct()) {
llvm::SmallVector<const parser::Name *> ivs;
if (x.IsDoNormal()) {
const parser::Name *iv{GetLoopIndex(x)};
@@ -2714,7 +2712,7 @@ void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
void OmpAttributeVisitor::Post(const parser::Name &name) {
auto *symbol{name.symbol};
- if (symbol && WithinContstruct()) {
+ if (symbol && WithinConstruct()) {
if (IsPrivatizable(symbol) && !IsObjectWithDSA(*symbol)) {
// TODO: create a separate function to go through the rules for
// predetermined, explicitly determined, and implicitly
diff --git a/flang/test/Semantics/OpenACC/acc-parallel.f90 b/flang/test/Semantics/OpenACC/acc-parallel.f90
index 52e267f6910da..45c0fafbed1b6 100644
--- a/flang/test/Semantics/OpenACC/acc-parallel.f90
+++ b/flang/test/Semantics/OpenACC/acc-parallel.f90
@@ -221,4 +221,4 @@ subroutine acc_parallel_default_none
end do
!$acc end parallel
!$acc end data
-end subroutine acc_parallel_default_none
\ No newline at end of file
+end subroutine acc_parallel_default_none
More information about the flang-commits
mailing list