content: /*
   * Copyright (C) 2016 The Android Open Source Project
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   *      http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  /**
   * Tests on loop optimizations related to induction.
   */
  public class Main {
  
    static int[] a = new int[10];
  
    static int[] novec = new int[20];  // to prevent vectorization
  
    /// CHECK-START: void Main.deadSingleLoop() loop_optimization (before)
    /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
    //
    /// CHECK-START: void Main.deadSingleLoop() loop_optimization (after)
    /// CHECK-NOT: Phi
    static void deadSingleLoop() {
      for (int i = 0; i < 4; i++) {
      }
    }
  
    /// CHECK-START: void Main.deadSingleLoop() loop_optimization (before)
    /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
    //
    /// CHECK-START: void Main.deadSingleLoop() loop_optimization (after)
    /// CHECK-NOT: Phi
    static void deadSingleLoopN(int n) {
      for (int i = 0; i < n; i++) {
      }
    }
  
    /// CHECK-START: void Main.potentialInfiniteLoop(int) loop_optimization (before)
    /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
    //
    /// CHECK-START: void Main.potentialInfiniteLoop(int) loop_optimization (after)
    /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
    static void potentialInfiniteLoop(int n) {
      for (int i = 0; i <= n; i++) {  // loops forever when n = MAX_INT
      }
    }
  
    /// CHECK-START: void Main.deadNestedLoops() loop_optimization (before)
    /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: Phi loop:{{B\d+}}      outer_loop:<<Loop>>
    //
    /// CHECK-START: void Main.deadNestedLoops() loop_optimization (after)
    /// CHECK-NOT: Phi
    static void deadNestedLoops() {
      for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
        }
      }
    }
  
    /// CHECK-START: void Main.deadNestedAndFollowingLoops() loop_optimization (before)
    /// CHECK-DAG: Phi loop:<<Loop1:B\d+>> outer_loop:none
    /// CHECK-DAG: Phi loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
    /// CHECK-DAG: Phi loop:{{B\d+}}       outer_loop:<<Loop2>>
    /// CHECK-DAG: Phi loop:{{B\d+}}       outer_loop:<<Loop2>>
    /// CHECK-DAG: Phi loop:<<Loop3:B\d+>> outer_loop:<<Loop1>>
    /// CHECK-DAG: Phi loop:{{B\d+}}       outer_loop:<<Loop3>>
    /// CHECK-DAG: Phi loop:{{B\d+}}       outer_loop:none
    //
    /// CHECK-START: void Main.deadNestedAndFollowingLoops() loop_optimization (after)
    /// CHECK-NOT: Phi
    static void deadNestedAndFollowingLoops() {
      for (int i = 0; i < 4; i++) {
        for (int j = 0; j < 4; j++) {
          for (int k = 0; k < 4; k++) {
          }
          for (int k = 0; k < 4; k++) {
          }
        }
        for (int j = 0; j < 4; j++) {
          for (int k = 0; k < 4; k++) {
          }
        }
      }
      for (int i = 0; i < 4; i++) {
      }
    }
  
    /// CHECK-START: void Main.deadConditional(int) loop_optimization (before)
    /// CHECK-DAG: Phi loop:{{B\d+}} outer_loop:none
    //
    /// CHECK-START: void Main.deadConditional(int) loop_optimization (after)
    /// CHECK-NOT: Phi
    public static void deadConditional(int n) {
      int k = 0;
      int m = 0;
      for (int i = 0; i < n; i++) {
        if (i == 3)
          k = i;
        else
          m = i;
      }
    }
  
    /// CHECK-START: void Main.deadConditionalCycle(int) loop_optimization (before)
    /// CHECK-DAG: Phi loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: Phi loop:<<Loop>>      outer_loop:none
    //
    /// CHECK-START: void Main.deadConditionalCycle(int) loop_optimization (after)
    /// CHECK-NOT: Phi
    public static void deadConditionalCycle(int n) {
      int k = 0;
      int m = 0;
      for (int i = 0; i < n; i++) {
        if (i == 3)
          k--;
        else
          m++;
      }
    }
  
  
    /// CHECK-START: void Main.deadInduction() loop_optimization (before)
    /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: Phi      loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
    //
    /// CHECK-START: void Main.deadInduction() loop_optimization (after)
    /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-NOT: Phi      loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
    static void deadInduction() {
      int dead = 0;
      for (int i = 0; i < a.length; i++) {
        a[i] = novec[2 * i] + 1;
        dead += 5;
      }
    }
  
    /// CHECK-START: void Main.deadManyInduction() loop_optimization (before)
    /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: Phi      loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: Phi      loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: Phi      loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
    //
    /// CHECK-START: void Main.deadManyInduction() loop_optimization (after)
    /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-NOT: Phi      loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
    static void deadManyInduction() {
      int dead1 = 0, dead2 = 1, dead3 = 3;
      for (int i = 0; i < a.length; i++) {
        dead1 += 5;
        a[i] = novec[2 * i] + 2;
        dead2 += 10;
        dead3 += 100;
      }
    }
  
    /// CHECK-START: void Main.deadSequence() loop_optimization (before)
    /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: Phi      loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
    //
    /// CHECK-START: void Main.deadSequence() loop_optimization (after)
    /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-NOT: Phi      loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
    static void deadSequence() {
      int dead = 0;
      for (int i = 0; i < a.length; i++) {
        a[i] = novec[2 * i] + 3;
        // Increment value defined inside loop,
        // but sequence itself not used anywhere.
        dead += i;
      }
    }
  
    /// CHECK-START: void Main.deadCycleWithException(int) loop_optimization (before)
    /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: Phi      loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
    /// CHECK-NOT: BoundsCheck
    //
    /// CHECK-START: void Main.deadCycleWithException(int) loop_optimization (after)
    /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-NOT: Phi      loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
    /// CHECK-NOT: ArrayGet loop:<<Loop>>      outer_loop:none
    static void deadCycleWithException(int k) {
      int dead = 0;
      for (int i = 0; i < a.length; i++) {
        a[i] = novec[2 * i] + 4;
        // Increment value of dead cycle may throw exception. Dynamic
        // BCE takes care of the bounds check though, which enables
        // removing the ArrayGet after removing the dead cycle.
        dead += a[k];
      }
    }
  
    /// CHECK-START: int Main.closedFormInductionUp() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi1>>] loop:none
    //
    /// CHECK-START: int Main.closedFormInductionUp() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: int Main.closedFormInductionUp() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 12395 loop:none
    /// CHECK-DAG:               Return [<<Int>>]  loop:none
    static int closedFormInductionUp() {
      int closed = 12345;
      for (int i = 0; i < 10; i++) {
        closed += 5;
      }
      return closed;  // only needs last value
    }
  
    /// CHECK-START: int Main.closedFormInductionInAndDown(int) loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: int Main.closedFormInductionInAndDown(int) loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: int Main.closedFormInductionInAndDown(int) instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Par:i\d+>>  ParameterValue        loop:none
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant -50       loop:none
    /// CHECK-DAG: <<Add:i\d+>>  Add [<<Int>>,<<Par>>] loop:none
    /// CHECK-DAG:               Return [<<Add>>]      loop:none
    static int closedFormInductionInAndDown(int closed) {
      for (int i = 0; i < 10; i++) {
        closed -= 5;
      }
      return closed;  // only needs last value
    }
  
    /// CHECK-START: int Main.closedFormInductionTrivialIf() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Select            loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi1>>] loop:none
    //
    /// CHECK-START: int Main.closedFormInductionTrivialIf() loop_optimization (after)
    /// CHECK-NOT:               Phi
    /// CHECK-NOT:               Select
    //
    /// CHECK-START: int Main.closedFormInductionTrivialIf() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 81    loop:none
    /// CHECK-DAG:               Return [<<Int>>]  loop:none
    static int closedFormInductionTrivialIf() {
      int closed = 11;
      for (int i = 0; i < 10; i++) {
        // Trivial if becomes trivial select at HIR level.
        // Make sure this is still recognized as induction.
        if (i < 5) {
          closed += 7;
        } else {
          closed += 7;
        }
      }
      return closed;  // only needs last value
    }
  
    /// CHECK-START: int Main.closedFormNested() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop1:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop1>>      outer_loop:none
    /// CHECK-DAG: <<Phi3:i\d+>> Phi               loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
    /// CHECK-DAG: <<Phi4:i\d+>> Phi               loop:<<Loop2>>      outer_loop:<<Loop1>>
    /// CHECK-DAG:               Return [<<Phi1>>] loop:none
    //
    /// CHECK-START: int Main.closedFormNested() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: int Main.closedFormNested() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 100  loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    static int closedFormNested() {
      int closed = 0;
      for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 10; j++) {
          closed++;
        }
      }
      return closed;  // only needs last-value
    }
  
    /// CHECK-START: int Main.closedFormNestedAlt() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop1:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop1>>      outer_loop:none
    /// CHECK-DAG: <<Phi3:i\d+>> Phi               loop:<<Loop2:B\d+>> outer_loop:<<Loop1>>
    /// CHECK-DAG: <<Phi4:i\d+>> Phi               loop:<<Loop2>>      outer_loop:<<Loop1>>
    /// CHECK-DAG:               Return [<<Phi1>>] loop:none
    //
    /// CHECK-START: int Main.closedFormNestedAlt() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: int Main.closedFormNestedAlt() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 15082 loop:none
    /// CHECK-DAG:               Return [<<Int>>]  loop:none
    static int closedFormNestedAlt() {
      int closed = 12345;
      for (int i = 0; i < 17; i++) {
        for (int j = 0; j < 23; j++) {
          closed += 7;
        }
      }
      return closed;  // only needs last-value
    }
  
    // TODO: taken test around closed form?
    static int closedFormInductionUpN(int n) {
      int closed = 12345;
      for (int i = 0; i < n; i++) {
        closed += 5;
      }
      return closed;  // only needs last value
    }
  
    // TODO: taken test around closed form?
    static int closedFormInductionInAndDownN(int closed, int n) {
      for (int i = 0; i < n; i++) {
        closed -= 5;
      }
      return closed;  // only needs last value
    }
  
    // TODO: move closed form even further out?
    static int closedFormNestedN(int n) {
      int closed = 0;
      for (int i = 0; i < n; i++) {
        for (int j = 0; j < 10; j++) {
          closed++;
        }
      }
      return closed;  // only needs last-value
    }
  
    // TODO: move closed form even further out?
    static int closedFormNestedNAlt(int n) {
      int closed = 12345;
      for (int i = 0; i < n; i++) {
        for (int j = 0; j < 23; j++) {
          closed += 7;
        }
      }
      return closed;  // only needs last-value
    }
  
    // TODO: move closed form even further out?
    static int closedFormNestedMN(int m, int n) {
      int closed = 0;
      for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
          closed++;
        }
      }
      return closed;  // only needs last-value
    }
  
    // TODO: move closed form even further out?
    static int closedFormNestedMNAlt(int m, int n) {
      int closed = 12345;
      for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
          closed += 7;
        }
      }
      return closed;  // only needs last-value
    }
  
    /// CHECK-START: int Main.mainIndexReturned() loop_optimization (before)
    /// CHECK-DAG: <<Phi:i\d+>> Phi              loop:{{B\d+}} outer_loop:none
    /// CHECK-DAG:              Return [<<Phi>>] loop:none
    //
    /// CHECK-START: int Main.mainIndexReturned() loop_optimization (after)
    /// CHECK-NOT:              Phi
    //
    /// CHECK-START: int Main.mainIndexReturned() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 10   loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    static int mainIndexReturned() {
      int i;
      for (i = 0; i < 10; i++);
      return i;
    }
  
    /// CHECK-START: int Main.periodicReturned9() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: int Main.periodicReturned9() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: int Main.periodicReturned9() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 1    loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    static int periodicReturned9() {
      int k = 0;
      for (int i = 0; i < 9; i++) {
        k = 1 - k;
      }
      return k;
    }
  
    /// CHECK-START: int Main.periodicReturned10() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: int Main.periodicReturned10() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: int Main.periodicReturned10() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 0    loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    static int periodicReturned10() {
      int k = 0;
      for (int i = 0; i < 10; i++) {
        k = 1 - k;
      }
      return k;
    }
  
    /// CHECK-START: int Main.getSum21() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: <<Phi3:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi3>>] loop:none
    //
    /// CHECK-START: int Main.getSum21() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: int Main.getSum21() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 21   loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    private static int getSum21() {
      int k = 0;
      int sum = 0;
      for (int i = 0; i < 6; i++) {
        k++;
        sum += k;
      }
      return sum;
    }
  
    // TODO: handle as closed/empty eventually?
    static int mainIndexReturnedN(int n) {
      int i;
      for (i = 0; i < n; i++);
      return i;
    }
  
    // TODO: handle as closed/empty eventually?
    static int mainIndexShort1(short s) {
      int i = 0;
      for (i = 0; i < s; i++) { }
      return i;
    }
  
    // TODO: handle as closed/empty eventually?
    static int mainIndexShort2(short s) {
      int i = 0;
      for (i = 0; s > i; i++) { }
      return i;
    }
  
    /// CHECK-START: int Main.periodicReturnedN(int) loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: int Main.periodicReturnedN(int) loop_optimization (after)
    /// CHECK-NOT:               Phi
    static int periodicReturnedN(int n) {
      int k = 0;
      for (int i = 0; i < n; i++) {
        k = 1 - k;
      }
      return k;
    }
  
    // If ever replaced by closed form, last value should be correct!
    private static int getSumN(int n) {
      int k = 0;
      int sum = 0;
      for (int i = 0; i < n; i++) {
        k++;
        sum += k;
      }
      return sum;
    }
  
    // If ever replaced by closed form, last value should be correct!
    private static int closedTwice() {
      int closed = 0;
      for (int i = 0; i < 10; i++) {
        closed++;
      }
      // Closed form of first loop defines trip count of second loop.
      int other_closed = 0;
      for (int i = 0; i < closed; i++) {
        other_closed++;
      }
      return other_closed;
    }
  
    /// CHECK-START: int Main.closedFeed() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop1:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop1>>      outer_loop:none
    /// CHECK-DAG: <<Phi3:i\d+>> Phi               loop:<<Loop2:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi4:i\d+>> Phi               loop:<<Loop2>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi3>>] loop:none
    /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
    //
    /// CHECK-START: int Main.closedFeed() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: int Main.closedFeed() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 20   loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    private static int closedFeed() {
      int closed = 0;
      for (int i = 0; i < 10; i++) {
        closed++;
      }
      // Closed form of first loop feeds into initial value of second loop,
      // used when generating closed form for the latter.
      for (int i = 0; i < 10; i++) {
        closed++;
      }
      return closed;
    }
  
    /// CHECK-START: int Main.closedLargeUp() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi1>>] loop:none
    //
    /// CHECK-START: int Main.closedLargeUp() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: int Main.closedLargeUp() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant -10  loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    private static int closedLargeUp() {
      int closed = 0;
      for (int i = 0; i < 10; i++) {
        closed += 0x7fffffff;
      }
      return closed;
    }
  
    /// CHECK-START: int Main.closedLargeDown() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi1>>] loop:none
    //
    /// CHECK-START: int Main.closedLargeDown() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: int Main.closedLargeDown() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 10   loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    private static int closedLargeDown() {
      int closed = 0;
      for (int i = 0; i < 10; i++) {
        closed -= 0x7fffffff;
      }
      return closed;
    }
  
    /// CHECK-START: int Main.waterFall() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop1:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop2:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi3:i\d+>> Phi               loop:<<Loop3:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi4:i\d+>> Phi               loop:<<Loop4:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi5:i\d+>> Phi               loop:<<Loop5:B\d+>> outer_loop:none
    /// CHECK-DAG:               Return [<<Phi5>>] loop:none
    //
    /// CHECK-START: int Main.waterFall() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: int Main.waterFall() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 50   loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    private static int waterFall() {
      int i = 0;
      for (; i < 10; i++);
      for (; i < 20; i++);
      for (; i < 30; i++);
      for (; i < 40; i++);
      for (; i < 50; i++);
      return i;  // this should become just 50
    }
  
    /// CHECK-START: boolean Main.periodicBoolIdiom1() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: boolean Main.periodicBoolIdiom1() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: boolean Main.periodicBoolIdiom1() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 0    loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    private static boolean periodicBoolIdiom1() {
      boolean x = true;
      for (int i = 0; i < 7; i++) {
        x = !x;
      }
      return x;
    }
  
    /// CHECK-START: boolean Main.periodicBoolIdiom2() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: boolean Main.periodicBoolIdiom2() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: boolean Main.periodicBoolIdiom2() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 0    loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    private static boolean periodicBoolIdiom2() {
      boolean x = true;
      for (int i = 0; i < 7; i++) {
        x = (x != true);
      }
      return x;
    }
  
    /// CHECK-START: boolean Main.periodicBoolIdiom3() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: boolean Main.periodicBoolIdiom3() loop_optimization (after)
    /// CHECK-NOT:               Phi
    //
    /// CHECK-START: boolean Main.periodicBoolIdiom3() instruction_simplifier$after_bce (after)
    /// CHECK-DAG: <<Int:i\d+>>  IntConstant 0    loop:none
    /// CHECK-DAG:               Return [<<Int>>] loop:none
    private static boolean periodicBoolIdiom3() {
      boolean x = true;
      for (int i = 0; i < 7; i++) {
        x = (x == false);
      }
      return x;
    }
  
    /// CHECK-START: boolean Main.periodicBoolIdiom1N(boolean, int) loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: boolean Main.periodicBoolIdiom1N(boolean, int) loop_optimization (after)
    /// CHECK-NOT:               Phi
    private static boolean periodicBoolIdiom1N(boolean x, int n) {
      for (int i = 0; i < n; i++) {
        x = !x;
      }
      return x;
    }
  
    /// CHECK-START: boolean Main.periodicBoolIdiom2N(boolean, int) loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: boolean Main.periodicBoolIdiom2N(boolean, int) loop_optimization (after)
    /// CHECK-NOT:               Phi
    private static boolean periodicBoolIdiom2N(boolean x, int n) {
      for (int i = 0; i < n; i++) {
        x = (x != true);
      }
      return x;
    }
  
    /// CHECK-START: boolean Main.periodicBoolIdiom3N(boolean, int) loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:i\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: boolean Main.periodicBoolIdiom3N(boolean, int) loop_optimization (after)
    /// CHECK-NOT:               Phi
    private static boolean periodicBoolIdiom3N(boolean x, int n) {
      for (int i = 0; i < n; i++) {
        x = (x == false);
      }
      return x;
    }
  
    /// CHECK-START: float Main.periodicFloat10() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:f\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: <<Phi3:f\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: <<Phi4:f\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: float Main.periodicFloat10() loop_optimization (after)
    /// CHECK-NOT: Phi
    //
    /// CHECK-START: float Main.periodicFloat10() loop_optimization (after)
    /// CHECK-DAG: <<Float:f\d+>>  FloatConstant 2    loop:none
    /// CHECK-DAG:                 Return [<<Float>>] loop:none
    private static float periodicFloat10() {
      float r = 4.5f;
      float s = 2.0f;
      float t = -1.0f;
      for (int i = 0; i < 10; i++) {
        float tmp = t; t = r; r = s; s = tmp;
      }
      return r;
    }
  
    /// CHECK-START: float Main.periodicFloat11() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:f\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: <<Phi3:f\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: <<Phi4:f\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: float Main.periodicFloat11() loop_optimization (after)
    /// CHECK-NOT: Phi
    //
    /// CHECK-START: float Main.periodicFloat11() loop_optimization (after)
    /// CHECK-DAG: <<Float:f\d+>>  FloatConstant -1   loop:none
    /// CHECK-DAG:                 Return [<<Float>>] loop:none
    private static float periodicFloat11() {
      float r = 4.5f;
      float s = 2.0f;
      float t = -1.0f;
      for (int i = 0; i < 11; i++) {
        float tmp = t; t = r; r = s; s = tmp;
      }
      return r;
    }
  
    /// CHECK-START: float Main.periodicFloat12() loop_optimization (before)
    /// CHECK-DAG: <<Phi1:i\d+>> Phi               loop:<<Loop:B\d+>> outer_loop:none
    /// CHECK-DAG: <<Phi2:f\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: <<Phi3:f\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG: <<Phi4:f\d+>> Phi               loop:<<Loop>>      outer_loop:none
    /// CHECK-DAG:               Return [<<Phi2>>] loop:none
    //
    /// CHECK-START: float Main.periodicFloat12() loop_optimization (after)
    /// CHECK-NOT: Phi
    //
    /// CHECK-START: float Main.periodicFloat12() loop_optimization (after)
    /// CHECK-DAG: <<Float:f\d+>>  FloatConstant 4.5  loop:none
    /// CHECK-DAG:                 Return [<<Float>>] loop:none
    private static float periodicFloat12() {
      float r = 4.5f;
      float s = 2.0f;
      float t = -1.0f;
      for (int i = 0; i < 12; i++) {
        float tmp = t; t = r; r = s; s = tmp;
      }
      return r;
    }
  
    private static int exceptionExitBeforeAdd() {
      int k = 0;
      try {
        for (int i = 0; i < 10; i++) {
          a[i] = 0;
          k += 10;  // increment last
        }
      } catch(Exception e) {
        // Flag error by returning current
        // value of k negated.
        return -k-1;
      }
      return k;
    }
  
    private static int exceptionExitAfterAdd() {
      int k = 0;
      try {
        for (int i = 0; i < 10; i++) {
          k += 10;  // increment first
          a[i] = 0;
        }
      } catch(Exception e) {
        // Flag error by returning current
        // value of k negated.
        return -k-1;
      }
      return k;
    }
  
    public static void main(String[] args) {
      deadSingleLoop();
      deadSingleLoopN(4);
      potentialInfiniteLoop(4);
      deadNestedLoops();
      deadNestedAndFollowingLoops();
      deadConditional(4);
      deadConditionalCycle(4);
  
      deadInduction();
      for (int i = 0; i < a.length; i++) {
        expectEquals(1, a[i]);
      }
      deadManyInduction();
      for (int i = 0; i < a.length; i++) {
        expectEquals(2, a[i]);
      }
      deadSequence();
      for (int i = 0; i < a.length; i++) {
        expectEquals(3, a[i]);
      }
      try {
        deadCycleWithException(-1);
        throw new Error("Expected: IOOB exception");
      } catch (IndexOutOfBoundsException e) {
      }
      for (int i = 0; i < a.length; i++) {
        expectEquals(i == 0 ? 4 : 3, a[i]);
      }
      deadCycleWithException(0);
      for (int i = 0; i < a.length; i++) {
        expectEquals(4, a[i]);
      }
  
      expectEquals(12395, closedFormInductionUp());
      expectEquals(12295, closedFormInductionInAndDown(12345));
      expectEquals(81, closedFormInductionTrivialIf());
      expectEquals(10 * 10, closedFormNested());
      expectEquals(12345 + 17 * 23 * 7, closedFormNestedAlt());
      for (int n = -4; n < 10; n++) {
        int tc = (n <= 0) ? 0 : n;
        expectEquals(12345 + tc * 5, closedFormInductionUpN(n));
        expectEquals(12345 - tc * 5, closedFormInductionInAndDownN(12345, n));
        expectEquals(tc * 10, closedFormNestedN(n));
        expectEquals(12345 + tc * 23 * 7, closedFormNestedNAlt(n));
        expectEquals(tc * (tc + 1), closedFormNestedMN(n, n + 1));
        expectEquals(12345 + tc * (tc + 1) * 7, closedFormNestedMNAlt(n, n + 1));
      }
  
      expectEquals(10, mainIndexReturned());
      expectEquals(1, periodicReturned9());
      expectEquals(0, periodicReturned10());
      expectEquals(21, getSum21());
      for (int n = -4; n < 4; n++) {
        int tc = (n <= 0) ? 0 : n;
        expectEquals(tc, mainIndexReturnedN(n));
        expectEquals(tc, mainIndexShort1((short) n));
        expectEquals(tc, mainIndexShort2((short) n));
        expectEquals(tc & 1, periodicReturnedN(n));
        expectEquals((tc * (tc + 1)) / 2, getSumN(n));
      }
  
      expectEquals(10, closedTwice());
      expectEquals(20, closedFeed());
      expectEquals(-10, closedLargeUp());
      expectEquals(10, closedLargeDown());
      expectEquals(50, waterFall());
  
      expectEquals(false, periodicBoolIdiom1());
      expectEquals(false, periodicBoolIdiom2());
      expectEquals(false, periodicBoolIdiom3());
      for (int n = -4; n < 10; n++) {
        int tc = (n <= 0) ? 0 : n;
        boolean even = (tc & 1) == 0;
        expectEquals(even, periodicBoolIdiom1N(true, n));
        expectEquals(!even, periodicBoolIdiom1N(false, n));
        expectEquals(even, periodicBoolIdiom2N(true, n));
        expectEquals(!even, periodicBoolIdiom2N(false, n));
        expectEquals(even, periodicBoolIdiom3N(true, n));
        expectEquals(!even, periodicBoolIdiom3N(false, n));
      }
  
      expectEquals( 2.0f, periodicFloat10());
      expectEquals(-1.0f, periodicFloat11());
      expectEquals( 4.5f, periodicFloat12());
  
      expectEquals(100, exceptionExitBeforeAdd());
      expectEquals(100, exceptionExitAfterAdd());
      a = null;
      expectEquals(-1, exceptionExitBeforeAdd());
      expectEquals(-11, exceptionExitAfterAdd());
      a = new int[4];
      expectEquals(-41, exceptionExitBeforeAdd());
      expectEquals(-51, exceptionExitAfterAdd());
  
      System.out.println("passed");
    }
  
    private static void expectEquals(float expected, float result) {
      if (expected != result) {
        throw new Error("Expected: " + expected + ", found: " + result);
      }
    }
  
    private static void expectEquals(int expected, int result) {
      if (expected != result) {
        throw new Error("Expected: " + expected + ", found: " + result);
      }
    }
  
    private static void expectEquals(boolean expected, boolean result) {
      if (expected != result) {
        throw new Error("Expected: " + expected + ", found: " + result);
      }
    }
  }
  