[flang-commits] [flang] ff25b2d - [flang][openacc] Basic name resolution infrastructure for OpenACC construct
via flang-commits
flang-commits at lists.llvm.org
Sun Jul 26 17:01:49 PDT 2020
Author: Valentin Clement
Date: 2020-07-26T20:01:35-04:00
New Revision: ff25b2da2ab9049e154cc8b9af06a24f79a74209
URL: https://github.com/llvm/llvm-project/commit/ff25b2da2ab9049e154cc8b9af06a24f79a74209
DIFF: https://github.com/llvm/llvm-project/commit/ff25b2da2ab9049e154cc8b9af06a24f79a74209.diff
LOG: [flang][openacc] Basic name resolution infrastructure for OpenACC construct
Reviewed By: tskeith, klausler, ichoyjx
Differential Revision: https://reviews.llvm.org/D83998
Added:
flang/test/Semantics/acc-resolve01.f90
flang/test/Semantics/acc-resolve02.f90
flang/test/Semantics/acc-symbols01.f90
Modified:
flang/include/flang/Semantics/symbol.h
flang/lib/Semantics/resolve-names.cpp
flang/lib/Semantics/unparse-with-symbols.cpp
flang/test/Semantics/test_symbols.sh
Removed:
################################################################################
diff --git a/flang/include/flang/Semantics/symbol.h b/flang/include/flang/Semantics/symbol.h
index a1fd1baef78d..3000a39c3b58 100644
--- a/flang/include/flang/Semantics/symbol.h
+++ b/flang/include/flang/Semantics/symbol.h
@@ -492,6 +492,13 @@ class Symbol {
LocalityShared, // named in SHARED locality-spec
InDataStmt, // initialized in a DATA statement
+ // OpenACC data-sharing attribute
+ AccPrivate, AccFirstPrivate, AccShared,
+ // OpenACC data-mapping attribute
+ AccCopyIn, AccCopyOut, AccCreate, AccDelete, AccPresent,
+ // OpenACC miscellaneous flags
+ AccCommonBlock, AccThreadPrivate, AccReduction, AccNone, AccPreDetermined,
+
// OpenMP data-sharing attribute
OmpShared, OmpPrivate, OmpLinear, OmpFirstPrivate, OmpLastPrivate,
// OpenMP data-mapping attribute
diff --git a/flang/lib/Semantics/resolve-names.cpp b/flang/lib/Semantics/resolve-names.cpp
index 8ea2e8ed9a60..8d3e97d20521 100644
--- a/flang/lib/Semantics/resolve-names.cpp
+++ b/flang/lib/Semantics/resolve-names.cpp
@@ -7,6 +7,7 @@
#include "resolve-names.h"
#include "assignment.h"
+#include "check-acc-structure.h"
#include "check-omp-structure.h"
#include "mod-file.h"
#include "pointer-assignment.h"
@@ -1081,6 +1082,305 @@ class ConstructVisitor : public virtual DeclarationVisitor {
void PopAssociation();
};
+template <typename T> class DirectiveAttributeVisitor {
+public:
+ explicit DirectiveAttributeVisitor(
+ SemanticsContext &context, ResolveNamesVisitor &resolver)
+ : context_{context}, resolver_{resolver} {}
+
+protected:
+ struct DirContext {
+ DirContext(const parser::CharBlock &source, T d, Scope &s)
+ : directiveSource{source}, directive{d}, scope{s} {}
+ parser::CharBlock directiveSource;
+ T directive;
+ Scope &scope;
+ Symbol::Flag defaultDSA{Symbol::Flag::AccShared}; // TODOACC
+ std::map<const Symbol *, Symbol::Flag> objectWithDSA;
+ bool withinConstruct{false};
+ int64_t associatedLoopLevel{0};
+ };
+
+ DirContext &GetContext() {
+ CHECK(!dirContext_.empty());
+ return dirContext_.back();
+ }
+ void PushContext(const parser::CharBlock &source, T dir) {
+ dirContext_.emplace_back(source, dir, context_.FindScope(source));
+ }
+ void PopContext() { dirContext_.pop_back(); }
+ void SetContextDirectiveSource(parser::CharBlock &dir) {
+ GetContext().directiveSource = dir;
+ }
+ void SetContextDirectiveEnum(T dir) { GetContext().directive = dir; }
+ Scope &currScope() { return GetContext().scope; }
+ void SetContextDefaultDSA(Symbol::Flag flag) {
+ GetContext().defaultDSA = flag;
+ }
+ void AddToContextObjectWithDSA(
+ const Symbol &symbol, Symbol::Flag flag, DirContext &context) {
+ context.objectWithDSA.emplace(&symbol, flag);
+ }
+ void AddToContextObjectWithDSA(const Symbol &symbol, Symbol::Flag flag) {
+ AddToContextObjectWithDSA(symbol, flag, GetContext());
+ }
+ bool IsObjectWithDSA(const Symbol &symbol) {
+ auto it{GetContext().objectWithDSA.find(&symbol)};
+ return it != GetContext().objectWithDSA.end();
+ }
+ void SetContextAssociatedLoopLevel(int64_t level) {
+ GetContext().associatedLoopLevel = level;
+ }
+ Symbol &MakeAssocSymbol(const SourceName &name, Symbol &prev, Scope &scope) {
+ const auto pair{scope.try_emplace(name, Attrs{}, HostAssocDetails{prev})};
+ return *pair.first->second;
+ }
+ Symbol &MakeAssocSymbol(const SourceName &name, Symbol &prev) {
+ return MakeAssocSymbol(name, prev, currScope());
+ }
+ static const parser::Name *GetDesignatorNameIfDataRef(
+ const parser::Designator &designator) {
+ const auto *dataRef{std::get_if<parser::DataRef>(&designator.u)};
+ return dataRef ? std::get_if<parser::Name>(&dataRef->u) : nullptr;
+ }
+ void AddDataSharingAttributeObject(SymbolRef object) {
+ dataSharingAttributeObjects_.insert(object);
+ }
+ void ClearDataSharingAttributeObjects() {
+ dataSharingAttributeObjects_.clear();
+ }
+ bool HasDataSharingAttributeObject(const Symbol &);
+ const parser::Name &GetLoopIndex(const parser::DoConstruct &);
+ const parser::DoConstruct *GetDoConstructIf(
+ const parser::ExecutionPartConstruct &);
+ Symbol *DeclarePrivateAccessEntity(
+ const parser::Name &, Symbol::Flag, Scope &);
+ Symbol *DeclarePrivateAccessEntity(Symbol &, Symbol::Flag, Scope &);
+ Symbol *DeclareOrMarkOtherAccessEntity(const parser::Name &, Symbol::Flag);
+
+ SymbolSet dataSharingAttributeObjects_; // on one directive
+ SemanticsContext &context_;
+ ResolveNamesVisitor &resolver_;
+ std::vector<DirContext> dirContext_; // used as a stack
+};
+
+template <typename T>
+bool DirectiveAttributeVisitor<T>::HasDataSharingAttributeObject(
+ const Symbol &object) {
+ auto it{dataSharingAttributeObjects_.find(object)};
+ return it != dataSharingAttributeObjects_.end();
+}
+
+template <typename T>
+const parser::Name &DirectiveAttributeVisitor<T>::GetLoopIndex(
+ const parser::DoConstruct &x) {
+ auto &loopControl{x.GetLoopControl().value()};
+ using Bounds = parser::LoopControl::Bounds;
+ const Bounds &bounds{std::get<Bounds>(loopControl.u)};
+ return bounds.name.thing;
+}
+
+template <typename T>
+const parser::DoConstruct *DirectiveAttributeVisitor<T>::GetDoConstructIf(
+ const parser::ExecutionPartConstruct &x) {
+ return parser::Unwrap<parser::DoConstruct>(x);
+}
+
+template <typename T>
+Symbol *DirectiveAttributeVisitor<T>::DeclarePrivateAccessEntity(
+ const parser::Name &name, Symbol::Flag flag, Scope &scope) {
+ if (!name.symbol) {
+ return nullptr; // not resolved by Name Resolution step, do nothing
+ }
+ name.symbol = DeclarePrivateAccessEntity(*name.symbol, flag, scope);
+ return name.symbol;
+}
+
+template <typename T>
+Symbol *DirectiveAttributeVisitor<T>::DeclarePrivateAccessEntity(
+ Symbol &object, Symbol::Flag flag, Scope &scope) {
+ if (object.owner() != currScope()) {
+ auto &symbol{MakeAssocSymbol(object.name(), object, scope)};
+ symbol.set(flag);
+ return &symbol;
+ } else {
+ object.set(flag);
+ return &object;
+ }
+}
+
+// Create scopes for OpenACC constructs
+class AccVisitor : public virtual DeclarationVisitor {
+public:
+ void AddAccSourceRange(const parser::CharBlock &);
+
+ static bool NeedsScope(const parser::OpenACCBlockConstruct &);
+
+ bool Pre(const parser::OpenACCBlockConstruct &);
+ void Post(const parser::OpenACCBlockConstruct &);
+ bool Pre(const parser::AccBeginBlockDirective &x) {
+ AddAccSourceRange(x.source);
+ return true;
+ }
+ void Post(const parser::AccBeginBlockDirective &) {
+ messageHandler().set_currStmtSource(std::nullopt);
+ }
+ bool Pre(const parser::AccEndBlockDirective &x) {
+ AddAccSourceRange(x.source);
+ return true;
+ }
+ void Post(const parser::AccEndBlockDirective &) {
+ messageHandler().set_currStmtSource(std::nullopt);
+ }
+ bool Pre(const parser::AccBeginLoopDirective &x) {
+ AddAccSourceRange(x.source);
+ return true;
+ }
+ void Post(const parser::AccBeginLoopDirective &x) {
+ messageHandler().set_currStmtSource(std::nullopt);
+ }
+};
+
+bool AccVisitor::NeedsScope(const parser::OpenACCBlockConstruct &x) {
+ const auto &beginBlockDir{std::get<parser::AccBeginBlockDirective>(x.t)};
+ const auto &beginDir{std::get<parser::AccBlockDirective>(beginBlockDir.t)};
+ switch (beginDir.v) {
+ case llvm::acc::Directive::ACCD_data:
+ case llvm::acc::Directive::ACCD_host_data:
+ case llvm::acc::Directive::ACCD_kernels:
+ case llvm::acc::Directive::ACCD_parallel:
+ case llvm::acc::Directive::ACCD_serial:
+ return true;
+ default:
+ return false;
+ }
+}
+
+void AccVisitor::AddAccSourceRange(const parser::CharBlock &source) {
+ messageHandler().set_currStmtSource(source);
+ currScope().AddSourceRange(source);
+}
+
+bool AccVisitor::Pre(const parser::OpenACCBlockConstruct &x) {
+ if (NeedsScope(x)) {
+ PushScope(Scope::Kind::Block, nullptr);
+ }
+ return true;
+}
+
+void AccVisitor::Post(const parser::OpenACCBlockConstruct &x) {
+ if (NeedsScope(x)) {
+ PopScope();
+ }
+}
+
+class AccAttributeVisitor : DirectiveAttributeVisitor<llvm::acc::Directive> {
+public:
+ explicit AccAttributeVisitor(
+ SemanticsContext &context, ResolveNamesVisitor &resolver)
+ : DirectiveAttributeVisitor(context, resolver) {}
+
+ template <typename A> void Walk(const A &x) { parser::Walk(x, *this); }
+ template <typename A> bool Pre(const A &) { return true; }
+ template <typename A> void Post(const A &) {}
+
+ bool Pre(const parser::SpecificationPart &x) {
+ Walk(std::get<std::list<parser::OpenACCDeclarativeConstruct>>(x.t));
+ return false;
+ }
+
+ bool Pre(const parser::OpenACCBlockConstruct &);
+ void Post(const parser::OpenACCBlockConstruct &) { PopContext(); }
+ bool Pre(const parser::OpenACCCombinedConstruct &);
+ void Post(const parser::OpenACCCombinedConstruct &) { PopContext(); }
+
+ void Post(const parser::AccBeginBlockDirective &) {
+ GetContext().withinConstruct = true;
+ }
+
+ bool Pre(const parser::OpenACCLoopConstruct &);
+ void Post(const parser::OpenACCLoopConstruct &) { PopContext(); }
+ void Post(const parser::AccLoopDirective &) {
+ GetContext().withinConstruct = true;
+ }
+
+ bool Pre(const parser::OpenACCStandaloneConstruct &);
+ void Post(const parser::OpenACCStandaloneConstruct &) { PopContext(); }
+ void Post(const parser::AccStandaloneDirective &) {
+ GetContext().withinConstruct = true;
+ }
+
+ void Post(const parser::AccDefaultClause &);
+
+ bool Pre(const parser::AccClause::Copy &x) {
+ ResolveAccObjectList(x.v, Symbol::Flag::AccCopyIn);
+ ResolveAccObjectList(x.v, Symbol::Flag::AccCopyOut);
+ return false;
+ }
+
+ bool Pre(const parser::AccClause::Create &x) {
+ const auto &objectList{std::get<parser::AccObjectList>(x.v.t)};
+ ResolveAccObjectList(objectList, Symbol::Flag::AccCreate);
+ return false;
+ }
+
+ bool Pre(const parser::AccClause::Copyin &x) {
+ const auto &objectList{std::get<parser::AccObjectList>(x.v.t)};
+ ResolveAccObjectList(objectList, Symbol::Flag::AccCopyIn);
+ return false;
+ }
+
+ bool Pre(const parser::AccClause::Copyout &x) {
+ const auto &objectList{std::get<parser::AccObjectList>(x.v.t)};
+ ResolveAccObjectList(objectList, Symbol::Flag::AccCopyOut);
+ return false;
+ }
+
+ bool Pre(const parser::AccClause::Present &x) {
+ ResolveAccObjectList(x.v, Symbol::Flag::AccPresent);
+ return false;
+ }
+ bool Pre(const parser::AccClause::Private &x) {
+ ResolveAccObjectList(x.v, Symbol::Flag::AccPrivate);
+ return false;
+ }
+ bool Pre(const parser::AccClause::FirstPrivate &x) {
+ ResolveAccObjectList(x.v, Symbol::Flag::AccFirstPrivate);
+ return false;
+ }
+
+ void Post(const parser::Name &);
+
+private:
+ int64_t GetAssociatedLoopLevelFromClauses(const parser::AccClauseList &);
+
+ static constexpr Symbol::Flags dataSharingAttributeFlags{
+ Symbol::Flag::AccShared, Symbol::Flag::AccPrivate,
+ Symbol::Flag::AccPresent, Symbol::Flag::AccFirstPrivate,
+ Symbol::Flag::AccReduction};
+
+ static constexpr Symbol::Flags dataMappingAttributeFlags{
+ Symbol::Flag::AccCreate, Symbol::Flag::AccCopyIn,
+ Symbol::Flag::AccCopyOut, Symbol::Flag::AccDelete};
+
+ static constexpr Symbol::Flags accFlagsRequireNewSymbol{
+ Symbol::Flag::AccPrivate, Symbol::Flag::AccFirstPrivate,
+ Symbol::Flag::AccReduction};
+
+ static constexpr Symbol::Flags accFlagsRequireMark{};
+
+ void PrivatizeAssociatedLoopIndex(const parser::OpenACCLoopConstruct &);
+ void ResolveAccObjectList(const parser::AccObjectList &, Symbol::Flag);
+ void ResolveAccObject(const parser::AccObject &, Symbol::Flag);
+ Symbol *ResolveAcc(const parser::Name &, Symbol::Flag, Scope &);
+ Symbol *ResolveAcc(Symbol &, Symbol::Flag, Scope &);
+ Symbol *ResolveAccCommonBlockName(const parser::Name *);
+ Symbol *DeclareOrMarkOtherAccessEntity(const parser::Name &, Symbol::Flag);
+ Symbol *DeclareOrMarkOtherAccessEntity(Symbol &, Symbol::Flag);
+ void CheckMultipleAppearances(
+ const parser::Name &, const Symbol &, Symbol::Flag);
+};
+
// Create scopes for OpenMP constructs
class OmpVisitor : public virtual DeclarationVisitor {
public:
@@ -1178,11 +1478,11 @@ void OmpVisitor::Post(const parser::OpenMPBlockConstruct &x) {
}
// Data-sharing and Data-mapping attributes for data-refs in OpenMP construct
-class OmpAttributeVisitor {
+class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
public:
explicit OmpAttributeVisitor(
SemanticsContext &context, ResolveNamesVisitor &resolver)
- : context_{context}, resolver_{resolver} {}
+ : DirectiveAttributeVisitor(context, resolver) {}
template <typename A> void Walk(const A &x) { parser::Walk(x, *this); }
@@ -1235,70 +1535,8 @@ class OmpAttributeVisitor {
void Post(const parser::Name &);
private:
- struct OmpContext {
- OmpContext(
- const parser::CharBlock &source, llvm::omp::Directive d, Scope &s)
- : directiveSource{source}, directive{d}, scope{s} {}
- parser::CharBlock directiveSource;
- llvm::omp::Directive directive;
- Scope &scope;
- // TODO: default DSA is implicitly determined in
diff erent ways
- Symbol::Flag defaultDSA{Symbol::Flag::OmpShared};
- // variables on Data-sharing attribute clauses
- std::map<const Symbol *, Symbol::Flag> objectWithDSA;
- bool withinConstruct{false};
- std::int64_t associatedLoopLevel{0};
- };
- // back() is the top of the stack
- OmpContext &GetContext() {
- CHECK(!ompContext_.empty());
- return ompContext_.back();
- }
- void PushContext(const parser::CharBlock &source, llvm::omp::Directive dir) {
- ompContext_.emplace_back(source, dir, context_.FindScope(source));
- }
- void PopContext() { ompContext_.pop_back(); }
- void SetContextDirectiveSource(parser::CharBlock &dir) {
- GetContext().directiveSource = dir;
- }
- void SetContextDirectiveEnum(llvm::omp::Directive dir) {
- GetContext().directive = dir;
- }
- Scope &currScope() { return GetContext().scope; }
- void SetContextDefaultDSA(Symbol::Flag flag) {
- GetContext().defaultDSA = flag;
- }
- void AddToContextObjectWithDSA(
- const Symbol &symbol, Symbol::Flag flag, OmpContext &context) {
- context.objectWithDSA.emplace(&symbol, flag);
- }
- void AddToContextObjectWithDSA(const Symbol &symbol, Symbol::Flag flag) {
- AddToContextObjectWithDSA(symbol, flag, GetContext());
- }
- bool IsObjectWithDSA(const Symbol &symbol) {
- auto it{GetContext().objectWithDSA.find(&symbol)};
- return it != GetContext().objectWithDSA.end();
- }
-
- void SetContextAssociatedLoopLevel(std::int64_t level) {
- GetContext().associatedLoopLevel = level;
- }
std::int64_t GetAssociatedLoopLevelFromClauses(const parser::OmpClauseList &);
- Symbol &MakeAssocSymbol(const SourceName &name, Symbol &prev, Scope &scope) {
- const auto pair{scope.try_emplace(name, Attrs{}, HostAssocDetails{prev})};
- return *pair.first->second;
- }
- Symbol &MakeAssocSymbol(const SourceName &name, Symbol &prev) {
- return MakeAssocSymbol(name, prev, currScope());
- }
-
- static const parser::Name *GetDesignatorNameIfDataRef(
- const parser::Designator &designator) {
- const auto *dataRef{std::get_if<parser::DataRef>(&designator.u)};
- return dataRef ? std::get_if<parser::Name>(&dataRef->u) : nullptr;
- }
-
static constexpr Symbol::Flags dataSharingAttributeFlags{
Symbol::Flag::OmpShared, Symbol::Flag::OmpPrivate,
Symbol::Flag::OmpFirstPrivate, Symbol::Flag::OmpLastPrivate,
@@ -1312,19 +1550,8 @@ class OmpAttributeVisitor {
static constexpr Symbol::Flags ompFlagsRequireMark{
Symbol::Flag::OmpThreadprivate};
- void AddDataSharingAttributeObject(SymbolRef object) {
- dataSharingAttributeObjects_.insert(object);
- }
- void ClearDataSharingAttributeObjects() {
- dataSharingAttributeObjects_.clear();
- }
- bool HasDataSharingAttributeObject(const Symbol &);
-
- const parser::DoConstruct *GetDoConstructIf(
- const parser::ExecutionPartConstruct &);
// Predetermined DSA rules
void PrivatizeAssociatedLoopIndex(const parser::OpenMPLoopConstruct &);
- const parser::Name &GetLoopIndex(const parser::DoConstruct &);
void ResolveSeqLoopIndexInParallelOrTaskConstruct(const parser::Name &);
void ResolveOmpObjectList(const parser::OmpObjectList &, Symbol::Flag);
@@ -1332,18 +1559,10 @@ class OmpAttributeVisitor {
Symbol *ResolveOmp(const parser::Name &, Symbol::Flag, Scope &);
Symbol *ResolveOmp(Symbol &, Symbol::Flag, Scope &);
Symbol *ResolveOmpCommonBlockName(const parser::Name *);
- Symbol *DeclarePrivateAccessEntity(
- const parser::Name &, Symbol::Flag, Scope &);
- Symbol *DeclarePrivateAccessEntity(Symbol &, Symbol::Flag, Scope &);
Symbol *DeclareOrMarkOtherAccessEntity(const parser::Name &, Symbol::Flag);
Symbol *DeclareOrMarkOtherAccessEntity(Symbol &, Symbol::Flag);
void CheckMultipleAppearances(
const parser::Name &, const Symbol &, Symbol::Flag);
- SymbolSet dataSharingAttributeObjects_; // on one directive
-
- SemanticsContext &context_;
- ResolveNamesVisitor &resolver_;
- std::vector<OmpContext> ompContext_; // used as a stack
};
// Walk the parse tree and resolve names to symbols.
@@ -1351,8 +1570,11 @@ class ResolveNamesVisitor : public virtual ScopeHandler,
public ModuleVisitor,
public SubprogramVisitor,
public ConstructVisitor,
- public OmpVisitor {
+ public OmpVisitor,
+ public AccVisitor {
public:
+ using AccVisitor::Post;
+ using AccVisitor::Pre;
using ArraySpecVisitor::Post;
using ConstructVisitor::Post;
using ConstructVisitor::Pre;
@@ -1450,6 +1672,7 @@ class ResolveNamesVisitor : public virtual ScopeHandler,
void FinishSpecificationParts(const ProgramTree &);
void FinishDerivedTypeInstantiation(Scope &);
void ResolveExecutionParts(const ProgramTree &);
+ void ResolveAccParts(const parser::ProgramUnit &);
void ResolveOmpParts(const parser::ProgramUnit &);
};
@@ -6275,7 +6498,12 @@ bool ResolveNamesVisitor::Pre(const parser::ProgramUnit &x) {
inExecutionPart_ = true;
ResolveExecutionParts(root);
inExecutionPart_ = false;
- ResolveOmpParts(x);
+ if (context().IsEnabled(common::LanguageFeature::OpenACC)) {
+ ResolveAccParts(x);
+ }
+ if (context().IsEnabled(common::LanguageFeature::OpenMP)) {
+ ResolveOmpParts(x);
+ }
return false;
}
@@ -6468,6 +6696,287 @@ class DeferredCheckVisitor {
bool pushedScope_{false};
};
+bool AccAttributeVisitor::Pre(const parser::OpenACCBlockConstruct &x) {
+ const auto &beginBlockDir{std::get<parser::AccBeginBlockDirective>(x.t)};
+ const auto &blockDir{std::get<parser::AccBlockDirective>(beginBlockDir.t)};
+ switch (blockDir.v) {
+ case llvm::acc::Directive::ACCD_data:
+ case llvm::acc::Directive::ACCD_host_data:
+ case llvm::acc::Directive::ACCD_kernels:
+ case llvm::acc::Directive::ACCD_parallel:
+ case llvm::acc::Directive::ACCD_serial:
+ PushContext(blockDir.source, blockDir.v);
+ break;
+ default:
+ break;
+ }
+ ClearDataSharingAttributeObjects();
+ return true;
+}
+
+bool AccAttributeVisitor::Pre(const parser::OpenACCLoopConstruct &x) {
+ const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};
+ const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)};
+ const auto &clauseList{std::get<parser::AccClauseList>(beginDir.t)};
+ if (loopDir.v == llvm::acc::Directive::ACCD_loop) {
+ PushContext(loopDir.source, loopDir.v);
+ }
+ ClearDataSharingAttributeObjects();
+ SetContextAssociatedLoopLevel(GetAssociatedLoopLevelFromClauses(clauseList));
+ PrivatizeAssociatedLoopIndex(x);
+ return true;
+}
+
+bool AccAttributeVisitor::Pre(const parser::OpenACCStandaloneConstruct &x) {
+ const auto &standaloneDir{std::get<parser::AccStandaloneDirective>(x.t)};
+ switch (standaloneDir.v) {
+ case llvm::acc::Directive::ACCD_cache:
+ case llvm::acc::Directive::ACCD_enter_data:
+ case llvm::acc::Directive::ACCD_exit_data:
+ case llvm::acc::Directive::ACCD_init:
+ case llvm::acc::Directive::ACCD_set:
+ case llvm::acc::Directive::ACCD_shutdown:
+ case llvm::acc::Directive::ACCD_update:
+ PushContext(standaloneDir.source, standaloneDir.v);
+ break;
+ default:
+ break;
+ }
+ ClearDataSharingAttributeObjects();
+ return true;
+}
+
+bool AccAttributeVisitor::Pre(const parser::OpenACCCombinedConstruct &x) {
+ const auto &beginBlockDir{std::get<parser::AccBeginCombinedDirective>(x.t)};
+ const auto &combinedDir{
+ std::get<parser::AccCombinedDirective>(beginBlockDir.t)};
+ switch (combinedDir.v) {
+ case llvm::acc::Directive::ACCD_kernels_loop:
+ case llvm::acc::Directive::ACCD_parallel_loop:
+ case llvm::acc::Directive::ACCD_serial_loop:
+ PushContext(combinedDir.source, combinedDir.v);
+ break;
+ default:
+ break;
+ }
+ ClearDataSharingAttributeObjects();
+ return true;
+}
+
+int64_t AccAttributeVisitor::GetAssociatedLoopLevelFromClauses(
+ const parser::AccClauseList &x) {
+ int64_t collapseLevel{0};
+ for (const auto &clause : x.v) {
+ if (const auto *collapseClause{
+ std::get_if<parser::AccClause::Collapse>(&clause.u)}) {
+ if (const auto v{evaluate::ToInt64(
+ resolver_.EvaluateIntExpr(collapseClause->v))}) {
+ collapseLevel = *v;
+ }
+ }
+ }
+
+ if (collapseLevel) {
+ return collapseLevel;
+ }
+ return 1; // default is outermost loop
+}
+
+void AccAttributeVisitor::PrivatizeAssociatedLoopIndex(
+ const parser::OpenACCLoopConstruct &x) {
+ int64_t level{GetContext().associatedLoopLevel};
+ if (level <= 0) { // collpase value was negative or 0
+ return;
+ }
+ Symbol::Flag ivDSA{Symbol::Flag::AccPrivate};
+
+ const auto &outer{std::get<std::optional<parser::DoConstruct>>(x.t)};
+ for (const parser::DoConstruct *loop{&*outer}; loop && level > 0; --level) {
+ // go through all the nested do-loops and resolve index variables
+ const parser::Name &iv{GetLoopIndex(*loop)};
+ if (auto *symbol{ResolveAcc(iv, ivDSA, currScope())}) {
+ symbol->set(Symbol::Flag::AccPreDetermined);
+ iv.symbol = symbol; // adjust the symbol within region
+ AddToContextObjectWithDSA(*symbol, ivDSA);
+ }
+
+ const auto &block{std::get<parser::Block>(loop->t)};
+ const auto it{block.begin()};
+ loop = it != block.end() ? GetDoConstructIf(*it) : nullptr;
+ }
+ CHECK(level == 0);
+}
+
+void AccAttributeVisitor::Post(const parser::AccDefaultClause &x) {
+ if (!dirContext_.empty()) {
+ switch (x.v) {
+ case parser::AccDefaultClause::Arg::Present:
+ SetContextDefaultDSA(Symbol::Flag::AccPresent);
+ break;
+ case parser::AccDefaultClause::Arg::None:
+ SetContextDefaultDSA(Symbol::Flag::AccNone);
+ break;
+ }
+ }
+}
+
+// For OpenACC constructs, check all the data-refs within the constructs
+// 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->owner().IsDerivedType() && !symbol->has<ProcEntityDetails>() &&
+ !IsObjectWithDSA(*symbol)) {
+ if (Symbol * found{currScope().FindSymbol(name.source)}) {
+ if (symbol != found) {
+ name.symbol = found; // adjust the symbol within region
+ } else if (GetContext().defaultDSA == Symbol::Flag::AccNone) {
+ // 2.5.14.
+ context_.Say(name.source,
+ "The DEFAULT(NONE) clause requires that '%s' must be listed in "
+ "a data-mapping clause"_err_en_US,
+ symbol->name());
+ }
+ }
+ }
+ } // within OpenACC construct
+}
+
+Symbol *AccAttributeVisitor::ResolveAccCommonBlockName(
+ const parser::Name *name) {
+ if (!name) {
+ return nullptr;
+ } else if (auto *prev{
+ GetContext().scope.parent().FindCommonBlock(name->source)}) {
+ name->symbol = prev;
+ return prev;
+ } else {
+ return nullptr;
+ }
+}
+
+void AccAttributeVisitor::ResolveAccObjectList(
+ const parser::AccObjectList &accObjectList, Symbol::Flag accFlag) {
+ for (const auto &accObject : accObjectList.v) {
+ ResolveAccObject(accObject, accFlag);
+ }
+}
+
+void AccAttributeVisitor::ResolveAccObject(
+ const parser::AccObject &accObject, Symbol::Flag accFlag) {
+ std::visit(
+ common::visitors{
+ [&](const parser::Designator &designator) {
+ if (const auto *name{GetDesignatorNameIfDataRef(designator)}) {
+ if (auto *symbol{ResolveAcc(*name, accFlag, currScope())}) {
+ AddToContextObjectWithDSA(*symbol, accFlag);
+ if (dataSharingAttributeFlags.test(accFlag)) {
+ CheckMultipleAppearances(*name, *symbol, accFlag);
+ }
+ }
+ } else if (const auto *designatorName{
+ resolver_.ResolveDesignator(designator)};
+ designatorName->symbol) {
+ // Array sections to be changed to substrings as needed
+ if (AnalyzeExpr(context_, designator)) {
+ if (std::holds_alternative<parser::Substring>(designator.u)) {
+ context_.Say(designator.source,
+ "Substrings are not allowed on OpenACC "
+ "directives or clauses"_err_en_US);
+ }
+ }
+ // other checks, more TBD
+ if (const auto *details{designatorName->symbol
+ ->detailsIf<ObjectEntityDetails>()}) {
+ if (details->IsArray()) {
+ // TODO: check Array Sections
+ } else if (designatorName->symbol->owner().IsDerivedType()) {
+ // TODO: check Structure Component
+ }
+ }
+ }
+ },
+ [&](const parser::Name &name) { // common block
+ if (auto *symbol{ResolveAccCommonBlockName(&name)}) {
+ CheckMultipleAppearances(
+ name, *symbol, Symbol::Flag::AccCommonBlock);
+ for (auto &object : symbol->get<CommonBlockDetails>().objects()) {
+ if (auto *resolvedObject{
+ ResolveAcc(*object, accFlag, currScope())}) {
+ AddToContextObjectWithDSA(*resolvedObject, accFlag);
+ }
+ }
+ } else {
+ context_.Say(name.source,
+ "COMMON block must be declared in the same scoping unit "
+ "in which the OpenACC directive or clause appears"_err_en_US);
+ }
+ },
+ },
+ accObject.u);
+}
+
+Symbol *AccAttributeVisitor::ResolveAcc(
+ const parser::Name &name, Symbol::Flag accFlag, Scope &scope) {
+ if (accFlagsRequireNewSymbol.test(accFlag)) {
+ return DeclarePrivateAccessEntity(name, accFlag, scope);
+ } else {
+ return DeclareOrMarkOtherAccessEntity(name, accFlag);
+ }
+}
+
+Symbol *AccAttributeVisitor::ResolveAcc(
+ Symbol &symbol, Symbol::Flag accFlag, Scope &scope) {
+ if (accFlagsRequireNewSymbol.test(accFlag)) {
+ return DeclarePrivateAccessEntity(symbol, accFlag, scope);
+ } else {
+ return DeclareOrMarkOtherAccessEntity(symbol, accFlag);
+ }
+}
+
+Symbol *AccAttributeVisitor::DeclareOrMarkOtherAccessEntity(
+ const parser::Name &name, Symbol::Flag accFlag) {
+ Symbol *prev{currScope().FindSymbol(name.source)};
+ if (!name.symbol || !prev) {
+ return nullptr;
+ } else if (prev != name.symbol) {
+ name.symbol = prev;
+ }
+ return DeclareOrMarkOtherAccessEntity(*prev, accFlag);
+}
+
+Symbol *AccAttributeVisitor::DeclareOrMarkOtherAccessEntity(
+ Symbol &object, Symbol::Flag accFlag) {
+ if (accFlagsRequireMark.test(accFlag)) {
+ object.set(accFlag);
+ }
+ return &object;
+}
+
+static bool WithMultipleAppearancesAccException(
+ const Symbol &symbol, Symbol::Flag flag) {
+ return false; // Place holder
+}
+
+void AccAttributeVisitor::CheckMultipleAppearances(
+ const parser::Name &name, const Symbol &symbol, Symbol::Flag accFlag) {
+ const auto *target{&symbol};
+ if (accFlagsRequireNewSymbol.test(accFlag)) {
+ if (const auto *details{symbol.detailsIf<HostAssocDetails>()}) {
+ target = &details->symbol();
+ }
+ }
+ if (HasDataSharingAttributeObject(*target) &&
+ !WithMultipleAppearancesAccException(symbol, accFlag)) {
+ context_.Say(name.source,
+ "'%s' appears in more than one data-sharing clause "
+ "on the same OpenACC directive"_err_en_US,
+ name.ToString());
+ } else {
+ AddDataSharingAttributeObject(*target);
+ }
+}
+
bool OmpAttributeVisitor::Pre(const parser::OpenMPBlockConstruct &x) {
const auto &beginBlockDir{std::get<parser::OmpBeginBlockDirective>(x.t)};
const auto &beginDir{std::get<parser::OmpBlockDirective>(beginBlockDir.t)};
@@ -6532,19 +7041,11 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) {
return true;
}
-const parser::Name &OmpAttributeVisitor::GetLoopIndex(
- const parser::DoConstruct &x) {
- auto &loopControl{x.GetLoopControl().value()};
- using Bounds = parser::LoopControl::Bounds;
- const Bounds &bounds{std::get<Bounds>(loopControl.u)};
- return bounds.name.thing;
-}
-
void OmpAttributeVisitor::ResolveSeqLoopIndexInParallelOrTaskConstruct(
const parser::Name &iv) {
- auto targetIt{ompContext_.rbegin()};
+ auto targetIt{dirContext_.rbegin()};
for (;; ++targetIt) {
- if (targetIt == ompContext_.rend()) {
+ if (targetIt == dirContext_.rend()) {
return;
}
if (llvm::omp::parallelSet.test(targetIt->directive) ||
@@ -6556,7 +7057,7 @@ void OmpAttributeVisitor::ResolveSeqLoopIndexInParallelOrTaskConstruct(
targetIt++;
symbol->set(Symbol::Flag::OmpPreDetermined);
iv.symbol = symbol; // adjust the symbol within region
- for (auto it{ompContext_.rbegin()}; it != targetIt; ++it) {
+ for (auto it{dirContext_.rbegin()}; it != targetIt; ++it) {
AddToContextObjectWithDSA(*symbol, Symbol::Flag::OmpPrivate, *it);
}
}
@@ -6567,7 +7068,7 @@ void OmpAttributeVisitor::ResolveSeqLoopIndexInParallelOrTaskConstruct(
// or task generating construct is private in the innermost such
// construct that encloses the loop
bool OmpAttributeVisitor::Pre(const parser::DoConstruct &x) {
- if (!ompContext_.empty() && GetContext().withinConstruct) {
+ if (!dirContext_.empty() && GetContext().withinConstruct) {
if (const auto &iv{GetLoopIndex(x)}; iv.symbol) {
if (!iv.symbol->test(Symbol::Flag::OmpPreDetermined)) {
ResolveSeqLoopIndexInParallelOrTaskConstruct(iv);
@@ -6579,16 +7080,6 @@ bool OmpAttributeVisitor::Pre(const parser::DoConstruct &x) {
return true;
}
-const parser::DoConstruct *OmpAttributeVisitor::GetDoConstructIf(
- const parser::ExecutionPartConstruct &x) {
- if (auto *y{std::get_if<parser::ExecutableConstruct>(&x.u)}) {
- if (auto *z{std::get_if<Indirection<parser::DoConstruct>>(&y->u)}) {
- return &z->value();
- }
- }
- return nullptr;
-}
-
std::int64_t OmpAttributeVisitor::GetAssociatedLoopLevelFromClauses(
const parser::OmpClauseList &x) {
std::int64_t orderedLevel{0};
@@ -6685,7 +7176,7 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPThreadprivate &x) {
}
void OmpAttributeVisitor::Post(const parser::OmpDefaultClause &x) {
- if (!ompContext_.empty()) {
+ if (!dirContext_.empty()) {
switch (x.v) {
case parser::OmpDefaultClause::Type::Private:
SetContextDefaultDSA(Symbol::Flag::OmpPrivate);
@@ -6707,7 +7198,7 @@ void OmpAttributeVisitor::Post(const parser::OmpDefaultClause &x) {
// and adjust the symbol for each Name if necessary
void OmpAttributeVisitor::Post(const parser::Name &name) {
auto *symbol{name.symbol};
- if (symbol && !ompContext_.empty() && GetContext().withinConstruct) {
+ if (symbol && !dirContext_.empty() && GetContext().withinConstruct) {
if (!symbol->owner().IsDerivedType() && !symbol->has<ProcEntityDetails>() &&
!IsObjectWithDSA(*symbol)) {
// TODO: create a separate function to go through the rules for
@@ -6727,11 +7218,6 @@ void OmpAttributeVisitor::Post(const parser::Name &name) {
} // within OpenMP construct
}
-bool OmpAttributeVisitor::HasDataSharingAttributeObject(const Symbol &object) {
- auto it{dataSharingAttributeObjects_.find(object)};
- return it != dataSharingAttributeObjects_.end();
-}
-
Symbol *OmpAttributeVisitor::ResolveOmpCommonBlockName(
const parser::Name *name) {
if (auto *prev{name
@@ -6826,27 +7312,6 @@ Symbol *OmpAttributeVisitor::ResolveOmp(
}
}
-Symbol *OmpAttributeVisitor::DeclarePrivateAccessEntity(
- const parser::Name &name, Symbol::Flag ompFlag, Scope &scope) {
- if (!name.symbol) {
- return nullptr; // not resolved by Name Resolution step, do nothing
- }
- name.symbol = DeclarePrivateAccessEntity(*name.symbol, ompFlag, scope);
- return name.symbol;
-}
-
-Symbol *OmpAttributeVisitor::DeclarePrivateAccessEntity(
- Symbol &object, Symbol::Flag ompFlag, Scope &scope) {
- if (object.owner() != currScope()) {
- auto &symbol{MakeAssocSymbol(object.name(), object, scope)};
- symbol.set(ompFlag);
- return &symbol;
- } else {
- object.set(ompFlag);
- return &object;
- }
-}
-
Symbol *OmpAttributeVisitor::DeclareOrMarkOtherAccessEntity(
const parser::Name &name, Symbol::Flag ompFlag) {
Symbol *prev{currScope().FindSymbol(name.source)};
@@ -6866,11 +7331,11 @@ Symbol *OmpAttributeVisitor::DeclareOrMarkOtherAccessEntity(
return &object;
}
-static bool WithMultipleAppearancesException(
- const Symbol &symbol, Symbol::Flag ompFlag) {
- return (ompFlag == Symbol::Flag::OmpFirstPrivate &&
+static bool WithMultipleAppearancesOmpException(
+ const Symbol &symbol, Symbol::Flag flag) {
+ return (flag == Symbol::Flag::OmpFirstPrivate &&
symbol.test(Symbol::Flag::OmpLastPrivate)) ||
- (ompFlag == Symbol::Flag::OmpLastPrivate &&
+ (flag == Symbol::Flag::OmpLastPrivate &&
symbol.test(Symbol::Flag::OmpFirstPrivate));
}
@@ -6883,7 +7348,7 @@ void OmpAttributeVisitor::CheckMultipleAppearances(
}
}
if (HasDataSharingAttributeObject(*target) &&
- !WithMultipleAppearancesException(symbol, ompFlag)) {
+ !WithMultipleAppearancesOmpException(symbol, ompFlag)) {
context_.Say(name.source,
"'%s' appears in more than one data-sharing clause "
"on the same OpenMP directive"_err_en_US,
@@ -6962,6 +7427,10 @@ void ResolveNamesVisitor::ResolveExecutionParts(const ProgramTree &node) {
}
}
+void ResolveNamesVisitor::ResolveAccParts(const parser::ProgramUnit &node) {
+ AccAttributeVisitor{context(), *this}.Walk(node);
+}
+
void ResolveNamesVisitor::ResolveOmpParts(const parser::ProgramUnit &node) {
OmpAttributeVisitor{context(), *this}.Walk(node);
if (!context().AnyFatalError()) {
diff --git a/flang/lib/Semantics/unparse-with-symbols.cpp b/flang/lib/Semantics/unparse-with-symbols.cpp
index 44ceb9fe08bb..67016e85777c 100644
--- a/flang/lib/Semantics/unparse-with-symbols.cpp
+++ b/flang/lib/Semantics/unparse-with-symbols.cpp
@@ -35,6 +35,11 @@ class SymbolDumpVisitor {
template <typename T> void Post(const parser::Statement<T> &) {
currStmt_ = std::nullopt;
}
+ bool Pre(const parser::AccClause &clause) {
+ currStmt_ = clause.source;
+ return true;
+ }
+ void Post(const parser::AccClause &) { currStmt_ = std::nullopt; }
bool Pre(const parser::OmpClause &clause) {
currStmt_ = clause.source;
return true;
diff --git a/flang/test/Semantics/acc-resolve01.f90 b/flang/test/Semantics/acc-resolve01.f90
new file mode 100644
index 000000000000..7e904b525926
--- /dev/null
+++ b/flang/test/Semantics/acc-resolve01.f90
@@ -0,0 +1,22 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenacc
+
+! Data-Mapping Attribute Clauses
+! 2.15.14 default Clause
+
+subroutine default_none()
+ integer a(3)
+
+ A = 1
+ B = 2
+ !$acc parallel default(none) private(c)
+ !ERROR: The DEFAULT(NONE) clause requires that 'a' must be listed in a data-mapping clause
+ A(1:2) = 3
+ !ERROR: The DEFAULT(NONE) clause requires that 'b' must be listed in a data-mapping clause
+ B = 4
+ C = 5
+ !$acc end parallel
+end subroutine default_none
+
+program mm
+ call default_none()
+end
\ No newline at end of file
diff --git a/flang/test/Semantics/acc-resolve02.f90 b/flang/test/Semantics/acc-resolve02.f90
new file mode 100644
index 000000000000..da1a417bba52
--- /dev/null
+++ b/flang/test/Semantics/acc-resolve02.f90
@@ -0,0 +1,17 @@
+! RUN: %S/test_errors.sh %s %t %f18 -fopenacc
+
+subroutine compute()
+ integer :: a(3), c, i
+
+ a = 1
+ !ERROR: 'c' appears in more than one data-sharing clause on the same OpenACC directive
+ !$acc parallel firstprivate(c) private(c)
+ do i = 1, 3
+ a(i) = c
+ end do
+ !$acc end parallel
+end subroutine compute
+
+program mm
+ call compute()
+end
diff --git a/flang/test/Semantics/acc-symbols01.f90 b/flang/test/Semantics/acc-symbols01.f90
new file mode 100644
index 000000000000..23d54eb93fbe
--- /dev/null
+++ b/flang/test/Semantics/acc-symbols01.f90
@@ -0,0 +1,26 @@
+! RUN: %S/test_symbols.sh %s %t %f18 -fopenacc
+
+!DEF: /mm MainProgram
+program mm
+ !DEF: /mm/x ObjectEntity REAL(4)
+ !DEF: /mm/y ObjectEntity REAL(4)
+ real x, y
+ !DEF: /mm/a ObjectEntity INTEGER(4)
+ !DEF: /mm/b ObjectEntity INTEGER(4)
+ !DEF: /mm/c ObjectEntity INTEGER(4)
+ !DEF: /mm/i ObjectEntity INTEGER(4)
+ integer a(10), b(10), c(10), i
+ !REF: /mm/b
+ b = 2
+ !$acc parallel present(c) firstprivate(b) private(a)
+ !$acc loop
+ !DEF: /mm/Block1/i (AccPrivate, AccPreDetermined) HostAssoc INTEGER(4)
+ do i=1,10
+ !DEF: /mm/Block1/a (AccPrivate) HostAssoc INTEGER(4)
+ !REF: /mm/Block1/i
+ !DEF: /mm/Block1/b (AccFirstPrivate) HostAssoc INTEGER(4)
+ a(i) = b(i)
+ end do
+ !$acc end parallel
+ end program
+
diff --git a/flang/test/Semantics/test_symbols.sh b/flang/test/Semantics/test_symbols.sh
index d2b3d688a39b..61ff7fdb1e7b 100755
--- a/flang/test/Semantics/test_symbols.sh
+++ b/flang/test/Semantics/test_symbols.sh
@@ -16,8 +16,9 @@
diff s=$temp/
diff s
# Strip out blank lines and all comments except "!DEF:", "!REF:", and "!$omp"
sed -e 's/!\([DR]EF:\)/KEEP \1/' -e 's/!\($omp\)/KEEP \1/' \
- -e 's/!.*//' -e 's/ *$//' -e '/^$/d' -e 's/KEEP \([DR]EF:\)/!\1/' \
- -e 's/KEEP \($omp\)/!\1/' \
+ -e 's/!\($acc\)/KEEP \1/' -e 's/!.*//' -e 's/ *$//' -e '/^$/d' \
+ -e 's/KEEP \([DR]EF:\)/!\1/' -e 's/KEEP \($omp\)/!\1/' \
+ -e 's/KEEP \($acc\)/!\1/' \
$src > $src1
egrep -v '![DR]EF:' $src1 > $src2 # strip out DEF and REF comments
# compile, inserting comments for symbols:
More information about the flang-commits
mailing list