Skip to content

Commit e73ec1a

Browse files
[Flang][OpenMP] Add some semantic checks for Linear clause (#111354)
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 - A linear-modifier may be specified as ref or uval only on a declare simd directive. - If linear-modifier is not ref, all list items must be of type integer. - If linear-modifier is ref or uval, all list items must be dummy arguments without the VALUE attribute. - List items must not be Cray pointers or variables that have the POINTER attribute. Cray pointer support has been deprecated. - If linear-modifier is ref, list items must be polymorphic variables, assumed-shape arrays, or variables with the ALLOCATABLE attribute. - A common block name must not appear in a linear clause. - The list-item cannot appear more than once 4.4.4 ordered Clause restriction - If n is explicitly specified, a linear clause must not be specified on the same directive. 5.11 aligned Clause restriction - Each list item must have C_PTR or Cray pointer type or have the POINTER or ALLOCATABLE attribute. Cray pointer support has been deprecated.
1 parent 02db35a commit e73ec1a

File tree

4 files changed

+144
-6
lines changed

4 files changed

+144
-6
lines changed

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

Lines changed: 97 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,19 @@ void OmpStructureChecker::CheckMultListItems() {
411411
CheckMultipleOccurrence(
412412
listVars, nontempNameList, clause->source, "NONTEMPORAL");
413413
}
414+
415+
// Linear clause
416+
for (auto [_, clause] : FindClauses(llvm::omp::Clause::OMPC_linear)) {
417+
const auto &linearClause{std::get<parser::OmpClause::Linear>(clause->u)};
418+
std::list<parser::Name> nameList;
419+
common::visit(
420+
[&](const auto &u) {
421+
std::copy(
422+
u.names.begin(), u.names.end(), std::back_inserter(nameList));
423+
},
424+
linearClause.v.u);
425+
CheckMultipleOccurrence(listVars, nameList, clause->source, "LINEAR");
426+
}
414427
}
415428

416429
bool OmpStructureChecker::HasInvalidWorksharingNesting(
@@ -2714,12 +2727,12 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
27142727
}
27152728
}
27162729
}
2717-
2718-
// Sema checks related to presence of multiple list items within the same
2719-
// clause
2720-
CheckMultListItems();
27212730
} // SIMD
27222731

