-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[Flang][OpenMP] Add some semantic checks for Linear clause #111354
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
… on the OpenMP 5.2 restrictions
…use with (n) is specified
@llvm/pr-subscribers-flang-openmp @llvm/pr-subscribers-flang-semantics Author: Thirumalai Shaktivel (Thirumalai-Shaktivel) ChangesFull diff: https://github.com/llvm/llvm-project/pull/111354.diff 3 Files Affected:
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 5ef504aa72326e..d409d7b548767e 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -303,6 +303,30 @@ void OmpStructureChecker::CheckMultListItems() {
CheckMultipleOccurrence(
listVars, nontempNameList, itr->second->source, "NONTEMPORAL");
}
+
+ // Linear clause
+ auto linearClauses{FindClauses(llvm::omp::Clause::OMPC_linear)};
+ for (auto itr = linearClauses.first; itr != linearClauses.second; ++itr) {
+ const auto &linearClause{
+ std::get<parser::OmpClause::Linear>(itr->second->u)};
+ std::list<parser::Name> nameList;
+ common::visit(
+ common::visitors{
+ [&](const parser::OmpLinearClause::WithoutModifier
+ &withoutModifier) {
+ for (const auto &name : withoutModifier.names) {
+ nameList.push_back(name);
+ }
+ },
+ [&](const parser::OmpLinearClause::WithModifier &withModifier) {
+ for (const auto &name : withModifier.names) {
+ nameList.push_back(name);
+ }
+ },
+ },
+ linearClause.v.u);
+ CheckMultipleOccurrence(listVars, nameList, itr->second->source, "LINEAR");
+ }
}
bool OmpStructureChecker::HasInvalidWorksharingNesting(
@@ -2256,11 +2280,12 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
}
}
}
- // Sema checks related to presence of multiple list items within the same
- // clause
- CheckMultListItems();
} // SIMD
+ // Semantics checks related to presence of multiple list items within the same
+ // clause
+ CheckMultListItems();
+
// 2.7.3 Single Construct Restriction
if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) {
CheckNotAllowedIfClause(
@@ -2975,16 +3000,101 @@ void OmpStructureChecker::Enter(const parser::OmpClause::If &x) {
void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_linear);
+ parser::CharBlock source = GetContext().clauseSource;
// 2.7 Loop Construct Restriction
if ((llvm::omp::allDoSet | llvm::omp::allSimdSet)
.test(GetContext().directive)) {
if (std::holds_alternative<parser::OmpLinearClause::WithModifier>(x.v.u)) {
- context_.Say(GetContext().clauseSource,
+ context_.Say(source,
"A modifier may not be specified in a LINEAR clause "
"on the %s directive"_err_en_US,
ContextDirectiveAsFortran());
+ return;
+ }
+ }
+
+ // 4.4.4 Ordered clause restriction
+ if (const auto *clause{
+ FindClause(GetContext(), llvm::omp::Clause::OMPC_ordered)}) {
+ const auto &orderedClause{std::get<parser::OmpClause::Ordered>(clause->u)};
+ if (orderedClause.v) {
+ return;
}
}
+
+ auto checkForValidLinearClaue = [&](const parser::Name &name, bool is_ref) {
+ parser::CharBlock source = GetContext().clauseSource;
+ std::string list_item_name = name.ToString();
+ if (!is_ref && !name.symbol->GetType()->IsNumeric(TypeCategory::Integer)) {
+ context_.Say(source,
+ "The list item `%s` specified with other than linear-modifier `REF`"
+ " must be of type INTEGER"_err_en_US,
+ list_item_name);
+ }
+ if (GetContext().directive == llvm::omp::Directive::OMPD_declare_simd &&
+ !IsDummy(*name.symbol)) {
+ context_.Say(source,
+ "The list item `%s` must be a dummy argument"_err_en_US,
+ list_item_name);
+ }
+ if (IsPointer(*name.symbol) ||
+ name.symbol->test(Symbol::Flag::CrayPointer)) {
+ context_.Say(source,
+ "The list item `%s` in a LINEAR clause must not be Cray Pointer "
+ "or a variable with POINTER attribute"_err_en_US,
+ list_item_name);
+ }
+ if (FindCommonBlockContaining(*name.symbol)) {
+ context_.Say(source,
+ "'%s' is a common block name and must not appear in an "
+ "LINEAR clause"_err_en_US,
+ list_item_name);
+ }
+ };
+
+ // 5.4.6 Linear clause Restrictions
+ common::visit(
+ common::visitors{
+ [&](const parser::OmpLinearClause::WithoutModifier &withoutModifier) {
+ for (const auto &name : withoutModifier.names) {
+ if (name.symbol) {
+ checkForValidLinearClaue(name, false);
+ }
+ }
+ },
+ [&](const parser::OmpLinearClause::WithModifier &withModifier) {
+ for (const auto &name : withModifier.names) {
+ if (name.symbol) {
+ checkForValidLinearClaue(name,
+ (withModifier.modifier.v ==
+ parser::OmpLinearModifier::Type::Ref));
+ std::string list_item_name = name.ToString();
+ if (withModifier.modifier.v !=
+ parser::OmpLinearModifier::Type::Val &&
+ IsDummy(*name.symbol) && IsValue(*name.symbol)) {
+ context_.Say(source,
+ "The list item `%s` specified with the linear-modifier "
+ "`REF` or `UVAL` must be a dummy argument without "
+ "`VALUE` attribute"_err_en_US,
+ list_item_name);
+ }
+ if (withModifier.modifier.v ==
+ parser::OmpLinearModifier::Type::Ref &&
+ !(IsAllocatable(*name.symbol) ||
+ IsAssumedShape(*name.symbol) ||
+ IsPolymorphic(*name.symbol))) {
+ context_.Say(source,
+ "The list item `%s` specified with the linear-modifier "
+ "`REF` must be polymorphic variable, assumed-shape "
+ "array, "
+ "or a variable with the `ALLOCATABLE` attribute"_err_en_US,
+ list_item_name);
+ }
+ }
+ }
+ },
+ },
+ x.v.u);
}
void OmpStructureChecker::CheckAllowedMapTypes(
diff --git a/flang/test/Semantics/OpenMP/declarative-directive.f90 b/flang/test/Semantics/OpenMP/declarative-directive.f90
index 8d6762b87adb95..17dc50b70e5421 100644
--- a/flang/test/Semantics/OpenMP/declarative-directive.f90
+++ b/flang/test/Semantics/OpenMP/declarative-directive.f90
@@ -23,6 +23,7 @@ end subroutine requires_2
subroutine declare_simd_1(a, b)
real(8), intent(inout) :: a, b
+ !ERROR: 'a' in ALIGNED clause must be of type C_PTR, POINTER or ALLOCATABLE
!$omp declare simd(declare_simd_1) aligned(a)
a = 3.14 + b
end subroutine declare_simd_1
diff --git a/flang/test/Semantics/OpenMP/linear-cluase01.f90 b/flang/test/Semantics/OpenMP/linear-cluase01.f90
new file mode 100644
index 00000000000000..a56709aae7ad73
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/linear-cluase01.f90
@@ -0,0 +1,50 @@
+! REQUIRES: openmp_runtime
+! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags
+! OpenMP Version 5.2
+! Various checks for the linear clause
+! 5.4.6 `linear` Clause
+
+! Case 1
+subroutine linear_clause_01(arg)
+ integer, intent(in) :: arg(:)
+ !ERROR: A modifier may not be specified in a LINEAR clause on the DO directive
+ !$omp do linear(uval(arg))
+ do i = 1, 5
+ print *, arg(i)
+ end do
+end subroutine linear_clause_01
+
+! Case 2
+subroutine linear_clause_02(arg_01, arg_02, arg_03)
+ !ERROR: The list item `arg_01` specified with other than linear-modifier `REF` must be of type INTEGER
+ !$omp declare simd linear(val(arg_01))
+ real, intent(in) :: arg_01(:)
+
+ !ERROR: The list item `arg_02` specified with the linear-modifier `REF` or `UVAL` must be a dummy argument without `VALUE` attribute
+ !$omp declare simd linear(uval(arg_02))
+ integer, value, intent(in) :: arg_02
+
+ !ERROR: The list item `arg_03` specified with other than linear-modifier `REF` must be of type INTEGER
+ !ERROR: The list item `arg_03` in a LINEAR clause must not be Cray Pointer or a variable with POINTER attribute
+ !$omp declare simd linear(arg_03)
+ real, pointer :: arg_03
+
+ !ERROR: The list item `var` must be a dummy argument
+ !ERROR: The list item `var` in a LINEAR clause must not be Cray Pointer or a variable with POINTER attribute
+ !$omp declare simd linear(uval(var))
+ integer, pointer :: var
+end subroutine linear_clause_02
+
+! Case 3
+subroutine linear_clause_03(arg)
+ integer, intent(in) :: arg
+ !ERROR: The list item `arg` specified with the linear-modifier `REF` must be polymorphic variable, assumed-shape array, or a variable with the `ALLOCATABLE` attribute
+ !ERROR: List item 'arg' present at multiple LINEAR clauses
+ !$omp declare simd linear(ref(arg)) linear(arg)
+
+ integer :: i
+ common /cc/ i
+ !ERROR: The list item `i` must be a dummy argument
+ !ERROR: 'i' is a common block name and must not appear in an LINEAR clause
+ !$omp declare simd linear(i)
+end subroutine linear_clause_03
|
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.
Typo: cluase -> clause.
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.
Done.
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.
A few nit comments.
Could you expand the summary to list the checks implemented in the patch with a reference to the standard and section?
@@ -2975,16 +3000,101 @@ void OmpStructureChecker::Enter(const parser::OmpClause::If &x) { | |||
void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) { | |||
CheckAllowedClause(llvm::omp::Clause::OMPC_linear); | |||
|
|||
parser::CharBlock source = GetContext().clauseSource; |
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.
Use braced initialized in frontend code.
} | ||
} | ||
|
||
auto checkForValidLinearClaue = [&](const parser::Name &name, bool is_ref) { |
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.
auto checkForValidLinearClaue = [&](const parser::Name &name, bool is_ref) { | |
auto checkForValidLinearClause = [&](const parser::Name &name, bool is_ref) { |
|
||
auto checkForValidLinearClaue = [&](const parser::Name &name, bool is_ref) { | ||
parser::CharBlock source = GetContext().clauseSource; | ||
std::string list_item_name = name.ToString(); |
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.
std::string list_item_name = name.ToString(); | |
std::string listItemName = name.ToString(); |
} | ||
} | ||
|
||
auto checkForValidLinearClaue = [&](const parser::Name &name, bool is_ref) { | ||
parser::CharBlock source = GetContext().clauseSource; |
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.
Nit: Use braced initialization.
checkForValidLinearClaue(name, | ||
(withModifier.modifier.v == | ||
parser::OmpLinearModifier::Type::Ref)); | ||
std::string list_item_name = name.ToString(); |
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.
std::string list_item_name = name.ToString(); | |
std::string listItemName = name.ToString(); |
|
||
// Linear clause | ||
auto linearClauses{FindClauses(llvm::omp::Clause::OMPC_linear)}; | ||
for (auto itr = linearClauses.first; itr != linearClauses.second; ++itr) { |
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.
for (auto itr = linearClauses.first; itr != linearClauses.second; ++itr) { | |
for (auto itr{linearClauses.first}; itr != linearClauses.second; ++itr) { |
5922503
to
7a760f0
Compare
FindClause(GetContext(), llvm::omp::Clause::OMPC_ordered)}) { | ||
const auto &orderedClause{std::get<parser::OmpClause::Ordered>(clause->u)}; | ||
if (orderedClause.v) { | ||
return; |
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.
Flang-new already throws an error, Clause LINEAR is not allowed if clause ORDERED appears on the DO directive
. So, I skipped here.
I addressed all the comments, @kiranchandramohan. Thanks for the reviews. |
OpenMP 5.2 restriction: Each list item must have C_PTR or Cray pointer type or have the POINTER or ALLOCATABLE attribute.
7a760f0
to
599b31f
Compare
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.
One small comment on ALIGNED clause test added in this PR.
Ultra nit: "If n is explicitly specified, a linear clause must not be specified on the same directive" in description -> "If an ordered clause is explicitly specified......"
@@ -23,6 +23,7 @@ end subroutine requires_2 | |||
|
|||
subroutine declare_simd_1(a, b) | |||
real(8), intent(inout) :: a, b | |||
!ERROR: 'a' in ALIGNED clause must be of type C_PTR, POINTER or ALLOCATABLE |
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.
Do we also deal with ALIGNED clause in this PR? A similar issue is causing the Linux CI failure:
flang/test/Examples/omp-declarative-directive.f90:11:38: error: 'a' in ALIGNED clause must be of type C_PTR, POINTER or ALLOCATABLE
--
| !$omp declare simd(declare_simd_1) aligned(a)
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.
Yes, this line: https://github.com/llvm/llvm-project/pull/111354/files#diff-be225bc038e95a229024c9f227284112f98fe31762bc0bb80605de425aadd084R2287 is responsible for the change.
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.
I fixed it in the recent commit.
599b31f
to
b67a77d
Compare
auto linearClauses{FindClauses(llvm::omp::Clause::OMPC_linear)}; | ||
for (auto itr{linearClauses.first}; itr != linearClauses.second; ++itr) { | ||
const auto &linearClause{ | ||
std::get<parser::OmpClause::Linear>(itr->second->u)}; |
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.
FindClauses
now returns an iterator range, please use range-for here.
common::visitors{ | ||
[&](const parser::OmpLinearClause::WithoutModifier | ||
&withoutModifier) { | ||
for (const auto &name : withoutModifier.names) { | ||
nameList.push_back(name); | ||
} | ||
}, | ||
[&](const parser::OmpLinearClause::WithModifier &withModifier) { | ||
for (const auto &name : withModifier.names) { | ||
nameList.push_back(name); | ||
} | ||
}, | ||
}, |
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.
You can only have a single visitor, plus you can simplify the copy:
[&](auto &&s) {
std::copy(s.names.begin(), s.names.end(), std::back_inserter(nameList));
}
}, | ||
[&](const parser::OmpLinearClause::WithModifier &withModifier) { | ||
for (const auto &name : withModifier.names) { | ||
if (name.symbol) { |
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.
You can extract this into a lamda to reduce indentation.
"The list item `%s` specified with the linear-modifier " | ||
"`REF` or `UVAL` must be a dummy argument without " | ||
"`VALUE` attribute"_err_en_US, |
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.
Please concatenate messages into a single string. This is to make grepping for messages easier.
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.
Yes
"The list item `%s` specified with the linear-modifier " | ||
"`REF` must be polymorphic variable, assumed-shape " | ||
"array, " | ||
"or a variable with the `ALLOCATABLE` attribute"_err_en_US, |
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.
Same here.
I will change the modifier representation in LINEAR in a week or so. Please finish this soon, otherwise my code will create conflicts for you. |
b67a77d
to
37458b5
Compare
Thanks for the review, @kparzysz! I addressed all the comments. If anything else to be done, please let me know. |
✅ With the latest revision this PR passed the C/C++ code formatter. |
37458b5
to
82cf1bd
Compare
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.
Almost ready, a few more comments.
for (const auto &name : withoutModifier.names) | ||
if (name.symbol) | ||
checkForValidLinearClause_01(name, false); |
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.
Please add {} for nested statements.
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.
Do you mean the following?
for (const auto &name : withoutModifier.names) | |
if (name.symbol) | |
checkForValidLinearClause_01(name, false); | |
for (const auto &name : withoutModifier.names) { | |
if (name.symbol) { | |
checkForValidLinearClause_01(name, false); | |
} | |
} |
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.
Yes
common::visitors{ | ||
[&](const auto &u) { | ||
std::copy( | ||
u.names.begin(), u.names.end(), std::back_inserter(nameList)); | ||
}, | ||
}, |
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.
You only have one visitor, so you don't need common::visitors
. Do common::visit([&]...)
.
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.
Yea, sure.
auto checkForValidLinearClause_01 = [&](const parser::Name &name, | ||
bool is_ref) { |
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.
Please concatenate all error message strings in this function.
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.
I'm sorry, but I'm not getting this.
Concatenate in the sense, for the following:
context_.Say(source,
"The list item `%s` specified with other than linear-modifier `REF`"
" must be of type INTEGER"_err_en_US,
listItemName);
should I do?
context_.Say(source,
"The list item `%s` specified with other than linear-modifier `REF` must be of type INTEGER"_err_en_US,
listItemName);
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.
Yes
auto checkForValidLinearClause_02 = | ||
[&](const parser::Name &name, | ||
const parser::OmpLinearModifier::Value &modifierValue) { |
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.
Please concatenate all error message strings in this function.
Please don't use force-pushes. That messes up previous comments. |
Sorry about that. I rebased the commits and I had to force-push the changes. |
82cf1bd
to
4c63c16
Compare
Done. |
Thank you! |
This PR adds all the missing semantics for the Linear clause based on the OpenMP 5.2 restrictions. The restriction details are mentioned below.
OpenMP 5.2:
5.4.6 linear Clause restrictions
4.4.4 ordered Clause restriction
5.11 aligned Clause restriction