[flang] make lowering to scf.while default (#184234)

We've tested the implementation of fortran do-while loops being lowered
to scf.while and want to make it the default option.
This commit is contained in:
Susan Tan (ス-ザン タン) 2026-03-03 18:26:36 -05:00 committed by GitHub
parent 393bbd5520
commit 62144f48d4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
7 changed files with 61 additions and 76 deletions

View File

@ -28,10 +28,6 @@ static llvm::cl::opt<bool> clDisableStructuredFir(
using namespace Fortran;
namespace {
static llvm::cl::opt<bool> lowerDoWhileToSCFWhile(
"lower-do-while-to-scf-while", llvm::cl::init(false),
llvm::cl::desc("lower structured DO WHILE loops to scf.while"),
llvm::cl::Hidden);
/// Helpers to unveil parser node inside Fortran::parser::Statement<>,
/// Fortran::parser::UnlabeledStatement, and Fortran::common::Indirection<>
template <typename A>
@ -1062,12 +1058,6 @@ private:
if (bounds->Name().thing.symbol->GetType()->IsNumeric(
common::TypeCategory::Real))
eval.isUnstructured = true; // real-valued loop control
} else if (std::get_if<parser::ScalarLogicalExpr>(
&loopControl->u)) {
// Leave DO WHILE structured when -lower-do-while-to-scf-while is
// enabled; branch analysis will mark unstructured cases.
if (!lowerDoWhileToSCFWhile)
eval.isUnstructured = true; // while loop
}
},
[&](const parser::EndDoStmt &) {

View File

@ -684,12 +684,21 @@ subroutine target_unstructured
!CHECK-NO-FPRIV: %[[VAL_8:.*]]:2 = hlfir.declare %[[VAL_6]] {uniq_name = "_QFtarget_unstructuredEi"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK-NO-FPRIV: %[[VAL_9:.*]]:2 = hlfir.declare %[[VAL_7]] {uniq_name = "_QFtarget_unstructuredEj"} : (!fir.ref<i32>) -> (!fir.ref<i32>, !fir.ref<i32>)
!CHECK: ^bb1:
!CHECK: scf.while : () -> () {
!CHECK: %[[I_CUR:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref<i32>
!CHECK: %[[J_CUR:.*]] = fir.load %[[VAL_9]]#0 : !fir.ref<i32>
!CHECK: %[[COND:.*]] = arith.cmpi sle, %[[I_CUR]], %[[J_CUR]] : i32
!CHECK: scf.condition(%[[COND]])
!CHECK: } do {
!CHECK: %[[I_BODY:.*]] = fir.load %[[VAL_8]]#0 : !fir.ref<i32>
!CHECK: %[[ONE:.*]] = arith.constant 1 : i32
!CHECK: %[[I_NEXT:.*]] = arith.addi %[[I_BODY]], %[[ONE]] : i32
!CHECK: hlfir.assign %[[I_NEXT]] to %[[VAL_8]]#0 : i32, !fir.ref<i32>
!CHECK: scf.yield
!CHECK: }
do while (i <= j)
!CHECK: ^bb2:
i = i + 1
end do
!CHECK: ^bb3:
!CHECK: omp.terminator
!$omp end target
!CHECK: }

View File

@ -1,4 +1,4 @@
! RUN: bbc -emit-hlfir -lower-do-while-to-scf-while %s -o - | FileCheck %s
! RUN: bbc -emit-hlfir %s -o - | FileCheck %s
! CHECK-LABEL: func.func @_QPsimple_do_while()
! CHECK: scf.while

View File

@ -147,12 +147,12 @@ end
! CHECK-LABEL: print_nothing
subroutine print_nothing(k1, k2)
if (k1 > 0) then
! CHECK: br [[header:\^bb[0-9]+]]
! CHECK: [[header]]
! CHECK: scf.while : () -> () {
! CHECK: scf.condition
do while (k1 > k2)
print*, k1, k2 ! no output
k2 = k2 + 1
! CHECK: br [[header]]
! CHECK: scf.yield
end do
end if
end

View File

@ -3,7 +3,6 @@
! Test while loop inside do loop.
! CHECK-LABEL: while_inside_do_loop
subroutine while_inside_do_loop
! CHECK-DAG: %[[T_REF:.*]] = fir.alloca i32
! CHECK-DAG: %[[I_ADDR:.*]] = fir.alloca i32 {bindc_name = "i", uniq_name = "_QFwhile_inside_do_loopEi"}
! CHECK-DAG: %[[I:.*]]:2 = hlfir.declare %[[I_ADDR]]
! CHECK-DAG: %[[J_ADDR:.*]] = fir.alloca i32 {bindc_name = "j", uniq_name = "_QFwhile_inside_do_loopEj"}
@ -12,52 +11,40 @@ subroutine while_inside_do_loop
! CHECK-DAG: %[[C8:.*]] = arith.constant 8 : i32
! CHECK-DAG: %[[C13:.*]] = arith.constant 13 : i32
! CHECK-DAG: %[[C1:.*]] = arith.constant 1 : i32
! CHECK: %[[DIFF:.*]] = arith.subi %[[C13]], %[[C8]] : i32
! CHECK: %[[RANGE:.*]] = arith.addi %[[DIFF]], %[[C1]] : i32
! CHECK: %[[HIGH:.*]] = arith.divsi %[[RANGE]], %[[C1]] : i32
! CHECK: fir.store %[[HIGH]] to %[[T_REF]] : !fir.ref<i32>
! CHECK: fir.store %[[C8]] to %[[I]]#0 : !fir.ref<i32>
! CHECK: cf.br ^[[HDR1:.*]]
! CHECK: ^[[HDR1]]: // 2 preds: ^{{.*}}, ^[[EXIT2:.*]]
! CHECK: %[[T:.*]] = fir.load %[[T_REF]] : !fir.ref<i32>
! CHECK: %[[C0:.*]] = arith.constant 0 : i32
! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[T]], %[[C0]] : i32
! CHECK: cf.cond_br %[[COND]], ^[[BODY1:.*]], ^[[EXIT1:.*]]
! CHECK-DAG: %[[C1:.*]] = arith.constant 1 : index
! CHECK-DAG: %[[LB:.*]] = fir.convert %[[C8]] : (i32) -> index
! CHECK-DAG: %[[UB:.*]] = fir.convert %[[C13]] : (i32) -> index
! CHECK-DAG: %[[INIT:.*]] = fir.convert %[[LB]] : (index) -> i32
! CHECK: %[[RES:.*]] = fir.do_loop %{{.*}} = %[[LB]] to %[[UB]] step %[[C1]] iter_args(%[[I_IV:.*]] = %[[INIT]]) -> (i32) {
! CHECK: fir.store %[[I_IV]] to %[[I]]#0 : !fir.ref<i32>
do i=8,13
! CHECK: ^[[BODY1]]: // pred: ^[[HDR1]]
! CHECK: %[[C3:.*]] = arith.constant 3 : i32
! CHECK: hlfir.assign %[[C3]] to %[[J]]#0 : i32, !fir.ref<i32>
j=3
! CHECK: cf.br ^[[HDR2:.*]]
! CHECK: ^[[HDR2]]: // 2 preds: ^[[BODY1]], ^[[BODY2:.*]]
! CHECK: scf.while : () -> () {
! CHECK: %[[JVAL:.*]] = fir.load %[[J]]#0 : !fir.ref<i32>
! CHECK: %[[IVAL:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: %[[COND2:.*]] = arith.cmpi slt, %[[JVAL]], %[[IVAL]] : i32
! CHECK: cf.cond_br %[[COND2]], ^[[BODY2:.*]], ^[[EXIT2]]
! CHECK: scf.condition(%[[COND2]])
! CHECK: } do {
do while (j .lt. i)
! CHECK: ^[[BODY2]]: // pred: ^[[HDR2]]
! CHECK: %[[C2:.*]] = arith.constant 2 : i32
! CHECK: %[[JVAL2:.*]] = fir.load %[[J]]#0 : !fir.ref<i32>
! CHECK: %[[INC2:.*]] = arith.muli %[[C2]], %[[JVAL2]] : i32
! CHECK: hlfir.assign %[[INC2]] to %[[J]]#0 : i32, !fir.ref<i32>
j=j*2
! CHECK: cf.br ^[[HDR2]]
! CHECK: scf.yield
end do
! CHECK: }
! CHECK: ^[[EXIT2]]: // pred: ^[[HDR2]]
! CHECK: %[[T2:.*]] = fir.load %[[T_REF]] : !fir.ref<i32>
! CHECK: %[[TDEC:.*]] = arith.subi %[[T2]], {{.*}} : i32
! CHECK: fir.store %[[TDEC]] to %[[T_REF]]
! CHECK: %[[I3:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: %[[IINC:.*]] = arith.addi %[[I3]], {{.*}} overflow<nsw> : i32
! CHECK: fir.store %[[IINC]] to %[[I]]#0 : !fir.ref<i32>
! CHECK: cf.br ^[[HDR1]]
! CHECK: %[[STEP_I32:.*]] = fir.convert %[[C1]] : (index) -> i32
! CHECK: %[[I_CUR:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: %[[I_NEXT:.*]] = arith.addi %[[I_CUR]], %[[STEP_I32]] overflow<nsw> : i32
! CHECK: fir.result %[[I_NEXT]] : i32
! CHECK: fir.store %[[RES]] to %[[I]]#0 : !fir.ref<i32>
end do
! CHECK: ^[[EXIT1]]: // pred: ^[[HDR1]]
! CHECK: %[[IPRINT:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[IPRINT]])
! CHECK: %[[JPRINT:.*]] = fir.load %[[J]]#0 : !fir.ref<i32>
@ -78,19 +65,21 @@ subroutine do_inside_while_loop
! CHECK: hlfir.assign %[[C3]] to %[[J]]#0 : i32, !fir.ref<i32>
j=3
! CHECK: cf.br ^[[HDR1:.*]]
! CHECK: ^[[HDR1]]: // 2 preds: ^{{.*}}, ^[[BODY1:.*]]
! CHECK: scf.while : () -> () {
! CHECK: %[[JVAL:.*]] = fir.load %[[J]]#0 : !fir.ref<i32>
! CHECK: %[[UL:.*]] = arith.constant 21 : i32
! CHECK: %[[COND:.*]] = arith.cmpi slt, %[[JVAL]], %[[UL]] : i32
! CHECK: cf.cond_br %[[COND]], ^[[BODY1]], ^[[EXIT1:.*]]
! CHECK: scf.condition(%[[COND]])
! CHECK: } do {
do while (j .lt. 21)
! CHECK: ^[[BODY1]]: // pred: ^[[HDR1]]
! CHECK-DAG: %[[C8:.*]] = arith.constant 8 : i32
! CHECK-DAG: %[[C13:.*]] = arith.constant 13 : i32
! CHECK-DAG: %[[C1:.*]] = arith.constant 1 : index
! CHECK: %{{.*}} = fir.do_loop %{{.*}} = {{.*}} to {{.*}} step {{.*}} iter_args(%[[I_IV:.*]] = {{.*}}) -> (i32) {
! CHECK-DAG: %[[LB:.*]] = fir.convert %[[C8]] : (i32) -> index
! CHECK-DAG: %[[UB:.*]] = fir.convert %[[C13]] : (i32) -> index
! CHECK-DAG: %[[INIT:.*]] = fir.convert %[[LB]] : (index) -> i32
! CHECK: %{{.*}} = fir.do_loop %{{.*}} = %[[LB]] to %[[UB]] step %[[C1]] iter_args(%[[I_IV:.*]] = %[[INIT]]) -> (i32) {
! CHECK: fir.store %[[I_IV]] to %[[I]]#0 : !fir.ref<i32>
! CHECK: %[[C2:.*]] = arith.constant 2 : i32
! CHECK: %[[J2VAL:.*]] = fir.load %[[J]]#0 : !fir.ref<i32>
@ -105,10 +94,10 @@ subroutine do_inside_while_loop
! CHECK: fir.store %{{.*}} to %[[I]]#0 : !fir.ref<i32>
end do
! CHECK: cf.br ^[[HDR1]]
! CHECK: scf.yield
end do
! CHECK: }
! CHECK: ^[[EXIT1]]: // pred: ^[[HDR1]]
! CHECK: %[[IPRINT:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[IPRINT]])
! CHECK: %[[JPRINT:.*]] = fir.load %[[J]]#0 : !fir.ref<i32>

View File

@ -82,15 +82,15 @@ program test_prog
! CHECK: CaseStmt
case default
! Note: label-do-loop are canonicalized into do constructs
! CHECK: <<DoConstruct!>>
! CHECK: NonLabelDoStmt
! CHECK: <<DoConstruct>>
! CHECK: [[DO_HDR:[0-9]+]] NonLabelDoStmt -> [[DO_END:[0-9]+]]: do 22 while(l<=k)
do 22 while(l<=k)
! CHECK: IfStmt
if (p(l)<0.) p(l)=cos(p(l))
! CHECK: CallStmt
! CHECK: [[CALL_ID:[0-9]+]] CallStmt: 22 call incr(l)
22 call incr(l)
! CHECK: EndDoStmt
! CHECK: <<End DoConstruct!>>
! CHECK: [[DO_END]] EndDoStmt -> [[DO_HDR]]
! CHECK: <<End DoConstruct>>
! CHECK: CaseStmt
case (100:)
! CHECK: EndSelectStmt

View File

@ -11,23 +11,22 @@ subroutine simple_loop
! CHECK: hlfir.assign %[[C5]] to %[[I]]#0
i = 5
! CHECK: cf.br ^[[BB1:.*]]
! CHECK: ^[[BB1]]: // 2 preds: ^{{.*}}, ^[[BB2:.*]]
! CHECK: scf.while : () -> () {
! CHECK: %[[IVAL:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: %[[C1:.*]] = arith.constant 1 : i32
! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[IVAL]], %[[C1]] : i32
! CHECK: cf.cond_br %[[COND]], ^[[BB2]], ^[[BB3:.*]]
! CHECK: ^[[BB2]]: // pred: ^[[BB1]]
! CHECK: scf.condition(%[[COND]])
! CHECK: } do {
! CHECK: %[[IVAL2:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: %[[C2:.*]] = arith.constant 2 : i32
! CHECK: %[[INC:.*]] = arith.subi %[[IVAL2]], %[[C2]] : i32
! CHECK: hlfir.assign %[[INC]] to %[[I]]#0 : i32, !fir.ref<i32>
! CHECK: cf.br ^[[BB1]]
! CHECK: scf.yield
! CHECK: }
do while (i .gt. 1)
i = i - 2
end do
! CHECK: ^[[BB3]]: // pred: ^[[BB1]]
! CHECK: %[[IVAL3:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[IVAL3]])
print *, i
@ -46,14 +45,13 @@ subroutine while_inside_while_loop
! CHECK: hlfir.assign %[[C13]] to %[[I]]#0
i = 13
! CHECK: cf.br ^[[HDR1:.*]]
! CHECK: ^[[HDR1]]: // 2 preds: ^{{.*}}, ^[[EXIT2:.*]]
! CHECK: scf.while : () -> () {
! CHECK: %[[IVAL:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: %[[C8:.*]] = arith.constant 8 : i32
! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[IVAL]], %[[C8]] : i32
! CHECK: cf.cond_br %[[COND]], ^[[BODY1:.*]], ^[[EXIT1:.*]]
! CHECK: scf.condition(%[[COND]])
! CHECK: } do {
do while (i .gt. 8)
! CHECK: ^[[BODY1]]: // pred: ^[[HDR1]]
! CHECK: %[[IVAL2:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: %[[C5:.*]] = arith.constant 5 : i32
! CHECK: %[[INC:.*]] = arith.subi %[[IVAL2]], %[[C5]] : i32
@ -64,27 +62,26 @@ subroutine while_inside_while_loop
! CHECK: hlfir.assign %[[C3]] to %[[J]]#0
j = 3
! CHECK: cf.br ^[[HDR2:.*]]
! CHECK: ^[[HDR2]]: // 2 preds: ^[[BODY1]], ^[[BODY2:.*]]
! CHECK: scf.while : () -> () {
! CHECK: %[[JVAL:.*]] = fir.load %[[J]]#0 : !fir.ref<i32>
! CHECK: %[[IVAL3:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: %[[COND2:.*]] = arith.cmpi slt, %[[JVAL]], %[[IVAL3]] : i32
! CHECK: cf.cond_br %[[COND2]], ^[[BODY2]], ^[[EXIT2:.*]]
! CHECK: scf.condition(%[[COND2]])
! CHECK: } do {
do while (j .lt. i)
! CHECK: ^[[BODY2]]: // pred: ^[[HDR2]]
! CHECK: %[[C2:.*]] = arith.constant 2 : i32
! CHECK: %[[JVAL2:.*]] = fir.load %[[J]]#0 : !fir.ref<i32>
! CHECK: %[[INC2:.*]] = arith.muli %[[C2]], %[[JVAL2]] : i32
! CHECK: hlfir.assign %[[INC2]] to %[[J]]#0 : i32, !fir.ref<i32>
j = j * 2
! CHECK: cf.br ^[[HDR2]]
! CHECK: scf.yield
end do
! CHECK: }
! CHECK: ^[[EXIT2]]: // pred: ^[[HDR2]]
! CHECK: cf.br ^[[HDR1]]
! CHECK: scf.yield
end do
! CHECK: }
! CHECK: ^[[EXIT1]]: // pred: ^[[HDR1]]
! CHECK: %[[IPRINT:.*]] = fir.load %[[I]]#0 : !fir.ref<i32>
! CHECK: fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[IPRINT]])
! CHECK: %[[JPRINT:.*]] = fir.load %[[J]]#0 : !fir.ref<i32>