llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-flang-fir-hlfir Author: jeanPerier <details> <summary>Changes</summary> 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. --- Full diff: https://github.com/llvm/llvm-project/pull/228577.diff 2 Files Affected: - (modified) flang/lib/Lower/Bridge.cpp (+27-3) - (added) flang/test/Lower/execute_region_wrap_locations.f90 (+119) ``````````diff diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 9a35b82b8f20ca..939d8d134552e9 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 00000000000000..1ad163e246331a --- /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 `````````` </details> https://github.com/llvm/llvm-project/pull/228577 _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
