[flang-commits] [flang] [llvm] [OpenMP] [TASK] Add semantic checks for detach clause (PR #119172)
Thirumalai Shaktivel via flang-commits
flang-commits at lists.llvm.org
Sun Dec 8 22:38:07 PST 2024
https://github.com/Thirumalai-Shaktivel created https://github.com/llvm/llvm-project/pull/119172
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.
>From 3da984c20fc1f077f92b1542e7c037b4e16be030 Mon Sep 17 00:00:00 2001
From: Thirumalai-Shaktivel <thirumalaishaktivel at gmail.com>
Date: Mon, 9 Dec 2024 06:35:46 +0000
Subject: [PATCH] [OpenMP] [TASK] Add semantic checks for detach clause
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.
---
flang/lib/Semantics/check-omp-structure.cpp | 140 +++++++++++++++-----
flang/lib/Semantics/check-omp-structure.h | 2 +
flang/test/Semantics/OpenMP/detach01.f90 | 65 +++++++++
llvm/include/llvm/Frontend/OpenMP/OMP.td | 2 +-
4 files changed, 178 insertions(+), 31 deletions(-)
create mode 100644 flang/test/Semantics/OpenMP/detach01.f90
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>,
More information about the flang-commits
mailing list