[flang-commits] [flang] 7f0d54b - [flang][openmp] Allocators construct semantic checks
Ethan Luis McDonough via flang-commits
flang-commits at lists.llvm.org
Wed Aug 2 10:59:14 PDT 2023
Author: Ethan Luis McDonough
Date: 2023-08-02T12:59:06-05:00
New Revision: 7f0d54b4299547856073632c460bed53e63f40c4
URL: https://github.com/llvm/llvm-project/commit/7f0d54b4299547856073632c460bed53e63f40c4
DIFF: https://github.com/llvm/llvm-project/commit/7f0d54b4299547856073632c460bed53e63f40c4.diff
LOG: [flang][openmp] Allocators construct semantic checks
This patch applies the semantic checks for executable allocation directives to the new allocators construct. It also introduces a new check that ensures all items in the list appear in the corresponding Fortran allocate statement.
Reviewed By: kiranchandramohan
Differential Revision: https://reviews.llvm.org/D150428
Added:
flang/test/Semantics/OpenMP/allocate-clause01.f90
flang/test/Semantics/OpenMP/allocators01.f90
flang/test/Semantics/OpenMP/allocators02.f90
flang/test/Semantics/OpenMP/allocators03.f90
flang/test/Semantics/OpenMP/allocators04.f90
flang/test/Semantics/OpenMP/allocators05.f90
flang/test/Semantics/OpenMP/allocators06.f90
Modified:
flang/include/flang/Parser/parse-tree.h
flang/lib/Semantics/check-omp-structure.cpp
flang/lib/Semantics/check-omp-structure.h
flang/lib/Semantics/resolve-directives.cpp
llvm/include/llvm/Frontend/OpenMP/OMP.td
Removed:
################################################################################
diff --git a/flang/include/flang/Parser/parse-tree.h b/flang/include/flang/Parser/parse-tree.h
index 73956338a31fef..5ee7ecc61a4e2e 100644
--- a/flang/include/flang/Parser/parse-tree.h
+++ b/flang/include/flang/Parser/parse-tree.h
@@ -3544,17 +3544,17 @@ struct OmpInReductionClause {
// variable-name-list)
// allocate-modifier -> allocator | align
struct OmpAllocateClause {
- TUPLE_CLASS_BOILERPLATE(OmpAllocateClause);
struct AllocateModifier {
- UNION_CLASS_BOILERPLATE(AllocateModifier);
WRAPPER_CLASS(Allocator, ScalarIntExpr);
WRAPPER_CLASS(Align, ScalarIntExpr);
struct ComplexModifier {
TUPLE_CLASS_BOILERPLATE(ComplexModifier);
std::tuple<Allocator, Align> t;
};
+ UNION_CLASS_BOILERPLATE(AllocateModifier);
std::variant<Allocator, ComplexModifier, Align> u;
};
+ TUPLE_CLASS_BOILERPLATE(OmpAllocateClause);
std::tuple<std::optional<AllocateModifier>, OmpObjectList> t;
};
diff --git a/flang/lib/Semantics/check-omp-structure.cpp b/flang/lib/Semantics/check-omp-structure.cpp
index b4b838a45f7eae..b26f3e23f9ec73 100644
--- a/flang/lib/Semantics/check-omp-structure.cpp
+++ b/flang/lib/Semantics/check-omp-structure.cpp
@@ -311,11 +311,12 @@ void OmpStructureChecker::CheckPredefinedAllocatorRestriction(
(IsSaved(*symbol) || commonBlock ||
containingScope.kind() == Scope::Kind::Module)) {
context_.Say(source,
- "If list items within the ALLOCATE directive have the "
+ "If list items within the %s 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);
+ "in the allocator clause"_err_en_US,
+ ContextDirectiveAsFortran());
}
}
}
@@ -1140,6 +1141,39 @@ void OmpStructureChecker::Enter(const parser::OmpClause::Allocator &x) {
RequiresPositiveParameter(llvm::omp::Clause::OMPC_allocator, x.v);
}
+void OmpStructureChecker::Enter(const parser::OmpClause::Allocate &x) {
+ CheckAllowed(llvm::omp::Clause::OMPC_allocate);
+ if (const auto &modifier{
+ std::get<std::optional<parser::OmpAllocateClause::AllocateModifier>>(
+ x.v.t)}) {
+ common::visit(
+ common::visitors{
+ [&](const parser::OmpAllocateClause::AllocateModifier::Allocator
+ &y) {
+ RequiresPositiveParameter(llvm::omp::Clause::OMPC_allocate, y.v);
+ isPredefinedAllocator = GetIntValue(y.v).has_value();
+ },
+ [&](const parser::OmpAllocateClause::AllocateModifier::
+ ComplexModifier &y) {
+ const auto &alloc = std::get<
+ parser::OmpAllocateClause::AllocateModifier::Allocator>(y.t);
+ const auto &align =
+ std::get<parser::OmpAllocateClause::AllocateModifier::Align>(
+ y.t);
+ RequiresPositiveParameter(
+ llvm::omp::Clause::OMPC_allocate, alloc.v);
+ RequiresPositiveParameter(
+ llvm::omp::Clause::OMPC_allocate, align.v);
+ isPredefinedAllocator = GetIntValue(alloc.v).has_value();
+ },
+ [&](const parser::OmpAllocateClause::AllocateModifier::Align &y) {
+ RequiresPositiveParameter(llvm::omp::Clause::OMPC_allocate, y.v);
+ },
+ },
+ modifier->u);
+ }
+}
+
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);
@@ -1218,6 +1252,33 @@ void OmpStructureChecker::Leave(const parser::OpenMPExecutableAllocate &x) {
dirContext_.pop_back();
}
+void OmpStructureChecker::Enter(const parser::OpenMPAllocatorsConstruct &x) {
+ isPredefinedAllocator = true;
+ const auto &dir{std::get<parser::Verbatim>(x.t)};
+ PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_allocators);
+ const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
+ for (const auto &clause : clauseList.v) {
+ if (const auto *allocClause{
+ parser::Unwrap<parser::OmpClause::Allocate>(clause)}) {
+ CheckIsVarPartOfAnotherVar(
+ dir.source, std::get<parser::OmpObjectList>(allocClause->v.t));
+ }
+ }
+}
+
+void OmpStructureChecker::Leave(const parser::OpenMPAllocatorsConstruct &x) {
+ const auto &dir{std::get<parser::Verbatim>(x.t)};
+ const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
+ for (const auto &clause : clauseList.v) {
+ if (const auto *allocClause{
+ std::get_if<parser::OmpClause::Allocate>(&clause.u)}) {
+ CheckPredefinedAllocatorRestriction(
+ dir.source, std::get<parser::OmpObjectList>(allocClause->v.t));
+ }
+ }
+ dirContext_.pop_back();
+}
+
void OmpStructureChecker::CheckBarrierNesting(
const parser::OpenMPSimpleStandaloneConstruct &x) {
// A barrier region may not be `closely nested` inside a worksharing, loop,
@@ -1893,7 +1954,6 @@ CHECK_SIMPLE_CLAUSE(AcqRel, OMPC_acq_rel)
CHECK_SIMPLE_CLAUSE(Acquire, OMPC_acquire)
CHECK_SIMPLE_CLAUSE(AtomicDefaultMemOrder, OMPC_atomic_default_mem_order)
CHECK_SIMPLE_CLAUSE(Affinity, OMPC_affinity)
-CHECK_SIMPLE_CLAUSE(Allocate, OMPC_allocate)
CHECK_SIMPLE_CLAUSE(Capture, OMPC_capture)
CHECK_SIMPLE_CLAUSE(Default, OMPC_default)
CHECK_SIMPLE_CLAUSE(Depobj, OMPC_depobj)
@@ -2189,6 +2249,7 @@ bool OmpStructureChecker::IsDataRefTypeParamInquiry(
void OmpStructureChecker::CheckIsVarPartOfAnotherVar(
const parser::CharBlock &source, const parser::OmpObjectList &objList) {
OmpDirectiveSet nonPartialVarSet{llvm::omp::Directive::OMPD_allocate,
+ llvm::omp::Directive::OMPD_allocators,
llvm::omp::Directive::OMPD_threadprivate,
llvm::omp::Directive::OMPD_declare_target};
for (const auto &ompObject : objList.v) {
diff --git a/flang/lib/Semantics/check-omp-structure.h b/flang/lib/Semantics/check-omp-structure.h
index b99a19013c8c12..195b0c2326f548 100644
--- a/flang/lib/Semantics/check-omp-structure.h
+++ b/flang/lib/Semantics/check-omp-structure.h
@@ -152,6 +152,8 @@ class OmpStructureChecker
void Leave(const parser::OpenMPDeclareTargetConstruct &);
void Enter(const parser::OpenMPExecutableAllocate &);
void Leave(const parser::OpenMPExecutableAllocate &);
+ void Enter(const parser::OpenMPAllocatorsConstruct &);
+ void Leave(const parser::OpenMPAllocatorsConstruct &);
void Enter(const parser::OpenMPRequiresConstruct &);
void Leave(const parser::OpenMPRequiresConstruct &);
void Enter(const parser::OpenMPThreadprivate &);
diff --git a/flang/lib/Semantics/resolve-directives.cpp b/flang/lib/Semantics/resolve-directives.cpp
index 401ffee6badc92..747f1e414eb21f 100644
--- a/flang/lib/Semantics/resolve-directives.cpp
+++ b/flang/lib/Semantics/resolve-directives.cpp
@@ -364,6 +364,9 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
bool Pre(const parser::OpenMPExecutableAllocate &);
void Post(const parser::OpenMPExecutableAllocate &);
+ bool Pre(const parser::OpenMPAllocatorsConstruct &);
+ void Post(const parser::OpenMPAllocatorsConstruct &);
+
// 2.15.3 Data-Sharing Attribute Clauses
void Post(const parser::OmpDefaultClause &);
bool Pre(const parser::OmpClause::Shared &x) {
@@ -606,6 +609,11 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
sourceLabels_.clear();
targetLabels_.clear();
};
+ void CheckAllNamesInAllocateStmt(const parser::CharBlock &source,
+ const parser::OmpObjectList &ompObjectList,
+ const parser::AllocateStmt &allocate);
+ void CheckNameInAllocateStmt(const parser::CharBlock &source,
+ const parser::Name &ompObject, const parser::AllocateStmt &allocate);
bool HasSymbolInEnclosingScope(const Symbol &, Scope &);
std::int64_t ordCollapseLevel{0};
@@ -1548,6 +1556,19 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPExecutableAllocate &x) {
return true;
}
+bool OmpAttributeVisitor::Pre(const parser::OpenMPAllocatorsConstruct &x) {
+ PushContext(x.source, llvm::omp::Directive::OMPD_allocators);
+ const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
+ for (const auto &clause : clauseList.v) {
+ if (const auto *allocClause{
+ std::get_if<parser::OmpClause::Allocate>(&clause.u)}) {
+ ResolveOmpObjectList(std::get<parser::OmpObjectList>(allocClause->v.t),
+ Symbol::Flag::OmpExecutableAllocateDirective);
+ }
+ }
+ return true;
+}
+
void OmpAttributeVisitor::Post(const parser::OmpDefaultClause &x) {
if (!dirContext_.empty()) {
switch (x.v) {
@@ -1600,6 +1621,36 @@ void OmpAttributeVisitor::Post(const parser::OpenMPExecutableAllocate &x) {
PopContext();
}
+void OmpAttributeVisitor::Post(const parser::OpenMPAllocatorsConstruct &x) {
+ const auto &dir{std::get<parser::Verbatim>(x.t)};
+ const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
+ for (const auto &clause : clauseList.v) {
+ if (const auto *alloc{
+ std::get_if<parser::OmpClause::Allocate>(&clause.u)}) {
+ CheckAllNamesInAllocateStmt(dir.source,
+ std::get<parser::OmpObjectList>(alloc->v.t),
+ std::get<parser::Statement<parser::AllocateStmt>>(x.t).statement);
+
+ const auto &allocMod{
+ std::get<std::optional<parser::OmpAllocateClause::AllocateModifier>>(
+ alloc->v.t)};
+ // TODO: As with allocate directive, exclude the case when a requires
+ // directive with the dynamic_allocators clause is present in
+ // the same compilation unit (OMP5.0 2.11.3).
+ if (IsNestedInDirective(llvm::omp::Directive::OMPD_target) &&
+ (!allocMod.has_value() ||
+ std::holds_alternative<
+ parser::OmpAllocateClause::AllocateModifier::Align>(
+ allocMod->u))) {
+ context_.Say(x.source,
+ "ALLOCATORS directives that appear in a TARGET region "
+ "must specify an allocator"_err_en_US);
+ }
+ }
+ }
+ PopContext();
+}
+
// For OpenMP constructs, check all the data-refs within the constructs
// and adjust the symbol for each Name if necessary
void OmpAttributeVisitor::Post(const parser::Name &name) {
@@ -1772,7 +1823,11 @@ void OmpAttributeVisitor::ResolveOmpObject(
ResolveOmpObjectScope(name) == nullptr) {
context_.Say(designator.source, // 2.15.3
"List items must be declared in the same scoping unit "
- "in which the ALLOCATE directive appears"_err_en_US);
+ "in which the %s directive appears"_err_en_US,
+ parser::ToUpperCaseLetters(
+ llvm::omp::getOpenMPDirectiveName(
+ GetContext().directive)
+ .str()));
}
}
} else {
@@ -2021,4 +2076,39 @@ bool OmpAttributeVisitor::HasSymbolInEnclosingScope(
return llvm::is_contained(symbols, symbol);
}
+// Goes through the names in an OmpObjectList and checks if each name appears
+// in the given allocate statement
+void OmpAttributeVisitor::CheckAllNamesInAllocateStmt(
+ const parser::CharBlock &source, const parser::OmpObjectList &ompObjectList,
+ const parser::AllocateStmt &allocate) {
+ for (const auto &obj : ompObjectList.v) {
+ if (const auto *d{std::get_if<parser::Designator>(&obj.u)}) {
+ if (const auto *ref{std::get_if<parser::DataRef>(&d->u)}) {
+ if (const auto *n{std::get_if<parser::Name>(&ref->u)}) {
+ CheckNameInAllocateStmt(source, *n, allocate);
+ }
+ }
+ }
+ }
+}
+
+void OmpAttributeVisitor::CheckNameInAllocateStmt(
+ const parser::CharBlock &source, const parser::Name &name,
+ const parser::AllocateStmt &allocate) {
+ for (const auto &allocation :
+ std::get<std::list<parser::Allocation>>(allocate.t)) {
+ const auto &allocObj = std::get<parser::AllocateObject>(allocation.t);
+ if (const auto *n{std::get_if<parser::Name>(&allocObj.u)}) {
+ if (n->source == name.source) {
+ return;
+ }
+ }
+ }
+ context_.Say(source,
+ "Object '%s' in %s directive not "
+ "found in corresponding ALLOCATE statement"_err_en_US,
+ name.ToString(),
+ parser::ToUpperCaseLetters(
+ llvm::omp::getOpenMPDirectiveName(GetContext().directive).str()));
+}
} // namespace Fortran::semantics
diff --git a/flang/test/Semantics/OpenMP/allocate-clause01.f90 b/flang/test/Semantics/OpenMP/allocate-clause01.f90
new file mode 100644
index 00000000000000..7e2f64397f738d
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/allocate-clause01.f90
@@ -0,0 +1,22 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+! OpenMP Version 5.2
+! The allocate clause's allocator modifier must be of type allocator_handle
+! and the align modifier must be constant, positive integer expression
+
+subroutine allocate()
+ use omp_lib
+
+ integer, allocatable :: a, b, c
+
+ !ERROR: The parameter of the ALLOCATE clause must be a positive integer expression
+ !$omp allocators allocate(-1: a)
+ allocate(a)
+
+ !ERROR: The parameter of the ALLOCATE clause must be a positive integer expression
+ !$omp allocators allocate(allocator(-2), align(-3): b)
+ allocate(b)
+
+ !ERROR: The parameter of the ALLOCATE clause must be a positive integer expression
+ !$omp allocators allocate(align(-4): c)
+ allocate(c)
+end subroutine
diff --git a/flang/test/Semantics/OpenMP/allocators01.f90 b/flang/test/Semantics/OpenMP/allocators01.f90
new file mode 100644
index 00000000000000..d674438b2ab207
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/allocators01.f90
@@ -0,0 +1,21 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+! OpenMP Version 5.2
+! 6.7 allocators construct
+! A list item that appears in an allocate clause must appear as
+! one of the variables that is allocated by the allocate-stmt in
+! the associated allocator structured block.
+
+subroutine allocate()
+use omp_lib
+
+ integer, allocatable :: arr1(:), arr2(:, :), arr3(:), arr4(:, :)
+
+ !$omp allocators allocate(arr3)
+ allocate(arr3(3), arr4(4, 4))
+ !$omp end allocators
+
+ !ERROR: Object 'arr1' in ALLOCATORS directive not found in corresponding ALLOCATE statement
+ !$omp allocators allocate(omp_default_mem_alloc: arr1, arr2)
+ allocate(arr2(2, 2))
+
+end subroutine allocate
diff --git a/flang/test/Semantics/OpenMP/allocators02.f90 b/flang/test/Semantics/OpenMP/allocators02.f90
new file mode 100644
index 00000000000000..32e7bc18ad99b0
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/allocators02.f90
@@ -0,0 +1,20 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+! OpenMP Version 5.2
+! 6.7 allocators construct
+! A variable that is part of another variable (as an array or
+! structure element) cannot appear in an allocatprs construct.
+
+subroutine allocate()
+use omp_lib
+
+ type my_type
+ integer, allocatable :: array(:)
+ end type my_type
+
+ type(my_type) :: my_var
+
+ !ERROR: A variable that is part of another variable (as an array or structure element) cannot appear on the ALLOCATORS directive
+ !$omp allocators allocate(my_var%array)
+ allocate(my_var%array(10))
+
+end subroutine allocate
diff --git a/flang/test/Semantics/OpenMP/allocators03.f90 b/flang/test/Semantics/OpenMP/allocators03.f90
new file mode 100644
index 00000000000000..533434c2ace0f1
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/allocators03.f90
@@ -0,0 +1,15 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+! OpenMP Version 5.2
+! 6.7 allocators construct
+! Only the allocate clause is allowed on the allocators construct
+
+subroutine allocate()
+use omp_lib
+
+ integer, allocatable :: arr1(:), arr2(:)
+
+ !ERROR: PRIVATE clause is not allowed on the ALLOCATORS directive
+ !$omp allocators allocate(arr1) private(arr2)
+ allocate(arr1(23), arr2(2))
+
+end subroutine allocate
diff --git a/flang/test/Semantics/OpenMP/allocators04.f90 b/flang/test/Semantics/OpenMP/allocators04.f90
new file mode 100644
index 00000000000000..d4467a2052a7dc
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/allocators04.f90
@@ -0,0 +1,29 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+! OpenMP Version 5.2
+! Inherited from 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
+! SAVE and common block names can't be declared as allocatable, only module scope variables are tested
+
+module AllocateModule
+ integer, allocatable :: a, b
+end module
+
+subroutine allocate()
+ use omp_lib
+ use AllocateModule
+
+ integer(kind=omp_allocator_handle_kind) :: custom_allocator
+ type(omp_alloctrait) :: trait(1)
+
+ trait(1)%key = fallback
+ trait(1)%value = default_mem_fb
+ custom_allocator = omp_init_allocator(omp_default_mem_space, 1, trait)
+
+ !$omp allocators allocate(omp_default_mem_alloc: a)
+ allocate(a)
+
+ !ERROR: If list items within the ALLOCATORS 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 allocators allocate(custom_allocator: b)
+ allocate(b)
+end subroutine
diff --git a/flang/test/Semantics/OpenMP/allocators05.f90 b/flang/test/Semantics/OpenMP/allocators05.f90
new file mode 100644
index 00000000000000..684eef69504951
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/allocators05.f90
@@ -0,0 +1,24 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+! OpenMP Version 5.2
+! Inherited from 2.11.3 allocate directive
+! allocate directives that appear in a target region must specify an
+! allocator clause unless a requires directive with the dynamic_allocators
+! clause is present in the same compilation unit.
+
+subroutine allocate()
+ use omp_lib
+
+ integer :: i
+ integer, allocatable :: a(:), b(:)
+ integer, parameter :: LEN = 2
+
+ !$omp target private(a, b)
+ !ERROR: List items must be declared in the same scoping unit in which the ALLOCATORS directive appears
+ !$omp allocators allocate(omp_default_mem_alloc: a)
+ allocate(a(LEN))
+ !ERROR: ALLOCATORS directives that appear in a TARGET region must specify an allocator
+ !ERROR: List items must be declared in the same scoping unit in which the ALLOCATORS directive appears
+ !$omp allocators allocate(b)
+ allocate(b(LEN))
+ !$omp end target
+end subroutine
diff --git a/flang/test/Semantics/OpenMP/allocators06.f90 b/flang/test/Semantics/OpenMP/allocators06.f90
new file mode 100644
index 00000000000000..17e168d4cfe0cb
--- /dev/null
+++ b/flang/test/Semantics/OpenMP/allocators06.f90
@@ -0,0 +1,16 @@
+! RUN: %python %S/../test_errors.py %s %flang_fc1 -fopenmp
+! OpenMP Version 5.2
+! Inherited from 2.11.3 allocate directive
+! The allocate directive must appear in the same scope as the declarations of
+! each of its list items and must follow all such declarations.
+
+subroutine allocate()
+ use omp_lib
+ integer, allocatable :: a
+contains
+ subroutine test()
+ !ERROR: List items must be declared in the same scoping unit in which the ALLOCATORS directive appears
+ !$omp allocators allocate(omp_default_mem_alloc: a)
+ allocate(a)
+ end subroutine
+end subroutine
diff --git a/llvm/include/llvm/Frontend/OpenMP/OMP.td b/llvm/include/llvm/Frontend/OpenMP/OMP.td
index 68f7eca4daffbf..f7a980476bac0c 100644
--- a/llvm/include/llvm/Frontend/OpenMP/OMP.td
+++ b/llvm/include/llvm/Frontend/OpenMP/OMP.td
@@ -1727,6 +1727,11 @@ def OMP_Allocate : Directive<"allocate"> {
VersionedClause<OMPC_Align, 51>
];
}
+def OMP_Allocators : Directive<"allocators"> {
+ let allowedClauses = [
+ VersionedClause<OMPC_Allocate>
+ ];
+}
def OMP_DeclareVariant : Directive<"declare variant"> {
let allowedClauses = [
VersionedClause<OMPC_Match>
More information about the flang-commits
mailing list