summaryrefslogtreecommitdiff
path: root/flang/lib/Semantics/resolve-directives.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'flang/lib/Semantics/resolve-directives.cpp')
-rw-r--r--flang/lib/Semantics/resolve-directives.cpp257
1 files changed, 199 insertions, 58 deletions
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 96d95162beb7..1b7718d1314d 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,13 @@ protected:
parser::OmpDefaultmapClause::ImplicitBehavior>
defaultMap;
+ std::optional<Symbol::Flag> FindSymbolWithDSA(const Symbol &symbol) {
+ if (auto it{objectWithDSA.find(&symbol)}; it != objectWithDSA.end()) {
+ return it->second;
+ }
+ return std::nullopt;
+ }
+
bool withinConstruct{false};
std::int64_t associatedLoopLevel{0};
};
@@ -75,10 +81,19 @@ protected:
: 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>) {
+ dirContext_.emplace_back(source, dir, scope);
+ if (std::size_t size{dirContext_.size()}; size > 1) {
+ std::size_t lastIndex{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 +115,21 @@ protected:
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 WithinConstruct() {
+ return !dirContext_.empty() && GetContext().withinConstruct;
+ }
+
void SetContextAssociatedLoopLevel(std::int64_t level) {
GetContext().associatedLoopLevel = level;
}
@@ -277,6 +304,12 @@ public:
return false;
}
+ bool Pre(const parser::AccClause::Reduction &x) {
+ const auto &objectList{std::get<parser::AccObjectList>(x.v.t)};
+ ResolveAccObjectList(objectList, Symbol::Flag::AccReduction);
+ return false;
+ }
+
void Post(const parser::Name &);
private:
@@ -384,8 +417,8 @@ public:
}
void Post(const parser::OmpMetadirectiveDirective &) { PopContext(); }
- bool Pre(const parser::OpenMPBlockConstruct &);
- void Post(const parser::OpenMPBlockConstruct &);
+ bool Pre(const parser::OmpBlockConstruct &);
+ void Post(const parser::OmpBlockConstruct &);
void Post(const parser::OmpBeginDirective &x) {
GetContext().withinConstruct = true;
@@ -531,6 +564,9 @@ public:
bool Pre(const parser::OpenMPDeclarativeAllocate &);
void Post(const parser::OpenMPDeclarativeAllocate &) { PopContext(); }
+ bool Pre(const parser::OpenMPAssumeConstruct &);
+ void Post(const parser::OpenMPAssumeConstruct &) { PopContext(); }
+
bool Pre(const parser::OpenMPAtomicConstruct &);
void Post(const parser::OpenMPAtomicConstruct &) { PopContext(); }
@@ -820,7 +856,23 @@ public:
const parser::OmpClause *GetAssociatedClause() { return associatedClause; }
private:
- std::int64_t GetAssociatedLoopLevelFromClauses(const parser::OmpClauseList &);
+ /// Given a vector of loop levels and a vector of corresponding clauses find
+ /// the largest loop level and set the associated loop level to the found
+ /// maximum. This is used for error handling to ensure that the number of
+ /// affected loops is not larger that the number of available loops.
+ std::int64_t SetAssociatedMaxClause(llvm::SmallVector<std::int64_t> &,
+ llvm::SmallVector<const parser::OmpClause *> &);
+ std::int64_t GetNumAffectedLoopsFromLoopConstruct(
+ const parser::OpenMPLoopConstruct &);
+ void CollectNumAffectedLoopsFromLoopConstruct(
+ const parser::OpenMPLoopConstruct &, llvm::SmallVector<std::int64_t> &,
+ llvm::SmallVector<const parser::OmpClause *> &);
+ void CollectNumAffectedLoopsFromInnerLoopContruct(
+ const parser::OpenMPLoopConstruct &, llvm::SmallVector<std::int64_t> &,
+ llvm::SmallVector<const parser::OmpClause *> &);
+ void CollectNumAffectedLoopsFromClauses(const parser::OmpClauseList &,
+ llvm::SmallVector<std::int64_t> &,
+ llvm::SmallVector<const parser::OmpClause *> &);
Symbol::Flags dataSharingAttributeFlags{Symbol::Flag::OmpShared,
Symbol::Flag::OmpPrivate, Symbol::Flag::OmpFirstPrivate,
@@ -1570,10 +1622,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 && WithinConstruct()) {
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
@@ -1723,7 +1775,7 @@ static std::string ScopeSourcePos(const Fortran::semantics::Scope &scope);
#endif
-bool OmpAttributeVisitor::Pre(const parser::OpenMPBlockConstruct &x) {
+bool OmpAttributeVisitor::Pre(const parser::OmpBlockConstruct &x) {
const parser::OmpDirectiveSpecification &dirSpec{x.BeginDir()};
llvm::omp::Directive dirId{dirSpec.DirId()};
switch (dirId) {
@@ -1740,10 +1792,13 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPBlockConstruct &x) {
case llvm::omp::Directive::OMPD_task:
case llvm::omp::Directive::OMPD_taskgroup:
case llvm::omp::Directive::OMPD_teams:
+ case llvm::omp::Directive::OMPD_workdistribute:
case llvm::omp::Directive::OMPD_workshare:
case llvm::omp::Directive::OMPD_parallel_workshare:
case llvm::omp::Directive::OMPD_target_teams:
+ case llvm::omp::Directive::OMPD_target_teams_workdistribute:
case llvm::omp::Directive::OMPD_target_parallel:
+ case llvm::omp::Directive::OMPD_teams_workdistribute:
PushContext(dirSpec.source, dirId);
break;
default:
@@ -1759,7 +1814,7 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPBlockConstruct &x) {
return true;
}
-void OmpAttributeVisitor::Post(const parser::OpenMPBlockConstruct &x) {
+void OmpAttributeVisitor::Post(const parser::OmpBlockConstruct &x) {
const parser::OmpDirectiveSpecification &dirSpec{x.BeginDir()};
llvm::omp::Directive dirId{dirSpec.DirId()};
switch (dirId) {
@@ -1773,9 +1828,12 @@ void OmpAttributeVisitor::Post(const parser::OpenMPBlockConstruct &x) {
case llvm::omp::Directive::OMPD_target:
case llvm::omp::Directive::OMPD_task:
case llvm::omp::Directive::OMPD_teams:
+ case llvm::omp::Directive::OMPD_workdistribute:
case llvm::omp::Directive::OMPD_parallel_workshare:
case llvm::omp::Directive::OMPD_target_teams:
- case llvm::omp::Directive::OMPD_target_parallel: {
+ case llvm::omp::Directive::OMPD_target_parallel:
+ case llvm::omp::Directive::OMPD_target_teams_workdistribute:
+ case llvm::omp::Directive::OMPD_teams_workdistribute: {
bool hasPrivate;
for (const auto *allocName : allocateNames_) {
hasPrivate = false;
@@ -1826,7 +1884,6 @@ bool OmpAttributeVisitor::Pre(
bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) {
const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
const auto &beginDir{std::get<parser::OmpLoopDirective>(beginLoopDir.t)};
- const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
switch (beginDir.v) {
case llvm::omp::Directive::OMPD_distribute:
case llvm::omp::Directive::OMPD_distribute_parallel_do:
@@ -1877,7 +1934,7 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) {
beginDir.v == llvm::omp::Directive::OMPD_target_loop)
IssueNonConformanceWarning(beginDir.v, beginDir.source, 52);
ClearDataSharingAttributeObjects();
- SetContextAssociatedLoopLevel(GetAssociatedLoopLevelFromClauses(clauseList));
+ SetContextAssociatedLoopLevel(GetNumAffectedLoopsFromLoopConstruct(x));
if (beginDir.v == llvm::omp::Directive::OMPD_do) {
auto &optLoopCons = std::get<std::optional<parser::NestedConstruct>>(x.t);
@@ -1891,7 +1948,7 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPLoopConstruct &x) {
}
}
PrivatizeAssociatedLoopIndexAndCheckLoopLevel(x);
- ordCollapseLevel = GetAssociatedLoopLevelFromClauses(clauseList) + 1;
+ ordCollapseLevel = GetNumAffectedLoopsFromLoopConstruct(x) + 1;
return true;
}
@@ -1950,7 +2007,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 (WithinConstruct()) {
llvm::SmallVector<const parser::Name *> ivs;
if (x.IsDoNormal()) {
const parser::Name *iv{GetLoopIndex(x)};
@@ -1979,44 +2036,111 @@ bool OmpAttributeVisitor::Pre(const parser::DoConstruct &x) {
return true;
}
-std::int64_t OmpAttributeVisitor::GetAssociatedLoopLevelFromClauses(
- const parser::OmpClauseList &x) {
- std::int64_t orderedLevel{0};
- std::int64_t collapseLevel{0};
+static bool isSizesClause(const parser::OmpClause *clause) {
+ return std::holds_alternative<parser::OmpClause::Sizes>(clause->u);
+}
+
+std::int64_t OmpAttributeVisitor::SetAssociatedMaxClause(
+ llvm::SmallVector<std::int64_t> &levels,
+ llvm::SmallVector<const parser::OmpClause *> &clauses) {
+
+ // Find the tile level to ensure that the COLLAPSE clause value
+ // does not exeed the number of tiled loops.
+ std::int64_t tileLevel = 0;
+ for (auto [level, clause] : llvm::zip_equal(levels, clauses))
+ if (isSizesClause(clause))
+ tileLevel = level;
+
+ std::int64_t maxLevel = 1;
+ const parser::OmpClause *maxClause = nullptr;
+ for (auto [level, clause] : llvm::zip_equal(levels, clauses)) {
+ if (tileLevel > 0 && tileLevel < level) {
+ context_.Say(clause->source,
+ "The value of the parameter in the COLLAPSE clause must"
+ " not be larger than the number of the number of tiled loops"
+ " because collapse currently is limited to independent loop"
+ " iterations."_err_en_US);
+ return 1;
+ }
+
+ if (level > maxLevel) {
+ maxLevel = level;
+ maxClause = clause;
+ }
+ }
+ if (maxClause)
+ SetAssociatedClause(maxClause);
+ return maxLevel;
+}
+
+std::int64_t OmpAttributeVisitor::GetNumAffectedLoopsFromLoopConstruct(
+ const parser::OpenMPLoopConstruct &x) {
+ llvm::SmallVector<std::int64_t> levels;
+ llvm::SmallVector<const parser::OmpClause *> clauses;
+
+ CollectNumAffectedLoopsFromLoopConstruct(x, levels, clauses);
+ return SetAssociatedMaxClause(levels, clauses);
+}
+
+void OmpAttributeVisitor::CollectNumAffectedLoopsFromLoopConstruct(
+ const parser::OpenMPLoopConstruct &x,
+ llvm::SmallVector<std::int64_t> &levels,
+ llvm::SmallVector<const parser::OmpClause *> &clauses) {
+ const auto &beginLoopDir{std::get<parser::OmpBeginLoopDirective>(x.t)};
+ const auto &clauseList{std::get<parser::OmpClauseList>(beginLoopDir.t)};
+
+ CollectNumAffectedLoopsFromClauses(clauseList, levels, clauses);
+ CollectNumAffectedLoopsFromInnerLoopContruct(x, levels, clauses);
+}
+
+void OmpAttributeVisitor::CollectNumAffectedLoopsFromInnerLoopContruct(
+ const parser::OpenMPLoopConstruct &x,
+ llvm::SmallVector<std::int64_t> &levels,
+ llvm::SmallVector<const parser::OmpClause *> &clauses) {
- const parser::OmpClause *ordClause{nullptr};
- const parser::OmpClause *collClause{nullptr};
+ const auto &nestedOptional =
+ std::get<std::optional<parser::NestedConstruct>>(x.t);
+ assert(nestedOptional.has_value() &&
+ "Expected a DoConstruct or OpenMPLoopConstruct");
+ const auto *innerConstruct =
+ std::get_if<common::Indirection<parser::OpenMPLoopConstruct>>(
+ &(nestedOptional.value()));
+ if (innerConstruct) {
+ CollectNumAffectedLoopsFromLoopConstruct(
+ innerConstruct->value(), levels, clauses);
+ }
+}
+
+void OmpAttributeVisitor::CollectNumAffectedLoopsFromClauses(
+ const parser::OmpClauseList &x, llvm::SmallVector<std::int64_t> &levels,
+ llvm::SmallVector<const parser::OmpClause *> &clauses) {
for (const auto &clause : x.v) {
- if (const auto *orderedClause{
+ if (const auto oclause{
std::get_if<parser::OmpClause::Ordered>(&clause.u)}) {
- if (const auto v{EvaluateInt64(context_, orderedClause->v)}) {
- orderedLevel = *v;
+ std::int64_t level = 0;
+ if (const auto v{EvaluateInt64(context_, oclause->v)}) {
+ level = *v;
}
- ordClause = &clause;
+ levels.push_back(level);
+ clauses.push_back(&clause);
}
- if (const auto *collapseClause{
+
+ if (const auto cclause{
std::get_if<parser::OmpClause::Collapse>(&clause.u)}) {
- if (const auto v{EvaluateInt64(context_, collapseClause->v)}) {
- collapseLevel = *v;
+ std::int64_t level = 0;
+ if (const auto v{EvaluateInt64(context_, cclause->v)}) {
+ level = *v;
}
- collClause = &clause;
+ levels.push_back(level);
+ clauses.push_back(&clause);
}
- }
- if (orderedLevel && (!collapseLevel || orderedLevel >= collapseLevel)) {
- SetAssociatedClause(ordClause);
- return orderedLevel;
- } else if (!orderedLevel && collapseLevel) {
- SetAssociatedClause(collClause);
- return collapseLevel;
- } else {
- SetAssociatedClause(nullptr);
+ if (const auto tclause{std::get_if<parser::OmpClause::Sizes>(&clause.u)}) {
+ levels.push_back(tclause->v.size());
+ clauses.push_back(&clause);
+ }
}
- // orderedLevel < collapseLevel is an error handled in structural
- // checks
-
- return 1; // default is outermost loop
}
// 2.15.1.1 Data-sharing Attribute Rules - Predetermined
@@ -2048,10 +2172,21 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndexAndCheckLoopLevel(
const parser::OmpClause *clause{GetAssociatedClause()};
bool hasCollapseClause{
clause ? (clause->Id() == llvm::omp::OMPC_collapse) : false};
+ const parser::OpenMPLoopConstruct *innerMostLoop = &x;
+ const parser::NestedConstruct *innerMostNest = nullptr;
+ while (auto &optLoopCons{
+ std::get<std::optional<parser::NestedConstruct>>(innerMostLoop->t)}) {
+ innerMostNest = &(optLoopCons.value());
+ if (const auto *innerLoop{
+ std::get_if<common::Indirection<parser::OpenMPLoopConstruct>>(
+ innerMostNest)}) {
+ innerMostLoop = &(innerLoop->value());
+ } else
+ break;
+ }
- auto &optLoopCons = std::get<std::optional<parser::NestedConstruct>>(x.t);
- if (optLoopCons.has_value()) {
- if (const auto &outer{std::get_if<parser::DoConstruct>(&*optLoopCons)}) {
+ if (innerMostNest) {
+ if (const auto &outer{std::get_if<parser::DoConstruct>(innerMostNest)}) {
for (const parser::DoConstruct *loop{&*outer}; loop && level > 0;
--level) {
if (loop->IsDoConcurrent()) {
@@ -2087,7 +2222,7 @@ void OmpAttributeVisitor::PrivatizeAssociatedLoopIndexAndCheckLoopLevel(
CheckAssocLoopLevel(level, GetAssociatedClause());
} else if (const auto &loop{std::get_if<
common::Indirection<parser::OpenMPLoopConstruct>>(
- &*optLoopCons)}) {
+ innerMostNest)}) {
auto &beginDirective =
std::get<parser::OmpBeginLoopDirective>(loop->value().t);
auto &beginLoopDirective =
@@ -2214,6 +2349,11 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPDeclarativeAllocate &x) {
return false;
}
+bool OmpAttributeVisitor::Pre(const parser::OpenMPAssumeConstruct &x) {
+ PushContext(x.source, llvm::omp::Directive::OMPD_assume);
+ return true;
+}
+
bool OmpAttributeVisitor::Pre(const parser::OpenMPAtomicConstruct &x) {
PushContext(x.source, llvm::omp::Directive::OMPD_atomic);
return true;
@@ -2455,7 +2595,7 @@ static bool IsTargetCaptureImplicitlyFirstprivatizeable(const Symbol &symbol,
// investigate the flags we can intermix with.
if (!(dsa & (dataSharingAttributeFlags | dataMappingAttributeFlags))
.none() ||
- !checkSym.flags().none() || semantics::IsAssumedShape(checkSym) ||
+ !checkSym.flags().none() || IsAssumedShape(checkSym) ||
semantics::IsAllocatableOrPointer(checkSym)) {
return false;
}
@@ -2476,14 +2616,15 @@ static bool IsTargetCaptureImplicitlyFirstprivatizeable(const Symbol &symbol,
return false;
};
- if (checkSymbol(symbol)) {
- const auto *hostAssoc{symbol.detailsIf<HostAssocDetails>()};
- if (hostAssoc) {
- return checkSymbol(hostAssoc->symbol());
- }
- return true;
- }
- return false;
+ return common::visit(
+ common::visitors{
+ [&](const UseDetails &x) -> bool { return checkSymbol(x.symbol()); },
+ [&](const HostAssocDetails &x) -> bool {
+ return checkSymbol(x.symbol());
+ },
+ [&](const auto &) -> bool { return checkSymbol(symbol); },
+ },
+ symbol.details());
}
void OmpAttributeVisitor::CreateImplicitSymbols(const Symbol *symbol) {
@@ -2671,7 +2812,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 && WithinConstruct()) {
if (IsPrivatizable(symbol) && !IsObjectWithDSA(*symbol)) {
// TODO: create a separate function to go through the rules for
// predetermined, explicitly determined, and implicitly