Skip to content

Commit c1b5b7c

Browse files
authored
[flang][Lower] Emit exiting branches from within constructs (#92455)
When lowering IfConstruct, CaseConstruct, and SelectTypeConstruct, emit branches that exit the construct in each block that is still unterminated after the FIR has been generated in it. The same thing may be needed for SelectRankConstruct, once it's supported. This eliminates the need for inserting branches in `genFIR(Evaluation)`. Follow-up to PR #91614.
1 parent 263224e commit c1b5b7c

File tree

3 files changed

+167
-29
lines changed

3 files changed

+167
-29
lines changed

flang/lib/Lower/Bridge.cpp

Lines changed: 66 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1302,6 +1302,43 @@ class FirConverter : public Fortran::lower::AbstractConverter {
13021302
genBranch(targetEval.block);
13031303
}
13041304

1305+
/// A construct contains nested evaluations. Some of these evaluations
1306+
/// may start a new basic block, others will add code to an existing
1307+
/// block.
1308+
/// Collect the list of nested evaluations that are last in their block,
1309+
/// organize them into two sets:
1310+
/// 1. Exiting evaluations: they may need a branch exiting from their
1311+
/// parent construct,
1312+
/// 2. Fall-through evaluations: they will continue to the following
1313+
/// evaluation. They may still need a branch, but they do not exit
1314+
/// the construct. They appear in cases where the following evaluation
1315+
/// is a target of some branch.
1316+
void collectFinalEvaluations(
1317+
Fortran::lower::pft::Evaluation &construct,
1318+
llvm::SmallVector<Fortran::lower::pft::Evaluation *> &exits,
1319+
llvm::SmallVector<Fortran::lower::pft::Evaluation *> &fallThroughs) {
1320+
Fortran::lower::pft::EvaluationList &nested =
1321+
construct.getNestedEvaluations();
1322+
if (nested.empty())
1323+
return;
1324+
1325+
Fortran::lower::pft::Evaluation *exit = construct.constructExit;
1326+
Fortran::lower::pft::Evaluation *previous = &nested.front();
1327+
1328+
for (auto it = ++nested.begin(), end = nested.end(); it != end;
1329+
previous = &*it++) {
1330+
if (it->block == nullptr)
1331+
continue;
1332+
// "*it" starts a new block, check what to do with "previous"
1333+
if (it->isIntermediateConstructStmt() && previous != exit)
1334+
exits.push_back(previous);
1335+
else if (previous->lexicalSuccessor && previous->lexicalSuccessor->block)
1336+
fallThroughs.push_back(previous);
1337+
}
1338+
if (previous != exit)
1339+
exits.push_back(previous);
1340+
}
1341+
13051342
/// Generate a SelectOp or branch sequence that compares \p selector against
13061343
/// values in \p valueList and targets corresponding labels in \p labelList.
13071344
/// If no value matches the selector, branch to \p defaultEval.
@@ -2109,6 +2146,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
21092146
}
21102147

21112148
// Unstructured branch sequence.
2149+
llvm::SmallVector<Fortran::lower::pft::Evaluation *> exits, fallThroughs;
2150+
collectFinalEvaluations(eval, exits, fallThroughs);
2151+
21122152
for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
21132153
auto genIfBranch = [&](mlir::Value cond) {
21142154
if (e.lexicalSuccessor == e.controlSuccessor) // empty block -> exit
@@ -2129,6 +2169,12 @@ class FirConverter : public Fortran::lower::AbstractConverter {
21292169
genIfBranch(genIfCondition(s));
21302170
} else {
21312171
genFIR(e);
2172+
if (blockIsUnterminated()) {
2173+
if (llvm::is_contained(exits, &e))
2174+
genConstructExitBranch(*eval.constructExit);
2175+
else if (llvm::is_contained(fallThroughs, &e))
2176+
genBranch(e.lexicalSuccessor->block);
2177+
}
21322178
}
21332179
}
21342180
}
@@ -2137,11 +2183,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
21372183
Fortran::lower::pft::Evaluation &eval = getEval();
21382184
Fortran::lower::StatementContext stmtCtx;
21392185
pushActiveConstruct(eval, stmtCtx);
2186+
2187+
llvm::SmallVector<Fortran::lower::pft::Evaluation *> exits, fallThroughs;
2188+
collectFinalEvaluations(eval, exits, fallThroughs);
2189+
21402190
for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) {
21412191
if (e.getIf<Fortran::parser::EndSelectStmt>())
21422192
maybeStartBlock(e.block);
21432193
else
21442194
genFIR(e);
2195+
if (blockIsUnterminated()) {
2196+
if (llvm::is_contained(exits, &e))
2197+
genConstructExitBranch(*eval.constructExit);
2198+
else if (llvm::is_contained(fallThroughs, &e))
2199+
genBranch(e.lexicalSuccessor->block);
2200+
}
21452201
}
21462202
popActiveConstruct();
21472203
}
@@ -3007,6 +3063,10 @@ class FirConverter : public Fortran::lower::AbstractConverter {
30073063
}
30083064

