/*
 * Copyright (C) 2015 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.
 */


public class Main {

  /// CHECK-START: void Main.loop1(boolean) liveness (after)
  /// CHECK-DAG:     <<Arg:z\d+>>  ParameterValue  liveness:<<ArgLiv:\d+>>  ranges:{[<<ArgLiv>>,<<ArgUse:\d+>>)} uses:[<<ArgUse>>]
  /// CHECK-DAG:                   If [<<Arg>>]    liveness:<<IfLiv:\d+>> loop:none
  /// CHECK-DAG:                   Goto                                   loop:B{{\d+}}
  /// CHECK-DAG:                   Exit
  /// CHECK-EVAL:    <<IfLiv>> + 1 == <<ArgUse>>
  //
  // Loop invariant exit check is hoisted from the loop by peeling.

  public static void loop1(boolean incoming) {
    while (incoming) {}
  }

  /// CHECK-START: void Main.loop2(boolean) liveness (after)
  /// CHECK-DAG:     <<Arg:z\d+>>  ParameterValue  liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse>>]
  /// CHECK-DAG:                   If [<<Arg>>]    liveness:<<IfLiv:\d+>>    loop:<<Loop1:B\d+>>
  /// CHECK-DAG:                   Goto            liveness:<<GotoLiv1:\d+>> loop:<<Loop1>>
  /// CHECK-DAG:                   Goto            liveness:<<GotoLiv2:\d+>> loop:<<Loop2:B\d+>>
  /// CHECK-EVAL:    <<IfLiv>> + 1 == <<ArgUse>>
  /// CHECK-EVAL:    <<GotoLiv1>> < <<GotoLiv2>>
  /// CHECK-EVAL:    <<GotoLiv1>> + 2 == <<ArgLoopUse>>
  //
  // Loop invariant exit check is hoisted from the loop by peeling.

  public static void loop2(boolean incoming) {
    // Add some code at entry to avoid having the entry block be a pre header.
    // This avoids having to create a synthesized block.
    System.out.println("Enter");
    while (true) {
      System.out.println("foo");
      while (incoming) {}
    }
  }

  /// CHECK-START: void Main.loop3(boolean) liveness (after)
  /// CHECK:         <<Arg:z\d+>>  ParameterValue  liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse>>]
  /// CHECK:                       Goto            liveness:<<GotoLiv1:\d+>>
  /// CHECK:                       InvokeVirtual   [{{l\d+}},<<Arg>>] method_name:java.io.PrintStream.println liveness:<<InvokeLiv:\d+>>
  /// CHECK:                       Goto            liveness:<<GotoLiv2:\d+>>
  /// CHECK-EVAL:    <<InvokeLiv>> == <<ArgUse>>
  /// CHECK-EVAL:    <<GotoLiv1>> < <<GotoLiv2>>
  /// CHECK-EVAL:    <<GotoLiv2>> + 2 == <<ArgLoopUse>>

  public static void loop3(boolean incoming) {
    // 'incoming' only needs a use at the outer loop's back edge.
    while (System.currentTimeMillis() != 42) {
      while (Runtime.getRuntime() != null) {}
      System.out.println(incoming);
    }
  }

  /// CHECK-START: void Main.loop4(boolean) liveness (after)
  /// CHECK:         <<Arg:z\d+>> ParameterValue  liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgUse:\d+>>)} uses:[<<ArgUse>>]
  /// CHECK:                      InvokeVirtual   [{{l\d+}},<<Arg>>] method_name:java.io.PrintStream.println liveness:<<InvokeLiv:\d+>>
  /// CHECK-EVAL:    <<InvokeLiv>> == <<ArgUse>>

  public static void loop4(boolean incoming) {
    // 'incoming' has no loop use, so should not have back edge uses.
    System.out.println(incoming);
    while (System.currentTimeMillis() != 42) {
      while (Runtime.getRuntime() != null) {}
    }
  }

  /// CHECK-START: void Main.loop5(boolean) liveness (after)
  /// CHECK:         <<Arg:z\d+>>  ParameterValue  liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse2:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse1:\d+>>,<<ArgLoopUse2>>]
  /// CHECK:                       InvokeVirtual   [{{l\d+}},<<Arg>>] method_name:java.io.PrintStream.println liveness:<<InvokeLiv:\d+>>
  /// CHECK:                       Goto            liveness:<<GotoLiv1:\d+>>
  /// CHECK:                       Goto            liveness:<<GotoLiv2:\d+>>
  /// CHECK:                       Exit
  /// CHECK-EVAL:    <<InvokeLiv>> == <<ArgUse>>
  /// CHECK-EVAL:    <<GotoLiv1>> < <<GotoLiv2>>
  /// CHECK-EVAL:    <<GotoLiv1>> + 2 == <<ArgLoopUse1>>
  /// CHECK-EVAL:    <<GotoLiv2>> + 2 == <<ArgLoopUse2>>

  public static void loop5(boolean incoming) {
    // 'incoming' must have a use at both back edges.
    for (long i = System.nanoTime(); i < 42; ++i) {
      for (long j = System.currentTimeMillis(); j != 42; ++j) {
        System.out.println(incoming);
      }
    }
  }

