Skip to content

Commit 414ea0c

Browse files
[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.
1 parent eaa1b05 commit 414ea0c

File tree

4 files changed

+179
-31
lines changed

4 files changed

+179
-31
lines changed

flang/lib/Semantics/check-omp-structure.cpp

+111-30
Original file line numberDiff line numberDiff line change
@@ -2739,6 +2739,59 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
27392739
llvm::omp::Clause::OMPC_copyprivate, {llvm::omp::Clause::OMPC_nowait});
27402740
}
27412741

2742+
if (GetContext().directive == llvm::omp::Directive::OMPD_task) {
2743+
if (auto *d_clause{FindClause(llvm::omp::Clause::OMPC_detach)}) {
2744+
// OpenMP 5.0: Task construct restrictions
2745+
CheckNotAllowedIfClause(
2746+
llvm::omp::Clause::OMPC_detach, {llvm::omp::Clause::OMPC_mergeable});
2747+
2748+
// OpenMP 5.2: Task construct restrictions
2749+
if (FindClause(llvm::omp::Clause::OMPC_final)) {
2750+
context_.Say(GetContext().clauseSource,
2751+
"If a DETACH clause appears on a directive, then the encountering task must not be a FINAL task"_err_en_US);
2752+
}
2753+
2754+
const auto &detachClause{
2755+
std::get<parser::OmpClause::Detach>(d_clause->u)};
2756+
if (const auto *name{parser::Unwrap<parser::Name>(detachClause.v.v)}) {
2757+
if (name->symbol) {
2758+
std::string eventHandleSymName{name->ToString()};
2759+
auto checkVarAppearsInDataEnvClause = [&](const parser::OmpObjectList
2760+
&objs,
2761+
std::string clause) {
2762+
for (const auto &obj : objs.v) {
2763+
if (const parser::Name *objName{
2764+
parser::Unwrap<parser::Name>(obj)}) {
2765+
if (objName->ToString() == eventHandleSymName) {
2766+
context_.Say(GetContext().clauseSource,
2767+
"A variable: `%s` that appears in a DETACH clause cannot appear on %s clause on the same construct"_err_en_US,
2768+
eventHandleSymName, clause);
2769+
}
2770+
}
2771+
}
2772+
};
2773+
if (auto *dataEnvClause{
2774+
FindClause(llvm::omp::Clause::OMPC_private)}) {
2775+
const auto &pClause{
2776+
std::get<parser::OmpClause::Private>(dataEnvClause->u)};
2777+
checkVarAppearsInDataEnvClause(pClause.v, "PRIVATE");
2778+
} else if (auto *dataEnvClause{
2779+
FindClause(llvm::omp::Clause::OMPC_firstprivate)}) {
2780+
const auto &fpClause{
2781+
std::get<parser::OmpClause::Firstprivate>(dataEnvClause->u)};
2782+
checkVarAppearsInDataEnvClause(fpClause.v, "FIRSTPRIVATE");
2783+
} else if (auto *dataEnvClause{
2784+
FindClause(llvm::omp::Clause::OMPC_in_reduction)}) {
2785+
const auto &irClause{
2786+
std::get<parser::OmpClause::InReduction>(dataEnvClause->u)};
2787+
checkVarAppearsInDataEnvClause(
2788+
std::get<parser::OmpObjectList>(irClause.v.t), "IN_REDUCTION");
2789+
}
2790+
}
2791+
}
2792+
}
2793+
}
2794+
27422795
auto testThreadprivateVarErr = [&](Symbol sym, parser::Name name,
27432796
llvmOmpClause clauseTy) {
27442797
if (sym.test(Symbol::Flag::OmpThreadprivate))
@@ -2823,7 +2876,6 @@ CHECK_SIMPLE_CLAUSE(Capture, OMPC_capture)
28232876
CHECK_SIMPLE_CLAUSE(Contains, OMPC_contains)
28242877
CHECK_SIMPLE_CLAUSE(Default, OMPC_default)
28252878
CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj)
2826-
CHECK_SIMPLE_CLAUSE(Detach, OMPC_detach)
28272879
CHECK_SIMPLE_CLAUSE(DeviceType, OMPC_device_type)
28282880
CHECK_SIMPLE_CLAUSE(DistSchedule, OMPC_dist_schedule)
28292881
CHECK_SIMPLE_CLAUSE(Exclusive, OMPC_exclusive)
@@ -3352,40 +3404,45 @@ void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
33523404
const parser::CharBlock &source, const parser::OmpObjectList &objList,
33533405
llvm::StringRef clause) {
33543406
for (const auto &ompObject : objList.v) {
3355-
common::visit(
3356-
common::visitors{
3357-
[&](const parser::Designator &designator) {
3358-
if (const auto *dataRef{
3359-
std::get_if<parser::DataRef>(&designator.u)}) {
3360-
if (IsDataRefTypeParamInquiry(dataRef)) {
3407+
CheckIsVarPartOfAnotherVar(source, ompObject, clause);
3408+
}
3409+
}
3410+
3411+
void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
3412+
const parser::CharBlock &source, const parser::OmpObject &ompObject,
3413+
llvm::StringRef clause) {
3414+
common::visit(
3415+
common::visitors{
3416+
[&](const parser::Designator &designator) {
3417+
if (const auto *dataRef{
3418+
std::get_if<parser::DataRef>(&designator.u)}) {
3419+
if (IsDataRefTypeParamInquiry(dataRef)) {
3420+
context_.Say(source,
3421+
"A type parameter inquiry cannot appear on the %s "
3422+
"directive"_err_en_US,
3423+
ContextDirectiveAsFortran());
3424+
} else if (parser::Unwrap<parser::StructureComponent>(
3425+
ompObject) ||
3426+
parser::Unwrap<parser::ArrayElement>(ompObject)) {
3427+
if (llvm::omp::nonPartialVarSet.test(GetContext().directive)) {
33613428
context_.Say(source,
3362-
"A type parameter inquiry cannot appear on the %s "
3429+
"A variable that is part of another variable (as an "
3430+
"array or structure element) cannot appear on the %s "
33633431
"directive"_err_en_US,
33643432
ContextDirectiveAsFortran());
3365-
} else if (parser::Unwrap<parser::StructureComponent>(
3366-
ompObject) ||
3367-
parser::Unwrap<parser::ArrayElement>(ompObject)) {
3368-
if (llvm::omp::nonPartialVarSet.test(
3369-
GetContext().directive)) {
3370-
context_.Say(source,
3371-
"A variable that is part of another variable (as an "
3372-
"array or structure element) cannot appear on the %s "
3373-
"directive"_err_en_US,
3374-
ContextDirectiveAsFortran());
3375-
} else {
3376-
context_.Say(source,
3377-
"A variable that is part of another variable (as an "
3378-
"array or structure element) cannot appear in a "
3379-
"%s clause"_err_en_US,
3380-
clause.data());
3381-
}
3433+
} else {
3434+
context_.Say(source,
3435+
"A variable that is part of another variable (as an "
3436+
"array or structure element) cannot appear in a "
3437+
"%s clause"_err_en_US,
3438+
clause.data());
33823439
}
33833440
}
3384-
},
3385-
[&](const parser::Name &name) {},
3386-
},
3387-
ompObject.u);
3388-
}
3441+
}
3442+
},
3443+
[&](const parser::Name &name) {},
3444+
},
3445+
ompObject.u);
33893446
}
33903447