30093065
pushActiveConstruct(getEval(), stmtCtx);
3066+
llvm::SmallVector<Fortran::lower::pft::Evaluation *> exits, fallThroughs;
3067+
collectFinalEvaluations(getEval(), exits, fallThroughs);
3068+
Fortran::lower::pft::Evaluation &constructExit = *getEval().constructExit;
3069+
30103070
for (Fortran::lower::pft::Evaluation &eval :
30113071
getEval().getNestedEvaluations()) {
30123072
setCurrentPosition(eval.position);
@@ -3203,6 +3263,12 @@ class FirConverter : public Fortran::lower::AbstractConverter {
32033263
} else {
32043264
genFIR(eval);
32053265
}
3266+
if (blockIsUnterminated()) {
3267+
if (llvm::is_contained(exits, &eval))
3268+
genConstructExitBranch(constructExit);
3269+
else if (llvm::is_contained(fallThroughs, &eval))
3270+
genBranch(eval.lexicalSuccessor->block);
3271+
}
32063272
}
32073273
popActiveConstruct();
32083274
}
@@ -4535,28 +4601,6 @@ class FirConverter : public Fortran::lower::AbstractConverter {
45354601
setCurrentEval(eval);
45364602
setCurrentPosition(eval.position);
45374603
eval.visit([&](const auto &stmt) { genFIR(stmt); });
4538-
4539-
// Generate an end-of-block branch for several special cases. For
4540-
// constructs, this can be done for either the end construct statement,
4541-
// or for the construct itself, which will skip this code if the
4542-
// end statement was visited first and generated a branch.
4543-
Fortran::lower::pft::Evaluation *successor = [&]() {
4544-
if (eval.isConstruct() ||
4545-
(eval.isDirective() && eval.hasNestedEvaluations()))
4546-
return eval.getLastNestedEvaluation().lexicalSuccessor;
4547-
return eval.lexicalSuccessor;
4548-
}();
4549-
4550-
if (successor && blockIsUnterminated()) {
4551-
if (successor->isIntermediateConstructStmt() &&
4552-
successor->parentConstruct->lowerAsUnstructured())
4553-
// Exit from an intermediate unstructured IF or SELECT construct block.
4554-
genBranch(successor->parentConstruct->constructExit->block);
4555-
else if (unstructuredContext && eval.isConstructStmt() &&
4556-
successor == eval.controlSuccessor)
4557-
// Exit from a degenerate, empty construct block.
4558-
genBranch(eval.parentConstruct->constructExit->block);
4559-
}
45604604
}
45614605

45624606
/// Map mlir function block arguments to the corresponding Fortran dummy
Lines changed: 70 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,88 @@
1-
!RUN: flang-new -fc1 -emit-hlfir -fopenmp -o - %s | FileCheck %s
1+
!RUN: bbc -emit-hlfir -fopenacc -fopenmp -o - %s | FileCheck %s
22

33
!https://github.com/llvm/llvm-project/issues/91526
44

5+
!CHECK-LABEL: func.func @_QPsimple1
56
!CHECK: cf.cond_br %{{[0-9]+}}, ^bb[[THEN:[0-9]+]], ^bb[[ELSE:[0-9]+]]
67
!CHECK: ^bb[[THEN]]:
7-
!CHECK: cf.br ^bb[[EXIT:[0-9]+]]
8+
!CHECK: omp.parallel
9+
!CHECK: cf.br ^bb[[ENDIF:[0-9]+]]
810
!CHECK: ^bb[[ELSE]]:
911
!CHECK: fir.call @_FortranAStopStatement
1012
!CHECK: fir.unreachable
11-
!CHECK: ^bb[[EXIT]]:
13+
!CHECK: ^bb[[ENDIF]]:
14+
!CHECK: return
1215

