-
Notifications
You must be signed in to change notification settings - Fork 14.8k
[flang][acc] Add a semantic check for the validity of nested parallelism #152225
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
@llvm/pr-subscribers-openacc Author: None (khaki3) ChangesThis PR implements a semantic checker to ensure the legality of nested OpenACC parallelism. The following are quotes from Spec 3.3. We need to disallow loops from having parallelism at the same level as or at a sub-level of child loops. >2.9.2 gang clause >[2074] <ins>When the parent compute construct is a kernels construct</ins>, the gang clause behaves as follows. (...) >2.9.3 worker clause >2.9.4 vector clause https://openacc.org/sites/default/files/inline-images/Specification/OpenACC-3.3-final.pdf Full diff: https://github.com/llvm/llvm-project/pull/152225.diff 4 Files Affected:
diff --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp
index 77e2b01578641..ebfaa01660523 100644
--- a/flang/lib/Semantics/check-acc-structure.cpp
+++ b/flang/lib/Semantics/check-acc-structure.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
#include "check-acc-structure.h"
+#include "resolve-names-utils.h"
#include "flang/Common/enum-set.h"
#include "flang/Evaluate/tools.h"
#include "flang/Parser/parse-tree.h"
@@ -106,18 +107,27 @@ bool AccStructureChecker::IsComputeConstruct(
directive == llvm::acc::ACCD_kernels_loop;
}
-bool AccStructureChecker::IsInsideComputeConstruct() const {
- if (dirContext_.size() <= 1) {
- return false;
- }
+bool AccStructureChecker::IsLoopConstruct(
+ llvm::acc::Directive directive) const {
+ return directive == llvm::acc::Directive::ACCD_loop ||
+ directive == llvm::acc::ACCD_parallel_loop ||
+ directive == llvm::acc::ACCD_serial_loop ||
+ directive == llvm::acc::ACCD_kernels_loop;
+}
+std::optional<llvm::acc::Directive>
+AccStructureChecker::getParentComputeConstruct() const {
// Check all nested context skipping the first one.
for (std::size_t i = dirContext_.size() - 1; i > 0; --i) {
if (IsComputeConstruct(dirContext_[i - 1].directive)) {
- return true;
+ return dirContext_[i - 1].directive;
}
}
- return false;
+ return std::nullopt;
+}
+
+bool AccStructureChecker::IsInsideComputeConstruct() const {
+ return getParentComputeConstruct().has_value();
}
void AccStructureChecker::CheckNotInComputeConstruct() {
@@ -128,6 +138,16 @@ void AccStructureChecker::CheckNotInComputeConstruct() {
}
}
+bool AccStructureChecker::IsInsideParallelConstruct() const {
+ if (auto directive = getParentComputeConstruct()) {
+ if (*directive == llvm::acc::ACCD_parallel ||
+ *directive == llvm::acc::ACCD_parallel_loop) {
+ return true;
+ }
+ }
+ return false;
+}
+
void AccStructureChecker::Enter(const parser::AccClause &x) {
SetContextClause(x);
}
@@ -250,6 +270,95 @@ void AccStructureChecker::Leave(const parser::OpenACCCombinedConstruct &x) {
dirContext_.pop_back();
}
+std::optional<std::int64_t> AccStructureChecker::getGangDimensionSize(
+ DirectiveContext &dirContext) {
+ for (auto it : dirContext.clauseInfo) {
+ const auto *clause{it.second};
+ if (const auto *gangClause{
+ std::get_if<parser::AccClause::Gang>(&clause->u)}) {
+ if (gangClause->v) {
+ const Fortran::parser::AccGangArgList &x{*gangClause->v};
+ for (const Fortran::parser::AccGangArg &gangArg : x.v) {
+ if (const auto *dim{
+ std::get_if<Fortran::parser::AccGangArg::Dim>(&gangArg.u)}) {
+ if (const auto v{EvaluateInt64(context_, dim->v)}) {
+ return *v;
+ }
+ }
+ }
+ }
+ }
+ }
+ return std::nullopt;
+}
+
+void AccStructureChecker::CheckNotInSameOrSubLevelLoopConstruct() {
+ for (std::size_t i = dirContext_.size() - 1; i > 0; --i) {
+ auto &parent{dirContext_[i - 1]};
+ if (IsLoopConstruct(parent.directive)) {
+ for (auto parentClause : parent.actualClauses) {
+ for (auto cl : GetContext().actualClauses) {
+ bool invalid{false};
+ if (parentClause == llvm::acc::Clause::ACCC_gang &&
+ cl == llvm::acc::Clause::ACCC_gang) {
+ if (IsInsideParallelConstruct()) {
+ auto parentDim = getGangDimensionSize(parent);
+ auto currentDim = getGangDimensionSize(GetContext());
+ std::int64_t parentDimNum = 1, currentDimNum = 1;
+ if (parentDim) {
+ parentDimNum = *parentDim;
+ }
+ if (currentDim) {
+ currentDimNum = *currentDim;
+ }
+ if (parentDimNum <= currentDimNum) {
+ std::string parentDimStr, currentDimStr;
+ if (parentDim) {
+ parentDimStr = "(dim:" + std::to_string(parentDimNum) + ")";
+ }
+ if (currentDim) {
+ currentDimStr = "(dim:" + std::to_string(currentDimNum) + ")";
+ }
+ context_.Say(GetContext().clauseSource,
+ "%s%s clause is not allowed in the region of a loop with the %s%s clause"_err_en_US,
+ parser::ToUpperCaseLetters(
+ llvm::acc::getOpenACCClauseName(cl).str()),
+ currentDimStr,
+ parser::ToUpperCaseLetters(
+ llvm::acc::getOpenACCClauseName(parentClause).str()),
+ parentDimStr);
+ continue;
+ }
+ } else {
+ invalid = true;
+ }
+ } else if (parentClause == llvm::acc::Clause::ACCC_worker &&
+ (cl == llvm::acc::Clause::ACCC_gang ||
+ cl == llvm::acc::Clause::ACCC_worker)) {
+ invalid = true;
+ } else if (parentClause == llvm::acc::Clause::ACCC_vector &&
+ (cl == llvm::acc::Clause::ACCC_gang ||
+ cl == llvm::acc::Clause::ACCC_worker ||
+ cl == llvm::acc::Clause::ACCC_vector)) {
+ invalid = true;
+ }
+ if (invalid) {
+ context_.Say(GetContext().clauseSource,
+ "%s clause is not allowed in the region of a loop with the %s clause"_err_en_US,
+ parser::ToUpperCaseLetters(
+ llvm::acc::getOpenACCClauseName(cl).str()),
+ parser::ToUpperCaseLetters(
+ llvm::acc::getOpenACCClauseName(parentClause).str()));
+ }
+ }
+ }
+ }
+ if (IsComputeConstruct(parent.directive)) {
+ break;
+ }
+ }
+}
+
void AccStructureChecker::Enter(const parser::OpenACCLoopConstruct &x) {
const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};
const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)};
@@ -267,6 +376,8 @@ void AccStructureChecker::Leave(const parser::OpenACCLoopConstruct &x) {
CheckNotAllowedIfClause(llvm::acc::Clause::ACCC_seq,
{llvm::acc::Clause::ACCC_gang, llvm::acc::Clause::ACCC_vector,
llvm::acc::Clause::ACCC_worker});
+ // Restriction - 2.9.2, 2.9.3, 2.9.4
+ CheckNotInSameOrSubLevelLoopConstruct();
}
dirContext_.pop_back();
}
@@ -570,8 +681,8 @@ void AccStructureChecker::Enter(const parser::OpenACCCacheConstruct &x) {
PushContextAndClauseSets(verbatim.source, llvm::acc::Directive::ACCD_cache);
SetContextDirectiveSource(verbatim.source);
if (loopNestLevel == 0) {
- context_.Say(verbatim.source,
- "The CACHE directive must be inside a loop"_err_en_US);
+ context_.Say(
+ verbatim.source, "The CACHE directive must be inside a loop"_err_en_US);
}
}
void AccStructureChecker::Leave(const parser::OpenACCCacheConstruct &x) {
diff --git a/flang/lib/Semantics/check-acc-structure.h b/flang/lib/Semantics/check-acc-structure.h
index 359f1557b62cb..711d0326349a4 100644
--- a/flang/lib/Semantics/check-acc-structure.h
+++ b/flang/lib/Semantics/check-acc-structure.h
@@ -98,8 +98,14 @@ class AccStructureChecker
bool CheckAllowedModifier(llvm::acc::Clause clause);
bool IsComputeConstruct(llvm::acc::Directive directive) const;
+ bool IsLoopConstruct(llvm::acc::Directive directive) const;
+ std::optional<llvm::acc::Directive> getParentComputeConstruct() const;
bool IsInsideComputeConstruct() const;
+ bool IsInsideParallelConstruct() const;
void CheckNotInComputeConstruct();
+ std::optional<std::int64_t> getGangDimensionSize(
+ DirectiveContext &dirContext);
+ void CheckNotInSameOrSubLevelLoopConstruct();
void CheckMultipleOccurrenceInDeclare(
const parser::AccObjectList &, llvm::acc::Clause);
void CheckMultipleOccurrenceInDeclare(
diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index b1bf3e550aebc..1b5909ffeb992 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -160,7 +160,7 @@ template <typename D> class NoBranchingEnforce {
if (numDoConstruct_ > 0) {
return;
}
- // did not found an enclosing looping construct within the OpenMP/OpenACC
+ // did not find an enclosing looping construct within the OpenMP/OpenACC
// directive
EmitUnlabelledBranchOutError(stmt);
}
diff --git a/flang/test/Semantics/OpenACC/acc-loop.f90 b/flang/test/Semantics/OpenACC/acc-loop.f90
index 859cf3feec0d6..9301cf85305d4 100644
--- a/flang/test/Semantics/OpenACC/acc-loop.f90
+++ b/flang/test/Semantics/OpenACC/acc-loop.f90
@@ -13,7 +13,7 @@ program openacc_loop_validity
integer :: n
end type atype
- integer :: i, j, k, b, gang_size, vector_size, worker_size
+ integer :: i, j, k, l, m, b, gang_size, vector_size, worker_size
integer, parameter :: N = 256
integer, dimension(N) :: c
logical, dimension(N) :: d, e
@@ -259,6 +259,98 @@ program openacc_loop_validity
end do
!$acc end parallel
+ !$acc parallel
+ !$acc loop gang
+ do i = 1, n
+ !$acc loop worker
+ do j = 1, n
+ !ERROR: GANG clause is not allowed in the region of a loop with the WORKER clause
+ !ERROR: GANG clause is not allowed in the region of a loop with the GANG clause
+ !$acc loop gang vector
+ do k = 1, i
+ end do
+ end do
+ end do
+ !$acc end parallel
+
+ !$acc parallel loop vector
+ do i = 1, n
+ !ERROR: GANG clause is not allowed in the region of a loop with the VECTOR clause
+ !$acc loop gang
+ do j = 1, n
+ !ERROR: WORKER clause is not allowed in the region of a loop with the VECTOR clause
+ !$acc loop worker
+ do k = 1, i
+ !ERROR: VECTOR clause is not allowed in the region of a loop with the VECTOR clause
+ !$acc loop vector
+ do l = 1, 1
+ end do
+ end do
+ end do
+ end do
+ !$acc end parallel loop
+
+ !$acc kernels
+ do i = 1, n
+ !$acc loop gang worker
+ do j = 1, n
+ !ERROR: WORKER clause is not allowed in the region of a loop with the WORKER clause
+ !$acc loop worker vector
+ do k = 1, i
+ end do
+ end do
+ end do
+ !$acc end kernels
+
+ !$acc parallel
+ !$acc loop gang(dim:1)
+ do i = 1, n
+ !ERROR: GANG(dim:1) clause is not allowed in the region of a loop with the GANG(dim:1) clause
+ !$acc loop gang(dim:1)
+ do j = 1, n
+ !ERROR: GANG(dim:2) clause is not allowed in the region of a loop with the GANG(dim:1) clause
+ !$acc loop gang(dim:2)
+ do k = 1, i
+ !ERROR: GANG(dim:3) clause is not allowed in the region of a loop with the GANG(dim:2) clause
+ !ERROR: GANG(dim:3) clause is not allowed in the region of a loop with the GANG(dim:1) clause
+ !$acc loop gang(dim:3)
+ do l = 1, 1
+ !ERROR: GANG(dim:3) clause is not allowed in the region of a loop with the GANG(dim:3) clause
+ !ERROR: GANG(dim:3) clause is not allowed in the region of a loop with the GANG(dim:2) clause
+ !ERROR: GANG(dim:3) clause is not allowed in the region of a loop with the GANG(dim:1) clause
+ !$acc loop gang(dim:3)
+ do m = 1, 1
+ end do
+ end do
+ end do
+ end do
+ end do
+ !$acc end parallel
+
+ !$acc parallel loop gang(dim:3)
+ do i = 1, n
+ !$acc loop gang(dim:2)
+ do j = 1, n
+ !$acc loop gang(dim:1) worker vector
+ do k = 1, i
+ end do
+ end do
+ end do
+ !$acc end parallel loop
+
+ !$acc kernels loop gang(dim:3)
+ do i = 1, n
+ !ERROR: GANG clause is not allowed in the region of a loop with the GANG clause
+ !$acc loop gang(dim:2)
+ do j = 1, n
+ !ERROR: GANG clause is not allowed in the region of a loop with the GANG clause
+ !$acc loop gang(dim:1) worker vector
+ do k = 1, i
+ end do
+ end do
+ end do
+ !$acc end kernels loop
+
!ERROR: Clause IF is not allowed after clause DEVICE_TYPE on the PARALLEL directive
!$acc parallel device_type(*) if(.TRUE.)
!$acc loop
|
@llvm/pr-subscribers-flang-semantics Author: None (khaki3) ChangesThis PR implements a semantic checker to ensure the legality of nested OpenACC parallelism. The following are quotes from Spec 3.3. We need to disallow loops from having parallelism at the same level as or at a sub-level of child loops. >2.9.2 gang clause >[2074] <ins>When the parent compute construct is a kernels construct</ins>, the gang clause behaves as follows. (...) >2.9.3 worker clause >2.9.4 vector clause https://openacc.org/sites/default/files/inline-images/Specification/OpenACC-3.3-final.pdf Full diff: https://github.com/llvm/llvm-project/pull/152225.diff 4 Files Affected:
diff --git a/flang/lib/Semantics/check-acc-structure.cpp b/flang/lib/Semantics/check-acc-structure.cpp
index 77e2b01578641..ebfaa01660523 100644
--- a/flang/lib/Semantics/check-acc-structure.cpp
+++ b/flang/lib/Semantics/check-acc-structure.cpp
@@ -6,6 +6,7 @@
//
//===----------------------------------------------------------------------===//
#include "check-acc-structure.h"
+#include "resolve-names-utils.h"
#include "flang/Common/enum-set.h"
#include "flang/Evaluate/tools.h"
#include "flang/Parser/parse-tree.h"
@@ -106,18 +107,27 @@ bool AccStructureChecker::IsComputeConstruct(
directive == llvm::acc::ACCD_kernels_loop;
}
-bool AccStructureChecker::IsInsideComputeConstruct() const {
- if (dirContext_.size() <= 1) {
- return false;
- }
+bool AccStructureChecker::IsLoopConstruct(
+ llvm::acc::Directive directive) const {
+ return directive == llvm::acc::Directive::ACCD_loop ||
+ directive == llvm::acc::ACCD_parallel_loop ||
+ directive == llvm::acc::ACCD_serial_loop ||
+ directive == llvm::acc::ACCD_kernels_loop;
+}
+std::optional<llvm::acc::Directive>
+AccStructureChecker::getParentComputeConstruct() const {
// Check all nested context skipping the first one.
for (std::size_t i = dirContext_.size() - 1; i > 0; --i) {
if (IsComputeConstruct(dirContext_[i - 1].directive)) {
- return true;
+ return dirContext_[i - 1].directive;
}
}
- return false;
+ return std::nullopt;
+}
+
+bool AccStructureChecker::IsInsideComputeConstruct() const {
+ return getParentComputeConstruct().has_value();
}
void AccStructureChecker::CheckNotInComputeConstruct() {
@@ -128,6 +138,16 @@ void AccStructureChecker::CheckNotInComputeConstruct() {
}
}
+bool AccStructureChecker::IsInsideParallelConstruct() const {
+ if (auto directive = getParentComputeConstruct()) {
+ if (*directive == llvm::acc::ACCD_parallel ||
+ *directive == llvm::acc::ACCD_parallel_loop) {
+ return true;
+ }
+ }
+ return false;
+}
+
void AccStructureChecker::Enter(const parser::AccClause &x) {
SetContextClause(x);
}
@@ -250,6 +270,95 @@ void AccStructureChecker::Leave(const parser::OpenACCCombinedConstruct &x) {
dirContext_.pop_back();
}
+std::optional<std::int64_t> AccStructureChecker::getGangDimensionSize(
+ DirectiveContext &dirContext) {
+ for (auto it : dirContext.clauseInfo) {
+ const auto *clause{it.second};
+ if (const auto *gangClause{
+ std::get_if<parser::AccClause::Gang>(&clause->u)}) {
+ if (gangClause->v) {
+ const Fortran::parser::AccGangArgList &x{*gangClause->v};
+ for (const Fortran::parser::AccGangArg &gangArg : x.v) {
+ if (const auto *dim{
+ std::get_if<Fortran::parser::AccGangArg::Dim>(&gangArg.u)}) {
+ if (const auto v{EvaluateInt64(context_, dim->v)}) {
+ return *v;
+ }
+ }
+ }
+ }
+ }
+ }
+ return std::nullopt;
+}
+
+void AccStructureChecker::CheckNotInSameOrSubLevelLoopConstruct() {
+ for (std::size_t i = dirContext_.size() - 1; i > 0; --i) {
+ auto &parent{dirContext_[i - 1]};
+ if (IsLoopConstruct(parent.directive)) {
+ for (auto parentClause : parent.actualClauses) {
+ for (auto cl : GetContext().actualClauses) {
+ bool invalid{false};
+ if (parentClause == llvm::acc::Clause::ACCC_gang &&
+ cl == llvm::acc::Clause::ACCC_gang) {
+ if (IsInsideParallelConstruct()) {
+ auto parentDim = getGangDimensionSize(parent);
+ auto currentDim = getGangDimensionSize(GetContext());
+ std::int64_t parentDimNum = 1, currentDimNum = 1;
+ if (parentDim) {
+ parentDimNum = *parentDim;
+ }
+ if (currentDim) {
+ currentDimNum = *currentDim;
+ }
+ if (parentDimNum <= currentDimNum) {
+ std::string parentDimStr, currentDimStr;
+ if (parentDim) {
+ parentDimStr = "(dim:" + std::to_string(parentDimNum) + ")";
+ }
+ if (currentDim) {
+ currentDimStr = "(dim:" + std::to_string(currentDimNum) + ")";
+ }
+ context_.Say(GetContext().clauseSource,
+ "%s%s clause is not allowed in the region of a loop with the %s%s clause"_err_en_US,
+ parser::ToUpperCaseLetters(
+ llvm::acc::getOpenACCClauseName(cl).str()),
+ currentDimStr,
+ parser::ToUpperCaseLetters(
+ llvm::acc::getOpenACCClauseName(parentClause).str()),
+ parentDimStr);
+ continue;
+ }
+ } else {
+ invalid = true;
+ }
+ } else if (parentClause == llvm::acc::Clause::ACCC_worker &&
+ (cl == llvm::acc::Clause::ACCC_gang ||
+ cl == llvm::acc::Clause::ACCC_worker)) {
+ invalid = true;
+ } else if (parentClause == llvm::acc::Clause::ACCC_vector &&
+ (cl == llvm::acc::Clause::ACCC_gang ||
+ cl == llvm::acc::Clause::ACCC_worker ||
+ cl == llvm::acc::Clause::ACCC_vector)) {
+ invalid = true;
+ }
+ if (invalid) {
+ context_.Say(GetContext().clauseSource,
+ "%s clause is not allowed in the region of a loop with the %s clause"_err_en_US,
+ parser::ToUpperCaseLetters(
+ llvm::acc::getOpenACCClauseName(cl).str()),
+ parser::ToUpperCaseLetters(
+ llvm::acc::getOpenACCClauseName(parentClause).str()));
+ }
+ }
+ }
+ }
+ if (IsComputeConstruct(parent.directive)) {
+ break;
+ }
+ }
+}
+
void AccStructureChecker::Enter(const parser::OpenACCLoopConstruct &x) {
const auto &beginDir{std::get<parser::AccBeginLoopDirective>(x.t)};
const auto &loopDir{std::get<parser::AccLoopDirective>(beginDir.t)};
@@ -267,6 +376,8 @@ void AccStructureChecker::Leave(const parser::OpenACCLoopConstruct &x) {
CheckNotAllowedIfClause(llvm::acc::Clause::ACCC_seq,
{llvm::acc::Clause::ACCC_gang, llvm::acc::Clause::ACCC_vector,
llvm::acc::Clause::ACCC_worker});
+ // Restriction - 2.9.2, 2.9.3, 2.9.4
+ CheckNotInSameOrSubLevelLoopConstruct();
}
dirContext_.pop_back();
}
@@ -570,8 +681,8 @@ void AccStructureChecker::Enter(const parser::OpenACCCacheConstruct &x) {
PushContextAndClauseSets(verbatim.source, llvm::acc::Directive::ACCD_cache);
SetContextDirectiveSource(verbatim.source);
if (loopNestLevel == 0) {
- context_.Say(verbatim.source,
- "The CACHE directive must be inside a loop"_err_en_US);
+ context_.Say(
+ verbatim.source, "The CACHE directive must be inside a loop"_err_en_US);
}
}
void AccStructureChecker::Leave(const parser::OpenACCCacheConstruct &x) {
diff --git a/flang/lib/Semantics/check-acc-structure.h b/flang/lib/Semantics/check-acc-structure.h
index 359f1557b62cb..711d0326349a4 100644
--- a/flang/lib/Semantics/check-acc-structure.h
+++ b/flang/lib/Semantics/check-acc-structure.h
@@ -98,8 +98,14 @@ class AccStructureChecker
bool CheckAllowedModifier(llvm::acc::Clause clause);
bool IsComputeConstruct(llvm::acc::Directive directive) const;
+ bool IsLoopConstruct(llvm::acc::Directive directive) const;
+ std::optional<llvm::acc::Directive> getParentComputeConstruct() const;
bool IsInsideComputeConstruct() const;
+ bool IsInsideParallelConstruct() const;
void CheckNotInComputeConstruct();
+ std::optional<std::int64_t> getGangDimensionSize(
+ DirectiveContext &dirContext);
+ void CheckNotInSameOrSubLevelLoopConstruct();
void CheckMultipleOccurrenceInDeclare(
const parser::AccObjectList &, llvm::acc::Clause);
void CheckMultipleOccurrenceInDeclare(
diff --git a/flang/lib/Semantics/check-directive-structure.h b/flang/lib/Semantics/check-directive-structure.h
index b1bf3e550aebc..1b5909ffeb992 100644
--- a/flang/lib/Semantics/check-directive-structure.h
+++ b/flang/lib/Semantics/check-directive-structure.h
@@ -160,7 +160,7 @@ template <typename D> class NoBranchingEnforce {
if (numDoConstruct_ > 0) {
return;
}
- // did not found an enclosing looping construct within the OpenMP/OpenACC
+ // did not find an enclosing looping construct within the OpenMP/OpenACC
// directive
EmitUnlabelledBranchOutError(stmt);
}
diff --git a/flang/test/Semantics/OpenACC/acc-loop.f90 b/flang/test/Semantics/OpenACC/acc-loop.f90
index 859cf3feec0d6..9301cf85305d4 100644
--- a/flang/test/Semantics/OpenACC/acc-loop.f90
+++ b/flang/test/Semantics/OpenACC/acc-loop.f90
@@ -13,7 +13,7 @@ program openacc_loop_validity
integer :: n
end type atype
- integer :: i, j, k, b, gang_size, vector_size, worker_size
+ integer :: i, j, k, l, m, b, gang_size, vector_size, worker_size
integer, parameter :: N = 256
integer, dimension(N) :: c
logical, dimension(N) :: d, e
@@ -259,6 +259,98 @@ program openacc_loop_validity
end do
!$acc end parallel
+ !$acc parallel
+ !$acc loop gang
+ do i = 1, n
+ !$acc loop worker
+ do j = 1, n
+ !ERROR: GANG clause is not allowed in the region of a loop with the WORKER clause
+ !ERROR: GANG clause is not allowed in the region of a loop with the GANG clause
+ !$acc loop gang vector
+ do k = 1, i
+ end do
+ end do
+ end do
+ !$acc end parallel
+
+ !$acc parallel loop vector
+ do i = 1, n
+ !ERROR: GANG clause is not allowed in the region of a loop with the VECTOR clause
+ !$acc loop gang
+ do j = 1, n
+ !ERROR: WORKER clause is not allowed in the region of a loop with the VECTOR clause
+ !$acc loop worker
+ do k = 1, i
+ !ERROR: VECTOR clause is not allowed in the region of a loop with the VECTOR clause
+ !$acc loop vector
+ do l = 1, 1
+ end do
+ end do
+ end do
+ end do
+ !$acc end parallel loop
+
+ !$acc kernels
+ do i = 1, n
+ !$acc loop gang worker
+ do j = 1, n
+ !ERROR: WORKER clause is not allowed in the region of a loop with the WORKER clause
+ !$acc loop worker vector
+ do k = 1, i
+ end do
+ end do
+ end do
+ !$acc end kernels
+
+ !$acc parallel
+ !$acc loop gang(dim:1)
+ do i = 1, n
+ !ERROR: GANG(dim:1) clause is not allowed in the region of a loop with the GANG(dim:1) clause
+ !$acc loop gang(dim:1)
+ do j = 1, n
+ !ERROR: GANG(dim:2) clause is not allowed in the region of a loop with the GANG(dim:1) clause
+ !$acc loop gang(dim:2)
+ do k = 1, i
+ !ERROR: GANG(dim:3) clause is not allowed in the region of a loop with the GANG(dim:2) clause
+ !ERROR: GANG(dim:3) clause is not allowed in the region of a loop with the GANG(dim:1) clause
+ !$acc loop gang(dim:3)
+ do l = 1, 1
+ !ERROR: GANG(dim:3) clause is not allowed in the region of a loop with the GANG(dim:3) clause
+ !ERROR: GANG(dim:3) clause is not allowed in the region of a loop with the GANG(dim:2) clause
+ !ERROR: GANG(dim:3) clause is not allowed in the region of a loop with the GANG(dim:1) clause
+ !$acc loop gang(dim:3)
+ do m = 1, 1
+ end do
+ end do
+ end do
+ end do
+ end do
+ !$acc end parallel
+
+ !$acc parallel loop gang(dim:3)
+ do i = 1, n
+ !$acc loop gang(dim:2)
+ do j = 1, n
+ !$acc loop gang(dim:1) worker vector
+ do k = 1, i
+ end do
+ end do
+ end do
+ !$acc end parallel loop
+
+ !$acc kernels loop gang(dim:3)
+ do i = 1, n
+ !ERROR: GANG clause is not allowed in the region of a loop with the GANG clause
+ !$acc loop gang(dim:2)
+ do j = 1, n
+ !ERROR: GANG clause is not allowed in the region of a loop with the GANG clause
+ !$acc loop gang(dim:1) worker vector
+ do k = 1, i
+ end do
+ end do
+ end do
+ !$acc end kernels loop
+
!ERROR: Clause IF is not allowed after clause DEVICE_TYPE on the PARALLEL directive
!$acc parallel device_type(*) if(.TRUE.)
!$acc loop
|
Looks ok in general but you have a lot of braces that can be removed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Just two places where braces are still needed.
Thank you for your review. |
No problem! Thanks for the additional check! |
…ism (llvm#152225) This PR implements a semantic checker to ensure the legality of nested OpenACC parallelism. The following are quotes from Spec 3.3. We need to disallow loops from having parallelism at the same level as or at a sub-level of child loops. >**2.9.2 gang clause** >[2064] <ins>When the parent compute construct is a parallel construct</ins>, or on an orphaned loop construct, the gang clause behaves as follows. (...) The associated dimension is the value of the dim argument, if it appears, or is dimension one. The dim argument must be a constant positive integer with value 1, 2, or 3. >[2112] The region of a loop with a gang(dim:d) clause may not contain a loop construct with a gang(dim:e) clause where e >= d unless it appears within a nested compute region. >[2074] <ins>When the parent compute construct is a kernels construct</ins>, the gang clause behaves as follows. (...) >[2148] The region of a loop with the gang clause may not contain another loop with a gang clause unless within a nested compute region. >**2.9.3 worker clause** >[2122]/[2129] The region of a loop with the worker clause may not contain a loop with the gang or worker clause unless within a nested compute region. >**2.9.4 vector clause** >[2141]/[2148] The region of a loop with the vector clause may not contain a loop with a gang, worker, or vector clause unless within a nested compute region. https://openacc.org/sites/default/files/inline-images/Specification/OpenACC-3.3-final.pdf
This PR implements a semantic checker to ensure the legality of nested OpenACC parallelism. The following are quotes from Spec 3.3. We need to disallow loops from having parallelism at the same level as or at a sub-level of child loops.
https://openacc.org/sites/default/files/inline-images/Specification/OpenACC-3.3-final.pdf