[flang][OpenMP] Added semantic checks for hint clause
authorNimish Mishra <neelam.nimish@gmail.com>
Thu, 14 Jul 2022 12:54:57 +0000 (18:24 +0530)
committerNimish Mishra <neelam.nimish@gmail.com>
Thu, 14 Jul 2022 12:54:57 +0000 (18:24 +0530)
This patch improves semantic checks for hint clause.
It checks "hint-expression is a constant expression
that evaluates to a scalar value with kind
`omp_sync_hint_kind` and a value that is a valid
synchronization hint."

Reviewed By: peixin

Differential Revision: https://reviews.llvm.org/D127615

flang/lib/Semantics/check-omp-structure.cpp
flang/lib/Semantics/check-omp-structure.h
flang/test/Semantics/OpenMP/omp-atomic-hint-clause.f90 [new file with mode: 0644]
flang/test/Semantics/OpenMP/omp-critical-hint-clause.f90 [new file with mode: 0644]

index 6dc97ea..64255d2 100644 (file)
@@ -314,6 +314,48 @@ void OmpStructureChecker::CheckPredefinedAllocatorRestriction(
   }
 }
 
+template <class D>
+void OmpStructureChecker::CheckHintClause(
+    D *leftOmpClauseList, D *rightOmpClauseList) {
+  auto checkForValidHintClause = [&](const D *clauseList) {
+    for (const auto &clause : clauseList->v) {
+      const Fortran::parser::OmpClause *ompClause = nullptr;
+      if constexpr (std::is_same_v<D,
+                        const Fortran::parser::OmpAtomicClauseList>) {
+        ompClause = std::get_if<Fortran::parser::OmpClause>(&clause.u);
+        if (!ompClause)
+          continue;
+      } else if constexpr (std::is_same_v<D,
+                               const Fortran::parser::OmpClauseList>) {
+        ompClause = &clause;
+      }
+      if (const Fortran::parser::OmpClause::Hint *
+          hintClause{
+              std::get_if<Fortran::parser::OmpClause::Hint>(&ompClause->u)}) {
+        std::optional<std::int64_t> hintValue = GetIntValue(hintClause->v);
+        if (hintValue && hintValue.value() >= 0) {
+          if((hintValue.value() & 0xC) == 0xC /*`omp_sync_hint_nonspeculative` and `omp_lock_hint_speculative`*/ 
+                  || (hintValue.value() & 0x3) == 0x3 /*`omp_sync_hint_uncontended` and omp_sync_hint_contended*/ )
+            context_.Say(clause.source,
+                "Hint clause value "
+                "is not a valid OpenMP synchronization value"_err_en_US);
+        } else {
+          context_.Say(clause.source,
+              "Hint clause must have non-negative constant "
+              "integer expression"_err_en_US);
+        }
+      }
+    }
+  };
+
+  if (leftOmpClauseList) {
+    checkForValidHintClause(leftOmpClauseList);
+  }
+  if (rightOmpClauseList) {
+    checkForValidHintClause(rightOmpClauseList);
+  }
+}
+
 void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) {
   // Simd Construct with Ordered Construct Nesting check
   // We cannot use CurrentDirectiveIsNested() here because
@@ -1277,6 +1319,7 @@ void OmpStructureChecker::Enter(const parser::OpenMPCriticalConstruct &x) {
         parser::MessageFormattedText{
             "Hint clause other than omp_sync_hint_none cannot be specified for an unnamed CRITICAL directive"_err_en_US});
   }
+  CheckHintClause<const parser::OmpClauseList>(&ompClause, nullptr);
 }
 
 void OmpStructureChecker::Leave(const parser::OpenMPCriticalConstruct &) {
@@ -1580,6 +1623,9 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
             CheckAtomicMemoryOrderClause(
                 &std::get<parser::OmpAtomicClauseList>(atomicConstruct.t),
                 nullptr);
+            CheckHintClause<const parser::OmpAtomicClauseList>(
+                &std::get<parser::OmpAtomicClauseList>(atomicConstruct.t),
+                nullptr);
           },
           [&](const parser::OmpAtomicUpdate &atomicUpdate) {
             const auto &dir{std::get<parser::Verbatim>(atomicUpdate.t)};
@@ -1591,6 +1637,8 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
                     .statement);
             CheckAtomicMemoryOrderClause(
                 &std::get<0>(atomicUpdate.t), &std::get<2>(atomicUpdate.t));
