Skip to content

Commit 53a9367

Browse files
authored
Rewrite "if (cond) cycle" statements to eliminate unstructured branches (#1134)
Where valid, this rewrite is analogous to rewriting "if (cond) goto N" branches.
1 parent 5024cb3 commit 53a9367

File tree

2 files changed

+124
-15
lines changed

2 files changed

+124
-15
lines changed

flang/lib/Lower/PFTBuilder.cpp

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -410,8 +410,9 @@ class PFTBuilder {
410410
evaluationListStack.pop_back();
411411
}
412412

413-
/// Rewrite IfConstructs containing a GotoStmt to eliminate an unstructured
414-
/// branch and a trivial basic block. The pre-branch-analysis code:
413+
/// Rewrite IfConstructs containing a GotoStmt or CycleStmt to eliminate an
414+
/// unstructured branch and a trivial basic block. The pre-branch-analysis
415+
/// code:
415416
///
416417
/// <<IfConstruct>>
417418
/// 1 If[Then]Stmt: if(cond) goto L
@@ -433,8 +434,8 @@ class PFTBuilder {
433434
/// 6 Statement: L ...
434435
///
435436
/// The If[Then]Stmt condition is implicitly negated. It is not modified
436-
/// in the PFT. It must be negated when generating FIR. The GotoStmt is
437-
/// deleted.
437+
/// in the PFT. It must be negated when generating FIR. The GotoStmt or
438+
/// CycleStmt is deleted.
438439
///
439440
/// The transformation is only valid for forward branch targets at the same
440441
/// construct nesting level as the IfConstruct. The result must not violate
@@ -452,30 +453,49 @@ class PFTBuilder {
452453
using T = struct {
453454
lower::pft::EvaluationList::iterator ifConstructIt;
454455
parser::Label ifTargetLabel;
456+
bool isCycleStmt = false;
455457
};
456-
llvm::SmallVector<T> ifExpansionStack;
458+
llvm::SmallVector<T> ifCandidateStack;
457459
auto &evaluationList = *evaluationListStack.back();
458460
for (auto it = evaluationList.begin(), end = evaluationList.end();
459461
it != end; ++it) {
460462
auto &eval = *it;
461463
if (eval.isA<parser::EntryStmt>()) {
462-
ifExpansionStack.clear();
464+
ifCandidateStack.clear();
463465
continue;
464466
}
465467
auto firstStmt = [](lower::pft::Evaluation *e) {
466468
return e->isConstruct() ? &*e->evaluationList->begin() : e;
467469
};
468470
auto &targetEval = *firstStmt(&eval);
469-
if (targetEval.label) {
470-
while (!ifExpansionStack.empty() &&
471-
ifExpansionStack.back().ifTargetLabel == *targetEval.label) {
472-
auto ifConstructIt = ifExpansionStack.back().ifConstructIt;
471+
bool targetEvalIsEndDoStmt = targetEval.isA<parser::EndDoStmt>();
472+
auto branchTargetMatch = [&]() {
473+
if (auto targetLabel = ifCandidateStack.back().ifTargetLabel)
474+
if (targetLabel == *targetEval.label)
475+
return true; // goto target match
476+
if (targetEvalIsEndDoStmt && ifCandidateStack.back().isCycleStmt) {
477+
auto cycleName = ifCandidateStack.back().ifConstructIt->visit(
478+
[&](const auto &stmt) { return getConstructName(stmt); });
479+
if (cycleName.empty())
480+
return true; // anonymous cycle target match
481+
auto doName = eval.visit(
482+
[&](const auto &stmt) { return getConstructName(stmt); });
483+
if (cycleName == doName)
484+
return true; // named cycle target match
485+
}
486+
return false;
487+
};
488+
if (targetEval.label || targetEvalIsEndDoStmt) {
489+
while (!ifCandidateStack.empty() && branchTargetMatch()) {
490+
auto ifConstructIt = ifCandidateStack.back().ifConstructIt;
473491
auto successorIt = std::next(ifConstructIt);
474492
if (successorIt != it) {
475493
auto &ifBodyList = *ifConstructIt->evaluationList;
476-
auto gotoStmtIt = std::next(ifBodyList.begin());
477-
assert(gotoStmtIt->isA<parser::GotoStmt>() && "expected GotoStmt");
478-
ifBodyList.erase(gotoStmtIt);
494+
auto branchStmtIt = std::next(ifBodyList.begin());
495+
assert((branchStmtIt->isA<parser::GotoStmt>() ||
496+
branchStmtIt->isA<parser::CycleStmt>()) &&
497+
"expected goto or cycle statement");
498+
ifBodyList.erase(branchStmtIt);
479499
auto &ifStmt = *ifBodyList.begin();
480500
ifStmt.negateCondition = true;
481501
ifStmt.lexicalSuccessor = firstStmt(&*successorIt);
@@ -486,13 +506,16 @@ class PFTBuilder {
486506
for (; successorIt != endIfStmtIt; ++successorIt)
487507
successorIt->parentConstruct = &*ifConstructIt;
488508
}
489-
ifExpansionStack.pop_back();
509+
ifCandidateStack.pop_back();
490510
}
491511
}
492512
if (eval.isA<parser::IfConstruct>() && eval.evaluationList->size() == 3) {
493513
if (auto *gotoStmt = std::next(eval.evaluationList->begin())
494514
->getIf<parser::GotoStmt>())
495-
ifExpansionStack.push_back({it, gotoStmt->v});
515+
ifCandidateStack.push_back({it, gotoStmt->v});
516+
else if (std::next(eval.evaluationList->begin())
517+
->isA<parser::CycleStmt>())
518+
ifCandidateStack.push_back({it, {}, true});
496519
}
497520
}
498521
}

flang/test/Lower/ifconvert.f90

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
! RUN: bbc -fdebug-dump-pre-fir %s |& FileCheck %s
2+
3+
! Note: PFT dump output is fairly stable, including node indexes and
4+
! annotations, so all output is CHECKed.
5+
6+
! CHECK: 1 Program <anonymous>
7+
! CHECK: 1 PrintStmt: print*
8+
print*
9+
10+
! CHECK: <<DoConstruct>> -> 8
11+
! CHECK: 2 NonLabelDoStmt -> 7: do i = 1, 5
12+
! CHECK: <<IfConstruct>> -> 7
13+
! CHECK: 3 ^IfStmt [negate] -> 7: if(i <= 1 .or. i >= 5) cycle
14+
! CHECK: 6 ^PrintStmt: print*, i
15+
! CHECK: 5 EndIfStmt
16+
! CHECK: <<End IfConstruct>>
17+
! CHECK: 7 EndDoStmt -> 2: end do
18+
! CHECK: <<End DoConstruct>>
19+
do i = 1, 5
20+
if (i <= 1 .or. i >= 5) cycle
21+
print*, i
22+
end do
23+
24+
! CHECK: 8 PrintStmt: print*
25+
print*
26+
27+
! CHECK: <<DoConstruct>> -> 15
28+
! CHECK: 9 NonLabelDoStmt -> 14: do i = 1, 5
29+
! CHECK: <<IfConstruct>> -> 14
30+
! CHECK: 10 ^IfStmt [negate] -> 14: if(i <= 1 .or. i >= 5) cycle
31+
! CHECK: 13 ^PrintStmt: print*, i
32+
! CHECK: 12 EndIfStmt
33+
! CHECK: <<End IfConstruct>>
34+
! CHECK: 14 EndDoStmt -> 9: 2 end do
35+
! CHECK: <<End DoConstruct>>
36+
do i = 1, 5
37+
if (i <= 1 .or. i >= 5) cycle
38+
print*, i
39+
2 end do
40+
41+
! CHECK: 15 PrintStmt: print*
42+
print*
43+
44+
! CHECK: <<DoConstruct>> -> 25
45+
! CHECK: 16 NonLabelDoStmt -> 24: abc: do i = 1, 5
46+
! CHECK: <<IfConstruct>> -> 24
47+
! CHECK: 17 ^IfStmt [negate] -> 24: if(i <= 1 .or. i >= 5) cycle abc
48+
! CHECK: <<IfConstruct>> -> 24
49+
! CHECK: 20 ^IfStmt [negate] -> 24: if(i == 3) goto 3
50+
! CHECK: 23 ^PrintStmt: print*, i
51+
! CHECK: 22 EndIfStmt
52+
! CHECK: <<End IfConstruct>>
53+
! CHECK: 19 EndIfStmt
54+
! CHECK: <<End IfConstruct>>
55+
! CHECK: 24 EndDoStmt -> 16: 3 end do abc
56+
! CHECK: <<End DoConstruct>>
57+
abc: do i = 1, 5
58+
if (i <= 1 .or. i >= 5) cycle abc
59+
if (i == 3) goto 3
60+
print*, i
61+
3 end do abc
62+
63+
! CHECK: 25 PrintStmt: print*
64+
print*
65+
66+
! CHECK: <<DoConstruct>> -> 35
67+
! CHECK: 26 NonLabelDoStmt -> 34: do i = 1, 5
68+
! CHECK: <<IfConstruct>> -> 34
69+
! CHECK: 27 ^IfStmt [negate] -> 34: if(i == 3) goto 4
70+
! CHECK: <<IfConstruct>> -> 34
71+
! CHECK: 30 ^IfStmt [negate] -> 34: if(i <= 1 .or. i >= 5) cycle
72+
! CHECK: 33 ^PrintStmt: print*, i
73+
! CHECK: 32 EndIfStmt
74+
! CHECK: <<End IfConstruct>>
75+
! CHECK: 29 EndIfStmt
76+
! CHECK: <<End IfConstruct>>
77+
! CHECK: 34 EndDoStmt -> 26: 4 end do
78+
! CHECK: <<End DoConstruct>>
79+
! CHECK: 35 EndProgramStmt: end
80+
! CHECK: End Program <anonymous>
81+
do i = 1, 5
82+
if (i == 3) goto 4
83+
if (i <= 1 .or. i >= 5) cycle
84+
print*, i
85+
4 end do
86+
end

0 commit comments

Comments
 (0)