Skip to content

Commit 6f1f00c

Browse files
authored
[flang][OpenMP] Move semantic checks for ALLOCATE to check-omp-structure (#161249)
The checks were previously in resolve-directives, which is mostly intended for determining symbol properties, not performing semantic checks.
1 parent 5e4eb33 commit 6f1f00c

File tree

5 files changed

+123
-123
lines changed

5 files changed

+123
-123
lines changed

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

Lines changed: 115 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,6 +351,17 @@ bool OmpStructureChecker::IsCloselyNestedRegion(const OmpDirectiveSet &set) {
351351
return false;
352352
}
353353

354+
bool OmpStructureChecker::IsNestedInDirective(llvm::omp::Directive directive) {
355+
if (dirContext_.size() >= 1) {
356+
for (size_t i = dirContext_.size() - 1; i > 0; --i) {
357+
if (dirContext_[i - 1].directive == directive) {
358+
return true;
359+
}
360+
}
361+
}
362+
return false;
363+
}
364+
354365
void OmpStructureChecker::CheckVariableListItem(
355366
const SymbolSourceMap &symbols) {
356367
for (auto &[symbol, source] : symbols) {
@@ -1880,12 +1891,89 @@ void OmpStructureChecker::Enter(const parser::OmpClause::At &x) {
18801891
}
18811892
}
18821893

1894+
// Goes through the names in an OmpObjectList and checks if each name appears
1895+
// in the given allocate statement
1896+
void OmpStructureChecker::CheckAllNamesInAllocateStmt(
1897+
const parser::CharBlock &source, const parser::OmpObjectList &ompObjectList,
1898+
const parser::AllocateStmt &allocate) {
1899+
for (const auto &obj : ompObjectList.v) {
1900+
if (const auto *d{std::get_if<parser::Designator>(&obj.u)}) {
1901+
if (const auto *ref{std::get_if<parser::DataRef>(&d->u)}) {
1902+
if (const auto *n{std::get_if<parser::Name>(&ref->u)}) {
1903+
CheckNameInAllocateStmt(source, *n, allocate);
1904+
}
1905+
}
1906+
}
1907+
}
1908+
}
1909+
1910+
void OmpStructureChecker::CheckNameInAllocateStmt(
1911+
const parser::CharBlock &source, const parser::Name &name,
1912+
const parser::AllocateStmt &allocate) {
1913+
for (const auto &allocation :
1914+
std::get<std::list<parser::Allocation>>(allocate.t)) {
1915+
const auto &allocObj = std::get<parser::AllocateObject>(allocation.t);
1916+
if (const auto *n{std::get_if<parser::Name>(&allocObj.u)}) {
1917+
if (n->source == name.source) {
1918+
return;
1919+
}
1920+
}
1921+
}
1922+
unsigned version{context_.langOptions().OpenMPVersion};
1923+
context_.Say(source,
1924+
"Object '%s' in %s directive not "
1925+
"found in corresponding ALLOCATE statement"_err_en_US,
1926+
name.ToString(),
1927+
parser::ToUpperCaseLetters(
1928+
llvm::omp::getOpenMPDirectiveName(GetContext().directive, version)
1929+
.str()));
1930+
}
1931+
18831932
void OmpStructureChecker::Enter(const parser::OpenMPExecutableAllocate &x) {
1884-
isPredefinedAllocator = true;
18851933
const auto &dir{std::get<parser::Verbatim>(x.t)};
1886-
const auto &objectList{std::get<std::optional<parser::OmpObjectList>>(x.t)};
18871934
PushContextAndClauseSets(dir.source, llvm::omp::Directive::OMPD_allocate);
1935+
1936+
unsigned version{context_.langOptions().OpenMPVersion};
1937+
if (version >= 52) {
1938+
context_.Warn(common::UsageWarning::OpenMPUsage, x.source,
1939+
"The executable form of the OpenMP ALLOCATE directive has been deprecated, please use ALLOCATORS instead"_warn_en_US);
1940+
}
1941+
1942+
bool hasAllocator = false;
1943+
// TODO: Investigate whether searching the clause list can be done with
1944+
// parser::Unwrap instead of the following loop
18881945
const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
1946+
for (const auto &clause : clauseList.v) {
1947+
if (std::get_if<parser::OmpClause::Allocator>(&clause.u)) {
1948+
hasAllocator = true;
1949+
}
1950+
}
1951+
1952+
if (IsNestedInDirective(llvm::omp::Directive::OMPD_target) && !hasAllocator) {
1953+
// TODO: expand this check to exclude the case when a requires
1954+
// directive with the dynamic_allocators clause is present
1955+
// in the same compilation unit (OMP5.0 2.11.3).
1956+
context_.Say(x.source,
1957+
"ALLOCATE directives that appear in a TARGET region must specify an allocator clause"_err_en_US);
1958+
}
1959+
1960+
const auto &allocateStmt =
1961+
std::get<parser::Statement<parser::AllocateStmt>>(x.t).statement;
1962+
if (const auto &list{std::get<std::optional<parser::OmpObjectList>>(x.t)}) {
1963+
CheckAllNamesInAllocateStmt(
1964+
std::get<parser::Verbatim>(x.t).source, *list, allocateStmt);
1965+
}
1966+
if (const auto &subDirs{
1967+
std::get<std::optional<std::list<parser::OpenMPDeclarativeAllocate>>>(
1968+
x.t)}) {
1969+
for (const auto &dalloc : *subDirs) {
1970+
CheckAllNamesInAllocateStmt(std::get<parser::Verbatim>(dalloc.t).source,
1971+
std::get<parser::OmpObjectList>(dalloc.t), allocateStmt);
1972+
}
1973+
}
1974+
1975+
isPredefinedAllocator = true;
1976+
const auto &objectList{std::get<std::optional<parser::OmpObjectList>>(x.t)};
18891977
for (const auto &clause : clauseList.v) {
18901978
CheckAlignValue(clause);
18911979
}
@@ -1920,7 +2008,31 @@ void OmpStructureChecker::Enter(const parser::OpenMPAllocatorsConstruct &x) {
19202008
const auto *allocate{
19212009
action ? parser::Unwrap<parser::AllocateStmt>(action.stmt) : nullptr};
19222010

1923-
if (!allocate) {
2011+
if (allocate) {
2012+
for (const auto &clause : dirSpec.Clauses().v) {
2013+
if (auto *alloc{std::get_if<parser::OmpClause::Allocate>(&clause.u)}) {
2014+
CheckAllNamesInAllocateStmt(
2015+
x.source, std::get<parser::OmpObjectList>(alloc->v.t), *allocate);
2016+
2017+
using OmpAllocatorSimpleModifier = parser::OmpAllocatorSimpleModifier;
2018+
using OmpAllocatorComplexModifier = parser::OmpAllocatorComplexModifier;
2019+
2020+
auto &modifiers{OmpGetModifiers(alloc->v)};
2021+
bool hasAllocator{
2022+
OmpGetUniqueModifier<OmpAllocatorSimpleModifier>(modifiers) ||
2023+
OmpGetUniqueModifier<OmpAllocatorComplexModifier>(modifiers)};
2024+
2025+
// TODO: As with allocate directive, exclude the case when a requires
2026+
// directive with the dynamic_allocators clause is present in
2027+
// the same compilation unit (OMP5.0 2.11.3).
2028+
if (IsNestedInDirective(llvm::omp::Directive::OMPD_target) &&
2029+
!hasAllocator) {
2030+
context_.Say(x.source,
2031+
"ALLOCATORS directives that appear in a TARGET region must specify an allocator"_err_en_US);
2032+
}
2033+
}
2034+
}
2035+
} else {
19242036
const parser::CharBlock &source = action ? action.source : x.source;
19252037
context_.Say(source,
19262038
"The body of the ALLOCATORS construct should be an ALLOCATE statement"_err_en_US);

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ class OmpStructureChecker
177177
bool HasInvalidWorksharingNesting(
178178
const parser::CharBlock &, const OmpDirectiveSet &);
179179
bool IsCloselyNestedRegion(const OmpDirectiveSet &set);
180+
bool IsNestedInDirective(llvm::omp::Directive directive);
180181
void HasInvalidTeamsNesting(
181182
const llvm::omp::Directive &dir, const parser::CharBlock &source);
182183
void HasInvalidDistributeNesting(const parser::OpenMPLoopConstruct &x);
@@ -309,6 +310,11 @@ class OmpStructureChecker
309310
const std::optional<parser::OmpClauseList> &maybeClauses);
310311
void CheckCancellationNest(
311312
const parser::CharBlock &source, llvm::omp::Directive type);
313+
void CheckAllNamesInAllocateStmt(const parser::CharBlock &source,
314+
const parser::OmpObjectList &ompObjectList,
315+
const parser::AllocateStmt &allocate);
316+
void CheckNameInAllocateStmt(const parser::CharBlock &source,
317+
const parser::Name &ompObject, const parser::AllocateStmt &allocate);
312318
std::int64_t GetOrdCollapseLevel(const parser::OpenMPLoopConstruct &x);
313319
void CheckReductionObjects(
314320
const parser::OmpObjectList &objects, llvm::omp::Clause clauseId);

flang/lib/Semantics/resolve-directives.cpp

Lines changed: 0 additions & 118 deletions
Original file line numberDiff line numberDiff line change
@@ -1011,11 +1011,6 @@ class OmpAttributeVisitor : DirectiveAttributeVisitor<llvm::omp::Directive> {
10111011
sourceLabels_.clear();
10121012
targetLabels_.clear();
10131013
};
1014-
void CheckAllNamesInAllocateStmt(const parser::CharBlock &source,
1015-
const parser::OmpObjectList &ompObjectList,
1016-
const parser::AllocateStmt &allocate);
1017-
void CheckNameInAllocateStmt(const parser::CharBlock &source,
1018-
const parser::Name &ompObject, const parser::AllocateStmt &allocate);
10191014

10201015
std::int64_t ordCollapseLevel{0};
10211016

@@ -2550,8 +2545,6 @@ bool OmpAttributeVisitor::Pre(const parser::OpenMPDispatchConstruct &x) {
25502545
}
25512546

25522547
bool OmpAttributeVisitor::Pre(const parser::OpenMPExecutableAllocate &x) {
2553-
IssueNonConformanceWarning(llvm::omp::Directive::OMPD_allocate, x.source, 52);
2554-
25552548
PushContext(x.source, llvm::omp::Directive::OMPD_allocate);
25562549
const auto &list{std::get<std::optional<parser::OmpObjectList>>(x.t)};
25572550
if (list) {
@@ -2632,83 +2625,10 @@ bool OmpAttributeVisitor::IsNestedInDirective(llvm::omp::Directive directive) {
26322625
}
26332626

26342627
void OmpAttributeVisitor::Post(const parser::OpenMPExecutableAllocate &x) {
2635-
bool hasAllocator = false;
2636-
// TODO: Investigate whether searching the clause list can be done with
2637-
// parser::Unwrap instead of the following loop
2638-
const auto &clauseList{std::get<parser::OmpClauseList>(x.t)};
2639-
for (const auto &clause : clauseList.v) {
2640-
if (std::get_if<parser::OmpClause::Allocator>(&clause.u)) {
2641-
hasAllocator = true;
2642-
}
2643-
}
2644-
2645-
if (IsNestedInDirective(llvm::omp::Directive::OMPD_target) && !hasAllocator) {
2646-
// TODO: expand this check to exclude the case when a requires
2647-
// directive with the dynamic_allocators clause is present
2648-
// in the same compilation unit (OMP5.0 2.11.3).
2649-
context_.Say(x.source,
2650-
"ALLOCATE directives that appear in a TARGET region "
2651-
"must specify an allocator clause"_err_en_US);
2652-
}
2653-
2654-
const auto &allocateStmt =
2655-
std::get<parser::Statement<parser::AllocateStmt>>(x.t).statement;
2656-
if (const auto &list{std::get<std::optional<parser::OmpObjectList>>(x.t)}) {
2657-
CheckAllNamesInAllocateStmt(
2658-
std::get<parser::Verbatim>(x.t).source, *list, allocateStmt);
2659-
}
2660-
if (const auto &subDirs{
2661-
std::get<std::optional<std::list<parser::OpenMPDeclarativeAllocate>>>(
2662-
x.t)}) {
2663-
for (const auto &dalloc : *subDirs) {
2664-
CheckAllNamesInAllocateStmt(std::get<parser::Verbatim>(dalloc.t).source,
2665-
std::get<parser::OmpObjectList>(dalloc.t), allocateStmt);
2666-
}
2667-
}
26682628
PopContext();
26692629
}
26702630

26712631
void OmpAttributeVisitor::Post(const parser::OpenMPAllocatorsConstruct &x) {
2672-
const parser::OmpDirectiveSpecification &dirSpec{x.BeginDir()};
2673-
auto &block{std::get<parser::Block>(x.t)};
2674-
2675-
omp::SourcedActionStmt action{omp::GetActionStmt(block)};
2676-
const parser::AllocateStmt *allocate{[&]() {
2677-
if (action) {
2678-
if (auto *alloc{std::get_if<common::Indirection<parser::AllocateStmt>>(
2679-
&action.stmt->u)}) {
2680-
return &alloc->value();
2681-
}
2682-
}
2683-
return static_cast<const parser::AllocateStmt *>(nullptr);
2684-
}()};
2685-
2686-
if (allocate) {
2687-
for (const auto &clause : dirSpec.Clauses().v) {
2688-
if (auto *alloc{std::get_if<parser::OmpClause::Allocate>(&clause.u)}) {
2689-
CheckAllNamesInAllocateStmt(
2690-
x.source, std::get<parser::OmpObjectList>(alloc->v.t), *allocate);
2691-
2692-
using OmpAllocatorSimpleModifier = parser::OmpAllocatorSimpleModifier;
2693-
using OmpAllocatorComplexModifier = parser::OmpAllocatorComplexModifier;
2694-
2695-
auto &modifiers{OmpGetModifiers(alloc->v)};
2696-
bool hasAllocator{
2697-
OmpGetUniqueModifier<OmpAllocatorSimpleModifier>(modifiers) ||
2698-
OmpGetUniqueModifier<OmpAllocatorComplexModifier>(modifiers)};
2699-
2700-
// TODO: As with allocate directive, exclude the case when a requires
2701-
// directive with the dynamic_allocators clause is present in
2702-
// the same compilation unit (OMP5.0 2.11.3).
2703-
if (IsNestedInDirective(llvm::omp::Directive::OMPD_target) &&
2704-
!hasAllocator) {
2705-
context_.Say(x.source,
2706-
"ALLOCATORS directives that appear in a TARGET region "
2707-
"must specify an allocator"_err_en_US);
2708-
}
2709-
}
2710-
}
2711-
}
27122632
PopContext();
27132633
}
27142634

@@ -3628,44 +3548,6 @@ void OmpAttributeVisitor::CheckLabelContext(const parser::CharBlock source,
36283548
}
36293549
}
36303550

3631-
// Goes through the names in an OmpObjectList and checks if each name appears
3632-
// in the given allocate statement
3633-
void OmpAttributeVisitor::CheckAllNamesInAllocateStmt(
3634-
const parser::CharBlock &source, const parser::OmpObjectList &ompObjectList,
3635-
const parser::AllocateStmt &allocate) {
3636-
for (const auto &obj : ompObjectList.v) {
3637-
if (const auto *d{std::get_if<parser::Designator>(&obj.u)}) {
3638-
if (const auto *ref{std::get_if<parser::DataRef>(&d->u)}) {
3639-
if (const auto *n{std::get_if<parser::Name>(&ref->u)}) {
3640-
CheckNameInAllocateStmt(source, *n, allocate);
3641-
}
3642-
}
3643-
}
3644-
}
3645-
}
3646-
3647-
void OmpAttributeVisitor::CheckNameInAllocateStmt(
3648-
const parser::CharBlock &source, const parser::Name &name,
3649-
const parser::AllocateStmt &allocate) {
3650-
for (const auto &allocation :
3651-
std::get<std::list<parser::Allocation>>(allocate.t)) {
3652-
const auto &allocObj = std::get<parser::AllocateObject>(allocation.t);
3653-
if (const auto *n{std::get_if<parser::Name>(&allocObj.u)}) {
3654-
if (n->source == name.source) {
3655-
return;
3656-
}
3657-
}
3658-
}
3659-
unsigned version{context_.langOptions().OpenMPVersion};
3660-
context_.Say(source,
3661-
"Object '%s' in %s directive not "
3662-
"found in corresponding ALLOCATE statement"_err_en_US,
3663-
name.ToString(),
3664-
parser::ToUpperCaseLetters(
3665-
llvm::omp::getOpenMPDirectiveName(GetContext().directive, version)
3666-
.str()));
3667-
}
3668-
36693551
void OmpAttributeVisitor::AddOmpRequiresToScope(Scope &scope,
36703552
WithOmpDeclarative::RequiresFlags flags,
36713553
std::optional<common::OmpMemoryOrderType> memOrder) {

flang/test/Semantics/OpenMP/allocate-align01.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ program allocate_align_tree
1313
z = 3
1414
!ERROR: The alignment value should be a constant positive integer
1515
!$omp allocate(j) align(xx)
16-
!WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. [-Wopen-mp-usage]
16+
!WARNING: The executable form of the OpenMP ALLOCATE directive has been deprecated, please use ALLOCATORS instead [-Wopen-mp-usage]
1717
!ERROR: The alignment value should be a constant positive integer
1818
!$omp allocate(xarray) align(-32) allocator(omp_large_cap_mem_alloc)
1919
allocate(j(z), xarray(t))

flang/test/Semantics/OpenMP/allocate01.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ subroutine sema()
1919
!$omp allocate(y)
2020
print *, a
2121

22-
!WARNING: OpenMP directive ALLOCATE has been deprecated, please use ALLOCATORS instead. [-Wopen-mp-usage]
22+
!WARNING: The executable form of the OpenMP ALLOCATE directive has been deprecated, please use ALLOCATORS instead [-Wopen-mp-usage]
2323
!$omp allocate(x) allocator(omp_default_mem_alloc)
2424
allocate ( x(a), darray(a, b) )
2525
end subroutine sema

0 commit comments

Comments
 (0)