[flang-commits] [flang] [flang] Detect loops whose branching is confined to their body (PR #225757)

Kareem Ergawy via flang-commits flang-commits at lists.llvm.org
Tue Sep 29 04:51:47 PDT 2026


================
@@ -2750,13 +2762,225 @@ static bool isOmpLoopBody(const Fortran::lower::pft::Evaluation &eval,
   return isAssociatedLoop(chain, loop->GetNestedLoop(), n);
 }
 
+/// The evaluations forming a loop's body: everything between the loop control
+/// statements, which bracket it and are lowered outside any body wrap.
+static llvm::iterator_range<Fortran::lower::pft::EvaluationList::const_iterator>
+loopBodyRange(const Fortran::lower::pft::Evaluation &loop) {
+  const auto &list = *loop.evaluationList;
+  return llvm::make_range(std::next(list.begin()), std::prev(list.end()));
+}
+
+/// True when \p eval lies in \p loop's body rather than in its loop control.
+static bool isInLoopBody(const Fortran::lower::pft::Evaluation *eval,
+                         const Fortran::lower::pft::Evaluation &loop) {
+  if (!eval || !loop.evaluationList || loop.evaluationList->empty())
+    return false;
+  const Fortran::lower::pft::Evaluation *first = &loop.evaluationList->front();
+  const Fortran::lower::pft::Evaluation *last = &loop.evaluationList->back();
+  for (const Fortran::lower::pft::Evaluation *p = eval; p;
+       p = p->parentConstruct)
+    if (p->parentConstruct == &loop)
+      return p != first && p != last;
+  return false;
+}
+
+/// A loop that can be lowered structurally even though its body holds
+/// unstructured control flow, because that control flow is confined to the body
+/// and can be folded into an SESE region.
+///
+/// The loop qualifies when:
+///   1. every branch leaving its body lands back inside that body, and
+///   2. every branch into its body comes from inside that body,
+/// and the body holds nothing a region cannot accommodate: an infinite DO
+/// never reaches the region's yield so RegionDCE would drop it, a ReturnStmt
+/// builds the function's final block in the current region, and a listless
+/// assigned GO TO has targets that cannot be enumerated -- so condition 1
+/// cannot be decided at all rather than merely failing.
+///
+/// A CYCLE is not an escape: its target is the EndDoStmt, which is where the
+/// wrap's yield sits, so it lands on the boundary. An EXIT targets the
+/// construct exit, beyond the loop entirely, and does escape.
+/// Follow the chain of unconditional GO TOs starting at \p start and return
+/// true if it closes on itself.
+///
+/// Such a cycle has no exit edge, which makes it a statically known infinite
+/// loop. Only unconditional transfers are followed, so the answer is a
+/// certainty rather than a guess -- the same bound the cf.br canonicalization
+/// applies when it declines to collapse cyclic branches.
+static bool
+startsExitFreeGotoCycle(const Fortran::lower::pft::Evaluation &start) {
+  auto gotoTarget = [](const Fortran::lower::pft::Evaluation &e) {
+    return e.getIf<parser::GotoStmt>() ? e.controlSuccessor : nullptr;
+  };
+
+  llvm::SmallPtrSet<const Fortran::lower::pft::Evaluation *, 4> visited;
+  for (const Fortran::lower::pft::Evaluation *e = &start; e; e = gotoTarget(*e))
+    if (!visited.insert(e).second)
+      return true;
+  return false;
----------------
ergawy wrote:

d49835623395039fcec15aea6ea45c48b2776fb4 adds a worklist algorithm to detect cycles across evaluations in general not just `goto`s. It's starting point is always a `goto` inside the loop but it follows the CF across other kinds of evaluations. 

https://github.com/llvm/llvm-project/pull/225757


More information about the flang-commits mailing list