Skip to content

Commit c81a189

Browse files
authored
[flang][OpenMP] Canonicalize loops with intervening OpenMP constructs (#169191)
Example based on the gfortran test a.6.1.f90 ``` do 100 i = 1,10 !$omp do do 100 j = 1,10 call work(i,j) 100 continue ``` During canonicalization of label-DO loops, if the body of an OpenMP construct ends with a label, treat the label as ending the construct itself. This will also allow handling of cases like ``` do 100 i = 1, 10 !$omp atomic write 100 x = i ``` which we were unable to before.
1 parent a2231af commit c81a189

File tree

5 files changed

+141
-3
lines changed

5 files changed

+141
-3
lines changed

flang/include/flang/Parser/openmp-utils.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@ template <typename T> struct IsStatement<Statement<T>> {
135135
};
136136

137137
std::optional<Label> GetStatementLabel(const ExecutionPartConstruct &x);
138+
std::optional<Label> GetFinalLabel(const OpenMPConstruct &x);
138139

139140
const OmpObjectList *GetOmpObjectList(const OmpClause &clause);
140141

flang/lib/Parser/openmp-utils.cpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "flang/Common/indirection.h"
1616
#include "flang/Common/template.h"
1717
#include "flang/Common/visit.h"
18+
#include "flang/Parser/tools.h"
1819

1920
#include <tuple>
2021
#include <type_traits>
@@ -77,6 +78,44 @@ std::optional<Label> GetStatementLabel(const ExecutionPartConstruct &x) {
7778
return GetStatementLabelHelper(x);
7879
}
7980

81+
static std::optional<Label> GetFinalLabel(const Block &x) {
82+
if (!x.empty()) {
83+
const ExecutionPartConstruct &last{x.back()};
84+
if (auto *omp{Unwrap<OpenMPConstruct>(last)}) {
85+
return GetFinalLabel(*omp);
86+
} else if (auto *doLoop{Unwrap<DoConstruct>(last)}) {
87+
return GetFinalLabel(std::get<Block>(doLoop->t));
88+
} else {
89+
return GetStatementLabel(x.back());
90+
}
91+
} else {
92+
return std::nullopt;
93+
}
94+
}
95+
96+
std::optional<Label> GetFinalLabel(const OpenMPConstruct &x) {
97+
return common::visit(
98+
[](auto &&s) -> std::optional<Label> {
99+
using TypeS = llvm::remove_cvref_t<decltype(s)>;
100+
if constexpr (std::is_same_v<TypeS, OpenMPSectionsConstruct>) {
101+
auto &list{std::get<std::list<OpenMPConstruct>>(s.t)};
102+
if (!list.empty()) {
103+
return GetFinalLabel(list.back());
104+
} else {
105+
return std::nullopt;
106+
}
107+
} else if constexpr ( //
108+
std::is_same_v<TypeS, OpenMPLoopConstruct> ||
109+
std::is_same_v<TypeS, OpenMPSectionConstruct> ||
110+
std::is_base_of_v<OmpBlockConstruct, TypeS>) {
111+
return GetFinalLabel(std::get<Block>(s.t));
112+
} else {
113+
return std::nullopt;
114+
}
115+
},
116+
x.u);
117+
}
118+
80119
const OmpObjectList *GetOmpObjectList(const OmpClause &clause) {
81120
// Clauses with OmpObjectList as its data member
82121
using MemberObjectListClauses = std::tuple<OmpClause::Copyin,

flang/lib/Semantics/canonicalize-do.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "canonicalize-do.h"
10+
#include "flang/Parser/openmp-utils.h"
1011
#include "flang/Parser/parse-tree-visitor.h"
1112

1213
namespace Fortran::parser {
@@ -87,6 +88,12 @@ class CanonicalizationOfDoLoops {
8788
[&](Statement<ActionStmt> &actionStmt) {
8889
CanonicalizeIfMatch(block, stack, i, actionStmt);
8990
},
91+
[&](common::Indirection<OpenMPConstruct> &construct) {
92+
// If the body of the OpenMP construct ends with a label,
93+
// treat the label as ending the construct itself.
94+
CanonicalizeIfMatch(
95+
block, stack, i, omp::GetFinalLabel(construct.value()));
96+
},
9097
},
9198
executableConstruct->u);
9299
}
@@ -97,10 +104,14 @@ class CanonicalizationOfDoLoops {
97104
template <typename T>
98105
void CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
99106
Block::iterator &i, Statement<T> &statement) {
100-
if (!stack.empty() && statement.label &&
101-
stack.back().label == *statement.label) {
107+
CanonicalizeIfMatch(originalBlock, stack, i, statement.label);
108+
}
109+
110+
void CanonicalizeIfMatch(Block &originalBlock, std::vector<LabelInfo> &stack,
111+
Block::iterator &i, std::optional<Label> label) {
112+
if (!stack.empty() && label && stack.back().label == *label) {
102113
auto currentLabel{stack.back().label};
103-
if constexpr (std::is_same_v<T, common::Indirection<EndDoStmt>>) {
114+
if (Unwrap<EndDoStmt>(*i)) {
104115
std::get<ExecutableConstruct>(i->u).u = Statement<ActionStmt>{
105116
std::optional<Label>{currentLabel}, ContinueStmt{}};
106117
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
!RUN: %flang_fc1 -fdebug-unparse -fopenmp %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
2+
!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s
3+
4+
subroutine f
5+
integer :: i, x
6+
do 100 i = 1, 10
7+
!$omp atomic write
8+
100 x = i
9+
end
10+
11+
!UNPARSE: SUBROUTINE f
12+
!UNPARSE: INTEGER i, x
13+
!UNPARSE: DO i=1_4,10_4
14+
!UNPARSE: !$OMP ATOMIC WRITE
15+
!UNPARSE: 100 x=i
16+
!UNPARSE: END DO
17+
!UNPARSE: END SUBROUTINE
18+
19+
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> DoConstruct
20+
!PARSE-TREE: | NonLabelDoStmt
21+
!PARSE-TREE: | | LoopControl -> LoopBounds
22+
!PARSE-TREE: | | | Scalar -> Name = 'i'
23+
!PARSE-TREE: | | | Scalar -> Expr = '1_4'
24+
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
25+
!PARSE-TREE: | | | Scalar -> Expr = '10_4'
26+
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '10'
27+
!PARSE-TREE: | Block
28+
!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPAtomicConstruct
29+
!PARSE-TREE: | | | OmpBeginDirective
30+
!PARSE-TREE: | | | | OmpDirectiveName -> llvm::omp::Directive = atomic
31+
!PARSE-TREE: | | | | OmpClauseList -> OmpClause -> Write
32+
!PARSE-TREE: | | | | Flags = None
33+
!PARSE-TREE: | | | Block
34+
!PARSE-TREE: | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> AssignmentStmt = 'x=i'
35+
!PARSE-TREE: | | | | | Variable = 'x'
36+
!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'x'
37+
!PARSE-TREE: | | | | | Expr = 'i'
38+
!PARSE-TREE: | | | | | | Designator -> DataRef -> Name = 'i'
39+
!PARSE-TREE: | EndDoStmt ->
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
!RUN: %flang_fc1 -fdebug-unparse -fopenmp %s | FileCheck --ignore-case --check-prefix="UNPARSE" %s
2+
!RUN: %flang_fc1 -fdebug-dump-parse-tree -fopenmp %s | FileCheck --check-prefix="PARSE-TREE" %s
3+
4+
subroutine f00
5+
integer :: i, j
6+
do 100 i = 1,10
7+
!$omp do
8+
do 100 j = 1,10
9+
100 continue
10+
end
11+
12+
!UNPARSE: SUBROUTINE f00
13+
!UNPARSE: INTEGER i, j
14+
!UNPARSE: DO i=1_4,10_4
15+
!UNPARSE: !$OMP DO
16+
!UNPARSE: DO j=1_4,10_4
17+
!UNPARSE: 100 CONTINUE
18+
!UNPARSE: END DO
19+
!UNPARSE: END DO
20+
!UNPARSE: END SUBROUTINE
21+
22+
!PARSE-TREE: ExecutionPartConstruct -> ExecutableConstruct -> DoConstruct
23+
!PARSE-TREE: | NonLabelDoStmt
24+
!PARSE-TREE: | | LoopControl -> LoopBounds
25+
!PARSE-TREE: | | | Scalar -> Name = 'i'
26+
!PARSE-TREE: | | | Scalar -> Expr = '1_4'
27+
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '1'
28+
!PARSE-TREE: | | | Scalar -> Expr = '10_4'
29+
!PARSE-TREE: | | | | LiteralConstant -> IntLiteralConstant = '10'
30+
!PARSE-TREE: | Block
31+
!PARSE-TREE: | | ExecutionPartConstruct -> ExecutableConstruct -> OpenMPConstruct -> OpenMPLoopConstruct
32+
!PARSE-TREE: | | | OmpBeginLoopDirective
33+
!PARSE-TREE: | | | | OmpDirectiveName -> llvm::omp::Directive = do
34+
!PARSE-TREE: | | | | OmpClauseList ->
35+
!PARSE-TREE: | | | | Flags = None
36+
!PARSE-TREE: | | | Block
37+
!PARSE-TREE: | | | | ExecutionPartConstruct -> ExecutableConstruct -> DoConstruct
38+
!PARSE-TREE: | | | | | NonLabelDoStmt
39+
!PARSE-TREE: | | | | | | LoopControl -> LoopBounds
40+
!PARSE-TREE: | | | | | | | Scalar -> Name = 'j'
41+
!PARSE-TREE: | | | | | | | Scalar -> Expr = '1_4'
42+
!PARSE-TREE: | | | | | | | | LiteralConstant -> IntLiteralConstant = '1'
43+
!PARSE-TREE: | | | | | | | Scalar -> Expr = '10_4'
44+
!PARSE-TREE: | | | | | | | | LiteralConstant -> IntLiteralConstant = '10'
45+
!PARSE-TREE: | | | | | Block
46+
!PARSE-TREE: | | | | | | ExecutionPartConstruct -> ExecutableConstruct -> ActionStmt -> ContinueStmt
47+
!PARSE-TREE: | | | | | EndDoStmt ->
48+
!PARSE-TREE: | EndDoStmt ->

0 commit comments

Comments
 (0)