[flang-commits] [flang] [flang] Keep a loop unstructured when its END DO is branched to from outside (PR #227597)
Kareem Ergawy via flang-commits
flang-commits at lists.llvm.org
Wed Sep 30 01:07:43 PDT 2026
https://github.com/ergawy created https://github.com/llvm/llvm-project/pull/227597
A loop whose body branching is self-contained is lowered structurally, with the body folded into a region. Its END DO is not part of that body: it becomes the structured loop's terminator rather than a block of its own. A branch from outside the loop targeting a label on the END DO therefore had nothing to land on, and lowering crashed.
Such a loop no longer qualifies for that form. A branch from within the body is unaffected: it is CYCLE-like and lands on the boundary the structured form already provides.
>From 74a63eb67359ddadb79d30d7384bbc1096f00571 Mon Sep 17 00:00:00 2001
From: ergawy <kareem.ergawy at gmail.com>
Date: Wed, 30 Sep 2026 01:05:52 -0700
Subject: [PATCH] [flang] Keep a loop unstructured when its END DO is branched
to from outside
A loop whose body branching is self-contained is lowered structurally, with the
body folded into a region. Its END DO is not part of that body: it becomes the
structured loop's terminator rather than a block of its own. A branch from
outside the loop targeting a label on the END DO therefore had nothing to land
on, and lowering crashed.
Such a loop no longer qualifies for that form. A branch from within the body is
unaffected: it is CYCLE-like and lands on the boundary the structured form
already provides.
---
flang/lib/Lower/PFTBuilder.cpp | 12 +++++
.../test/Lower/do-loop-branch-to-loop-end.f90 | 47 +++++++++++++++++++
2 files changed, 59 insertions(+)
create mode 100644 flang/test/Lower/do-loop-branch-to-loop-end.f90
diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index 2f665a6cbf693..d1fbf4e07e313 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -2987,6 +2987,18 @@ static bool isStructurableWithUnstructuredInternals(
if (!check(e))
return false;
+ // Condition 2 reaches the EndDoStmt too, with a wider notion of "outside". A
+ // branch from the body to it is CYCLE-like and lands on the wrap's boundary,
+ // which the structured form expresses. A branch from outside the loop is a
+ // different matter: the EndDoStmt is emitted as the structured loop's
+ // terminator, so no block is created for it and lowering has nothing to
+ // branch to.
+ if (auto it = unit.incomingBranches.find(&loop.evaluationList->back());
+ it != unit.incomingBranches.end())
+ for (const Fortran::lower::pft::Evaluation *src : it->second)
+ if (!isInLoopBody(src, loop))
+ return false;
+
return true;
}
diff --git a/flang/test/Lower/do-loop-branch-to-loop-end.f90 b/flang/test/Lower/do-loop-branch-to-loop-end.f90
new file mode 100644
index 0000000000000..7f71b91c15321
--- /dev/null
+++ b/flang/test/Lower/do-loop-branch-to-loop-end.f90
@@ -0,0 +1,47 @@
+! RUN: bbc -emit-fir -o - %s | FileCheck %s
+
+! A loop whose body branching is self-contained keeps its structured form, with
+! the body folded into an scf.execute_region. The EndDoStmt is not part of that
+! body: it is emitted as the structured loop's terminator, so no block is
+! created for it.
+!
+! That is fine for a branch from the body, which is CYCLE-like and lands on the
+! wrap's boundary. A branch from outside the loop has nowhere to land, so such a
+! loop stays unstructured and is lowered as raw blocks.
+
+! The GOTO targets the EndDoStmt from outside the loop.
+subroutine branch_to_loop_end(a)
+ real :: a(10)
+ integer :: i
+ do i = 1, 10
+ a(i) = 0.0
+20 end do
+ go to 20
+end subroutine
+
+! CHECK-LABEL: func.func @_QPbranch_to_loop_end
+! Raw blocks, so the branch has a block to target.
+! CHECK: cf.br ^bb1
+! CHECK: ^bb1:
+! CHECK-NOT: fir.do_loop
+! CHECK-NOT: scf.execute_region
+
+! The same branch from inside the body is CYCLE-like, so the loop keeps its
+! structured form. The ASSIGN makes a body statement a new block, so the body is
+! wrapped.
+subroutine cycle_to_loop_end(a, b)
+ real :: a(10), b(10)
+ integer :: i, m
+ do 42 i = 1, 10
+ assign 41 to m
+41 a(i) = b(i)
+ go to 42
+42 end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPcycle_to_loop_end
+! CHECK: fir.do_loop
+! CHECK: scf.execute_region no_inline {
+! CHECK: scf.yield
+! CHECK: }
+! CHECK: }
More information about the flang-commits
mailing list