[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