[flang-commits] [flang] 80ea006 - [flang] [openmp] Add Fortran specific semantic check 4 for OpenMP Allocate directive.

Isaac Perry via flang-commits flang-commits at lists.llvm.org
Tue Jun 15 08:04:27 PDT 2021


Author: Isaac Perry
Date: 2021-06-15T16:04:04+01:00
New Revision: 80ea006ef9e08364854394b633b904fa85e38e4e

URL: https://github.com/llvm/llvm-project/commit/80ea006ef9e08364854394b633b904fa85e38e4e
DIFF: https://github.com/llvm/llvm-project/commit/80ea006ef9e08364854394b633b904fa85e38e4e.diff

LOG: [flang] [openmp] Add Fortran specific semantic check 4 for OpenMP Allocate directive.

This patch adds the 4th Fortran specific semantic check for the OpenMP
allocate directive: "If a list item has the SAVE attribute, is a common
block name, or is declared in the scope of a module, then only predefined
memory allocator parameters can be used in the allocator clause".

Code in this patch was based on code from https://reviews.llvm.org/D93549/new/.

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

Added: 
    flang/test/Semantics/omp-allocate08.f90

Modified: 
    flang/include/flang/Semantics/tools.h
    flang/lib/Semantics/check-omp-structure.cpp
    flang/lib/Semantics/check-omp-structure.h

Removed: 
    


################################################################################
diff  --git a/flang/include/flang/Semantics/tools.h b/flang/include/flang/Semantics/tools.h
index bb7d0b6009ddb..aa48c7456aeb6 100644
--- a/flang/include/flang/Semantics/tools.h
+++ b/flang/include/flang/Semantics/tools.h
@@ -140,6 +140,9 @@ inline bool IsAllocatable(const Symbol &symbol) {
 inline bool IsAllocatableOrPointer(const Symbol &symbol) {
   return IsPointer(symbol) || IsAllocatable(symbol);
 }
+inline bool IsSave(const Symbol &symbol) {
+  return symbol.attrs().test(Attr::SAVE);
+}
 inline bool IsNamedConstant(const Symbol &symbol) {
   return symbol.attrs().test(Attr::PARAMETER);
 }

diff  --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index cfce1d0915d7d..07ca47d5c43b9 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -237,6 +237,47 @@ void OmpStructureChecker::HasInvalidTeamsNesting(
   }
 }
 
+void OmpStructureChecker::CheckPredefinedAllocatorRestriction(
+    const parser::CharBlock &source, const parser::Name &name) {
+  if (const auto *symbol{name.symbol}) {
+    const auto *commonBlock{FindCommonBlockContaining(*symbol)};
+    const auto &scope{context_.FindScope(symbol->name())};
+    const Scope &containingScope{GetProgramUnitContaining(scope)};
+    if (!isPredefinedAllocator &&
+        (IsSave(*symbol) || commonBlock ||
+            containingScope.kind() == Scope::Kind::Module)) {
+      context_.Say(source,
+          "If list items within the ALLOCATE directive have the "
+          "SAVE attribute, are a common block name, or are "
+          "declared in the scope of a module, then only "
+          "predefined memory allocator parameters can be used "
+          "in the allocator clause"_err_en_US);
+    }
+  }
+}
+
+void OmpStructureChecker::CheckPredefinedAllocatorRestriction(
+    const parser::CharBlock &source,
+    const parser::OmpObjectList &ompObjectList) {
+  for (const auto &ompObject : ompObjectList.v) {
+    std::visit(
+        common::visitors{
+            [&](const parser::Designator &designator) {
+              if (const auto *dataRef{
+                      std::get_if<parser::DataRef>(&designator.u)}) {
+                if (const auto *name{std::get_if<parser::Name>(&dataRef->u)}) {
+                  CheckPredefinedAllocatorRestriction(source, *name);
+                }
+              }
+            },
+            [&](const parser::Name &name) {
+              CheckPredefinedAllocatorRestriction(source, name);
+            },
+        },
+        ompObject.u);
+  }
+}
+
 void OmpStructureChecker::Enter(const parser::OpenMPConstruct &x) {
   // Simd Construct with Ordered Construct Nesting check
   // We cannot use CurrentDirectiveIsNested() here because
@@ -700,6 +741,7 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclareSimdConstruct &) {
 }
 
 void OmpStructureChecker::Enter(const parser::OpenMPDeclarativeAllocate &x) {
+  isPredefinedAllocator = true;
   const auto &dir{std::get<parser::Verbatim>(x.t)};
   const auto &objectList{std::get<parser::OmpObjectList>(x.t)};
   PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_allocate);
@@ -707,9 +749,21 @@ void OmpStructureChecker::Enter(const parser::OpenMPDeclarativeAllocate &x) {
 }
 
 void OmpStructureChecker::Leave(const parser::OpenMPDeclarativeAllocate &x) {
+  const auto &dir{std::get<parser::Verbatim>(x.t)};
+  const auto &objectList{std::get<parser::OmpObjectList>(x.t)};
+  CheckPredefinedAllocatorRestriction(dir.source, objectList);
   dirContext_.pop_back();
 }
 
