Skip to content

Commit 61a9d2c

Browse files
authored
[flang][OpenMP] Use OmpDirectiveSpecification in DISPATCH (#148008)
Dispatch is the last construct (after ATOMIC and ALLOCATORS) where the associated block requires a specific form. Using OmpDirectiveSpecification for the begin and the optional end directives will make the structure of all block directives more uniform.
1 parent c0a1825 commit 61a9d2c

File tree

7 files changed

+99
-83
lines changed

7 files changed

+99
-83
lines changed

flang/include/flang/Parser/dump-parse-tree.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -710,8 +710,6 @@ class ParseTreeDumper {
710710
NODE(parser, OpenMPDepobjConstruct)
711711
NODE(parser, OpenMPUtilityConstruct)
712712
NODE(parser, OpenMPDispatchConstruct)
713-
NODE(parser, OmpDispatchDirective)
714-
NODE(parser, OmpEndDispatchDirective)
715713
NODE(parser, OpenMPFlushConstruct)
716714
NODE(parser, OpenMPLoopConstruct)
717715
NODE(parser, OpenMPExecutableAllocate)

flang/include/flang/Parser/parse-tree.h

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4939,19 +4939,11 @@ struct OpenMPDepobjConstruct {
49394939
// nocontext-clause |
49404940
// novariants-clause |
49414941
// nowait-clause
4942-
struct OmpDispatchDirective {
4943-
TUPLE_CLASS_BOILERPLATE(OmpDispatchDirective);
4944-
CharBlock source;
4945-
std::tuple<Verbatim, OmpClauseList> t;
4946-
};
4947-
4948-
EMPTY_CLASS(OmpEndDispatchDirective);
4949-
49504942
struct OpenMPDispatchConstruct {
49514943
TUPLE_CLASS_BOILERPLATE(OpenMPDispatchConstruct);
49524944
CharBlock source;
4953-
std::tuple<OmpDispatchDirective, Block,
4954-
std::optional<OmpEndDispatchDirective>>
4945+
std::tuple<OmpDirectiveSpecification, Block,
4946+
std::optional<OmpDirectiveSpecification>>
49554947
t;
49564948
};
49574949

flang/lib/Parser/openmp-parsers.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,32 @@ TYPE_PARSER(sourced( //
13021302
construct<OpenMPAllocatorsConstruct>(
13031303
"ALLOCATORS"_tok >= OmpAllocatorsConstructParser{})))
13041304

1305+
struct OmpDispatchConstructParser {
1306+
using resultType = OpenMPDispatchConstruct;
1307+
1308+
std::optional<resultType> Parse(ParseState &state) const {
1309+
auto dirSpec{Parser<OmpDirectiveSpecification>{}.Parse(state)};
1310+
if (!dirSpec || dirSpec->DirId() != llvm::omp::Directive::OMPD_dispatch) {
1311+
return std::nullopt;
1312+
}
1313+
1314+
// This should be a function call. That will be checked in semantics.
1315+
Block block;
1316+
if (auto stmt{attempt(Parser<ExecutionPartConstruct>{}).Parse(state)}) {
1317+
block.emplace_back(std::move(*stmt));
1318+
}
1319+
// Allow empty block. Check for this in semantics.
1320+
1321+
auto end{OmpEndDirectiveParser{llvm::omp::Directive::OMPD_dispatch}};
1322+
return OpenMPDispatchConstruct{
1323+
std::move(*dirSpec), std::move(block), *maybe(end).Parse(state)};
1324+
}
1325+
};
1326+
1327+
TYPE_PARSER(sourced( //
1328+
construct<OpenMPDispatchConstruct>(
1329+
"DISPATCH"_tok >= OmpDispatchConstructParser{})))
1330+
13051331
// Parser for an arbitrary OpenMP ATOMIC construct.
13061332
//
13071333
// Depending on circumstances, an ATOMIC construct applies to one or more
@@ -1631,16 +1657,6 @@ TYPE_PARSER(sourced(construct<OmpCriticalDirective>(verbatim("CRITICAL"_tok),
16311657
TYPE_PARSER(construct<OpenMPCriticalConstruct>(
16321658
Parser<OmpCriticalDirective>{}, block, Parser<OmpEndCriticalDirective>{}))
16331659

1634-
TYPE_PARSER(sourced(construct<OmpDispatchDirective>(
1635-
verbatim("DISPATCH"_tok), Parser<OmpClauseList>{})))
1636-
1637-
TYPE_PARSER(
1638-
construct<OmpEndDispatchDirective>(startOmpLine >> "END DISPATCH"_tok))
1639-
1640-
TYPE_PARSER(sourced(construct<OpenMPDispatchConstruct>(
1641-
Parser<OmpDispatchDirective>{} / endOmpLine, block,
1642-
maybe(Parser<OmpEndDispatchDirective>{} / endOmpLine))))
1643-
16441660
// 2.11.3 Executable Allocate directive
16451661
TYPE_PARSER(
16461662
sourced(construct<OpenMPExecutableAllocate>(verbatim("ALLOCATE"_tok),

flang/lib/Parser/unparse.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2758,6 +2758,9 @@ class UnparseVisitor {
27582758
Put("\n");
27592759
EndOpenMP();
27602760
}
2761+
void Unparse(const OpenMPDispatchConstruct &x) { //
2762+
UnparseBlockConstruct(x);
2763+
}
27612764
void Unparse(const OpenMPRequiresConstruct &y) {
27622765
BeginOpenMP();
27632766
Word("!$OMP REQUIRES ");
@@ -2777,15 +2780,6 @@ class UnparseVisitor {
27772780
Walk(x.v);
27782781
return false;
27792782
}
2780-
void Unparse(const OmpDispatchDirective &x) {
2781-
Word("!$OMP DISPATCH");
2782-
Walk(x.t);
2783-
Put("\n");
2784-
}
2785-
void Unparse(const OmpEndDispatchDirective &) {
2786-
Word("!$OMP END DISPATCH");
2787-
Put("\n");
2788-
}
27892783
void Unparse(const OmpErrorDirective &x) {
27902784
Word("!$OMP ERROR ");
27912785
Walk(x.t);

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

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -509,8 +509,8 @@ template <typename Checker> struct DirectiveSpellingVisitor {
509509
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_allocate);
510510
return false;
511511
}
512-
bool Pre(const parser::OmpDispatchDirective &x) {
513-
checker_(std::get<parser::Verbatim>(x.t).source, Directive::OMPD_dispatch);
512+
bool Pre(const parser::OpenMPDispatchConstruct &x) {
513+
checker_(GetDirName(x.t).source, Directive::OMPD_dispatch);
514514
return false;
515515
}
516516
bool Pre(const parser::OmpErrorDirective &x) {
@@ -1595,28 +1595,31 @@ void OmpStructureChecker::Enter(const parser::OmpErrorDirective &x) {
15951595
}
15961596

15971597
void OmpStructureChecker::Enter(const parser::OpenMPDispatchConstruct &x) {
1598-
PushContextAndClauseSets(x.source, llvm::omp::Directive::OMPD_dispatch);
1598+
auto &dirSpec{std::get<parser::OmpDirectiveSpecification>(x.t)};
15991599
const auto &block{std::get<parser::Block>(x.t)};
1600-
if (block.empty() || block.size() > 1) {
1600+
PushContextAndClauseSets(
1601+
dirSpec.DirName().source, llvm::omp::Directive::OMPD_dispatch);
1602+
1603+
if (block.empty()) {
16011604
context_.Say(x.source,
1602-
"The DISPATCH construct is empty or contains more than one statement"_err_en_US);
1605+
"The DISPATCH construct should contain a single function or subroutine call"_err_en_US);
16031606
return;
16041607
}
16051608

1606-
auto it{block.begin()};
16071609
bool passChecks{false};
1608-
if (const parser::AssignmentStmt *
1609-
assignStmt{parser::Unwrap<parser::AssignmentStmt>(*it)}) {
1610+
omp::SourcedActionStmt action{omp::GetActionStmt(block)};
1611+
if (const auto *assignStmt{
1612+
parser::Unwrap<parser::AssignmentStmt>(*action.stmt)}) {
16101613
if (parser::Unwrap<parser::FunctionReference>(assignStmt->t)) {
16111614
passChecks = true;
16121615
}
1613-
} else if (parser::Unwrap<parser::CallStmt>(*it)) {
1616+
} else if (parser::Unwrap<parser::CallStmt>(*action.stmt)) {
16141617
passChecks = true;
16151618
}
16161619

16171620
if (!passChecks) {
1618-
context_.Say(x.source,
1619-
"The DISPATCH construct does not contain a SUBROUTINE or FUNCTION"_err_en_US);
1621+
context_.Say(action.source,
1622+
"The body of the DISPATCH construct should be a function or a subroutine call"_err_en_US);
16201623
}
16211624
}
16221625

flang/test/Parser/OpenMP/dispatch.f90

Lines changed: 45 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
! RUN: %flang_fc1 -fopenmp -fdebug-dump-parse-tree %s | FileCheck %s
1+
! RUN: %flang_fc1 -fopenmp -fdebug-dump-parse-tree %s | FileCheck %s --check-prefix=PARSE-TREE
22
! RUN: %flang_fc1 -fopenmp -fdebug-unparse %s | FileCheck %s --check-prefix="UNPARSE"
33

44
integer function func(a, b, c)
@@ -12,40 +12,57 @@ subroutine sub(x)
1212
integer :: r
1313
type(c_ptr) :: x
1414
integer :: a = 14, b = 7, c = 21
15+
1516
!UNPARSE: !$OMP DISPATCH DEVICE(3_4) NOWAIT NOCONTEXT(.false._4) NOVARIANTS(.true._4)
16-
!CHECK: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPDispatchConstruct
17-
!CHECK-NEXT: | | | OmpDispatchDirective
18-
!CHECK: | | | | OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
19-
!CHECK-NEXT: | | | | | Scalar -> Integer -> Expr = '3_4'
20-
!CHECK-NEXT: | | | | | | LiteralConstant -> IntLiteralConstant = '3'
21-
!CHECK-NEXT: | | | | OmpClause -> Nowait
22-
!CHECK-NEXT: | | | | OmpClause -> Nocontext -> Scalar -> Logical -> Expr = '.false._4'
23-
!CHECK-NEXT: | | | | | LiteralConstant -> LogicalLiteralConstant
24-
!CHECK-NEXT: | | | | | | bool = 'false'
25-
!CHECK-NEXT: | | | | OmpClause -> Novariants -> Scalar -> Logical -> Expr = '.true._4'
26-
!CHECK-NEXT: | | | | | EQ
27-
!CHECK-NEXT: | | | | | | Expr = '1_4'
28-
!CHECK-NEXT: | | | | | | | LiteralConstant -> IntLiteralConstant = '1'
29-
!CHECK-NEXT: | | | | | | Expr = '1_4'
30-
!CHECK-NEXT: | | | | | | | LiteralConstant -> IntLiteralConstant = '1'
31-
!CHECK-NEXT: | | | Block
32-
17+
!UNPARSE: r=func(a,b,c)
18+
!UNPARSE: !$OMP END DISPATCH
19+
20+
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPDispatchConstruct
21+
!PARSE-TREE: | OmpDirectiveSpecification
22+
!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = dispatch
23+
!PARSE-TREE: | | OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
24+
!PARSE-TREE: | | | Scalar -> Integer -> Expr = '3_4'
25+
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '3'
26+
!PARSE-TREE: | | OmpClause -> Nowait
27+
!PARSE-TREE: | | OmpClause -> Nocontext -> Scalar -> Logical -> Expr = '.false._4'
28+
!PARSE-TREE: | | | LiteralConstant -> LogicalLiteralConstant
29+
!PARSE-TREE: | | | | bool = 'false'
30+
!PARSE-TREE: | | OmpClause -> Novariants -> Scalar -> Logical -> Expr = '.true._4'
31+
!PARSE-TREE: | | | EQ
32+
!PARSE-TREE: | | | | Expr = '1_4'
33+
!PARSE-TREE: | | | | | LiteralConstant -> IntLiteralConstant = '1'
34+
!PARSE-TREE: | | | | Expr = '1_4'
35+
!PARSE-TREE: | | | | | LiteralConstant -> IntLiteralConstant = '1'
36+
!PARSE-TREE: | | Flags = None
37+
!PARSE-TREE: | Block
38+
!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt
39+
![...]
40+
!PARSE-TREE: | OmpDirectiveSpecification
41+
!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = dispatch
42+
!PARSE-TREE: | | OmpClauseList ->
43+
!PARSE-TREE: | | Flags = None
44+
3345
!$omp dispatch device(3) nowait nocontext(.false.) novariants(1.eq.1)
3446
r = func(a, b, c)
35-
!UNPARSE: !$OMP END DISPATCH
36-
!CHECK: | | | OmpEndDispatchDirective
3747
!$omp end dispatch
3848

3949
!! Test the "no end dispatch" option.
40-
!UNPARSE: !$OMP DISPATCH DEVICE(3_4) IS_DEVICE_PTR(x)
41-
!CHECK: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPDispatchConstruct
42-
!CHECK-NEXT: | | | OmpDispatchDirective
43-
!CHECK: | | | | OmpClause -> IsDevicePtr -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
50+
!UNPARSE: !$OMP DISPATCH DEVICE(3_4) IS_DEVICE_PTR(x)
51+
!UNPARSE: r=func(a+1_4,b+2_4,c+3_4)
52+
53+
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPDispatchConstruct
54+
!PARSE-TREE: | OmpDirectiveSpecification
55+
!PARSE-TREE: | | OmpDirectiveName -> llvm::omp::Directive = dispatch
56+
!PARSE-TREE: | | OmpClauseList -> OmpClause -> Device -> OmpDeviceClause
57+
!PARSE-TREE: | | | Scalar -> Integer -> Expr = '3_4'
58+
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '3'
59+
!PARSE-TREE: | | OmpClause -> IsDevicePtr -> OmpObjectList -> OmpObject -> Designator -> DataRef -> Name = 'x'
60+
!PARSE-TREE: | | Flags = None
61+
!PARSE-TREE: | Block
62+
!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt
63+
!PARSE-TREE-NOT: OmpDirectiveSpecification
64+
4465
!$omp dispatch device(3) is_device_ptr(x)
4566
r = func(a+1, b+2, c+3)
46-
!CHECK-NOT: | | | OmpEndDispatchDirective
4767

4868
end subroutine sub
49-
50-
51-
Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,20 @@
1-
! RUN: %python %S/../test_errors.py %s %flang -fopenmp
1+
! RUN: %python %S/../test_errors.py %s %flang -fopenmp -fopenmp-version=52
22

33
subroutine sb1
44
integer :: r
55
r = 1
6-
!ERROR: The DISPATCH construct does not contain a SUBROUTINE or FUNCTION
76
!$omp dispatch nowait
7+
!ERROR: The body of the DISPATCH construct should be a function or a subroutine call
88
print *,r
99
end subroutine
10+
1011
subroutine sb2
11-
integer :: r
12-
!ERROR: The DISPATCH construct is empty or contains more than one statement
12+
!ERROR: The DISPATCH construct should contain a single function or subroutine call
1313
!$omp dispatch
14-
call foo()
15-
r = bar()
1614
!$omp end dispatch
17-
contains
18-
subroutine foo
19-
end subroutine foo
20-
function bar
21-
integer :: bar
22-
bar = 2
23-
end function
15+
end subroutine
16+
17+
subroutine sb3
18+
!ERROR: The DISPATCH construct should contain a single function or subroutine call
19+
!$omp dispatch
2420
end subroutine

0 commit comments

Comments
 (0)