[flang-commits] [flang] 0098b5c - [flang] Fix locations of wrapped unstructured constructs and DO loop ends (#228577)
via flang-commits
flang-commits at lists.llvm.org
Mon Oct 5 00:41:48 PDT 2026
Author: jeanPerier
Date: 2026-10-05T09:41:36+02:00
New Revision: 0098b5c2887cd44f63364ea48f813dff36767f77
URL: https://github.com/llvm/llvm-project/commit/0098b5c2887cd44f63364ea48f813dff36767f77
DIFF: https://github.com/llvm/llvm-project/commit/0098b5c2887cd44f63364ea48f813dff36767f77.diff
LOG: [flang] Fix locations of wrapped unstructured constructs and DO loop ends (#228577)
Construct evaluations have no source position, so the scf.execute_region
wrapping an unstructured construct was given the location of the
previously lowered statement. Use the construct's first statement for
the region and its END statement for the scf.yield. Also attribute the
DO loop end code to the END DO statement rather than to the last
statement of the loop body.
This avoids going back to previous lines when stepping in a debugger.
Assisted-by: AI
Added:
flang/test/Lower/execute_region_wrap_locations.f90
Modified:
flang/lib/Lower/Bridge.cpp
Removed:
################################################################################
diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index 9a35b82b8f20c..939d8d134552e 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -1843,7 +1843,8 @@ class FirConverter : public Fortran::lower::AbstractConverter {
for (; iter != endDoIter; ++iter)
genFIR(*iter, /*unstructuredContext=*/false);
- mlir::scf::YieldOp::create(*builder, loc);
+ mlir::scf::YieldOp::create(*builder,
+ genConstructEndLocation(doConstructEval));
builder->setInsertionPointAfter(scfWhile);
}
@@ -2660,6 +2661,22 @@ class FirConverter : public Fortran::lower::AbstractConverter {
}
}
+ /// Return the location of the statement ending construct \p eval, or of its
+ /// opening statement when the ending one has no source position (e.g. the
+ /// END IF synthesized for an IF statement).
+ mlir::Location
+ genConstructEndLocation(Fortran::lower::pft::Evaluation &eval) {
+ const Fortran::parser::CharBlock &endPosition =
+ eval.getLastNestedEvaluation().position;
+ if (!endPosition.empty())
+ return toLocation(endPosition);
+ const Fortran::parser::CharBlock &beginPosition =
+ eval.getFirstNestedEvaluation().position;
+ if (!beginPosition.empty())
+ return toLocation(beginPosition);
+ return toLocation();
+ }
+
/// 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).
@@ -2670,6 +2687,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
eval, bridge.getSemanticsContext()))
return nullptr;
+ // A construct evaluation has no source position of its own, so the
+ // current position may still be that of a previous statement.
+ setCurrentPosition(eval.getFirstNestedEvaluation().position);
mlir::Location loc = toLocation();
auto wrapOp =
mlir::scf::ExecuteRegionOp::create(*builder, loc, mlir::TypeRange{},
@@ -2680,7 +2700,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
createEmptyBlocks(eval.getNestedEvaluations());
mlir::Block *yieldBlock = builder->createBlock(&wrapOp.getRegion());
builder->setInsertionPointToEnd(yieldBlock);
- mlir::scf::YieldOp::create(*builder, loc);
+ mlir::scf::YieldOp::create(*builder, genConstructEndLocation(eval));
if (eval.constructExit) {
savedExitBlock = eval.constructExit->block;
@@ -2706,6 +2726,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
return nullptr;
Fortran::lower::pft::EvaluationList &list = eval.getNestedEvaluations();
+ setCurrentPosition(eval.getFirstNestedEvaluation().position);
mlir::Location loc = toLocation();
auto wrapOp =
mlir::scf::ExecuteRegionOp::create(*builder, loc, mlir::TypeRange{},
@@ -2722,7 +2743,7 @@ class FirConverter : public Fortran::lower::AbstractConverter {
llvm::make_range(std::next(list.begin()), std::prev(list.end())));
yieldBlock = builder->createBlock(&wrapOp.getRegion());
builder->setInsertionPointToEnd(yieldBlock);
- mlir::scf::YieldOp::create(*builder, loc);
+ mlir::scf::YieldOp::create(*builder, genConstructEndLocation(eval));
// A CYCLE targets the EndDoStmt, which is the boundary between the loop
// body and the loop control. Inside the wrap that boundary is the region's
@@ -2997,6 +3018,9 @@ class FirConverter : public Fortran::lower::AbstractConverter {
// An EndDoStmt in unstructured code may start a new block.
Fortran::lower::pft::Evaluation &endDoEval = *iter;
assert(endDoEval.getIf<Fortran::parser::EndDoStmt>() && "no enddo stmt");
+ // The loop end code belongs to the END DO, not to the last statement
+ // lowered in the body.
+ setCurrentPosition(endDoEval.position);
if (unstructuredContext)
maybeStartBlock(endDoEval.block);
diff --git a/flang/test/Lower/execute_region_wrap_locations.f90 b/flang/test/Lower/execute_region_wrap_locations.f90
new file mode 100644
index 0000000000000..1ad163e246331
--- /dev/null
+++ b/flang/test/Lower/execute_region_wrap_locations.f90
@@ -0,0 +1,119 @@
+! RUN: %flang_fc1 -emit-hlfir -mmlir --mlir-print-debuginfo -mmlir --mlir-print-local-scope -o - %s | FileCheck %s
+! RUN: %flang_fc1 -emit-hlfir -mmlir --mlir-print-debuginfo -mmlir --mlir-print-local-scope -mmlir --lower-do-while-to-scf-while -o - %s | FileCheck %s --check-prefix=SCFWHILE
+
+! Source locations of the scf.execute_region wrapping an unstructured
+! construct and of the code ending a DO construct. The region entry is at the
+! construct's opening statement and its exit at the construct's END statement,
+! so that stepping through the generated code does not go back to a previous
+! line.
+
+! CHECK-LABEL: func.func @_QPif_first
+! CHECK: scf.yield loc("{{.*}}":[[@LINE+4]]:3)
+! CHECK-NEXT: } loc("{{.*}}":[[@LINE+3]]:3)
+subroutine if_first(var)
+ integer :: var
+ if (var .ne. 1) stop 1
+ call foo()
+end subroutine
+
+! CHECK-LABEL: func.func @_QPif_stmt
+! CHECK: scf.yield loc("{{.*}}":[[@LINE+5]]:3)
+! CHECK-NEXT: } loc("{{.*}}":[[@LINE+4]]:3)
+subroutine if_stmt(var)
+ integer :: var
+ call foo()
+ if (var .ne. 1) stop 1
+ call foo()
+end subroutine
+
+! CHECK-LABEL: func.func @_QPif_construct
+! CHECK: scf.yield loc("{{.*}}":[[@LINE+8]]:3)
+! CHECK-NEXT: } loc("{{.*}}":[[@LINE+4]]:3)
+subroutine if_construct(var)
+ integer :: var
+ call foo()
+ if (var .ne. 1) then
+ call foo()
+ stop 1
+ end if
+ call foo()
+end subroutine
+
+! CHECK-LABEL: func.func @_QPif_in_do
+! CHECK: fir.do_loop
+! CHECK: scf.yield loc("{{.*}}":[[@LINE+10]]:5)
+! CHECK-NEXT: } loc("{{.*}}":[[@LINE+6]]:5)
+! CHECK: } loc("{{.*}}":[[@LINE+4]]:3)
+! CHECK-NEXT: fir.convert {{.*}} loc("{{.*}}":[[@LINE+9]]:3)
+subroutine if_in_do(n)
+ integer :: n, i
+ do i = 1, n
+ if (i .eq. n) then
+ call foo()
+ stop 2
+ end if
+ call foo()
+ end do
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdo_exit
+! CHECK: scf.execute_region
+! CHECK: arith.addi {{.*}} loc("{{.*}}":[[@LINE+11]]:3)
+! CHECK-NEXT: fir.store {{.*}} loc("{{.*}}":[[@LINE+10]]:3)
+! CHECK-NEXT: cf.br ^bb{{[0-9]+}} loc("{{.*}}":[[@LINE+9]]:3)
+! CHECK: scf.yield loc("{{.*}}":[[@LINE+8]]:3)
+! CHECK-NEXT: } loc("{{.*}}":[[@LINE+4]]:3)
+subroutine do_exit(n)
+ integer :: n, i
+ call foo()
+ do i = 1, n
+ call foo()
+ if (i .eq. 5) exit
+ end do
+ call foo()
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdo_while
+! CHECK: scf.execute_region
+! CHECK: cf.br ^bb1 loc("{{.*}}":[[@LINE+9]]:3)
+! CHECK: scf.yield loc("{{.*}}":[[@LINE+8]]:3)
+! CHECK-NEXT: } loc("{{.*}}":[[@LINE+4]]:3)
+subroutine do_while(n)
+ integer :: n
+ call foo()
+ do while (n .gt. 0)
+ n = n - 1
+ if (n .eq. 5) exit
+ end do
+ call foo()
+end subroutine
+
+! CHECK-LABEL: func.func @_QPdo_body
+! CHECK: fir.do_loop
+! CHECK: scf.execute_region
+! CHECK: scf.yield loc("{{.*}}":[[@LINE+12]]:3)
+! CHECK-NEXT: } loc("{{.*}}":[[@LINE+4]]:3)
+subroutine do_body(n, a)
+ integer :: n, i
+ real :: a(n)
+ do i = 1, n
+ if (a(i) > 0.0) then
+ a(i) = 1.0
+ goto 90
+ end if
+ a(i) = 2.0
+90 continue
+ end do
+end subroutine
+
+! SCFWHILE-LABEL: func.func @_QPdo_while_structured
+! SCFWHILE: scf.while
+! SCFWHILE: scf.condition({{.*}}) loc("{{.*}}":[[@LINE+5]]:3)
+! SCFWHILE: scf.yield loc("{{.*}}":[[@LINE+6]]:3)
+! SCFWHILE-NEXT: } loc("{{.*}}":[[@LINE+3]]:3)
+subroutine do_while_structured(n)
+ integer :: n
+ do while (n .gt. 0)
+ n = n - 1
+ end do
+end subroutine
More information about the flang-commits
mailing list