[flang-commits] [flang] [flang][PFT-to-MLIR] Wrap unstructured Fortran constructs in scf.execute_region (PR #208635)
via flang-commits
flang-commits at lists.llvm.org
Fri Jul 10 00:12:28 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-openacc
@llvm/pr-subscribers-flang-fir-hlfir
Author: Kareem Ergawy (ergawy)
<details>
<summary>Changes</summary>
Extend the PFT-to-MLIR (HLFIR/FIR) lowering so unstructured DO and IF constructs are emitted inside scf.execute_region, hiding their multi-block CFG behind a single op. OpenACC and OpenMP lowerings that reject multi-block content (e.g. the "unstructured do loop in combined acc construct" TODO in OpenACC.cpp) now see a structured op instead.
Flag: -mmlir --wrap-unstructured-constructs-in-execute-region (default on).
An evaluation is wrappable iff all of the following hold:
* wrap flag on
* eval is parser::DoConstruct or parser::IfConstruct
* eval.isUnstructured
* branchesAreInternal(eval) -- every controlSuccessor in the subtree targets a nested eval or the constructExit
* !hasIncomingBranch(eval) -- no outside eval branches into the body (PFT's synthetic IfConstruct around `if(c) goto X` absorbs label targets between the IF and X; the incoming-branch check excludes such wrappers when an outer GOTO names one of those labels)
* does not contain a ReturnStmt -- its lowering creates the function's final block in the current region, which would mis-parent func.return
* not an infinite DO and does not contain one (no LoopControl in any nested DO): the wrap's yield is unreachable and the body has no write-shaped side effects, so RegionDCE treats the wrap as trivially dead and drops it. Excluding the whole enclosing construct keeps such infinite loops visible in the parent CFG.
* not the body DO of an enclosing OpenACCLoopConstruct or OpenACCCombinedConstruct -- nor one of the N collapsed iterator DOs reached by walking down through `collapse(N)`. Such DOs are driven directly into acc.loop by the OpenACC lowering, so wrapping them would hide the iteration from the acc.loop op.
Diagnostics
-----------
Emit per-wrap and per-function diagnostics on stderr so the wrapping is observable from a single compile invocation:
[wrap-unstructured] wrapped DO at <loc>
[wrap-unstructured] wrapped IF at <loc>
[wrap-unstructured] summary: N execute_region(s) wrapping unstructured
constructs at <loc>
The counter is reset per function and the summary is suppressed when no wraps fire.
Co-authored-by: Claude Opus 4.7 <noreply@<!-- -->anthropic.com>
---
Patch is 96.06 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/208635.diff
27 Files Affected:
- (modified) flang/include/flang/Lower/PFTBuilder.h (+10)
- (modified) flang/lib/Lower/Bridge.cpp (+101-2)
- (modified) flang/lib/Lower/PFTBuilder.cpp (+234-2)
- (modified) flang/lib/Lower/Runtime.cpp (+6-2)
- (modified) flang/test/HLFIR/assumed_shape_with_value_keyword.f90 (+10-7)
- (modified) flang/test/HLFIR/optional_dummy.f90 (+12-11)
- (modified) flang/test/Integration/OpenMP/parallel-private-reduction-worstcase.f90 (+2-1)
- (modified) flang/test/Lower/HLFIR/intrinsic-subroutines.f90 (+22-19)
- (modified) flang/test/Lower/MIF/change_team2.f90 (+15-12)
- (modified) flang/test/Lower/OpenACC/Todo/acc-unstructured-combined-construct.f90 (+2-62)
- (modified) flang/test/Lower/OpenACC/Todo/do-loops-to-acc-loops-todo.f90 (-19)
- (modified) flang/test/Lower/OpenACC/acc-terminator.f90 (+2-1)
- (modified) flang/test/Lower/OpenACC/acc-unstructured.f90 (+177-24)
- (modified) flang/test/Lower/OpenMP/loop-compound.f90 (+17-13)
- (modified) flang/test/Lower/OpenMP/parallel-reduction3.f90 (+16-13)
- (modified) flang/test/Lower/OpenMP/stop-stmt-in-region.f90 (+37-32)
- (modified) flang/test/Lower/OpenMP/unstructured.f90 (+103-102)
- (modified) flang/test/Lower/OpenMP/wsloop-unstructured.f90 (+17-18)
- (modified) flang/test/Lower/branching-directive.f90 (+42-3)
- (added) flang/test/Lower/do_loop_execute_region_wrap.f90 (+111)
- (modified) flang/test/Lower/do_loop_unstructured.f90 (+38-87)
- (modified) flang/test/Lower/fail_image.f90 (+10-9)
- (modified) flang/test/Lower/ifconvert.f90 (+3-3)
- (modified) flang/test/Lower/mixed_loops.f90 (+47-61)
- (modified) flang/test/Lower/nsw.f90 (+10-9)
- (modified) flang/test/Lower/pre-fir-tree02.f90 (+2-2)
- (modified) flang/test/Lower/while_loop.f90 (+12-3)
``````````diff
diff --git a/flang/include/flang/Lower/PFTBuilder.h b/flang/include/flang/Lower/PFTBuilder.h
index 0aabd8e642e44..cb23c6ea5686a 100644
--- a/flang/include/flang/Lower/PFTBuilder.h
+++ b/flang/include/flang/Lower/PFTBuilder.h
@@ -874,6 +874,16 @@ void visitAllSymbols(const FunctionLikeUnit &funit,
void visitAllSymbols(const Evaluation &eval,
std::function<void(const semantics::Symbol &)> callBack);
+/// Return true if every control-flow successor nested under \p construct
+/// points to an evaluation that is itself nested under \p construct or is \p
+/// construct's own constructExit. A false return means at least one branch
+/// leaves the construct (e.g. a GOTO to an outer label).
+bool branchesAreInternal(const Evaluation &construct);
+
+/// Return true when \p eval is an unstructured DO or IF construct that can
+/// folded into a self-contained scf.execute_region.
+bool isWrappableConstruct(const Evaluation &eval);
+
} // namespace Fortran::lower::pft
namespace Fortran::lower {
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 8658a6fb29a44..8aaf47c64d6c4 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -2536,6 +2536,50 @@ class FirConverter : public Fortran::lower::AbstractConverter {
}
}
+ /// Wrap an unstructured construct's CFG in a self-contained
+ /// scf.execute_region and set the builder insertion point inside it. Returns
+ /// the created op (null if the construct isn't wrappable).
+ mlir::scf::ExecuteRegionOp
+ wrapUnstructuredConstruct(Fortran::lower::pft::Evaluation &eval,
+ mlir::Block *&savedExitBlock) {
+ if (!Fortran::lower::pft::isWrappableConstruct(eval))
+ return nullptr;
+
+ mlir::Location loc = toLocation();
+ auto wrapOp =
+ mlir::scf::ExecuteRegionOp::create(*builder, loc, mlir::TypeRange{},
+ /*noInline=*/builder->getUnitAttr());
+ ++wrapUnstructuredCount;
+ mlir::Block *entry = builder->createBlock(&wrapOp.getRegion());
+ builder->setInsertionPointToEnd(entry);
+ createEmptyBlocks(eval.getNestedEvaluations());
+ mlir::Block *yieldBlock = builder->createBlock(&wrapOp.getRegion());
+ builder->setInsertionPointToEnd(yieldBlock);
+ mlir::scf::YieldOp::create(*builder, loc);
+
+ if (eval.constructExit) {
+ savedExitBlock = eval.constructExit->block;
+ eval.constructExit->block = yieldBlock;
+ }
+
+ builder->setInsertionPointToEnd(entry);
+ return wrapOp;
+ }
+
+ /// Finalize a wrap created by wrapUnstructuredConstruct: restore the
+ /// original exit block and set the insertion point after the wrap op.
+ void closeUnstructuredWrap(mlir::scf::ExecuteRegionOp wrapOp,
+ Fortran::lower::pft::Evaluation &eval,
+ mlir::Block *savedExitBlock) {
+ if (!wrapOp)
+ return;
+
+ if (eval.constructExit)
+ eval.constructExit->block = savedExitBlock;
+
+ builder->setInsertionPointAfter(wrapOp);
+ }
+
/// Generate FIR for a DO construct. There are six variants:
/// - unstructured infinite and while loops
/// - structured and unstructured increment loops
@@ -2545,6 +2589,19 @@ class FirConverter : public Fortran::lower::AbstractConverter {
Fortran::lower::pft::Evaluation &eval = getEval();
bool unstructuredContext = eval.lowerAsUnstructured();
+ mlir::Block *savedExitBlock = nullptr;
+ mlir::scf::ExecuteRegionOp wrapOp =
+ unstructuredContext ? wrapUnstructuredConstruct(eval, savedExitBlock)
+ : nullptr;
+
+ if (wrapOp) {
+ LLVM_DEBUG({
+ llvm::dbgs() << "[wrap-unstructured] wrapped DO at ";
+ wrapOp.getLoc().print(llvm::dbgs());
+ llvm::dbgs() << "\n";
+ });
+ }
+
// If this do-loop was absorbed by a collapse clause on a parent acc.loop,
// skip generating any loop — just lower the body. The IV value is
// already available from the parent acc.loop's block argument.
@@ -2717,6 +2774,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
for (IncrementLoopInfo &info : incrementLoopNestInfo)
if (auto loopOp = mlir::dyn_cast_if_present<fir::DoLoopOp>(info.loopOp))
attachAttributesToDoLoopOperations(loopOp, doStmtEval.dirs);
+
+ closeUnstructuredWrap(wrapOp, eval, savedExitBlock);
}
/// Generate FIR to evaluate loop control values (lower, upper and step).
@@ -3195,7 +3254,18 @@ class FirConverter : public Fortran::lower::AbstractConverter {
return;
}
- // Unstructured branch sequence.
+ mlir::Block *savedExitBlock = nullptr;
+ mlir::scf::ExecuteRegionOp wrapOp =
+ wrapUnstructuredConstruct(eval, savedExitBlock);
+
+ if (wrapOp) {
+ LLVM_DEBUG({
+ llvm::dbgs() << "[wrap-unstructured] wrapped IF at ";
+ wrapOp.getLoc().print(llvm::dbgs());
+ llvm::dbgs() << "\n";
+ });
+ }
+
llvm::SmallVector<Fortran::lower::pft::Evaluation *> exits, fallThroughs;
collectFinalEvaluations(eval, exits, fallThroughs);
@@ -3227,6 +3297,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
}
}
}
+
+ closeUnstructuredWrap(wrapOp, eval, savedExitBlock);
}
void genCaseOrRankConstruct() {
@@ -6414,7 +6486,16 @@ class FirConverter : public Fortran::lower::AbstractConverter {
if (eval.isNewBlock)
eval.block = builder->createBlock(region);
if (eval.isConstruct() || eval.isDirective()) {
- if (eval.lowerAsUnstructured()) {
+ if (Fortran::lower::pft::isWrappableConstruct(eval)) {
+ // The wrap owns internal blocks; only create the entry block here
+ // so the enclosing CFG can branch to it.
+ if (eval.hasNestedEvaluations()) {
+ Fortran::lower::pft::Evaluation &constructStmt =
+ eval.getFirstNestedEvaluation();
+ if (constructStmt.isNewBlock)
+ constructStmt.block = builder->createBlock(region);
+ }
+ } else if (eval.lowerAsUnstructured()) {
createEmptyBlocks(eval.getNestedEvaluations());
} else if (eval.hasNestedEvaluations()) {
// A structured construct that is a target starts a new block.
@@ -6596,8 +6677,21 @@ class FirConverter : public Fortran::lower::AbstractConverter {
entryIndex < last; ++entryIndex) {
funit.setActiveEntry(entryIndex);
startNewFunction(funit); // the entry point for lowering this procedure
+ wrapUnstructuredCount = 0;
+
for (Fortran::lower::pft::Evaluation &eval : funit.evaluationList)
genFIR(eval);
+
+ if (wrapUnstructuredCount > 0) {
+ LLVM_DEBUG({
+ llvm::dbgs()
+ << "[wrap-unstructured] summary: " << wrapUnstructuredCount
+ << " execute_region(s) wrapping unstructured constructs at ";
+ toLocation().print(llvm::dbgs());
+ llvm::dbgs() << "\n";
+ });
+ }
+
endNewFunction(funit);
}
funit.setActiveEntry(0);
@@ -7004,6 +7098,11 @@ class FirConverter : public Fortran::lower::AbstractConverter {
Fortran::parser::CharBlock currentPosition;
TypeInfoConverter typeInfoConverter;
+ /// Counter of `scf.execute_region` ops created when
+ /// `--wrap-unstructured-constructs-in-execute-region` is enabled for the
+ /// currently-lowered function.
+ unsigned wrapUnstructuredCount = 0;
+
// Stack to manage object deallocation and finalization at construct exits.
llvm::SmallVector<ConstructContext> activeConstructStack;
diff --git a/flang/lib/Lower/PFTBuilder.cpp b/flang/lib/Lower/PFTBuilder.cpp
index 0af0ff9e7d758..fae120e742b23 100644
--- a/flang/lib/Lower/PFTBuilder.cpp
+++ b/flang/lib/Lower/PFTBuilder.cpp
@@ -17,6 +17,7 @@
#include "llvm/ADT/IntervalMap.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
+#include <limits>
#define DEBUG_TYPE "flang-pft"
@@ -24,6 +25,11 @@ static llvm::cl::opt<bool> clDisableStructuredFir(
"no-structured-fir", llvm::cl::desc("disable generation of structured FIR"),
llvm::cl::init(false), llvm::cl::Hidden);
+llvm::cl::opt<bool> wrapUnstructuredConstructsInExecuteRegion(
+ "wrap-unstructured-constructs-in-execute-region", llvm::cl::init(true),
+ llvm::cl::desc("try to wrap unstructured constructs' CFGs in "
+ "self-contained MLIR regions"));
+
using namespace Fortran;
namespace {
@@ -1213,8 +1219,11 @@ class PFTBuilder {
if (eval.evaluationList)
analyzeBranches(&eval, *eval.evaluationList);
- // Propagate isUnstructured flag to enclosing construct.
- if (parentConstruct && eval.isUnstructured)
+ // Propagate isUnstructured flag to enclosing construct -- unless the
+ // wrap pass will fold this construct into a self-contained
+ // scf.execute_region, in which case the parent sees only a single op.
+ if (parentConstruct && eval.isUnstructured &&
+ !lower::pft::isWrappableConstruct(eval))
parentConstruct->isUnstructured = true;
// The successor of a branch starts a new block.
@@ -2334,3 +2343,226 @@ void Fortran::lower::pft::visitAllSymbols(
parser::Walk(functionParserNode, visitor);
});
}
+
+/// True if \p target lies within \p construct. In `strict` mode, a null
+/// target and the construct's own exit block count as *outside*; in
+/// non-strict mode they count as *inside* (a natural fall-through that
+/// doesn't leave the construct).
+static bool isInsideConstruct(const Fortran::lower::pft::Evaluation *target,
+ const Fortran::lower::pft::Evaluation &construct,
+ bool strict) {
+ if (!target)
+ return !strict;
+
+ if (target == construct.constructExit)
+ return !strict;
+
+ for (const Fortran::lower::pft::Evaluation *p = target; p;
+ p = p->parentConstruct)
+ if (p == &construct)
+ return true;
+
+ return false;
+}
+
+bool Fortran::lower::pft::branchesAreInternal(
+ const Fortran::lower::pft::Evaluation &construct) {
+ std::function<bool(const Fortran::lower::pft::EvaluationList &)> walk =
+ [&](const Fortran::lower::pft::EvaluationList &list) -> bool {
+ for (const Fortran::lower::pft::Evaluation &nested : list) {
+ if (nested.controlSuccessor &&
+ !isInsideConstruct(nested.controlSuccessor, construct,
+ /*strict=*/false))
+ return false;
+
+ if (nested.evaluationList && !walk(*nested.evaluationList))
+ return false;
+ }
+
+ return true;
+ };
+
+ if (!construct.evaluationList)
+ return false;
+
+ return walk(*construct.evaluationList);
+}
+
+/// True if any eval outside \p construct branches strictly inside it.
+/// Such branches would cross the scf.execute_region boundary at lowering.
+static bool
+hasIncomingBranch(const Fortran::lower::pft::Evaluation &construct) {
+ const Fortran::lower::pft::FunctionLikeUnit *funit =
+ construct.getOwningProcedure();
+ if (!funit)
+ return false;
+
+ std::function<bool(const Fortran::lower::pft::EvaluationList &)> walk =
+ [&](const Fortran::lower::pft::EvaluationList &list) -> bool {
+ for (const Fortran::lower::pft::Evaluation &e : list) {
+ if (!isInsideConstruct(&e, construct, /*strict=*/true) &&
+ e.controlSuccessor &&
+ isInsideConstruct(e.controlSuccessor, construct, /*strict=*/true))
+ return true;
+
+ if (e.evaluationList && walk(*e.evaluationList))
+ return true;
+ }
+
+ return false;
+ };
+
+ // TODO: This is potentially expensive and we might need to prevent running
+ // this walk more than once somehow.
+ return walk(funit->evaluationList);
+}
+
+/// True for a `do; end do` (no bounds, no while-condition), or for any
+/// construct that contains one. Such bodies can't reach the wrap's yield
+/// block, and the wrap has only reads/branches inside — RegionDCE then drops
+/// the whole scf.execute_region. Excluding the entire enclosing construct
+/// keeps the infinite loop visible in the parent CFG.
+static bool
+containsInfiniteDoConstruct(const Fortran::lower::pft::Evaluation &eval) {
+ auto isInfinite = [](const parser::DoConstruct *d) {
+ return d && !d->GetLoopControl().has_value();
+ };
+
+ if (isInfinite(eval.getIf<parser::DoConstruct>()))
+ return true;
+
+ if (!eval.evaluationList)
+ return false;
+
+ std::function<bool(const Fortran::lower::pft::EvaluationList &)> walk =
+ [&](const Fortran::lower::pft::EvaluationList &list) -> bool {
+ for (const Fortran::lower::pft::Evaluation &e : list) {
+ if (isInfinite(e.getIf<parser::DoConstruct>()))
+ return true;
+
+ if (e.evaluationList && walk(*e.evaluationList))
+ return true;
+ }
+
+ return false;
+ };
+
+ return walk(*eval.evaluationList);
+}
+
+/// True if \p eval is a DoConstruct driven directly into an enclosing acc.loop
+/// by the OpenACCLoopConstruct / OpenACCCombinedConstruct lowering — the
+/// immediate body DO, or one of the N collapsed iterator DOs reached by
+/// walking down from the body DO under a `collapse(N)` clause.
+static bool isAccLoopBody(const Fortran::lower::pft::Evaluation &eval) {
+ const auto *doConstruct = eval.getIf<parser::DoConstruct>();
+ if (!doConstruct)
+ return false;
+ // N from `collapse(N)`, or 1 if no clause. eval at depth d from the body
+ // (d == 0 means eval IS the body) is a collapsed iterator iff d < N. If the
+ // Collapse value isn't a compile-time constant, be conservative and treat
+ // every DO in the chain as collapsed (INT64_MAX) — wrapping is opt-in and
+ // a false "is collapsed" is safer than a false "is not".
+ auto collapseN = [](const parser::AccClauseList &cl) -> int64_t {
+ for (const parser::AccClause &c : cl.v)
+ if (const auto *cc = std::get_if<parser::AccClause::Collapse>(&c.u)) {
+ const auto &intExpr = std::get<parser::ScalarIntConstantExpr>(cc->v.t);
+ if (const auto *expr = semantics::GetExpr(intExpr))
+ if (auto v = evaluate::ToInt64(*expr))
+ return *v;
+ return std::numeric_limits<int64_t>::max();
+ }
+ return 1;
+ };
+
+ // candidates[k] is the DoConstruct at depth k above (and including) eval.
+ llvm::SmallVector<const parser::DoConstruct *, 4> candidates{doConstruct};
+
+ for (const Fortran::lower::pft::Evaluation *p = eval.parentConstruct; p;
+ p = p->parentConstruct) {
+ if (const auto *d = p->getIf<parser::DoConstruct>()) {
+ candidates.push_back(d);
+ continue;
+ }
+
+ if (const auto *acc = p->getIf<parser::OpenACCConstruct>()) {
+ const parser::DoConstruct *body = nullptr;
+ int64_t n = 1;
+ if (const auto *loop =
+ std::get_if<parser::OpenACCLoopConstruct>(&acc->u)) {
+ if (const auto &b =
+ std::get<std::optional<parser::DoConstruct>>(loop->t))
+ body = &b.value();
+ n = collapseN(std::get<parser::AccClauseList>(std::get<0>(loop->t).t));
+ } else if (const auto *comb =
+ std::get_if<parser::OpenACCCombinedConstruct>(&acc->u)) {
+ if (const auto &b =
+ std::get<std::optional<parser::DoConstruct>>(comb->t))
+ body = &b.value();
+ n = collapseN(std::get<parser::AccClauseList>(std::get<0>(comb->t).t));
+ }
+
+ if (body) {
+ // body is at index `candidates.size()-1` (the outermost candidate);
+ // eval at depth (candidates.size()-1) from body. Collapsed iff < N.
+ auto it = llvm::find(candidates, body);
+ if (it != candidates.end()) {
+ int64_t depth = std::distance(candidates.begin(), it);
+ if (depth < n)
+ return true;
+ }
+ }
+ }
+
+ break;
+ }
+
+ return false;
+}
+
+/// True if any nested eval is a ReturnStmt. Its lowering creates the
+/// function's final block in the current region, which would mis-parent
+/// the func.return if that region is the wrap's.
+static bool
+containsReturnStmt(const Fortran::lower::pft::Evaluation &construct) {
+ if (!construct.evaluationList)
+ return false;
+
+ std::function<bool(const Fortran::lower::pft::EvaluationList &)> walk =
+ [&](const Fortran::lower::pft::EvaluationList &list) -> bool {
+ for (const Fortran::lower::pft::Evaluation &e : list) {
+ if (e.isA<parser::ReturnStmt>())
+ return true;
+
+ if (e.evaluationList && walk(*e.evaluationList))
+ return true;
+ }
+
+ return false;
+ };
+
+ return walk(*construct.evaluationList);
+}
+
+bool Fortran::lower::pft::isWrappableConstruct(
+ const Fortran::lower::pft::Evaluation &eval) {
+ if (!wrapUnstructuredConstructsInExecuteRegion)
+ return false;
+
+ if (!eval.isUnstructured)
+ return false;
+
+ if (!(eval.isA<Fortran::parser::DoConstruct>() ||
+ eval.isA<Fortran::parser::IfConstruct>()))
+ return false;
+
+ // Wrapping requires self-contained CFG.
+ //
+ // Note: Loops attached to OpenACC constructs are not wrappable since
+ // genOpenACCLoopFromDoConstruct takes over code-gen when a DoConstruct is
+ // attached to an OpenACC directive. We might extend wrapping to such
+ // unstructured loops later on if needed.
+ return Fortran::lower::pft::branchesAreInternal(eval) &&
+ !hasIncomingBranch(eval) && !containsReturnStmt(eval) &&
+ !containsInfiniteDoConstruct(eval) && !isAccLoopBody(eval);
+}
diff --git a/flang/lib/Lower/Runtime.cpp b/flang/lib/Lower/Runtime.cpp
index ca1a1aca89606..ebbb9e3f74f03 100644
--- a/flang/lib/Lower/Runtime.cpp
+++ b/flang/lib/Lower/Runtime.cpp
@@ -19,6 +19,7 @@
#include "flang/Runtime/stop.h"
#include "flang/Semantics/tools.h"
#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include "mlir/Dialect/SCF/IR/SCF.h"
#include "llvm/Support/Debug.h"
#include <optional>
@@ -31,8 +32,11 @@ using namespace Fortran::runtime;
static void genUnreachable(fir::FirOpBuilder &builder, mlir::Location loc) {
mlir::Block *curBlock = builder.getBlock();
mlir::Operation *parentOp = curBlock->getParentOp();
- if (parentOp->getDialect()->getNamespace() ==
- mlir::omp::OpenMPDialect::getDialectNamespace())
+
+ if (mlir::isa<mlir::scf::ExecuteRegionOp>(parentOp))
+ fir::UnreachableOp::create(builder, loc);
+ else if (parentOp->getDialect()->getNamespace() ==
+ mlir::omp::OpenMPDialect::getDialectNamespace())
Fortran::lower::genOpenMPTerminator(builder, parentOp, loc);
else if (Fortran::lower::isInsideOpenACCComputeConstruct(builder))
Fortran::lower::genOpenACCTerminator(builder, parentOp, loc);
diff --git a/flang/test/HLFIR/assumed_shape_with_value_keyword.f90 b/flang/test/HLFIR/assumed_shape_with_value_keyword.f90
index 89f83863b560c..9e6cd57da785a 100644
--- a/flang/test/HLFIR/assumed_shape_with_value_keyword.f90
+++ b/flang/test/HLFIR/assumed_shape_with_value_keyword.f90
@@ -134,14 +134,17 @@ subroutine test_optional3(x)
! CHECK-LABEL: func.func @_QPtest_optional3(
! CHECK-SAME: %[[ARG0:.*]]: !fir.box<!fir.array<?xf32>> {fir.bindc_name = "x", fir.optional}) {
! CHECK: %[[VAL_0:.*]]:2 = hlfir.declare %[[ARG0]] dummy_scope %{{[0-9]+}} arg {{[0-9]+}} {fortran_attrs = #fir.var_attrs<optional, value>, uniq_name = "_QFtest_optional3Ex"} : (!fir.box<!fir.array<?xf32>>, !fir.dscope) -> (!fir.box<!fir.array<?xf32>>, !fir.box<!fir.array<?xf32>>)
-! CHECK: %[[VAL_1:.*]] = fir.is_present %[[VAL_0]]#1 : (!fir.box<!fir.array<?xf32>>) -> i1
-! CHECK: cf.cond_br %[[VAL_1]], ^bb1, ^bb2
+! CHECK: scf.execute_region no_inline {
+! CHECK: %[[VAL_1:.*]] = fir.is_present %[[VAL_0]]#1 : (!fir.box<!fir.array<?xf32>>) -> i1
+! CHECK: cf.cond_br %[[VAL_1]], ^bb1, ^bb2
! CHECK: b1: // pred: ^bb0
-! CHECK: %[[C0_I32:.*]] = arith.constant 0 : i32
-! CHECK: %[[FALSE:.*]] = arith.constant false
-! CHECK: %[[FALSE_0:.*]] = arith.constant false
-! CHECK: fir.call @_FortranAStopStatement(%[[C0_I32]], %[[FALSE]], %[[FALSE]]_0) fastmath<contract> : (i32, i1, i1) -> ()
-! CHECK: fir.unreachable
+! CHECK: %[[C0_I32:.*]] = arith.constant 0 : i32
+! CHECK: %[[FALSE:.*]] = arith.constant false
+! CHECK: %[[FALSE_0:.*]] = arith.constant false
+! CHECK: fir.call @_FortranAStopStatement(%[[...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/208635
More information about the flang-commits
mailing list