void Post(const parser::OmpBeginLoopDirective &) {
GetContext().withinConstruct = true;
}
+ bool Pre(const parser::DoConstruct &);
bool Pre(const parser::OpenMPSectionsConstruct &);
void Post(const parser::OpenMPSectionsConstruct &) { PopContext(); }
void SetContextDirectiveEnum(OmpDirective dir) {
GetContext().directive = dir;
}
- const Scope &currScope() { return GetContext().scope; }
+ 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) {
- GetContext().objectWithDSA.emplace(&symbol, flag);
+ AddToContextObjectWithDSA(symbol, flag, GetContext());
}
bool IsObjectWithDSA(const Symbol &symbol) {
auto it{GetContext().objectWithDSA.find(&symbol)};
return it != GetContext().objectWithDSA.end();
}
+
void SetContextAssociatedLoopLevel(std::size_t level) {
GetContext().associatedLoopLevel = level;
}
std::size_t GetAssociatedLoopLevelFromClauses(const parser::OmpClauseList &);
- Symbol &MakeAssocSymbol(const SourceName &name, Symbol &prev) {
- const auto pair{
- GetContext().scope.try_emplace(name, Attrs{}, HostAssocDetails{prev})};
+ 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 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);
void ResolveOmpObject(const parser::OmpObject &, Symbol::Flag);
- Symbol *ResolveOmp(const parser::Name &, Symbol::Flag);
- Symbol *ResolveOmp(Symbol &, Symbol::Flag);
+ 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);
- Symbol *DeclarePrivateAccessEntity(Symbol &, Symbol::Flag);
+ 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(
void FinishSpecificationParts(const ProgramTree &);
void FinishDerivedTypeInstantiation(Scope &);
void ResolveExecutionParts(const ProgramTree &);
+ void ResolveOmpParts(const parser::ProgramUnit &);
};
// ImplicitRules implementation
ResolveSpecificationParts(root);
FinishSpecificationParts(root);
ResolveExecutionParts(root);
- OmpAttributeVisitor{context(), *this}.Walk(x);
+ ResolveOmpParts(x);
return false;
}
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()};
+ for (;; ++targetIt) {
+ if (targetIt == ompContext_.rend()) {
+ return;
+ }
+ if (parallelSet.test(targetIt->directive) ||
+ taskGeneratingSet.test(targetIt->directive)) {
+ break;
+ }
+ }
+ if (auto *symbol{ResolveOmp(iv, Symbol::Flag::OmpPrivate, targetIt->scope)}) {
+ targetIt++;
+ symbol->set(Symbol::Flag::OmpPreDetermined);
+ iv.symbol = symbol; // adjust the symbol within region
+ for (auto it{ompContext_.rbegin()}; it != targetIt; ++it) {
+ AddToContextObjectWithDSA(*symbol, Symbol::Flag::OmpPrivate, *it);
+ }
+ }
+}
+
+// 2.15.1.1 Data-sharing Attribute Rules - Predetermined
+// - A loop iteration variable for a sequential loop in a parallel
+// 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 (const auto &iv{GetLoopIndex(x)}; iv.symbol) {
+ if (!iv.symbol->test(Symbol::Flag::OmpPreDetermined)) {
+ ResolveSeqLoopIndexInParallelOrTaskConstruct(iv);
+ } else {
+ // TODO: conflict checks with explicitly determined DSA
+ }
+ }
+ }
+ return true;
+}
+
const parser::DoConstruct *OmpAttributeVisitor::GetDoConstructIf(
const parser::ExecutionPartConstruct &x) {
if (auto *y{std::get_if<parser::ExecutableConstruct>(&x.u)}) {
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
- auto &loopControl{loop->GetLoopControl().value()};
- using Bounds = parser::LoopControl::Bounds;
- const Bounds &bounds{std::get<Bounds>(loopControl.u)};
- const parser::Name &iv{bounds.name.thing};
- if (auto *symbol{ResolveOmp(iv, ivDSA)}) {
+ const parser::Name &iv{GetLoopIndex(*loop)};
+ if (auto *symbol{ResolveOmp(iv, ivDSA, currScope())}) {
+ symbol->set(Symbol::Flag::OmpPreDetermined);
iv.symbol = symbol; // adjust the symbol within region
AddToContextObjectWithDSA(*symbol, ivDSA);
}
// predetermined, explicitly determined, and implicitly
// determined data-sharing attributes (2.15.1.1).
if (Symbol * found{currScope().FindSymbol(name.source)}) {
- if (IsObjectWithDSA(*found)) {
+ if (symbol != found) {
name.symbol = found; // adjust the symbol within region
} else if (GetContext().defaultDSA == Symbol::Flag::OmpNone) {
context_.Say(name.source,
common::visitors{
[&](const parser::Designator &designator) {
if (const auto *name{GetDesignatorNameIfDataRef(designator)}) {
- if (auto *symbol{ResolveOmp(*name, ompFlag)}) {
+ if (auto *symbol{ResolveOmp(*name, ompFlag, currScope())}) {
AddToContextObjectWithDSA(*symbol, ompFlag);
if (dataSharingAttributeFlags.test(ompFlag)) {
CheckMultipleAppearances(*name, *symbol, ompFlag);
for (const Symbol &object :
symbol->get<CommonBlockDetails>().objects()) {
Symbol &mutableObject{const_cast<Symbol &>(object)};
- if (auto *resolvedObject{ResolveOmp(mutableObject, ompFlag)}) {
+ if (auto *resolvedObject{
+ ResolveOmp(mutableObject, ompFlag, currScope())}) {
AddToContextObjectWithDSA(*resolvedObject, ompFlag);
}
}
}
Symbol *OmpAttributeVisitor::ResolveOmp(
- const parser::Name &name, Symbol::Flag ompFlag) {
+ const parser::Name &name, Symbol::Flag ompFlag, Scope &scope) {
if (ompFlagsRequireNewSymbol.test(ompFlag)) {
- return DeclarePrivateAccessEntity(name, ompFlag);
+ return DeclarePrivateAccessEntity(name, ompFlag, scope);
} else {
return DeclareOrMarkOtherAccessEntity(name, ompFlag);
}
}
-Symbol *OmpAttributeVisitor::ResolveOmp(Symbol &symbol, Symbol::Flag ompFlag) {
+Symbol *OmpAttributeVisitor::ResolveOmp(
+ Symbol &symbol, Symbol::Flag ompFlag, Scope &scope) {
if (ompFlagsRequireNewSymbol.test(ompFlag)) {
- return DeclarePrivateAccessEntity(symbol, ompFlag);
+ return DeclarePrivateAccessEntity(symbol, ompFlag, scope);
} else {
return DeclareOrMarkOtherAccessEntity(symbol, ompFlag);
}
}
Symbol *OmpAttributeVisitor::DeclarePrivateAccessEntity(
- const parser::Name &name, Symbol::Flag ompFlag) {
+ 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);
+ name.symbol = DeclarePrivateAccessEntity(*name.symbol, ompFlag, scope);
return name.symbol;
}
Symbol *OmpAttributeVisitor::DeclarePrivateAccessEntity(
- Symbol &object, Symbol::Flag ompFlag) {
+ Symbol &object, Symbol::Flag ompFlag, Scope &scope) {
if (object.owner() != currScope()) {
- auto &symbol{MakeAssocSymbol(object.name(), object)};
+ auto &symbol{MakeAssocSymbol(object.name(), object, scope)};
symbol.set(ompFlag);
return &symbol;
} else {
}
}
+void ResolveNamesVisitor::ResolveOmpParts(const parser::ProgramUnit &node) {
+ OmpAttributeVisitor{context(), *this}.Walk(node);
+ if (!context().AnyFatalError()) {
+ // The data-sharing attribute of the loop iteration variable for a
+ // sequential loop (2.15.1.1) can only be determined when visiting
+ // the corresponding DoConstruct, a second walk is to adjust the
+ // symbols for all the data-refs of that loop iteration variable
+ // prior to the DoConstruct.
+ OmpAttributeVisitor{context(), *this}.Walk(node);
+ }
+}
+
void ResolveNamesVisitor::Post(const parser::Program &) {
// ensure that all temps were deallocated
CHECK(!attrs_);
! increment of the associated do-loop.
! c) The loop iteration variables in the associated do-loops of a simd
! construct with multiple associated do-loops are lastprivate.
+! d) A loop iteration variable for a sequential loop in a parallel or task
+! generating construct is private in the innermost such construct that
+! encloses the loop.
! - TBD
! All the tests assume that the do-loops association for collapse/ordered
!REF: /test_do/i
i = 99
!$omp do collapse(2)
- !DEF: /test_do/Block1/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
+ !DEF: /test_do/Block1/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do i=1,5
- !DEF: /test_do/Block1/Block1/j (OmpPrivate) HostAssoc INTEGER(4)
+ !DEF: /test_do/Block1/Block1/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do j=6,10
!REF: /test_do/a
a(1,1,1) = 0.
- !REF: /test_do/k
+ !DEF: /test_do/Block1/k (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do k=11,15
!REF: /test_do/a
- !REF: /test_do/k
+ !REF: /test_do/Block1/k
!REF: /test_do/Block1/Block1/j
!REF: /test_do/Block1/Block1/i
a(k,j,i) = 1.
!DEF: /test_pardo/k ObjectEntity INTEGER(4)
integer i, j, k
!$omp parallel do collapse(2) private(k) ordered(2)
- !DEF: /test_pardo/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
+ !DEF: /test_pardo/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do i=1,5
- !DEF: /test_pardo/Block1/j (OmpPrivate) HostAssoc INTEGER(4)
- do j=6,10
+ !DEF: /test_pardo/Block1/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+ do j=6,10
!REF: /test_pardo/a
a(1,1,1) = 0.
- !DEF: /test_pardo/Block1/k (OmpPrivate) HostAssoc INTEGER(4)
+ !DEF: /test_pardo/Block1/k (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do k=11,15
!REF: /test_pardo/a
!REF: /test_pardo/Block1/k
!DEF: /test_taskloop/j ObjectEntity INTEGER(4)
integer i, j
!$omp taskloop private(j)
- !DEF: /test_taskloop/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
+ !DEF: /test_taskloop/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do i=1,5
- !DEF: /test_taskloop/Block1/j (OmpPrivate) HostAssoc INTEGER(4)
+ !DEF: /test_taskloop/Block1/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
!REF: /test_taskloop/Block1/i
do j=1,i
!REF: /test_taskloop/a
!$omp target map(to:b,c) map(tofrom:sum)
!$omp teams num_teams(num_teams) thread_limit(block_threads) reduction(+:sum)
!$omp distribute
- !DEF: /dotprod/Block1/Block1/Block1/i0 (OmpPrivate) HostAssoc INTEGER(4)
+ !DEF: /dotprod/Block1/Block1/Block1/i0 (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
!REF: /dotprod/n
!REF: /dotprod/block_size
do i0=1,n,block_size
!$omp parallel do reduction(+:sum)
- !DEF: /dotprod/Block1/Block1/Block1/Block1/i (OmpPrivate) HostAssoc INTEGER(4)
- !REF: /dotprod/i0
+ !DEF: /dotprod/Block1/Block1/Block1/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+ !REF: /dotprod/Block1/Block1/Block1/i0
!DEF: /dotprod/min INTRINSIC (Function) ProcEntity
!REF: /dotprod/block_size
!REF: /dotprod/n
!DEF: /test_simd/k ObjectEntity INTEGER(4)
integer i, j, k
!$omp parallel do simd
- !DEF: /test_simd/Block1/i (OmpLinear) HostAssoc INTEGER(4)
+ !DEF: /test_simd/Block1/i (OmpLinear, OmpPreDetermined) HostAssoc INTEGER(4)
do i=1,5
- !REF: /test_simd/j
+ !DEF: /test_simd/Block1/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do j=6,10
- !REF: /test_simd/k
+ !DEF: /test_simd/Block1/k (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do k=11,15
!REF: /test_simd/a
- !REF: /test_simd/k
- !REF: /test_simd/j
+ !REF: /test_simd/Block1/k
+ !REF: /test_simd/Block1/j
!REF: /test_simd/Block1/i
a(k,j,i) = 3.14
end do
!DEF: /test_simd_multi/k ObjectEntity INTEGER(4)
integer i, j, k
!$omp parallel do simd collapse(3)
- !DEF: /test_simd_multi/Block1/i (OmpLastPrivate) HostAssoc INTEGER(4)
+ !DEF: /test_simd_multi/Block1/i (OmpLastPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do i=1,5
- !DEF: /test_simd_multi/Block1/j (OmpLastPrivate) HostAssoc INTEGER(4)
+ !DEF: /test_simd_multi/Block1/j (OmpLastPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do j=6,10
- !DEF: /test_simd_multi/Block1/k (OmpLastPrivate) HostAssoc INTEGER(4)
+ !DEF: /test_simd_multi/Block1/k (OmpLastPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
do k=11,15
!REF: /test_simd_multi/a
!REF: /test_simd_multi/Block1/k
end do
end do
end subroutine test_simd_multi
+
+! Rule d)
+!DEF: /test_seq_loop (Subroutine) Subprogram
+subroutine test_seq_loop
+ implicit none
+ !DEF: /test_seq_loop/i ObjectEntity INTEGER(4)
+ !DEF: /test_seq_loop/j ObjectEntity INTEGER(4)
+ integer i, j
+ !REF: /test_seq_loop/i
+ i = -1
+ !REF: /test_seq_loop/j
+ j = -1
+ !$omp parallel
+ !REF: /test_seq_loop/i
+ !REF: /test_seq_loop/j
+ print *, i, j
+ !$omp parallel
+ !REF: /test_seq_loop/i
+ !DEF: /test_seq_loop/Block1/Block1/j (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+ print *, i, j
+ !$omp do
+ !DEF: /test_seq_loop/Block1/Block1/Block1/i (OmpPrivate, OmpPreDetermined) HostAssoc INTEGER(4)
+ do i=1,10
+ !REF: /test_seq_loop/Block1/Block1/j
+ do j=1,10
+ end do
+ end do
+ !REF: /test_seq_loop/i
+ !REF: /test_seq_loop/Block1/Block1/j
+ print *, i, j
+ !$omp end parallel
+ !REF: /test_seq_loop/i
+ !REF: /test_seq_loop/j
+ print *, i, j
+ !$omp end parallel
+ !REF: /test_seq_loop/i
+ !REF: /test_seq_loop/j
+ print *, i, j
+end subroutine test_seq_loop