Skip to content

[Flang][OpenMP] Add some semantic checks for Linear clause #111354

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

Merged
merged 4 commits into from
Dec 6, 2024

Conversation

Thirumalai-Shaktivel
Copy link
Member

@Thirumalai-Shaktivel Thirumalai-Shaktivel commented Oct 7, 2024

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.

@Thirumalai-Shaktivel Thirumalai-Shaktivel added flang Flang issues not falling into any other category flang:openmp flang:semantics labels Oct 7, 2024
@llvmbot
Copy link
Member

llvmbot commented Oct 7, 2024

@llvm/pr-subscribers-flang-openmp

@llvm/pr-subscribers-flang-semantics

Author: Thirumalai Shaktivel (Thirumalai-Shaktivel)

Changes

Full diff: https://github.com/llvm/llvm-project/pull/111354.diff

3 Files Affected:

  • (modified) flang/lib/Semantics/check-omp-structure.cpp (+114-4)
  • (modified) flang/test/Semantics/OpenMP/declarative-directive.f90 (+1)
  • (added) flang/test/Semantics/OpenMP/linear-cluase01.f90 (+50)
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index 5ef504aa72326e..d409d7b548767e 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -303,6 +303,30 @@ void OmpStructureChecker::CheckMultListItems() {
     CheckMultipleOccurrence(
         listVars, nontempNameList, itr->second->source, "NONTEMPORAL");
   }
+
+  // Linear clause
+  auto linearClauses{FindClauses(llvm::omp::Clause::OMPC_linear)};
+  for (auto itr = linearClauses.first; itr != linearClauses.second; ++itr) {
+    const auto &linearClause{
+        std::get<parser::OmpClause::Linear>(itr->second->u)};
+    std::list<parser::Name> nameList;
+    common::visit(
+        common::visitors{
+            [&](const parser::OmpLinearClause::WithoutModifier
+                    &withoutModifier) {
+              for (const auto &name : withoutModifier.names) {
+                nameList.push_back(name);
+              }
+            },
+            [&](const parser::OmpLinearClause::WithModifier &withModifier) {
+              for (const auto &name : withModifier.names) {
+                nameList.push_back(name);
+              }
+            },
+        },
+        linearClause.v.u);
+    CheckMultipleOccurrence(listVars, nameList, itr->second->source, "LINEAR");
+  }
 }
 
 bool OmpStructureChecker::HasInvalidWorksharingNesting(
@@ -2256,11 +2280,12 @@ void OmpStructureChecker::Leave(const parser::OmpClauseList &) {
         }
       }
     }
-    // Sema checks related to presence of multiple list items within the same
-    // clause
-    CheckMultListItems();
   } // SIMD
 