33913448
void OmpStructureChecker::Enter(const parser::OmpClause::Firstprivate &x) {
@@ -3711,6 +3768,30 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) {
37113768
x.v.u);
37123769
}
37133770

3771+
void OmpStructureChecker::Enter(const parser::OmpClause::Detach &x) {
3772+
// OpenMP 5.0: Task construct restrictions
3773+
CheckAllowedClause(llvm::omp::Clause::OMPC_detach);
3774+
3775+
// OpenMP 5.2: Detach clause restrictions
3776+
CheckIsVarPartOfAnotherVar(GetContext().clauseSource, x.v.v, "DETACH");
3777+
if (const auto *name{parser::Unwrap<parser::Name>(x.v.v)}) {
3778+
if (name->symbol) {
3779+
if (IsPointer(*name->symbol)) {
3780+
context_.Say(GetContext().clauseSource,
3781+
"The event-handle: `%s` must not have the POINTER attribute"_err_en_US,
3782+
name->ToString());
3783+
}
3784+
}
3785+
auto type{name->symbol->GetType()};
3786+
if (!name->symbol->GetType()->IsNumeric(TypeCategory::Integer) ||
3787+
evaluate::ToInt64(type->numericTypeSpec().kind()) != 8) {
3788+
context_.Say(GetContext().clauseSource,
3789+
"The event-handle: `%s` must be of type integer(kind=omp_event_handle_kind)"_err_en_US,
3790+
name->ToString());
3791+
}
3792+
}
3793+
}
3794+
37143795
void OmpStructureChecker::CheckAllowedMapTypes(
37153796
const parser::OmpMapType::Value &type,
37163797
const std::list<parser::OmpMapType::Value> &allowedMapTypeList) {

flang/lib/Semantics/check-omp-structure.h

+2
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,8 @@ class OmpStructureChecker
180180
const common::Indirection<parser::ArrayElement> &, const parser::Name &);
181181
void CheckDoacross(const parser::OmpDoacross &doa);
182182
bool IsDataRefTypeParamInquiry(const parser::DataRef *dataRef);
183+
void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source,
184+
const parser::OmpObject &obj, llvm::StringRef clause = "");
183185
void CheckIsVarPartOfAnotherVar(const parser::CharBlock &source,
184186
const parser::OmpObjectList &objList, llvm::StringRef clause = "");
185187
void CheckThreadprivateOrDeclareTargetVar(
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
! REQUIRES: openmp_runtime
2+
! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags -fopenmp-version=50
3+
4+
! OpenMP Version 5.2
5+
! Various checks for DETACH Clause (12.5.2)
6+
7+
program test_detach
8+
use omp_lib
9+
implicit none
10+
integer :: e, x
11+
integer(omp_event_handle_kind) :: event_01, event_02(2)
12+
integer(omp_event_handle_kind), pointer :: event_03
13+
14+
15+
type :: t
16+
integer(omp_event_handle_kind) :: event
17+
end type
18+
19+
type(t) :: t_01
20+
21+
!ERROR: The event-handle: `e` must be of type integer(kind=omp_event_handle_kind)
22+
!$omp task detach(e)
23+
x = x + 1
24+
!$omp end task
25+
26+
!ERROR: At most one DETACH clause can appear on the TASK directive
27+
!$omp task detach(event_01) detach(event_01)
28+
x = x + 1
29+
!$omp end task
30+
31+
!ERROR: Clause MERGEABLE is not allowed if clause DETACH appears on the TASK directive
32+
!$omp task detach(event_01) mergeable
33+
x = x + 1
34+
!$omp end task
35+
36+
!ERROR: If a DETACH clause appears on a directive, then the encountering task must not be a FINAL task
37+
!$omp task detach(event_01) final(.false.)
38+
x = x + 1
39+
!$omp end task
40+
41+
!ERROR: A variable: `event_01` that appears in a DETACH clause cannot appear on PRIVATE clause on the same construct
42+
!$omp task detach(event_01) private(event_01)
43+
x = x + 1
44+
!$omp end task
45+
46+
!ERROR: A variable: `event_01` that appears in a DETACH clause cannot appear on IN_REDUCTION clause on the same construct
47+
!$omp task detach(event_01) in_reduction(+:event_01)
48+
x = x + 1
49+
!$omp end task
50+
51+
!ERROR: A variable that is part of another variable (as an array or structure element) cannot appear in a DETACH clause
52+
!$omp task detach(event_02(1))
53+
x = x + 1
54+
!$omp end task
55+
56+
!ERROR: A variable that is part of another variable (as an array or structure element) cannot appear in a DETACH clause
57+
!$omp task detach(t_01%event)
58+
x = x + 1
59+
!$omp end task
60+
61+
!ERROR: The event-handle: `event_03` must not have the POINTER attribute
62+
!$omp task detach(event_03)
63+
x = x + 1
64+
!$omp end task
65+
end program

llvm/include/llvm/Frontend/OpenMP/OMP.td

+1-1
Original file line numberDiff line numberDiff line change
@@ -1085,7 +1085,6 @@ def OMP_Task : Directive<"task"> {
10851085
VersionedClause<OMPC_Affinity, 50>,
10861086
VersionedClause<OMPC_Allocate>,
10871087
VersionedClause<OMPC_Depend>,
1088-
VersionedClause<OMPC_Detach, 50>,
10891088
VersionedClause<OMPC_FirstPrivate>,
10901089
VersionedClause<OMPC_InReduction>,
10911090
VersionedClause<OMPC_Mergeable>,
@@ -1095,6 +1094,7 @@ def OMP_Task : Directive<"task"> {
10951094
];
10961095
let allowedOnceClauses = [
10971096
VersionedClause<OMPC_Default>,
1097+
VersionedClause<OMPC_Detach, 50>,
10981098
VersionedClause<OMPC_Final>,
10991099
VersionedClause<OMPC_If>,
11001100
VersionedClause<OMPC_Priority>,

0 commit comments

Comments
 (0)