  /// CHECK-START: void Main.loop6(boolean) liveness (after)
  /// CHECK:         <<Arg:z\d+>>  ParameterValue  liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse>>]
  /// CHECK:                       InvokeVirtual   [{{l\d+}},<<Arg>>] method_name:java.io.PrintStream.println liveness:<<InvokeLiv:\d+>>
  /// CHECK:                       Add
  /// CHECK:                       Goto            liveness:<<GotoLiv1:\d+>>
  /// CHECK:                       Add
  /// CHECK:                       Goto            liveness:<<GotoLiv2:\d+>>
  /// CHECK:                       Exit
  /// CHECK-EVAL:    <<InvokeLiv>> == <<ArgUse>>
  /// CHECK-EVAL:    <<GotoLiv1>> < <<GotoLiv2>>
  /// CHECK-EVAL:    <<GotoLiv2>> + 2 == <<ArgLoopUse>>

  public static void loop6(boolean incoming) {
    // 'incoming' must have a use only at the first loop's back edge.
    for (long i = System.nanoTime(); i < 42; ++i) {
      System.out.println(incoming);
      for (long j = System.currentTimeMillis(); j != 42; ++j) {
        System.out.print(j);  // non-empty body
      }
    }
  }

  /// CHECK-START: void Main.loop7(boolean) liveness (after)
  /// CHECK-DAG:     <<Arg:z\d+>>  ParameterValue  liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse:\d+>>)} uses:[<<ArgUse1:\d+>>,<<ArgUse2:\d+>>,<<ArgLoopUse>>]
  /// CHECK-DAG:                   InvokeVirtual   [{{l\d+}},<<Arg>>] method_name:java.io.PrintStream.println liveness:<<InvokeLiv:\d+>>
  /// CHECK-DAG:                   If              [<<Arg>>] liveness:<<IfLiv:\d+>> loop:<<Loop1:B\d+>>
  /// CHECK-DAG:                   Goto            liveness:<<GotoLiv1:\d+>>        loop:<<Loop1>>
  /// CHECK-DAG:                   Goto            liveness:<<GotoLiv2:\d+>>        loop:<<Loop2:B\d+>>
  /// CHECK-DAG:                   Exit
  /// CHECK-EVAL:    <<InvokeLiv>> == <<ArgUse1>>
  /// CHECK-EVAL:    <<IfLiv>> + 1 == <<ArgUse2>>
  /// CHECK-EVAL:    <<GotoLiv1>> < <<GotoLiv2>>
  /// CHECK-EVAL:    <<GotoLiv1>> + 2 == <<ArgLoopUse>>
  //
  // Loop invariant exit check is hoisted from the loop by peeling.

  public static void loop7(boolean incoming) {
    // 'incoming' must have a use at both back edges.
    while (Runtime.getRuntime() != null) {
      System.out.println(incoming);
      while (incoming) {}
      System.nanoTime();  // beat back edge splitting
    }
  }

  /// CHECK-START: void Main.loop8() liveness (after)
  /// CHECK-DAG:     <<Arg:z\d+>>  StaticFieldGet  liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgLoopUse:\d+>>)} uses:[<<ArgUse:\d+>>,<<ArgLoopUse>>]
  /// CHECK-DAG:                   If [<<Arg>>]    liveness:<<IfLiv:\d+>>     loop:<<Loop1:B\d+>>
  /// CHECK-DAG:                   Goto            liveness:<<GotoLiv1:\d+>>  loop:<<Loop1>>
  /// CHECK-DAG:                   Goto            liveness:<<GotoLiv2:\d+>>  loop:<<Loop2:B\d+>>
  /// CHECK-DAG:                   Exit
  /// CHECK-EVAL:    <<IfLiv>> + 1 == <<ArgUse>>
  /// CHECK-EVAL:    <<GotoLiv1>> < <<GotoLiv2>>
  /// CHECK-EVAL:    <<GotoLiv1>> + 2 == <<ArgLoopUse>>
  //
  // Loop invariant exit check is hoisted from the loop by peeling.

  public static void loop8() {
    // 'incoming' must have a use at both back edges.
    boolean incoming = field;
    while (Runtime.getRuntime() != null) {
      System.nanoTime();  // beat pre-header creation
      while (incoming) {}
      System.nanoTime();  // beat back edge splitting
    }
  }


  static boolean $opt$noinline$ensureSideEffects() {
    if (doThrow) throw new Error("");
    return true;
  }

  /// CHECK-START: void Main.loop9() liveness (after)
  /// CHECK-DAG:     <<Arg:z\d+>>  StaticFieldGet  liveness:<<ArgLiv:\d+>> ranges:{[<<ArgLiv>>,<<ArgUse:\d+>>)} uses:[<<ArgUse>>]
  /// CHECK-DAG:                   If [<<Arg>>]    liveness:<<IfLiv:\d+>>     loop:<<Loop1:B\d+>>
  /// CHECK-DAG:                   Goto            liveness:<<GotoLiv1:\d+>>  loop:<<Loop1>>
  /// CHECK-DAG:                   Goto            liveness:<<GotoLiv2:\d+>>  loop:<<Loop2:B\d+>>
  /// CHECK-DAG:                   Exit
  /// CHECK-EVAL:    <<IfLiv>> + 1 == <<ArgUse>>
  /// CHECK-EVAL:    <<GotoLiv1>> < <<GotoLiv2>>
  //
  // Loop invariant exit check is hoisted from the loop by peeling.

  public static void loop9() {
    // Add some code at entry to avoid having the entry block be a pre header.
    // This avoids having to create a synthesized block.
    System.out.println("Enter");
    while ($opt$noinline$ensureSideEffects()) {
      // 'incoming' must only have a use in the inner loop.
      boolean incoming = field;
      while (incoming) {}
    }
  }

  public static void main(String[] args) {
  }

  static boolean field;
  static boolean doThrow = false;
}
