Skip to content

Commit b1341e2

Browse files
authored
[flang][openacc] Fix unstructured code in OpenACC region ops (#66284)
For unstructured construct, the blocks are created in advance inside the function body. This causes issues when the unstructured construct is inside an OpenACC region operations. This patch adds the same fix than OpenMP lowering and re-create the blocks inside the op region. Initial OpenMP fix: 29f167a
1 parent 97edcde commit b1341e2

File tree

5 files changed

+171
-57
lines changed

5 files changed

+171
-57
lines changed

flang/lib/Lower/DirectivesCommon.h

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -587,7 +587,31 @@ void genOmpAccAtomicCapture(Fortran::lower::AbstractConverter &converter,
587587
firOpBuilder.setInsertionPointToStart(&block);
588588
}
589589

590+
/// Create empty blocks for the current region.
591+
/// These blocks replace blocks parented to an enclosing region.
592+
template <typename... TerminatorOps>
593+
void createEmptyRegionBlocks(
594+
fir::FirOpBuilder &builder,
595+
std::list<Fortran::lower::pft::Evaluation> &evaluationList) {
596+
mlir::Region *region = &builder.getRegion();
597+
for (Fortran::lower::pft::Evaluation &eval : evaluationList) {
598+
if (eval.block) {
599+
if (eval.block->empty()) {
600+
eval.block->erase();
601+
eval.block = builder.createBlock(region);
602+
} else {
603+
[[maybe_unused]] mlir::Operation &terminatorOp = eval.block->back();
604+
assert(mlir::isa<TerminatorOps...>(terminatorOp) &&
605+
"expected terminator op");
606+
}
607+
}
608+
if (!eval.isDirective() && eval.hasNestedEvaluations())
609+
createEmptyRegionBlocks<TerminatorOps...>(builder,
610+
eval.getNestedEvaluations());
611+
}
612+
}
613+
590614
} // namespace lower
591615
} // namespace Fortran
592616

593-
#endif // FORTRAN_LOWER_DIRECTIVES_COMMON_H
617+
#endif // FORTRAN_LOWER_DIRECTIVES_COMMON_H

flang/lib/Lower/OpenACC.cpp

Lines changed: 56 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1250,23 +1250,32 @@ static void addOperand(llvm::SmallVectorImpl<mlir::Value> &operands,
12501250
}
12511251