2732+
// Semantic checks related to presence of multiple list items within the same
2733+
// clause
2734+
CheckMultListItems();
2735+
27232736
// 2.7.3 Single Construct Restriction
27242737
if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) {
27252738
CheckNotAllowedIfClause(
@@ -3607,16 +3620,95 @@ void OmpStructureChecker::Enter(const parser::OmpClause::If &x) {
36073620
void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) {
36083621
CheckAllowedClause(llvm::omp::Clause::OMPC_linear);
36093622

3623+
parser::CharBlock source{GetContext().clauseSource};
36103624
// 2.7 Loop Construct Restriction
36113625
if ((llvm::omp::allDoSet | llvm::omp::allSimdSet)
36123626
.test(GetContext().directive)) {
36133627
if (std::holds_alternative<parser::OmpLinearClause::WithModifier>(x.v.u)) {
3614-
context_.Say(GetContext().clauseSource,
3628+
context_.Say(source,
36153629
"A modifier may not be specified in a LINEAR clause "
36163630
"on the %s directive"_err_en_US,
36173631
ContextDirectiveAsFortran());
3632+
return;
3633+
}
3634+
}
3635+
3636+
// OpenMP 5.2: Ordered clause restriction
3637+
if (const auto *clause{
3638+
FindClause(GetContext(), llvm::omp::Clause::OMPC_ordered)}) {
3639+
const auto &orderedClause{std::get<parser::OmpClause::Ordered>(clause->u)};
3640+
if (orderedClause.v) {
3641+
return;
36183642
}
36193643
}
3644+
3645+
auto checkForValidLinearClause_01 = [&](const parser::Name &name,
3646+
bool is_ref) {
3647+
std::string listItemName{name.ToString()};
3648+
if (!is_ref && !name.symbol->GetType()->IsNumeric(TypeCategory::Integer)) {
3649+
context_.Say(source,
3650+
"The list item `%s` specified with other than linear-modifier `REF` must be of type INTEGER"_err_en_US,
3651+
listItemName);
3652+
}
3653+
if (GetContext().directive == llvm::omp::Directive::OMPD_declare_simd &&
3654+
!IsDummy(*name.symbol)) {
3655+
context_.Say(source,
3656+
"The list item `%s` must be a dummy argument"_err_en_US,
3657+
listItemName);
3658+
}
3659+
if (IsPointer(*name.symbol) ||
3660+
name.symbol->test(Symbol::Flag::CrayPointer)) {
3661+
context_.Say(source,
3662+
"The list item `%s` in a LINEAR clause must not be Cray Pointer or a variable with POINTER attribute"_err_en_US,
3663+
listItemName);
3664+
}
3665+
if (FindCommonBlockContaining(*name.symbol)) {
3666+
context_.Say(source,
3667+
"'%s' is a common block name and must not appear in an LINEAR clause"_err_en_US,
3668+
listItemName);
3669+
}
3670+
};
3671+
3672+
auto checkForValidLinearClause_02 = [&](const parser::Name &name,
3673+
const parser::OmpLinearModifier::Value
3674+
&modifierValue) {
3675+
std::string listItemName{name.ToString()};
3676+
checkForValidLinearClause_01(
3677+
name, (modifierValue == parser::OmpLinearModifier::Value::Ref));
3678+
if (modifierValue != parser::OmpLinearModifier::Value::Val &&
3679+
IsDummy(*name.symbol) && IsValue(*name.symbol)) {
3680+
context_.Say(source,
3681+
"The list item `%s` specified with the linear-modifier `REF` or `UVAL` must be a dummy argument without `VALUE` attribute"_err_en_US,
3682+
listItemName);
3683+
}
3684+
if (modifierValue == parser::OmpLinearModifier::Value::Ref &&
3685+
!(IsAllocatable(*name.symbol) || IsAssumedShape(*name.symbol) ||
3686+
IsPolymorphic(*name.symbol))) {
3687+
context_.Say(source,
3688+
"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,
3689+
listItemName);
3690+
}
3691+
};
3692+
3693+
// OpenMP 5.2: Linear clause Restrictions
3694+
common::visit(
3695+
common::visitors{
3696+
[&](const parser::OmpLinearClause::WithoutModifier &withoutModifier) {
3697+
for (const auto &name : withoutModifier.names) {
3698+
if (name.symbol) {
3699+
checkForValidLinearClause_01(name, false);
3700+
}
3701+
}
3702+
},
3703+
[&](const parser::OmpLinearClause::WithModifier &withModifier) {
3704+
for (const auto &name : withModifier.names) {
3705+
if (name.symbol) {
3706+
checkForValidLinearClause_02(name, withModifier.modifier.v);
3707+
}
3708+
}
3709+
},
3710+
},
3711+
x.v.u);
36203712
}
36213713

36223714
void OmpStructureChecker::CheckAllowedMapTypes(

flang/test/Examples/omp-declarative-directive.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
! 2.8.2 declare-simd
88

99
subroutine declare_simd_1(a, b)
10-
real(8), intent(inout) :: a, b
10+
real(8), intent(inout), allocatable :: a, b
1111
!$omp declare simd(declare_simd_1) aligned(a)
1212
a = 3.14 + b
1313
end subroutine declare_simd_1

flang/test/Semantics/OpenMP/declarative-directive01.f90

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ end subroutine requires_2
2323

2424
subroutine declare_simd_1(a, b)
2525
real(8), intent(inout) :: a, b
26+
!ERROR: 'a' in ALIGNED clause must be of type C_PTR, POINTER or ALLOCATABLE
2627
!$omp declare simd(declare_simd_1) aligned(a)
2728
a = 3.14 + b
2829
end subroutine declare_simd_1
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
! REQUIRES: openmp_runtime
2+
! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags
3+
! OpenMP Version 5.2
4+
! Various checks for the linear clause
5+
! 5.4.6 `linear` Clause
6+
7+
! Case 1
8+
subroutine linear_clause_01(arg)
9+
integer, intent(in) :: arg(:)
10+
!ERROR: A modifier may not be specified in a LINEAR clause on the DO directive
11+
!$omp do linear(uval(arg))
12+
do i = 1, 5
13+
print *, arg(i)
14+
end do
15+
end subroutine linear_clause_01
16+
17+
! Case 2
18+
subroutine linear_clause_02(arg_01, arg_02)
19+
!ERROR: The list item `arg_01` specified with other than linear-modifier `REF` must be of type INTEGER
20+
!$omp declare simd linear(val(arg_01))
21+
real, intent(in) :: arg_01(:)
22+
23+
!ERROR: The list item `arg_02` specified with the linear-modifier `REF` or `UVAL` must be a dummy argument without `VALUE` attribute
24+
!$omp declare simd linear(uval(arg_02))
25+
integer, value, intent(in) :: arg_02
26+
27+
!ERROR: The list item `var` must be a dummy argument
28+
!ERROR: The list item `var` in a LINEAR clause must not be Cray Pointer or a variable with POINTER attribute
29+
!$omp declare simd linear(uval(var))
30+
integer, pointer :: var
31+
end subroutine linear_clause_02
32+
33+
! Case 3
34+
subroutine linear_clause_03(arg)
35+
integer, intent(in) :: arg
36+
!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
37+
!ERROR: List item 'arg' present at multiple LINEAR clauses
38+
!$omp declare simd linear(ref(arg)) linear(arg)
39+
40+
integer :: i
41+
common /cc/ i
42+
!ERROR: The list item `i` must be a dummy argument
43+
!ERROR: 'i' is a common block name and must not appear in an LINEAR clause
44+
!$omp declare simd linear(i)
45+
end subroutine linear_clause_03

0 commit comments

Comments
 (0)