-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[Flang] [OpenMP] Add semantic checks for detach clause in task #119172
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
base: main
Are you sure you want to change the base?
[Flang] [OpenMP] Add semantic checks for detach clause in task #119172
Conversation
@llvm/pr-subscribers-flang-openmp @llvm/pr-subscribers-flang-semantics Author: Thirumalai Shaktivel (Thirumalai-Shaktivel) ChangesFixes:
Restrictions:
OpenMP 5.2: Detach contruct
Full diff: https://github.com/llvm/llvm-project/pull/119172.diff 4 Files Affected:
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 3c9c5a02a338a6..23f7624182a556 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -2739,6 +2739,58 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait});
}
+ if (GetContext().directive == llvm::omp::Directive::OMPD_task) {
+ if (auto *d_clause{FindClause(llvm::omp::Clause::OMPC_detach)}) {
+ // OpenMP 5.0: Task construct restrictions
+ CheckNotAllowedIfClause(
+ llvm::omp::Clause::OMPC_detach, {llvm::omp::Clause::OMPC_mergeable});
+
+ // OpenMP 5.2: Task construct restrictions
+ if (FindClause(llvm::omp::Clause::OMPC_final)) {
+ context_.Say(GetContext().clauseSource,
+ "If a DETACH clause appears on a directive, then the encountering task must not be a FINAL task"_err_en_US);
+ }
+
+ const auto &detachClause{
+ std::get<parser::OmpClause::Detach>(d_clause->u)};
+ if (const auto *name{parser::Unwrap<parser::Name>(detachClause.v.v)}) {
+ if (name->symbol) {
+ std::string eventHandleSymName{name->ToString()};
+ auto checkVarAppearsInDataEnvClause = [&](const parser::OmpObjectList
+ &objs,
+ std::string clause) {
+ for (const auto &obj : objs.v) {
+ if (const parser::Name *name{parser::Unwrap<parser::Name>(obj)}) {
+ if (name->ToString() == eventHandleSymName) {
+ context_.Say(GetContext().clauseSource,
+ "A variable: `%s` that appears in a DETACH clause cannot appear on %s clause on the same construct"_err_en_US,
+ eventHandleSymName, clause);
+ }
+ }
+ }
+ };
+ if (auto *dataEnvClause{
+ FindClause(llvm::omp::Clause::OMPC_private)}) {
+ const auto &pClause{
+ std::get<parser::OmpClause::Private>(dataEnvClause->u)};
+ checkVarAppearsInDataEnvClause(pClause.v, "PRIVATE");
+ } else if (auto *dataEnvClause{
+ FindClause(llvm::omp::Clause::OMPC_firstprivate)}) {
+ const auto &fpClause{
+ std::get<parser::OmpClause::Firstprivate>(dataEnvClause->u)};
+ checkVarAppearsInDataEnvClause(fpClause.v, "FIRSTPRIVATE");
+ } else if (auto *dataEnvClause{
+ FindClause(llvm::omp::Clause::OMPC_in_reduction)}) {
+ const auto &irClause{
+ std::get<parser::OmpClause::InReduction>(dataEnvClause->u)};
+ checkVarAppearsInDataEnvClause(
+ std::get<parser::OmpObjectList>(irClause.v.t), "IN_REDUCTION");
+ }
+ }
+ }
+ }
+ }
+
auto testThreadprivateVarErr = [&](Symbol sym, parser::Name name,
llvmOmpClause clauseTy) {
if (sym.test(Symbol::Flag::OmpThreadprivate))
@@ -2823,7 +2875,6 @@ CHECK_SIMPLE_CLAUSE(Capture, OMPC_capture)
CHECK_SIMPLE_CLAUSE(Contains, OMPC_contains)
CHECK_SIMPLE_CLAUSE(Default, OMPC_default)
CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj)
-CHECK_SIMPLE_CLAUSE(Detach, OMPC_detach)
CHECK_SIMPLE_CLAUSE(DeviceType, OMPC_device_type)
CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule)
CHECK_SIMPLE_CLAUSE(Exclusive, OMPC_exclusive)
@@ -3352,40 +3403,45 @@ void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
const parser::CharBlock &source, const parser::OmpObjectList &objList,
llvm::StringRef clause) {
for (const auto &ompObject : objList.v) {
- common::visit(
- common::visitors{
- [&](const parser::Designator &designator) {
- if (const auto *dataRef{
- std::get_if<parser::DataRef>(&designator.u)}) {
- if (IsDataRefTypeParamInquiry(dataRef)) {
+ CheckIsVarPartOfAnotherVar(source, ompObject, clause);
+ }
+}
+
+void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
+ const parser::CharBlock &source, const parser::OmpObject &ompObject,
+ llvm::StringRef clause) {
+ common::visit(
+ common::visitors{
+ [&](const parser::Designator &designator) {
+ if (const auto *dataRef{
+ std::get_if<parser::DataRef>(&designator.u)}) {
+ if (IsDataRefTypeParamInquiry(dataRef)) {
+ context_.Say(source,
+ "A type parameter inquiry cannot appear on the %s "
+ "directive"_err_en_US,
+ ContextDirectiveAsFortran());
+ } else if (parser::Unwrap<parser::StructureComponent>(
+ ompObject) ||
+ parser::Unwrap<parser::ArrayElement>(ompObject)) {
+ if (llvm::omp::nonPartialVarSet.test(GetContext().directive)) {
context_.Say(source,
- "A type parameter inquiry cannot appear on the %s "
+ "A variable that is part of another variable (as an "
+ "array or structure element) cannot appear on the %s "
"directive"_err_en_US,
ContextDirectiveAsFortran());
- } else if (parser::Unwrap<parser::StructureComponent>(
- ompObject) ||
- parser::Unwrap<parser::ArrayElement>(ompObject)) {
- if (llvm::omp::nonPartialVarSet.test(
- GetContext().directive)) {
- context_.Say(source,
- "A variable that is part of another variable (as an "
- "array or structure element) cannot appear on the %s "
- "directive"_err_en_US,
- ContextDirectiveAsFortran());
- } else {
- context_.Say(source,
- "A variable that is part of another variable (as an "
- "array or structure element) cannot appear in a "
- "%s clause"_err_en_US,
- clause.data());
- }
+ } else {
+ context_.Say(source,
+ "A variable that is part of another variable (as an "
+ "array or structure element) cannot appear in a "
+ "%s clause"_err_en_US,
+ clause.data());
}
}
- },
- [&](const parser::Name &name) {},
- },
- ompObject.u);
- }
+ }
+ },
+ [&](const parser::Name &name) {},
+ },
+ ompObject.u);
}
void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) {
@@ -3711,6 +3767,30 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) {
x.v.u);
}
+void OmpStructureChecker::Enter(const parser::OmpClause::Detach &x) {
+ // OpenMP 5.0: Task construct restrictions
+ CheckAllowedClause(llvm::omp::Clause::OMPC_detach);
+
+ // OpenMP 5.2: Detach clause restrictions
+ CheckIsVarPartOfAnotherVar(GetContext().clauseSource, x.v.v, "DETACH");
+ if (const auto *name{parser::Unwrap<parser::Name>(x.v.v)}) {
+ if (name->symbol) {
+ if (IsPointer(*name->symbol)) {
+ context_.Say(GetContext().clauseSource,
+ "The event-handle: `%s` must not have the POINTER attribute"_err_en_US,
+ name->ToString());
+ }
+ }
+ auto type{name->symbol->GetType()};
+ if (!name->symbol->GetType()->IsNumeric(TypeCategory::Integer) ||
+ evaluate::ToInt64(type->numericTypeSpec().kind()) != 8) {
+ context_.Say(GetContext().clauseSource,
+ "The event-handle: `%s` must be of type integer(kind=omp_event_handle_kind)"_err_en_US,
+ name->ToString());
+ }
+ }
+}
+
void OmpStructureChecker::CheckAllowedMapTypes(
const parser::OmpMapType::Value &type,
const std::list<parser::OmpMapType::Value> &allowedMapTypeList) {
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 89af46d9171ad3..b8adbc77a8fce0 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -180,6 +180,8 @@ class OmpStructureChecker
const common::Indirection<parser::ArrayElement> &, const parser::Name &);
void CheckDoacross(const parser::OmpDoacross &doa);
bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
+ void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source,
+ const parser::OmpObject &obj, llvm::StringRef clause = "");
void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source,
const parser::OmpObjectList &objList, llvm::StringRef clause = "");
void CheckThreadprivateOrDeclareTargetVar(
diff --git a/flang/test/Semantics/OpenMP/detach01.f90 b/flang/test/Semantics/OpenMP/detach01.f90
new file mode 100644
index 00000000000000..e342fcd1b19b4a
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/detach01.f90
@@ -0,0 +1,65 @@
+! REQUIRES: openmp_runtime
+! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=50
+
+! OpenMP Version 5.2
+! Various checks for DETACH Clause (12.5.2)
+
+program test_detach
+ use omp_lib
+ implicit none
+ integer :: e, x
+ integer(omp_event_handle_kind) :: event_01, event_02(2)
+ integer(omp_event_handle_kind), pointer :: event_03
+
+
+ type :: t
+ integer(omp_event_handle_kind) :: event
+ end type
+
+ type(t) :: t_01
+
+ !ERROR: The event-handle: `e` must be of type integer(kind=omp_event_handle_kind)
+ !$omp task detach(e)
+ x = x + 1
+ !$omp end task
+
+ !ERROR: At most one DETACH clause can appear on the TASK directive
+ !$omp task detach(event_01) detach(event_01)
+ x = x + 1
+ !$omp end task
+
+ !ERROR: Clause MERGEABLE is not allowed if clause DETACH appears on the TASK directive
+ !$omp task detach(event_01) mergeable
+ x = x + 1
+ !$omp end task
+
+ !ERROR: If a DETACH clause appears on a directive, then the encountering task must not be a FINAL task
+ !$omp task detach(event_01) final(.false.)
+ x = x + 1
+ !$omp end task
+
+ !ERROR: A variable: `event_01` that appears in a DETACH clause cannot appear on PRIVATE clause on the same construct
+ !$omp task detach(event_01) private(event_01)
+ x = x + 1
+ !$omp end task
+
+ !ERROR: A variable: `event_01` that appears in a DETACH clause cannot appear on IN_REDUCTION clause on the same construct
+ !$omp task detach(event_01) in_reduction(+:event_01)
+ x = x + 1
+ !$omp end task
+
+ !ERROR: A variable that is part of another variable (as an array or structure element) cannot appear in a DETACH clause
+ !$omp task detach(event_02(1))
+ x = x + 1
+ !$omp end task
+
+ !ERROR: A variable that is part of another variable (as an array or structure element) cannot appear in a DETACH clause
+ !$omp task detach(t_01%event)
+ x = x + 1
+ !$omp end task
+
+ !ERROR: The event-handle: `event_03` must not have the POINTER attribute
+ !$omp task detach(event_03)
+ x = x + 1
+ !$omp end task
+end program
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index bd7fb2361aaeb1..9ada11241d3a56 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -1085,7 +1085,6 @@ def OMP_Task : Directive<"task"> {
VersionedClause<OMPC_Affinity, 50>,
VersionedClause<OMPC_Allocate>,
VersionedClause<OMPC_Depend>,
- VersionedClause<OMPC_Detach, 50>,
VersionedClause<OMPC_FirstPrivate>,
VersionedClause<OMPC_InReduction>,
VersionedClause<OMPC_Mergeable>,
@@ -1095,6 +1094,7 @@ def OMP_Task : Directive<"task"> {
];
let allowedOnceClauses = [
VersionedClause<OMPC_Default>,
+ VersionedClause<OMPC_Detach, 50>,
VersionedClause<OMPC_Final>,
VersionedClause<OMPC_If>,
VersionedClause<OMPC_Priority>,
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There seems to be some problem with I get the following locally $ git-clang-format
clang-format did not modify any files The failed line seems to be within the range (80 characters):
|
3da984c
to
414ea0c
Compare
Fixes: - Add semantic checks along with the tests - Move the detach clause to allowedOnceClauses list in Task construct Restrictions:\ OpenMP 5.0: Task construct - At most one detach clause can appear on the directive. - If a detach clause appears on the directive, then a mergeable clause cannot appear on the same directive. OpenMP 5.2: Detach contruct - If a detach clause appears on a directive, then the encountering task must not be a final task. - A variable that appears in a detach clause cannot appear as a list item on a data-environment attribute clause on the same construct. - A variable that is part of another variable (as an array element or a structure element) cannot appear in a detach clause. - event-handle must not have the POINTER attribute.
} | ||
auto type{name->symbol->GetType()}; | ||
if (!name->symbol->GetType()->IsNumeric(TypeCategory::Integer) || | ||
evaluate::ToInt64(type->numericTypeSpec().kind()) != 8) { |
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 remove the check of the kind
. We shouldn't be using hardcoded numbers.
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, I felt the same. But, the only info I had was the kind
=> 8
to throw an error for the following:
!ERROR: The event-handle: `e` must be of type integer(kind=omp_event_handle_kind)
!$omp task detach(e)
x = x + 1
!$omp end task
Do you know any other way to add a check for this?
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.
We don't have a way of checking this, unfortunately. In other cases we limit it to checking that it has an INTEGER type, but without checking the kind.
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. I will add only checking the integer type.
@@ -2739,6 +2739,59 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) { | |||
llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait}); | |||
} | |||
|
|||
if (GetContext().directive == llvm::omp::Directive::OMPD_task) { | |||
if (auto *d_clause{FindClause(llvm::omp::Clause::OMPC_detach)}) { |
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.
No snake_case please (d_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.
Good catch, I forgot to update this.
// OpenMP 5.0: Task construct restrictions | ||
CheckNotAllowedIfClause( | ||
llvm::omp::Clause::OMPC_detach, {llvm::omp::Clause::OMPC_mergeable}); | ||
|
||
// OpenMP 5.2: Task construct restrictions |
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.
If you're doing version-specific checks, please guard them with the actual version from -fopenmp-version. You can get it from the language options in context. This is done in a number of places in this file, you can check how to do it.
std::string eventHandleSymName{name->ToString()}; | ||
auto checkVarAppearsInDataEnvClause = [&](const parser::OmpObjectList | ||
&objs, | ||
std::string clause) { | ||
for (const auto &obj : objs.v) { | ||
if (const parser::Name *objName{ | ||
parser::Unwrap<parser::Name>(obj)}) { | ||
if (objName->ToString() == eventHandleSymName) { | ||
context_.Say(GetContext().clauseSource, | ||
"A variable: `%s` that appears in a DETACH clause cannot appear on %s clause on the same construct"_err_en_US, | ||
eventHandleSymName, 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.
Please compare symbols, not names. You can compare the results of &symbol->GetUltimate()
to be accurate.
// OpenMP 5.0: Task construct restrictions | ||
CheckAllowedClause(llvm::omp::Clause::OMPC_detach); | ||
|
||
// OpenMP 5.2: Detach clause restrictions |
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: please do version-specific checks based on the actual version.
Sure, thanks for the review. I will update it and report back soon. |
414ea0c
to
a3c6a45
Compare
integer(omp_event_handle_kind) :: event_01, event_02 | ||
|
||
!TODO: Throw following error for the versions 5.0 and 5.1 | ||
!ERR: At most one DETACH clause can appear on the TASK directive |
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.
This check is required for both OpenMP 5.0 and 5.1
So, for that, I can only add a check for this in OMP.td (by moving the clause to allowedOnceClauses
)
and call CheckAllowedClause
. but, this leads to throwing an error for OpenMP version >= 52. If I enclose CheckAllowedClause
within an if block (checking the version to be 50 and 51). The clause context wouldn't be set as SetContextClauseInfo
is called by this function, this caused a problem for version >= 52.
@kparzysz, do you have any suggestions here?
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.
This is not a blocker and can be fixed later on. Currently, we throw this error for every version with the latest commit
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.
Couldn't you call SetContextClauseInfo
manually for versions >= 52?
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 thought I shouldn't be doing that (calling SetContextClauseInfo
), but instead use only the CheckAllowed
.
I will check it again and see what I can do there. Thank you for the suggestion.
Done, @kparzysz, I addressed all of your comments |
Ping for review. |
@kparzysz, could you please review the changes again? |
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 this PR got lost. Please feel free to ping me if something does not get reviewed
checkVarAppearsInDataEnvClause( | ||
std::get<parser::OmpObjectList>(irClause.v.t), | ||
"IN_REDUCTION"); | ||
} |
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.
what about SHARED?
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.
Good catch, I don't know how I missed this.
} | ||
} | ||
|
||
void OmpStructureChecker::CheckIsVarPartOfAnotherVar( |
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.
Suggestion, feel free to ignore. I think this would be clearer
void OmpStructureChecker::CheckIsVarPartOfAnotherVar( | |
void OmpStructureChecker::CheckVarIsNotPartOfAnotherVar( |
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.
Sorry for the delay in reviewing. Looks ok to me, but please wait for @tblah's input as well.
const auto &detach{ | ||
std::get<parser::OmpClause::Detach>(detachClause->u)}; | ||
if (const auto *name{parser::Unwrap<parser::Name>(detach.v.v)}) { | ||
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.
All parser::Name's should have non-null symbols by now (it's an internal compiler error if they don't).
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
"A type parameter inquiry cannot appear on the %s " | ||
"directive"_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 make message strings be in a single line (here and in other places you've changed). This is to make it easier to find them in the source based on the compiler output.
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.
Thanks for the update. No need for another round of review for my nit comment.
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. The code formatting needs to be fixed though
Fixes:
Restrictions:
OpenMP 5.0: Task construct
OpenMP 5.2: Detach contruct