[llvm-branch-commits] [flang] [flang] Detect loops whose branching is confined to their body (PR #225757)
Kareem Ergawy via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Sep 24 02:58:14 PDT 2026
================
@@ -2750,13 +2762,169 @@ 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.
+static bool isStructurableWithUnstructuredInternals(
+ const Fortran::lower::pft::Evaluation &loop,
+ const Fortran::lower::pft::FunctionLikeUnit &unit) {
+
+ if (!loop.isUnstructured() || !loop.evaluationList ||
+ loop.evaluationList->size() < 3)
+ return false;
+
+ // Only an increment loop keeps all of its control outside the body. A DO
+ // WHILE or an infinite DO lowers through a header block and a back edge, and
+ // a do concurrent has no plain bounds triple either, so in each case the
+ // loop's own control flow runs through the body a wrap would cover.
+ const auto *doConstruct = loop.getIf<parser::DoConstruct>();
+ if (!doConstruct)
+ return false;
+
+ const auto &loopControl = doConstruct->GetLoopControl();
+ if (!loopControl)
+ return false;
+
+ const auto *bounds =
+ std::get_if<parser::LoopControl::Bounds>(&loopControl->u);
+ if (!bounds)
+ return false;
+
+ // A REAL control variable does not lower to fir.do_loop, whose induction
+ // variable must be a signless integer or index, so such a loop is lowered as
+ // raw CFG whatever its body looks like.
+ const semantics::Symbol *ctrlVar = bounds->Name().thing.symbol;
+ if (!ctrlVar)
+ return false;
+
+ const semantics::DeclTypeSpec *ctrlType = ctrlVar->GetType();
+ if (!ctrlType || ctrlType->category() != semantics::DeclTypeSpec::Numeric ||
+ ctrlType->numericTypeSpec().category() != common::TypeCategory::Integer)
+ return false;
+
+ const Fortran::lower::pft::Evaluation *endDoStmt =
+ &loop.evaluationList->back();
+
+ auto isInfiniteDo = [](const parser::DoConstruct *d) {
+ return d && !d->GetLoopControl().has_value();
+ };
+
+ auto targetEscapes = [&](const Fortran::lower::pft::Evaluation *target) {
+ return target != endDoStmt && !isInLoopBody(target, loop);
+ };
+
+ std::function<bool(const Fortran::lower::pft::Evaluation &)> check =
+ [&](const Fortran::lower::pft::Evaluation &e) -> bool {
+ if (e.isA<parser::ReturnStmt>() ||
+ isInfiniteDo(e.getIf<parser::DoConstruct>()))
+ return false;
+
+ if (const auto *g = e.getIf<parser::AssignedGotoStmt>())
+ if (std::get<std::list<parser::Label>>(g->t).empty())
+ return false;
----------------
ergawy wrote:
Updated in d952cf0f41eb3c57bc2ebd6bb2d08c8441c44e58.
https://github.com/llvm/llvm-project/pull/225757
More information about the llvm-branch-commits
mailing list