[flang-commits] [flang] 8c349d7 - [Flang] Lower the infinite do loop

Kiran Chandramohan via flang-commits flang-commits at lists.llvm.org
Wed Jun 1 05:07:15 PDT 2022


Author: Kiran Chandramohan
Date: 2022-06-01T12:06:40Z
New Revision: 8c349d707ec2677e6235b4e9e3efa1e0c4de11f2

URL: https://github.com/llvm/llvm-project/commit/8c349d707ec2677e6235b4e9e3efa1e0c4de11f2
DIFF: https://github.com/llvm/llvm-project/commit/8c349d707ec2677e6235b4e9e3efa1e0c4de11f2.diff

LOG: [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 at nvidia.com>
Co-authored-by: V Donaldson <vdonaldson at nvidia.com>

Added: 
    flang/test/Lower/infinite_loop.f90

Modified: 
    flang/lib/Lower/Bridge.cpp

Removed: 
    


################################################################################
diff  --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp
index bbce38eb3ad8..a1100ac0afe3 100644
--- a/flang/lib/Lower/Bridge.cpp
+++ b/flang/lib/Lower/Bridge.cpp
@@ -983,8 +983,13 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     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 @@ class FirConverter : public Fortran::lower::AbstractConverter {
       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 @@ class FirConverter : public Fortran::lower::AbstractConverter {
     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
index 000000000000..8c36ac105c46
--- /dev/null
+++ b/flang/test/Lower/infinite_loop.f90
@@ -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


        


More information about the flang-commits mailing list