+void OmpStructureChecker::Enter(const parser::OmpClause::Allocator &x) {
+  CheckAllowed(llvm::omp::Clause::OMPC_allocator);
+  // Note: Predefined allocators are stored in ScalarExpr as numbers
+  //   whereas custom allocators are stored as strings, so if the ScalarExpr
+  //   actually has an int value, then it must be a predefined allocator
+  isPredefinedAllocator = GetIntValue(x.v).has_value();
+  RequiresPositiveParameter(llvm::omp::Clause::OMPC_allocator, x.v);
+}
+
 void OmpStructureChecker::Enter(const parser::OpenMPDeclareTargetConstruct &x) {
   const auto &dir{std::get<parser::Verbatim>(x.t)};
   PushContext(dir.source, llvm::omp::Directive::OMPD_declare_target);
@@ -724,6 +778,7 @@ void OmpStructureChecker::Leave(const parser::OpenMPDeclareTargetConstruct &) {
 }
 
 void OmpStructureChecker::Enter(const parser::OpenMPExecutableAllocate &x) {
+  isPredefinedAllocator = true;
   const auto &dir{std::get<parser::Verbatim>(x.t)};
   const auto &objectList{std::get<std::optional<parser::OmpObjectList>>(x.t)};
   PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_allocate);
@@ -731,7 +786,11 @@ void OmpStructureChecker::Enter(const parser::OpenMPExecutableAllocate &x) {
     CheckIsVarPartOfAnotherVar(dir.source, *objectList);
 }
 
-void OmpStructureChecker::Leave(const parser::OpenMPExecutableAllocate &) {
+void OmpStructureChecker::Leave(const parser::OpenMPExecutableAllocate &x) {
+  const auto &dir{std::get<parser::Verbatim>(x.t)};
+  const auto &objectList{std::get<std::optional<parser::OmpObjectList>>(x.t)};
+  if (objectList)
+    CheckPredefinedAllocatorRestriction(dir.source, *objectList);
   dirContext_.pop_back();
 }
 
@@ -1019,7 +1078,6 @@ CHECK_SIMPLE_CLAUSE(Novariants, OMPC_novariants)
 CHECK_SIMPLE_CLAUSE(Nocontext, OMPC_nocontext)
 CHECK_SIMPLE_CLAUSE(Filter, OMPC_filter)
 
-CHECK_REQ_SCALAR_INT_CLAUSE(Allocator, OMPC_allocator)
 CHECK_REQ_SCALAR_INT_CLAUSE(Grainsize, OMPC_grainsize)
 CHECK_REQ_SCALAR_INT_CLAUSE(NumTasks, OMPC_num_tasks)
 CHECK_REQ_SCALAR_INT_CLAUSE(NumTeams, OMPC_num_teams)

diff  --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index 9ca69eb14c33e..be9de114ef21e 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -236,6 +236,11 @@ class OmpStructureChecker
   void CheckMultipleAppearanceAcrossContext(
       const parser::OmpObjectList &ompObjectList);
   const parser::OmpObjectList *GetOmpObjectList(const parser::OmpClause &);
+  void CheckPredefinedAllocatorRestriction(const parser::CharBlock &source,
+      const parser::OmpObjectList &ompObjectList);
+  void CheckPredefinedAllocatorRestriction(
+      const parser::CharBlock &source, const parser::Name &name);
+  bool isPredefinedAllocator{false};
 };
 } // namespace Fortran::semantics
 #endif // FORTRAN_SEMANTICS_CHECK_OMP_STRUCTURE_H_

diff  --git a/flang/test/Semantics/omp-allocate08.f90 b/flang/test/Semantics/omp-allocate08.f90
new file mode 100644
index 0000000000000..42caef9505e2f
--- /dev/null
+++ b/flang/test/Semantics/omp-allocate08.f90
@@ -0,0 +1,42 @@
+! RUN: %S/test_errors.sh %s %t %flang_fc1 -fopenmp
+! OpenMP Version 5.0
+! 2.11.3 allocate Directive
+! If list items within the ALLOCATE directive have the SAVE attribute, are a common block name, or are declared in the scope of a
+! module, then only predefined memory allocator parameters can be used in the allocator clause
+
+module AllocateModule
+  INTEGER :: z
+end module
+
+subroutine allocate()
+use omp_lib
+use AllocateModule
+  integer, SAVE :: x
+  integer :: w
+  COMMON /CommonName/ y
+
+  integer(kind=omp_allocator_handle_kind) :: custom_allocator
+  integer(kind=omp_memspace_handle_kind) :: memspace
+  type(omp_alloctrait), dimension(1) :: trait
+  memspace = omp_default_mem_space
+  trait(1)%key = fallback
+  trait(1)%value = default_mem_fb
+  custom_allocator = omp_init_allocator(memspace, 1, trait)
+
+  !$omp allocate(x) allocator(omp_default_mem_alloc)
+  !$omp allocate(y) allocator(omp_default_mem_alloc)
+  !$omp allocate(z) allocator(omp_default_mem_alloc)
+
+  !$omp allocate(x)
+  !$omp allocate(y)
+  !$omp allocate(z)
+
+  !$omp allocate(w) allocator(custom_allocator)
+
+  !ERROR: If list items within the ALLOCATE directive have the SAVE attribute, are a common block name, or are declared in the scope of a module, then only predefined memory allocator parameters can be used in the allocator clause
+  !$omp allocate(x) allocator(custom_allocator)
+  !ERROR: If list items within the ALLOCATE directive have the SAVE attribute, are a common block name, or are declared in the scope of a module, then only predefined memory allocator parameters can be used in the allocator clause
+  !$omp allocate(y) allocator(custom_allocator)
+  !ERROR: If list items within the ALLOCATE directive have the SAVE attribute, are a common block name, or are declared in the scope of a module, then only predefined memory allocator parameters can be used in the allocator clause
+  !$omp allocate(z) allocator(custom_allocator)
+end subroutine allocate


        


More information about the flang-commits mailing list