[flang] Fix invalid branch optimization
authorV Donaldson <vdonaldson@nvidia.com>
Sat, 10 Sep 2022 04:23:50 +0000 (21:23 -0700)
committerV Donaldson <vdonaldson@nvidia.com>
Mon, 12 Sep 2022 02:37:32 +0000 (19:37 -0700)
Branch optimization in function rewriteIfGotos attempts to rewrite code
such as

    <<IfConstruct>>
      1 If[Then]Stmt: if(cond) goto L
      2 GotoStmt: goto L
      3 EndIfStmt
    <<End IfConstruct>>
    4 Statement: ...
    5 Statement: ...
    6 Statement: L ...

to eliminate a branch and a trivial basic block to get:

    <<IfConstruct>>
      1 If[Then]Stmt [negate]: if(cond) goto L
      4 Statement: ...
      5 Statement: ...
      3 EndIfStmt
    <<End IfConstruct>>
    6 Statement: L ...

Among other requirements, this is invalid if any statement between the
GOTO and its target is an intermediate construct statement such as a
CASE or ELSE IF statement, like the CASE DEFAULT statement in:

  select case(i)
  case (:2)
    n = i * 10
  case (5:)
    n = i * 1000
    if (i <= 6) goto 9 ! exit over 'case default'; may not be rewritten
    n = i * 10000
  case default
    n = i * 100
9 end select

flang/lib/Lower/PFTBuilder.cpp
flang/test/Lower/select-case-statement.f90

index 16cfde1..59a9b2c 100644 (file)
@@ -503,7 +503,7 @@ private:
     for (auto it = evaluationList.begin(), end = evaluationList.end();
          it != end; ++it) {
       auto &eval = *it;
-      if (eval.isA<parser::EntryStmt>()) {
+      if (eval.isA<parser::EntryStmt>() || eval.isIntermediateConstructStmt()) {
         ifCandidateStack.clear();
         continue;
       }
index 5eaff33..d62e9e2 100644 (file)
     print*, n
   end subroutine
 
-
   ! CHECK-LABEL: func @_QPscharacter2
   subroutine scharacter2(s)
     ! CHECK-DAG: %[[V_0:[0-9]+]] = fir.alloca !fir.box<!fir.heap<!fir.char<1,?>>>
     ! CHECK:   return
   end subroutine
 
+  ! CHECK-LABEL: func @_QPsgoto
+  ! select case with goto exit
+  subroutine sgoto
+    n = 0
+    do i=1,8
+      ! CHECK:   %[[i:[0-9]+]] = fir.alloca {{.*}} "_QFsgotoEi"
+      ! CHECK: ^bb2:  // pred: ^bb1
+      ! CHECK:   %[[selector:[0-9]+]] = fir.load %[[i]] : !fir.ref<i32>
+      ! CHECK:   fir.select_case %[[selector]] : i32 [#fir.upper, %c2{{.*}}, ^bb3, #fir.lower, %c5{{.*}}, ^bb4, unit, ^bb7]
+      ! CHECK: ^bb3:  // pred: ^bb2
+      ! CHECK:   arith.muli %c10{{[^0]}}
+      ! CHECK:   br ^bb9
+      ! CHECK: ^bb4:  // pred: ^bb2
+      ! CHECK:   arith.muli %c1000{{[^0]}}
+      ! CHECK:   cond_br {{.*}}, ^bb5, ^bb6
+      ! CHECK: ^bb5:  // pred: ^bb4
+      ! CHECK:   br ^bb8
+      ! CHECK: ^bb6:  // pred: ^bb4
+      ! CHECK:   arith.muli %c10000{{[^0]}}
+      ! CHECK:   br ^bb9
+      ! CHECK: ^bb7:  // pred: ^bb2
+      ! CHECK:   arith.muli %c100{{[^0]}}
+      ! CHECK:   br ^bb8
+      ! CHECK: ^bb8:  // 2 preds: ^bb5, ^bb7
+      ! CHECK:   br ^bb9
+      ! CHECK: ^bb9:  // 3 preds: ^bb3, ^bb6, ^bb8
+      ! CHECK:   fir.call @_FortranAioBeginExternalListOutput
+      select case(i)
+      case (:2)
+        n = i * 10
+      case (5:)
+        n = i * 1000
+        if (i <= 6) goto 9
+        n = i * 10000
+      case default
+        n = i * 100
+  9   end select
+      print*, n
+    enddo
+    ! CHECK:   return
+  end
 
   ! CHECK-LABEL: func @_QPswhere
   subroutine swhere(num)
     call sempty(3)            ! expected output: 3 i:case default; 3 c:case default
 
     print*
+    call sgoto                ! expected output:  10 20 300 400 5000 6000 70000 80000 
+
+    print*
     call swhere(1)            ! expected output: 42.
     call sforall(1)           ! expected output: 42.
   end