+            CheckHintClause<const parser::OmpAtomicClauseList>(
+                &std::get<0>(atomicUpdate.t), &std::get<2>(atomicUpdate.t));
           },
           [&](const auto &atomicConstruct) {
             const auto &dir{std::get<parser::Verbatim>(atomicConstruct.t)};
@@ -1598,6 +1646,9 @@ void OmpStructureChecker::Enter(const parser::OpenMPAtomicConstruct &x) {
                 dir.source, llvm::omp::Directive::OMPD_atomic);
             CheckAtomicMemoryOrderClause(&std::get<0>(atomicConstruct.t),
                 &std::get<2>(atomicConstruct.t));
+            CheckHintClause<const parser::OmpAtomicClauseList>(
+                &std::get<0>(atomicConstruct.t),
+                &std::get<2>(atomicConstruct.t));
           },
       },
       x.u);
index a474815..0ff0b90 100644 (file)
@@ -268,6 +268,7 @@ private:
   void EnterDirectiveNest(const int index) { directiveNest_[index]++; }
   void ExitDirectiveNest(const int index) { directiveNest_[index]--; }
   int GetDirectiveNest(const int index) { return directiveNest_[index]; }
+  template <typename D> void CheckHintClause(D *, D *);
 
   enum directiveNestType {
     SIMDNest,
diff --git a/flang/test/Semantics/OpenMP/omp-atomic-hint-clause.f90 b/flang/test/Semantics/OpenMP/omp-atomic-hint-clause.f90
new file mode 100644 (file)
index 0000000..048dd97
--- /dev/null
@@ -0,0 +1,105 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp 
+! Semantic checks on hint clauses, as they appear on atomic constructs
+
+program sample
+    use omp_lib
+    integer :: x, y
+    logical :: z
+    real :: k
+    integer :: p(1)
+    integer, parameter :: a = 1
+    !$omp atomic hint(1) write
+        y = 2
+    
+    !$omp atomic read hint(2)
+        y = x    
+     
+    !ERROR: Hint clause value is not a valid OpenMP synchronization value
+    !$omp atomic hint(3)
+        y = y + 10
+    
+    !$omp atomic update hint(5)
+        y = x
+    
+    !ERROR: Hint clause value is not a valid OpenMP synchronization value
+    !$omp atomic hint(7) capture
+        y = x
+        x = y
+    !$omp end atomic
+   
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !ERROR: Must be a constant value
+    !$omp atomic update hint(x)
+        y = y * 1
+    
+    !$omp atomic read hint(4)
+        y = x
+
+    !$omp atomic hint(8)
+        x = x * y
+
+    !$omp atomic write hint(omp_sync_hint_uncontended)
+        x = 10 * y
+
+    !$omp atomic hint(omp_lock_hint_speculative)
+        x = y + x
+    
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !ERROR: Must be a constant value
+    !$omp atomic hint(omp_sync_hint_uncontended + omp_sync_hint) read
+        y = x 
+
+    !$omp atomic hint(omp_sync_hint_nonspeculative)
+        y = y * 9
+
+    !$omp atomic hint(omp_sync_hint_none) read
+        y = x
+
+    !$omp atomic read hint(omp_sync_hint_uncontended + omp_lock_hint_speculative)
+        y = x
+
+    !$omp atomic hint(omp_lock_hint_nonspeculative + omp_lock_hint_uncontended)
+        x = x * y
+
+    !$omp atomic write hint(omp_lock_hint_contended + omp_sync_hint_speculative)
+        x = 10 * y
+
+    !$omp atomic hint(omp_lock_hint_contended + omp_sync_hint_nonspeculative)
+        x = y + x
+
+    !ERROR: Hint clause value is not a valid OpenMP synchronization value
+    !$omp atomic hint(omp_sync_hint_uncontended + omp_sync_hint_contended) read
+        y = x 
+
+    !ERROR: Hint clause value is not a valid OpenMP synchronization value
+    !$omp atomic hint(omp_sync_hint_nonspeculative + omp_lock_hint_speculative)
+        y = y * 9
+
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !$omp atomic hint(1.0) read
+        y = x
+
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !ERROR: Operands of + must be numeric; have LOGICAL(4) and INTEGER(4)
+    !$omp atomic hint(z + omp_sync_hint_nonspeculative) read
+        y = x
+
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !ERROR: Must be a constant value
+    !$omp atomic hint(k + omp_sync_hint_speculative) read
+        y = x
+
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !ERROR: Must be a constant value
+    !$omp atomic hint(p(1) + omp_sync_hint_uncontended) write
+        x = 10 * y
+
+    !$omp atomic write hint(a)
+        x = y + x
+
+    !$omp atomic hint(abs(-1)) write
+        x = 7
+
+    !$omp atomic hint(omp_sync_hint_uncontended + omp_sync_hint_uncontended + omp_sync_hint_speculative) write
+        x = 7
+end program
diff --git a/flang/test/Semantics/OpenMP/omp-critical-hint-clause.f90 b/flang/test/Semantics/OpenMP/omp-critical-hint-clause.f90
new file mode 100644 (file)
index 0000000..33088c6
--- /dev/null
@@ -0,0 +1,118 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp 
+! Semantic checks on hint clauses, as they appear on critical construct
+
+program sample
+    use omp_lib
+    integer :: y
+    logical :: z
+    real :: k
+    integer :: p(1)
+    
+    !$omp critical (name) hint(1)
+        y = 2
+    !$omp end critical (name)
+    
+    !$omp critical (name) hint(2)
+        y = 2
+    !$omp end critical (name)
+     
+    !ERROR: Hint clause value is not a valid OpenMP synchronization value
+    !$omp critical (name) hint(3)
+        y = 2
+    !$omp end critical (name)
+    
+    !$omp critical (name)  hint(5)
+        y = 2
+    !$omp end critical (name)
+    
+    !ERROR: Hint clause value is not a valid OpenMP synchronization value
+    !$omp critical (name) hint(7)
+        y = 2
+    !$omp end critical (name)
+   
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !ERROR: Must be a constant value
+    !$omp critical (name) hint(x)
+        y = 2
+    !$omp end critical (name)
+    
+    !$omp critical (name) hint(4)
+        y = 2
+    !$omp end critical (name)
+
+    !$omp critical (name) hint(8)
+        y = 2
+    !$omp end critical (name)
+
+    !$omp critical (name) hint(omp_sync_hint_uncontended)
+        y = 2
+    !$omp end critical (name)
+
+    !$omp critical (name) hint(omp_lock_hint_speculative)
+        y = 2
+    !$omp end critical (name)
+    
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !ERROR: Must be a constant value
+    !$omp critical (name) hint(omp_sync_hint_uncontended + omp_sync_hint) 
+        y = 2
+    !$omp end critical (name)
+
+    !$omp critical (name) hint(omp_sync_hint_nonspeculative)
+        y = 2
+    !$omp end critical (name)
+
+     !$omp critical (name) hint(omp_sync_hint_none)
+        y = 2
+    !$omp end critical (name)
+
+    !$omp critical (name) hint(omp_sync_hint_uncontended + omp_lock_hint_speculative)
+        y = 2
+    !$omp end critical (name)
+
+    !$omp critical (name) hint(omp_lock_hint_nonspeculative + omp_lock_hint_uncontended)
+        y = 2
+    !$omp end critical (name)
+
+    !$omp critical (name) hint(omp_lock_hint_contended + omp_sync_hint_speculative)
+        y = 2
+    !$omp end critical (name)
+
+    !$omp critical (name) hint(omp_lock_hint_contended + omp_sync_hint_nonspeculative)
+        y = 2
+    !$omp end critical (name)
+
+    !ERROR: Hint clause value is not a valid OpenMP synchronization value
+     !$omp critical (name) hint(omp_sync_hint_uncontended + omp_sync_hint_contended)
+        y = 2
+    !$omp end critical (name)
+
+    !ERROR: Hint clause value is not a valid OpenMP synchronization value
+    !$omp critical (name) hint(omp_sync_hint_nonspeculative + omp_lock_hint_speculative)
+        y = 2
+    !$omp end critical (name)
+
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !$omp critical (name) hint(1.0) 
+        y = 2
+    !$omp end critical (name)
+
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !ERROR: Operands of + must be numeric; have LOGICAL(4) and INTEGER(4)
+    !$omp critical (name) hint(z + omp_sync_hint_nonspeculative)
+        y = 2
+    !$omp end critical (name)
+
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !ERROR: Must be a constant value
+    !$omp critical (name) hint(k + omp_sync_hint_speculative)
+        y = 2
+    !$omp end critical (name)
+
+    !ERROR: Hint clause must have non-negative constant integer expression
+    !ERROR: Must be a constant value
+    !$omp critical (name) hint(p(1) + omp_sync_hint_uncontended)
+        y = 2
+    !$omp end critical (name)
+end program
+