+  // Semantics checks related to presence of multiple list items within the same
+  // clause
+  CheckMultListItems();
+
   // 2.7.3 Single Construct Restriction
   if (GetContext().directive == llvm::omp::Directive::OMPD_end_single) {
     CheckNotAllowedIfClause(
@@ -2975,16 +3000,101 @@ void OmpStructureChecker::Enter(const parser::OmpClause::If &x) {
 void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) {
   CheckAllowedClause(llvm::omp::Clause::OMPC_linear);
 
+  parser::CharBlock source = GetContext().clauseSource;
   // 2.7 Loop Construct Restriction
   if ((llvm::omp::allDoSet | llvm::omp::allSimdSet)
           .test(GetContext().directive)) {
     if (std::holds_alternative<parser::OmpLinearClause::WithModifier>(x.v.u)) {
-      context_.Say(GetContext().clauseSource,
+      context_.Say(source,
           "A modifier may not be specified in a LINEAR clause "
           "on the %s directive"_err_en_US,
           ContextDirectiveAsFortran());
+      return;
+    }
+  }
+
+  // 4.4.4 Ordered clause restriction
+  if (const auto *clause{
+          FindClause(GetContext(), llvm::omp::Clause::OMPC_ordered)}) {
+    const auto &orderedClause{std::get<parser::OmpClause::Ordered>(clause->u)};
+    if (orderedClause.v) {
+      return;
     }
   }
+
+  auto checkForValidLinearClaue = [&](const parser::Name &name, bool is_ref) {
+    parser::CharBlock source = GetContext().clauseSource;
+    std::string list_item_name = name.ToString();
+    if (!is_ref && !name.symbol->GetType()->IsNumeric(TypeCategory::Integer)) {
+      context_.Say(source,
+          "The list item `%s` specified with other than linear-modifier `REF`"
+          " must be of type INTEGER"_err_en_US,
+          list_item_name);
+    }
+    if (GetContext().directive == llvm::omp::Directive::OMPD_declare_simd &&
+        !IsDummy(*name.symbol)) {
+      context_.Say(source,
+          "The list item `%s` must be a dummy argument"_err_en_US,
+          list_item_name);
+    }
+    if (IsPointer(*name.symbol) ||
+        name.symbol->test(Symbol::Flag::CrayPointer)) {
+      context_.Say(source,
+          "The list item `%s` in a LINEAR clause must not be Cray Pointer "
+          "or a variable with POINTER attribute"_err_en_US,
+          list_item_name);
+    }
+    if (FindCommonBlockContaining(*name.symbol)) {
+      context_.Say(source,
+          "'%s' is a common block name and must not appear in an "
+          "LINEAR clause"_err_en_US,
+          list_item_name);
+    }
+  };
+
+  // 5.4.6 Linear clause Restrictions
+  common::visit(
+      common::visitors{
+          [&](const parser::OmpLinearClause::WithoutModifier &withoutModifier) {
+            for (const auto &name : withoutModifier.names) {
+              if (name.symbol) {
+                checkForValidLinearClaue(name, false);
+              }
+            }
+          },
+          [&](const parser::OmpLinearClause::WithModifier &withModifier) {
+            for (const auto &name : withModifier.names) {
+              if (name.symbol) {
+                checkForValidLinearClaue(name,
+                    (withModifier.modifier.v ==
+                        parser::OmpLinearModifier::Type::Ref));
+                std::string list_item_name = name.ToString();
+                if (withModifier.modifier.v !=
+                        parser::OmpLinearModifier::Type::Val &&
+                    IsDummy(*name.symbol) && IsValue(*name.symbol)) {
+                  context_.Say(source,
+                      "The list item `%s` specified with the linear-modifier "
+                      "`REF` or `UVAL` must be a dummy argument without "
+                      "`VALUE` attribute"_err_en_US,
+                      list_item_name);
+                }
+                if (withModifier.modifier.v ==
+                        parser::OmpLinearModifier::Type::Ref &&
+                    !(IsAllocatable(*name.symbol) ||
+                        IsAssumedShape(*name.symbol) ||
+                        IsPolymorphic(*name.symbol))) {
+                  context_.Say(source,
+                      "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,
+                      list_item_name);
+                }
+              }
+            }
+          },
+      },
+      x.v.u);
 }
 
 void OmpStructureChecker::CheckAllowedMapTypes(
diff --git a/flang/test/Semantics/OpenMP/declarative-directive.f90 b/flang/test/Semantics/OpenMP/declarative-directive.f90
index 8d6762b87adb95..17dc50b70e5421 100644
--- a/flang/test/Semantics/OpenMP/declarative-directive.f90
+++ b/flang/test/Semantics/OpenMP/declarative-directive.f90
@@ -23,6 +23,7 @@ end subroutine requires_2
 
 subroutine declare_simd_1(a, b)
   real(8), intent(inout) :: a, b
+  !ERROR: 'a' in ALIGNED clause must be of type C_PTR, POINTER or ALLOCATABLE
   !$omp declare simd(declare_simd_1) aligned(a)
   a = 3.14 + b
 end subroutine declare_simd_1
diff --git a/flang/test/Semantics/OpenMP/linear-cluase01.f90 b/flang/test/Semantics/OpenMP/linear-cluase01.f90
new file mode 100644
index 00000000000000..a56709aae7ad73
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/linear-cluase01.f90
@@ -0,0 +1,50 @@
+! REQUIRES: openmp_runtime
+! RUN: %python %S/../test_errors.py %s %flang_fc1 %openmp_flags
+! OpenMP Version 5.2
+! Various checks for the linear clause
+! 5.4.6 `linear` Clause
+
+! Case 1
+subroutine linear_clause_01(arg)
+    integer, intent(in) :: arg(:)
+    !ERROR: A modifier may not be specified in a LINEAR clause on the DO directive
+    !$omp do linear(uval(arg))
+    do i = 1, 5
+        print *, arg(i)
+    end do
+end subroutine linear_clause_01
+
+! Case 2
+subroutine linear_clause_02(arg_01, arg_02, arg_03)
+    !ERROR: The list item `arg_01` specified with other than linear-modifier `REF` must be of type INTEGER
+    !$omp declare simd linear(val(arg_01))
+    real, intent(in) :: arg_01(:)
+
+    !ERROR: The list item `arg_02` specified with the linear-modifier `REF` or `UVAL` must be a dummy argument without `VALUE` attribute
+    !$omp declare simd linear(uval(arg_02))
+    integer, value, intent(in) :: arg_02
+
+    !ERROR: The list item `arg_03` specified with other than linear-modifier `REF` must be of type INTEGER
+    !ERROR: The list item `arg_03` in a LINEAR clause must not be Cray Pointer or a variable with POINTER attribute
+    !$omp declare simd linear(arg_03)
+    real, pointer :: arg_03
+
+    !ERROR: The list item `var` must be a dummy argument
+    !ERROR: The list item `var` in a LINEAR clause must not be Cray Pointer or a variable with POINTER attribute
+    !$omp declare simd linear(uval(var))
+    integer, pointer :: var
+end subroutine linear_clause_02
+
+! Case 3
+subroutine linear_clause_03(arg)
+    integer, intent(in) :: arg
+    !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
+    !ERROR: List item 'arg' present at multiple LINEAR clauses
+    !$omp declare simd linear(ref(arg)) linear(arg)
+
+    integer :: i
+    common /cc/ i
+    !ERROR: The list item `i` must be a dummy argument
+    !ERROR: 'i' is a common block name and must not appear in an LINEAR clause
+    !$omp declare simd linear(i)
+end subroutine linear_clause_03

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo: cluase -> clause.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Copy link
Contributor

@kiranchandramohan kiranchandramohan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few nit comments.

Could you expand the summary to list the checks implemented in the patch with a reference to the standard and section?

@@ -2975,16 +3000,101 @@ void OmpStructureChecker::Enter(const parser::OmpClause::If &x) {
void OmpStructureChecker::Enter(const parser::OmpClause::Linear &x) {
CheckAllowedClause(llvm::omp::Clause::OMPC_linear);

parser::CharBlock source = GetContext().clauseSource;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use braced initialized in frontend code.

}
}

auto checkForValidLinearClaue = [&](const parser::Name &name, bool is_ref) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
auto checkForValidLinearClaue = [&](const parser::Name &name, bool is_ref) {
auto checkForValidLinearClause = [&](const parser::Name &name, bool is_ref) {


auto checkForValidLinearClaue = [&](const parser::Name &name, bool is_ref) {
parser::CharBlock source = GetContext().clauseSource;
std::string list_item_name = name.ToString();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::string list_item_name = name.ToString();
std::string listItemName = name.ToString();

}
}

auto checkForValidLinearClaue = [&](const parser::Name &name, bool is_ref) {
parser::CharBlock source = GetContext().clauseSource;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Use braced initialization.

checkForValidLinearClaue(name,
(withModifier.modifier.v ==
parser::OmpLinearModifier::Type::Ref));
std::string list_item_name = name.ToString();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
std::string list_item_name = name.ToString();
std::string listItemName = name.ToString();


// Linear clause
auto linearClauses{FindClauses(llvm::omp::Clause::OMPC_linear)};
for (auto itr = linearClauses.first; itr != linearClauses.second; ++itr) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
for (auto itr = linearClauses.first; itr != linearClauses.second; ++itr) {
for (auto itr{linearClauses.first}; itr != linearClauses.second; ++itr) {

@Thirumalai-Shaktivel Thirumalai-Shaktivel marked this pull request as draft October 8, 2024 11:41
@Thirumalai-Shaktivel Thirumalai-Shaktivel force-pushed the amd/linear_01 branch 2 times, most recently from 5922503 to 7a760f0 Compare October 9, 2024 05:15
FindClause(GetContext(), llvm::omp::Clause::OMPC_ordered)}) {
const auto &orderedClause{std::get<parser::OmpClause::Ordered>(clause->u)};
if (orderedClause.v) {
return;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Flang-new already throws an error, Clause LINEAR is not allowed if clause ORDERED appears on the DO directive. So, I skipped here.

@Thirumalai-Shaktivel
Copy link
Member Author

I addressed all the comments, @kiranchandramohan.

Thanks for the reviews.

OpenMP 5.2 restriction: Each list item must have C_PTR or Cray pointer type or have the POINTER or ALLOCATABLE attribute.
Copy link
Contributor

@NimishMishra NimishMishra left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One small comment on ALIGNED clause test added in this PR.

Ultra nit: "If n is explicitly specified, a linear clause must not be specified on the same directive" in description -> "If an ordered clause is explicitly specified......"

@@ -23,6 +23,7 @@ end subroutine requires_2

subroutine declare_simd_1(a, b)
real(8), intent(inout) :: a, b
!ERROR: 'a' in ALIGNED clause must be of type C_PTR, POINTER or ALLOCATABLE
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we also deal with ALIGNED clause in this PR? A similar issue is causing the Linux CI failure:

flang/test/Examples/omp-declarative-directive.f90:11:38: error: 'a' in ALIGNED clause must be of type C_PTR, POINTER or ALLOCATABLE
--
  | !$omp declare simd(declare_simd_1) aligned(a)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed it in the recent commit.

Comment on lines 328 to 331
auto linearClauses{FindClauses(llvm::omp::Clause::OMPC_linear)};
for (auto itr{linearClauses.first}; itr != linearClauses.second; ++itr) {
const auto &linearClause{
std::get<parser::OmpClause::Linear>(itr->second->u)};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FindClauses now returns an iterator range, please use range-for here.

Comment on lines 334 to 395
common::visitors{
[&](const parser::OmpLinearClause::WithoutModifier
&withoutModifier) {
for (const auto &name : withoutModifier.names) {
nameList.push_back(name);
}
},
[&](const parser::OmpLinearClause::WithModifier &withModifier) {
for (const auto &name : withModifier.names) {
nameList.push_back(name);
}
},
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can only have a single visitor, plus you can simplify the copy:

[&](auto &&s) {
  std::copy(s.names.begin(), s.names.end(), std::back_inserter(nameList));
}

},
[&](const parser::OmpLinearClause::WithModifier &withModifier) {
for (const auto &name : withModifier.names) {
if (name.symbol) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can extract this into a lamda to reduce indentation.

Comment on lines 3140 to 3142
"The list item `%s` specified with the linear-modifier "
"`REF` or `UVAL` must be a dummy argument without "
"`VALUE` attribute"_err_en_US,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please concatenate messages into a single string. This is to make grepping for messages easier.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Comment on lines 3151 to 3154
"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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here.

@kparzysz
Copy link
Contributor

kparzysz commented Dec 2, 2024

I will change the modifier representation in LINEAR in a week or so. Please finish this soon, otherwise my code will create conflicts for you.

@Thirumalai-Shaktivel
Copy link
Member Author

Thanks for the review, @kparzysz!

I addressed all the comments. If anything else to be done, please let me know.

Copy link

github-actions bot commented Dec 6, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor

@kparzysz kparzysz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Almost ready, a few more comments.

Comment on lines 3640 to 3634
for (const auto &name : withoutModifier.names)
if (name.symbol)
checkForValidLinearClause_01(name, false);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add {} for nested statements.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you mean the following?

Suggested change
for (const auto &name : withoutModifier.names)
if (name.symbol)
checkForValidLinearClause_01(name, false);
for (const auto &name : withoutModifier.names) {
if (name.symbol) {
checkForValidLinearClause_01(name, false);
}
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Comment on lines 392 to 395
common::visitors{
[&](const auto &u) {
std::copy(
u.names.begin(), u.names.end(), std::back_inserter(nameList));
},
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You only have one visitor, so you don't need common::visitors. Do common::visit([&]...).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yea, sure.

Comment on lines +3582 to +3581
auto checkForValidLinearClause_01 = [&](const parser::Name &name,
bool is_ref) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please concatenate all error message strings in this function.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm sorry, but I'm not getting this.

Concatenate in the sense, for the following:

context_.Say(source,
          "The list item `%s` specified with other than linear-modifier `REF`"
          " must be of type INTEGER"_err_en_US,
          listItemName);

should I do?

context_.Say(source,
          "The list item `%s` specified with other than linear-modifier `REF` must be of type INTEGER"_err_en_US,
          listItemName);

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

Comment on lines 3612 to 3614
auto checkForValidLinearClause_02 =
[&](const parser::Name &name,
const parser::OmpLinearModifier::Value &modifierValue) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please concatenate all error message strings in this function.

@kparzysz
Copy link
Contributor

kparzysz commented Dec 6, 2024

Please don't use force-pushes. That messes up previous comments.

@Thirumalai-Shaktivel
Copy link
Member Author

Sorry about that.

I rebased the commits and I had to force-push the changes.
Next time I will make sure not to rebase it.

@Thirumalai-Shaktivel
Copy link
Member Author

Done.

@kparzysz kparzysz merged commit e73ec1a into llvm:main Dec 6, 2024
8 checks passed
@Thirumalai-Shaktivel Thirumalai-Shaktivel deleted the amd/linear_01 branch December 7, 2024 03:07
@Thirumalai-Shaktivel
Copy link
Member Author

Thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
flang:openmp flang:semantics flang Flang issues not falling into any other category
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants