[Flang] Lower the infinite do loop

The basic infinite loop is lowered to a branch to the body of the
loop, and the body containing a back edge as its terminator.

Note: This is part of upstreaming from the fir-dev branch of
https://github.com/flang-compiler/f18-llvm-project.

Reviewed By: rovka

Differential Revision: https://reviews.llvm.org/D126697

Co-authored-by: Eric Schweitz <eschweitz@nvidia.com>
Co-authored-by: V Donaldson <vdonaldson@nvidia.com>
This commit is contained in:
Kiran Chandramohan 2022-06-01 11:48:20 +00:00
parent 94552f0216
commit 8c349d707e
2 changed files with 137 additions and 7 deletions

View File

@ -983,8 +983,13 @@ private:
mlir::Block *exitBlock = doStmtEval.parentConstruct->constructExit->block; mlir::Block *exitBlock = doStmtEval.parentConstruct->constructExit->block;
IncrementLoopNestInfo incrementLoopNestInfo; IncrementLoopNestInfo incrementLoopNestInfo;
const Fortran::parser::ScalarLogicalExpr *whileCondition = nullptr; const Fortran::parser::ScalarLogicalExpr *whileCondition = nullptr;
if ((whileCondition = std::get_if<Fortran::parser::ScalarLogicalExpr>( bool infiniteLoop = !loopControl.has_value();
&loopControl->u))) { if (infiniteLoop) {
assert(unstructuredContext && "infinite loop must be unstructured");
startBlock(headerBlock);
} else if ((whileCondition =
std::get_if<Fortran::parser::ScalarLogicalExpr>(
&loopControl->u))) {
assert(unstructuredContext && "while loop must be unstructured"); assert(unstructuredContext && "while loop must be unstructured");
maybeStartBlock(preheaderBlock); // no block or empty block maybeStartBlock(preheaderBlock); // no block or empty block
startBlock(headerBlock); startBlock(headerBlock);
@ -1008,9 +1013,8 @@ private:
TODO(toLocation(), "infinite/unstructured loop/concurrent loop"); TODO(toLocation(), "infinite/unstructured loop/concurrent loop");
} }
// Increment loop begin code. (TODO: Infinite/while code was already // Increment loop begin code. (Infinite/while code was already generated.)
// generated.) if (!infiniteLoop && !whileCondition)
if (!whileCondition)
genFIRIncrementLoopBegin(incrementLoopNestInfo); genFIRIncrementLoopBegin(incrementLoopNestInfo);
// Loop body code - NonLabelDoStmt and EndDoStmt code is generated here. // Loop body code - NonLabelDoStmt and EndDoStmt code is generated here.
@ -1018,8 +1022,8 @@ private:
for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations()) for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations())
genFIR(e, unstructuredContext); genFIR(e, unstructuredContext);
// Loop end code. (TODO: infinite loop) // Loop end code.
if (whileCondition) if (infiniteLoop || whileCondition)
genFIRBranch(headerBlock); genFIRBranch(headerBlock);
else else
genFIRIncrementLoopEnd(incrementLoopNestInfo); genFIRIncrementLoopEnd(incrementLoopNestInfo);

View File