13-
subroutine simple(y)
16+
subroutine simple1(y)
1417
implicit none
1518
logical, intent(in) :: y
1619
integer :: i
1720
if (y) then
18-
!$omp parallel
21+
!$omp parallel
1922
i = 1
20-
!$omp end parallel
23+
!$omp end parallel
2124
else
2225
stop 1
2326
end if
24-
end subroutine simple
27+
end subroutine
28+
29+
!CHECK-LABEL: func.func @_QPsimple2
30+
!CHECK: cf.cond_br %{{[0-9]+}}, ^bb[[THEN:[0-9]+]], ^bb[[ELSE:[0-9]+]]
31+
!CHECK: ^bb[[THEN]]:
32+
!CHECK: omp.parallel
33+
!CHECK: cf.br ^bb[[ENDIF:[0-9]+]]
34+
!CHECK: ^bb[[ELSE]]:
35+
!CHECK: fir.call @_FortranAStopStatement
36+
!CHECK: fir.unreachable
37+
!CHECK: ^bb[[ENDIF]]:
38+
!CHECK: fir.call @_FortranAioOutputReal64
39+
!CHECK: return
40+
subroutine simple2(x, yn)
41+
implicit none
42+
logical, intent(in) :: yn
43+
integer, intent(in) :: x
44+
integer :: i
45+
real(8) :: E
46+
E = 0d0
47+
48+
if (yn) then
49+
!$omp parallel do private(i) reduction(+:E)
50+
do i = 1, x
51+
E = E + i
52+
end do
53+
!$omp end parallel do
54+
else
55+
stop 1
56+
end if
57+
print *, E
58+
end subroutine
59+
60+
!CHECK-LABEL: func.func @_QPacccase
61+
!CHECK: fir.select_case %{{[0-9]+}} : i32 [{{.*}}, ^bb[[CASE1:[0-9]+]], {{.*}}, ^bb[[CASE2:[0-9]+]], {{.*}}, ^bb[[CASE3:[0-9]+]]]
62+
!CHECK: ^bb[[CASE1]]:
63+
!CHECK: acc.serial
64+
!CHECK: cf.br ^bb[[EXIT:[0-9]+]]
65+
!CHECK: ^bb[[CASE2]]:
66+
!CHECK: fir.call @_FortranAioOutputAscii
67+
!CHECK: cf.br ^bb[[EXIT]]
68+
!CHECK: ^bb[[CASE3]]:
69+
!CHECK: fir.call @_FortranAioOutputAscii
70+
!CHECK: cf.br ^bb[[EXIT]]
71+
!CHECK: ^bb[[EXIT]]:
72+
!CHECK: return
73+
subroutine acccase(var)
74+
integer :: var
75+
integer :: res(10)
76+
select case (var)
77+
case (1)
78+
print *, "case 1"
79+
!$acc serial
80+
res(1) = 1
81+
!$acc end serial
82+
case (2)
83+
print *, "case 2"
84+
case default
85+
print *, "case default"
86+
end select
87+
end subroutine
2588

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
!RUN: bbc -emit-hlfir -o - %s | FileCheck %s
2+
3+
!CHECK-LABEL: func.func @_QPunstructured1
4+
!CHECK: fir.select %{{[0-9]+}} : i32 [{{.*}}, ^bb[[BLOCK3:[0-9]+]], {{.*}}, ^bb[[BLOCK4:[0-9]+]], {{.*}}, ^bb[[BLOCK5:[0-9]+]], {{.*}}, ^bb[[BLOCK1:[0-9]+]]]
5+
!CHECK: ^bb[[BLOCK1]]:
6+
!CHECK: cf.cond_br %{{[0-9]+}}, ^bb[[BLOCK2:[0-9]+]], ^bb[[BLOCK4]]
7+
!CHECK: ^bb[[BLOCK2]]:
8+
!CHECK: fir.if
9+
!CHECK: cf.br ^bb[[BLOCK3]]
10+
!CHECK: ^bb[[BLOCK3]]:
11+
!CHECK: %[[C10:[a-z0-9_]+]] = arith.constant 10 : i32
12+
!CHECK: arith.addi {{.*}}, %[[C10]]
13+
!CHECK: cf.br ^bb[[BLOCK4]]
14+
!CHECK: ^bb[[BLOCK4]]:
15+
!CHECK: %[[C100:[a-z0-9_]+]] = arith.constant 100 : i32
16+
!CHECK: arith.addi {{.*}}, %[[C100]]
17+
!CHECK: cf.br ^bb[[BLOCK5]]
18+
!CHECK: ^bb[[BLOCK5]]:
19+
!CHECK: %[[C1000:[a-z0-9_]+]] = arith.constant 1000 : i32
20+
!CHECK: arith.addi {{.*}}, %[[C1000]]
21+
!CHECK: return
22+
subroutine unstructured1(j, k)
23+
goto (11, 22, 33) j-3 ! computed goto - an expression outside [1,3] is a nop
24+
if (j == 2) goto 22
25+
if (j == 1) goto 11
26+
k = k + 1
27+
11 k = k + 10
28+
22 k = k + 100
29+
33 k = k + 1000
30+
end
31+

0 commit comments

Comments
 (0)