12521252
template <typename Op, typename Terminator>
1253-
static Op
1254-
createRegionOp(fir::FirOpBuilder &builder, mlir::Location loc,
1255-
const llvm::SmallVectorImpl<mlir::Value> &operands,
1256-
const llvm::SmallVectorImpl<int32_t> &operandSegments) {
1253+
static Op createRegionOp(fir::FirOpBuilder &builder, mlir::Location loc,
1254+
Fortran::lower::pft::Evaluation &eval,
1255+
const llvm::SmallVectorImpl<mlir::Value> &operands,
1256+
const llvm::SmallVectorImpl<int32_t> &operandSegments,
1257+
bool outerCombined = false) {
12571258
llvm::ArrayRef<mlir::Type> argTy;
12581259
Op op = builder.create<Op>(loc, argTy, operands);
12591260
builder.createBlock(&op.getRegion());
12601261
mlir::Block &block = op.getRegion().back();
12611262
builder.setInsertionPointToStart(&block);
1262-
builder.create<Terminator>(loc);
12631263

12641264
op->setAttr(Op::getOperandSegmentSizeAttr(),
12651265
builder.getDenseI32ArrayAttr(operandSegments));
12661266

12671267
// Place the insertion point to the start of the first block.
12681268
builder.setInsertionPointToStart(&block);
12691269

1270+
// If it is an unstructured region and is not the outer region of a combined
1271+
// construct, create empty blocks for all evaluations.
1272+
if (eval.lowerAsUnstructured() && !outerCombined)
1273+
Fortran::lower::createEmptyRegionBlocks<mlir::acc::TerminatorOp,
1274+
mlir::acc::YieldOp>(
1275+
builder, eval.getNestedEvaluations());
1276+
1277+
builder.create<Terminator>(loc);
1278+
builder.setInsertionPointToStart(&block);
12701279
return op;
12711280
}
12721281

@@ -1347,6 +1356,7 @@ static void genWaitClause(Fortran::lower::AbstractConverter &converter,
13471356
static mlir::acc::LoopOp
13481357
createLoopOp(Fortran::lower::AbstractConverter &converter,
13491358
mlir::Location currentLocation,
1359+
Fortran::lower::pft::Evaluation &eval,
13501360
Fortran::semantics::SemanticsContext &semanticsContext,
13511361
Fortran::lower::StatementContext &stmtCtx,
13521362
const Fortran::parser::AccClauseList &accClauseList) {
@@ -1455,7 +1465,7 @@ createLoopOp(Fortran::lower::AbstractConverter &converter,
14551465
addOperands(operands, operandSegments, cacheOperands);
14561466

14571467
auto loopOp = createRegionOp<mlir::acc::LoopOp, mlir::acc::YieldOp>(
1458-
builder, currentLocation, operands, operandSegments);
1468+
builder, currentLocation, eval, operands, operandSegments);
14591469

14601470
if (hasGang)
14611471
loopOp.setHasGangAttr(builder.getUnitAttr());
@@ -1504,6 +1514,7 @@ createLoopOp(Fortran::lower::AbstractConverter &converter,
15041514

15051515
static void genACC(Fortran::lower::AbstractConverter &converter,
15061516
Fortran::semantics::SemanticsContext &semanticsContext,
1517+
Fortran::lower::pft::Evaluation &eval,
15071518
const Fortran::parser::OpenACCLoopConstruct &loopConstruct) {
15081519

15091520
const auto &beginLoopDirective =
@@ -1518,7 +1529,7 @@ static void genACC(Fortran::lower::AbstractConverter &converter,
15181529
if (loopDirective.v == llvm::acc::ACCD_loop) {
15191530
const auto &accClauseList =
15201531
std::get<Fortran::parser::AccClauseList>(beginLoopDirective.t);
1521-
createLoopOp(converter, currentLocation, semanticsContext, stmtCtx,
1532+
createLoopOp(converter, currentLocation, eval, semanticsContext, stmtCtx,
15221533
accClauseList);
15231534
}
15241535
}
@@ -1551,9 +1562,11 @@ template <typename Op>
15511562
static Op
15521563
createComputeOp(Fortran::lower::AbstractConverter &converter,
15531564
mlir::Location currentLocation,
1565+
Fortran::lower::pft::Evaluation &eval,
15541566
Fortran::semantics::SemanticsContext &semanticsContext,
15551567
Fortran::lower::StatementContext &stmtCtx,
1556-
const Fortran::parser::AccClauseList &accClauseList) {
1568+
const Fortran::parser::AccClauseList &accClauseList,
1569+
bool outerCombined = false) {
15571570

15581571
// Parallel operation operands
15591572
mlir::Value async;
@@ -1769,10 +1782,12 @@ createComputeOp(Fortran::lower::AbstractConverter &converter,
17691782
Op computeOp;
17701783
if constexpr (std::is_same_v<Op, mlir::acc::KernelsOp>)
17711784
computeOp = createRegionOp<Op, mlir::acc::TerminatorOp>(
1772-
builder, currentLocation, operands, operandSegments);
1785+
builder, currentLocation, eval, operands, operandSegments,
1786+
outerCombined);
17731787
else
17741788
computeOp = createRegionOp<Op, mlir::acc::YieldOp>(
1775-
builder, currentLocation, operands, operandSegments);
1789+
builder, currentLocation, eval, operands, operandSegments,
1790+
outerCombined);
17761791

17771792
if (addAsyncAttr)
17781793
computeOp.setAsyncAttrAttr(builder.getUnitAttr());
@@ -1817,6 +1832,7 @@ createComputeOp(Fortran::lower::AbstractConverter &converter,
18171832

18181833
static void genACCDataOp(Fortran::lower::AbstractConverter &converter,
18191834
mlir::Location currentLocation,
1835+
Fortran::lower::pft::Evaluation &eval,
18201836
Fortran::semantics::SemanticsContext &semanticsContext,
18211837
Fortran::lower::StatementContext &stmtCtx,
18221838
const Fortran::parser::AccClauseList &accClauseList) {
@@ -1942,7 +1958,7 @@ static void genACCDataOp(Fortran::lower::AbstractConverter &converter,
19421958
return;
19431959

19441960
auto dataOp = createRegionOp<mlir::acc::DataOp, mlir::acc::TerminatorOp>(
1945-
builder, currentLocation, operands, operandSegments);
1961+
builder, currentLocation, eval, operands, operandSegments);
19461962

19471963
dataOp.setAsyncAttr(addAsyncAttr);
19481964
dataOp.setWaitAttr(addWaitAttr);
@@ -1971,6 +1987,7 @@ static void genACCDataOp(Fortran::lower::AbstractConverter &converter,
19711987
static void
19721988
genACCHostDataOp(Fortran::lower::AbstractConverter &converter,
19731989
mlir::Location currentLocation,
1990+
Fortran::lower::pft::Evaluation &eval,
19741991
Fortran::semantics::SemanticsContext &semanticsContext,
19751992
Fortran::lower::StatementContext &stmtCtx,
19761993
const Fortran::parser::AccClauseList &accClauseList) {
@@ -2020,7 +2037,7 @@ genACCHostDataOp(Fortran::lower::AbstractConverter &converter,
20202037

20212038
auto hostDataOp =
20222039
createRegionOp<mlir::acc::HostDataOp, mlir::acc::TerminatorOp>(
2023-
builder, currentLocation, operands, operandSegments);
2040+
builder, currentLocation, eval, operands, operandSegments);
20242041

20252042
if (addIfPresentAttr)
20262043
hostDataOp.setIfPresentAttr(builder.getUnitAttr());
@@ -2029,6 +2046,7 @@ genACCHostDataOp(Fortran::lower::AbstractConverter &converter,
20292046
static void
20302047
genACC(Fortran::lower::AbstractConverter &converter,
20312048
Fortran::semantics::SemanticsContext &semanticsContext,
2049+
Fortran::lower::pft::Evaluation &eval,
20322050
const Fortran::parser::OpenACCBlockConstruct &blockConstruct) {
20332051
const auto &beginBlockDirective =
20342052
std::get<Fortran::parser::AccBeginBlockDirective>(blockConstruct.t);
@@ -2041,26 +2059,30 @@ genACC(Fortran::lower::AbstractConverter &converter,
20412059
Fortran::lower::StatementContext stmtCtx;
20422060

20432061
if (blockDirective.v == llvm::acc::ACCD_parallel) {
2044-
createComputeOp<mlir::acc::ParallelOp>(
2045-
converter, currentLocation, semanticsContext, stmtCtx, accClauseList);
2062+
createComputeOp<mlir::acc::ParallelOp>(converter, currentLocation, eval,
2063+
semanticsContext, stmtCtx,
2064+
accClauseList);
20462065
} else if (blockDirective.v == llvm::acc::ACCD_data) {
2047-
genACCDataOp(converter, currentLocation, semanticsContext, stmtCtx,
2066+
genACCDataOp(converter, currentLocation, eval, semanticsContext, stmtCtx,
20482067
accClauseList);
20492068
} else if (blockDirective.v == llvm::acc::ACCD_serial) {
2050-
createComputeOp<mlir::acc::SerialOp>(
2051-
converter, currentLocation, semanticsContext, stmtCtx, accClauseList);
2069+
createComputeOp<mlir::acc::SerialOp>(converter, currentLocation, eval,
2070+
semanticsContext, stmtCtx,
2071+
accClauseList);
20522072
} else if (blockDirective.v == llvm::acc::ACCD_kernels) {
2053-
createComputeOp<mlir::acc::KernelsOp>(
2054-
converter, currentLocation, semanticsContext, stmtCtx, accClauseList);
2073+
createComputeOp<mlir::acc::KernelsOp>(converter, currentLocation, eval,
2074+
semanticsContext, stmtCtx,
2075+
accClauseList);
20552076
} else if (blockDirective.v == llvm::acc::ACCD_host_data) {
2056-
genACCHostDataOp(converter, currentLocation, semanticsContext, stmtCtx,
2057-
accClauseList);
2077+
genACCHostDataOp(converter, currentLocation, eval, semanticsContext,
2078+
stmtCtx, accClauseList);
20582079
}
20592080
}
20602081

20612082
static void
20622083
genACC(Fortran::lower::AbstractConverter &converter,
20632084
Fortran::semantics::SemanticsContext &semanticsContext,
2085+
Fortran::lower::pft::Evaluation &eval,
20642086
const Fortran::parser::OpenACCCombinedConstruct &combinedConstruct) {
20652087
const auto &beginCombinedDirective =
20662088
std::get<Fortran::parser::AccBeginCombinedDirective>(combinedConstruct.t);
@@ -2075,18 +2097,21 @@ genACC(Fortran::lower::AbstractConverter &converter,
20752097

20762098
if (combinedDirective.v == llvm::acc::ACCD_kernels_loop) {
20772099
createComputeOp<mlir::acc::KernelsOp>(
2078-
converter, currentLocation, semanticsContext, stmtCtx, accClauseList);
2079-
createLoopOp(converter, currentLocation, semanticsContext, stmtCtx,
2100+
converter, currentLocation, eval, semanticsContext, stmtCtx,
2101+
accClauseList, /*outerCombined=*/true);
2102+
createLoopOp(converter, currentLocation, eval, semanticsContext, stmtCtx,
20802103
accClauseList);
20812104
} else if (combinedDirective.v == llvm::acc::ACCD_parallel_loop) {
20822105
createComputeOp<mlir::acc::ParallelOp>(
2083-
converter, currentLocation, semanticsContext, stmtCtx, accClauseList);
2084-
createLoopOp(converter, currentLocation, semanticsContext, stmtCtx,
2106+
converter, currentLocation, eval, semanticsContext, stmtCtx,
2107+
accClauseList, /*outerCombined=*/true);
2108+
createLoopOp(converter, currentLocation, eval, semanticsContext, stmtCtx,
20852109
accClauseList);
20862110
} else if (combinedDirective.v == llvm::acc::ACCD_serial_loop) {
2087-
createComputeOp<mlir::acc::SerialOp>(
2088-
converter, currentLocation, semanticsContext, stmtCtx, accClauseList);
2089-
createLoopOp(converter, currentLocation, semanticsContext, stmtCtx,
2111+
createComputeOp<mlir::acc::SerialOp>(converter, currentLocation, eval,
2112+
semanticsContext, stmtCtx,
2113+
accClauseList, /*outerCombined=*/true);
2114+
createLoopOp(converter, currentLocation, eval, semanticsContext, stmtCtx,
20902115
accClauseList);
20912116
} else {
20922117
llvm::report_fatal_error("Unknown combined construct encountered");
@@ -3169,14 +3194,14 @@ void Fortran::lower::genOpenACCConstruct(
31693194
std::visit(
31703195
common::visitors{
31713196
[&](const Fortran::parser::OpenACCBlockConstruct &blockConstruct) {
3172-
genACC(converter, semanticsContext, blockConstruct);
3197+
genACC(converter, semanticsContext, eval, blockConstruct);
31733198
},
31743199
[&](const Fortran::parser::OpenACCCombinedConstruct
31753200
&combinedConstruct) {
3176-
genACC(converter, semanticsContext, combinedConstruct);
3201+
genACC(converter, semanticsContext, eval, combinedConstruct);
31773202
},
31783203
[&](const Fortran::parser::OpenACCLoopConstruct &loopConstruct) {
3179-
genACC(converter, semanticsContext, loopConstruct);
3204+
genACC(converter, semanticsContext, eval, loopConstruct);
31803205
},
31813206
[&](const Fortran::parser::OpenACCStandaloneConstruct
31823207
&standaloneConstruct) {

flang/lib/Lower/OpenMP.cpp

Lines changed: 3 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1981,29 +1981,6 @@ static mlir::Type getLoopVarType(Fortran::lower::AbstractConverter &converter,
19811981
return converter.getFirOpBuilder().getIntegerType(loopVarTypeSize);
19821982
}
19831983

1984-
/// Create empty blocks for the current region.
1985-
/// These blocks replace blocks parented to an enclosing region.
1986-
static void createEmptyRegionBlocks(
1987-
fir::FirOpBuilder &firOpBuilder,
1988-
std::list<Fortran::lower::pft::Evaluation> &evaluationList) {
1989-
mlir::Region *region = &firOpBuilder.getRegion();
1990-
for (Fortran::lower::pft::Evaluation &eval : evaluationList) {
1991-
if (eval.block) {
1992-
if (eval.block->empty()) {
1993-
eval.block->erase();
1994-
eval.block = firOpBuilder.createBlock(region);
1995-
} else {
1996-
[[maybe_unused]] mlir::Operation &terminatorOp = eval.block->back();
1997-
assert((mlir::isa<mlir::omp::TerminatorOp>(terminatorOp) ||
1998-
mlir::isa<mlir::omp::YieldOp>(terminatorOp)) &&
1999-
"expected terminator op");
2000-
}
2001-
}
2002-
if (!eval.isDirective() && eval.hasNestedEvaluations())
2003-
createEmptyRegionBlocks(firOpBuilder, eval.getNestedEvaluations());
2004-
}
2005-
}
2006-
20071984
static void resetBeforeTerminator(fir::FirOpBuilder &firOpBuilder,
20081985
mlir::Operation *storeOp,
20091986
mlir::Block &block) {
@@ -2092,7 +2069,9 @@ static void createBodyOfOp(
20922069
// If it is an unstructured region and is not the outer region of a combined
20932070
// construct, create empty blocks for all evaluations.
20942071
if (eval.lowerAsUnstructured() && !outerCombined)
2095-
createEmptyRegionBlocks(firOpBuilder, eval.getNestedEvaluations());
2072+
Fortran::lower::createEmptyRegionBlocks<mlir::omp::TerminatorOp,
2073+
mlir::omp::YieldOp>(
2074+
firOpBuilder, eval.getNestedEvaluations());
20962075

20972076
// Insert the terminator.
20982077
if constexpr (std::is_same_v<Op, mlir::omp::WsLoopOp> ||
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
! RUN: bbc -fopenacc -emit-fir %s -o - | FileCheck %s
2+
! RUN: bbc -fopenacc -emit-hlfir %s -o - | FileCheck %s
3+
4+
subroutine test_unstructured1(a, b, c)
5+
integer :: i, j, k
6+
real :: a(:,:,:), b(:,:,:), c(:,:,:)
7+
8+
!$acc data copy(a, b, c)
9+
10+
!$acc kernels
11+
a(:,:,:) = 0.0
12+
!$acc end kernels
13+
14+
!$acc kernels
15+
do i = 1, 10
16+
do j = 1, 10
17+
do k = 1, 10
18+
end do
19+
end do
20+
end do
21+
!$acc end kernels
22+
23+
do i = 1, 10
24+
do j = 1, 10
25+
do k = 1, 10
26+
end do
27+
end do
28+
29+
if (a(1,2,3) > 10) stop 'just to be unstructured'
30+
end do
31+
32+
!$acc end data
33+
34+
end subroutine
35+
36+
! CHECK-LABEL: func.func @_QPtest_unstructured1
37+
! CHECK: acc.data
38+
! CHECK: acc.kernels
39+
! CHECK: acc.kernels
40+
! CHECK: fir.call @_FortranAStopStatementText
41+
42+
43+
subroutine test_unstructured2(a, b, c)
44+
integer :: i, j, k
45+
real :: a(:,:,:), b(:,:,:), c(:,:,:)
46+
47+
!$acc parallel loop
48+
do i = 1, 10
49+
do j = 1, 10
50+
do k = 1, 10
51+
if (a(1,2,3) > 10) stop 'just to be unstructured'
52+
end do
53+
end do
54+
end do
55+
56+
! CHECK-LABEL: func.func @_QPtest_unstructured2
57+
! CHECK: acc.parallel
58+
! CHECK: acc.loop
59+
! CHECK: fir.call @_FortranAStopStatementText
60+
! CHECK: fir.unreachable
61+
! CHECK: acc.yield
62+
! CHECK: acc.yield
63+
64+
end subroutine
65+
66+
subroutine test_unstructured3(a, b, c)
67+
integer :: i, j, k
68+
real :: a(:,:,:), b(:,:,:), c(:,:,:)
69+
70+
!$acc parallel
71+
do i = 1, 10
72+
do j = 1, 10
73+
do k = 1, 10
74+
if (a(1,2,3) > 10) stop 'just to be unstructured'
75+
end do
76+
end do
77+
end do
78+
!$acc end parallel
79+
80+
! CHECK-LABEL: func.func @_QPtest_unstructured3
81+
! CHECK: acc.parallel
82+
! CHECK: fir.call @_FortranAStopStatementText
83+
! CHECK: fir.unreachable
84+
! CHECK: acc.yield
85+
86+
end subroutine

flang/test/Lower/OpenACC/stop-stmt-in-region.f90

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ subroutine test_stop_in_region1()
2929
! CHECK: %[[VAL_2:.*]] = arith.constant false
3030
! CHECK: %[[VAL_3:.*]] = arith.constant false
3131
! CHECK: %[[VAL_4:.*]] = fir.call @_FortranAStopStatement(%[[VAL_1]], %[[VAL_2]], %[[VAL_3]]) {{.*}} : (i32, i1, i1) -> none
32-
! CHECK: acc.yield
32+
! CHECK: fir.unreachable
3333
! CHECK: }
3434
! CHECK: return
3535
! CHECK: }

0 commit comments

Comments
 (0)