@ -0,0 +1,126 @@
! RUN: bbc -emit-fir -o - %s | FileCheck %s
! RUN: %flang_fc1 -emit-fir -o - %s | FileCheck %s
! Tests for infinite loop.
subroutine empty_infinite()
do
end do
end subroutine
! CHECK-LABEL: empty_infinite
! CHECK: cf.br ^[[BODY:.*]]
! CHECK: ^[[BODY]]:
! CHECK: cf.br ^[[BODY]]
subroutine simple_infinite(i)
integer :: i
do
if (i .gt. 100) exit
end do
end subroutine
! CHECK-LABEL: simple_infinite
! CHECK-SAME: %[[I_REF:.*]]: !fir.ref<i32>
! CHECK: cf.br ^[[BODY1:.*]]
! CHECK: ^[[BODY1]]:
! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref<i32>
! CHECK: %[[C100:.*]] = arith.constant 100 : i32
! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[I]], %[[C100]] : i32
! CHECK: cf.cond_br %[[COND]], ^[[EXIT:.*]], ^[[BODY1:.*]]
! CHECK: ^[[EXIT]]:
! CHECK: cf.br ^[[RETURN:.*]]
! CHECK: ^[[RETURN]]:
! CHECK: return
! CHECK: }
subroutine infinite_with_two_body_blocks(i)
integer :: i
do
i = i + 1
if (i .gt. 100) exit
i = i * 2
end do
end subroutine
! CHECK-LABEL: infinite_with_two_body_blocks
! CHECK-SAME: %[[I_REF:.*]]: !fir.ref<i32>
! CHECK: cf.br ^[[BODY1:.*]]
! CHECK: ^[[BODY1]]:
! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref<i32>
! CHECK: %[[C1:.*]] = arith.constant 1 : i32
! CHECK: %[[I_NEXT:.*]] = arith.addi %[[I]], %[[C1]] : i32
! CHECK: fir.store %[[I_NEXT]] to %[[I_REF]] : !fir.ref<i32>
! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref<i32>
! CHECK: %[[C100:.*]] = arith.constant 100 : i32
! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[I]], %[[C100]] : i32
! CHECK: cf.cond_br %[[COND]], ^[[EXIT:.*]], ^[[BODY2:.*]]
! CHECK: ^[[EXIT]]:
! CHECK: cf.br ^[[RETURN:.*]]
! CHECK: ^[[BODY2]]:
! CHECK: %[[C2:.*]] = arith.constant 2 : i32
! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref<i32>
! CHECK: %[[I_NEXT:.*]] = arith.muli %[[C2]], %[[I]] : i32
! CHECK: fir.store %[[I_NEXT]] to %[[I_REF]] : !fir.ref<i32>
! CHECK: cf.br ^[[BODY1]]
! CHECK: ^[[RETURN]]:
! CHECK: return
! CHECK: }
subroutine structured_loop_in_infinite(i)
integer :: i
integer :: j
do
if (i .gt. 100) exit
do j=1,10
end do
end do
end subroutine
! CHECK-LABEL: structured_loop_in_infinite
! CHECK-SAME: %[[I_REF:.*]]: !fir.ref<i32>
! CHECK: %[[J_REF:.*]] = fir.alloca i32 {bindc_name = "j", uniq_name = "_QFstructured_loop_in_infiniteEj"}
! CHECK: cf.br ^[[BODY1:.*]]
! CHECK: ^[[BODY1]]:
! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref<i32>
! CHECK: %[[C100:.*]] = arith.constant 100 : i32
! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[I]], %[[C100]] : i32
! CHECK: cf.cond_br %[[COND]], ^[[EXIT:.*]], ^[[BODY2:.*]]
! CHECK: ^[[EXIT]]:
! CHECK: cf.br ^[[RETURN:.*]]
! CHECK: ^[[BODY2:.*]]:
! CHECK: %[[C1:.*]] = arith.constant 1 : i32
! CHECK: %[[C1_INDEX:.*]] = fir.convert %[[C1]] : (i32) -> index
! CHECK: %[[C10:.*]] = arith.constant 10 : i32
! CHECK: %[[C10_INDEX:.*]] = fir.convert %[[C10]] : (i32) -> index
! CHECK: %[[C1_1:.*]] = arith.constant 1 : index
! CHECK: %[[J_FINAL:.*]] = fir.do_loop %[[J:.*]] = %[[C1_INDEX]] to %[[C10_INDEX]] step %[[C1_1]] -> index {
! CHECK: %[[J_I32:.*]] = fir.convert %[[J]] : (index) -> i32
! CHECK: fir.store %[[J_I32]] to %[[J_REF]] : !fir.ref<i32>
! CHECK: %[[J_NEXT:.*]] = arith.addi %[[J]], %[[C1_1]] : index
! CHECK: fir.result %[[J_NEXT]] : index
! CHECK: }
! CHECK: %[[J_I32:.*]] = fir.convert %[[J_FINAL]] : (index) -> i32
! CHECK: fir.store %[[J_I32]] to %[[J_REF]] : !fir.ref<i32>
! CHECK: cf.br ^[[BODY1]]
! CHECK: ^[[RETURN]]:
! CHECK: return
subroutine empty_infinite_in_while(i)
integer :: i
do while (i .gt. 50)
do
end do
end do
end subroutine
! CHECK-LABEL: empty_infinite_in_while
! CHECK-SAME: %[[I_REF:.*]]: !fir.ref<i32>
! CHECK: cf.br ^bb1
! CHECK: ^bb1:
! CHECK: %[[I:.*]] = fir.load %[[I_REF]] : !fir.ref<i32>
! CHECK: %[[C50:.*]] = arith.constant 50 : i32
! CHECK: %[[COND:.*]] = arith.cmpi sgt, %[[I]], %[[C50]] : i32
! CHECK: cf.cond_br %[[COND]], ^[[INF_HEADER:.*]], ^[[EXIT:.*]]
! CHECK: ^[[INF_HEADER]]:
! CHECK: cf.br ^[[INF_BODY:.*]]
! CHECK: ^[[INF_BODY]]:
! CHECK: cf.br ^[[INF_HEADER]]
! CHECK: ^[[EXIT]]:
! CHECK: return