[Flang] Lower the infinite do loop
authorKiran Chandramohan <kiran.chandramohan@arm.com>
Wed, 1 Jun 2022 11:48:20 +0000 (11:48 +0000)
committerKiran Chandramohan <kiran.chandramohan@arm.com>
Wed, 1 Jun 2022 12:06:40 +0000 (12:06 +0000)
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>
flang/lib/Lower/Bridge.cpp
flang/test/Lower/infinite_loop.f90 [new file with mode: 0644]

index bbce38e..a1100ac 100644 (file)
@@ -983,8 +983,13 @@ private:
     mlir::Block *exitBlock = doStmtEval.parentConstruct->constructExit->block;
     IncrementLoopNestInfo incrementLoopNestInfo;
     const Fortran::parser::ScalarLogicalExpr *whileCondition = nullptr;
-    if ((whileCondition = std::get_if<Fortran::parser::ScalarLogicalExpr>(
-             &loopControl->u))) {
+    bool infiniteLoop = !loopControl.has_value();
+    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");
       maybeStartBlock(preheaderBlock); // no block or empty block
       startBlock(headerBlock);
@@ -1008,9 +1013,8 @@ private:
       TODO(toLocation(), "infinite/unstructured loop/concurrent loop");
     }
 
-    // Increment loop begin code.  (TODO: Infinite/while code was already
-    // generated.)
-    if (!whileCondition)
+    // Increment loop begin code.  (Infinite/while code was already generated.)
+    if (!infiniteLoop && !whileCondition)
       genFIRIncrementLoopBegin(incrementLoopNestInfo);
 
     // Loop body code - NonLabelDoStmt and EndDoStmt code is generated here.
@@ -1018,8 +1022,8 @@ private:
     for (Fortran::lower::pft::Evaluation &e : eval.getNestedEvaluations())
       genFIR(e, unstructuredContext);
 
-    // Loop end code. (TODO: infinite loop)
-    if (whileCondition)
+    // Loop end code.
+    if (infiniteLoop || whileCondition)
       genFIRBranch(headerBlock);
     else
       genFIRIncrementLoopEnd(incrementLoopNestInfo);
diff --git a/flang/test/Lower/infinite_loop.f90 b/flang/test/Lower/infinite_loop.f90
new file mode 100644 (file)
index 0000000..8c36ac1
--- /dev/null
@@ -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