A few more tests for LICM.

Rationale:
These tests ensure that some possible improvements in LICM
(e.g. hoisting add in environment out of the loops) will
be done right in the future.

Test: test-art-host

Change-Id: Ic00775ccf03408273d427ee9399df55b091c9fa4
diff --git a/test/445-checker-licm/expected.txt b/test/445-checker-licm/expected.txt
index e69de29..b0aad4d 100644
--- a/test/445-checker-licm/expected.txt
+++ b/test/445-checker-licm/expected.txt
@@ -0,0 +1 @@
+passed
diff --git a/test/445-checker-licm/src/Main.java b/test/445-checker-licm/src/Main.java
index 061fe6e..00ce3a9 100644
--- a/test/445-checker-licm/src/Main.java
+++ b/test/445-checker-licm/src/Main.java
@@ -164,8 +164,43 @@
     return result;
   }
 
+  //
+  // All operations up to the null check can be hoisted out of the
+  // loop. The null check itself sees the induction in its environment.
+  //
+  /// CHECK-START: int Main.doWhile(int) licm (before)
+  /// CHECK-DAG: <<Add:i\d+>> Add                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:              LoadClass           loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get:l\d+>> StaticFieldGet      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:              NullCheck [<<Get>>] env:[[<<Add>>,<<Get>>,{{i\d+}}]] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:              ArrayLength         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:              BoundsCheck         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:              ArrayGet            loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START: int Main.doWhile(int) licm (after)
+  /// CHECK-NOT: LoadClass      loop:{{B\d+}}
+  /// CHECK-NOT: StaticFieldGet loop:{{B\d+}}
+  //
+  /// CHECK-START: int Main.doWhile(int) licm (after)
+  /// CHECK-DAG:              LoadClass           loop:none
+  /// CHECK-DAG: <<Get:l\d+>> StaticFieldGet      loop:none
+  /// CHECK-DAG: <<Add:i\d+>> Add                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:              NullCheck [<<Get>>] env:[[<<Add>>,<<Get>>,{{i\d+}}]] loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:              ArrayLength         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:              BoundsCheck         loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:              ArrayGet            loop:<<Loop>>      outer_loop:none
+  public static int doWhile(int k) {
+    int i = k;
+    do {
+      i += 2;
+    } while (staticArray[i] == 0);
+    return i;
+  }
+
   public static int staticField = 42;
 
+  public static int[] staticArray = null;
+
   public static void assertEquals(int expected, int actual) {
     if (expected != actual) {
       throw new Error("Expected " + expected + ", got " + actual);
@@ -181,5 +216,24 @@
     assertEquals(21, divAndIntrinsic(new int[] { 4, -2, 8, -3 }));
     assertEquals(45, invariantBoundIntrinsic(-10));
     assertEquals(30, invariantBodyIntrinsic(2, 3));
+
+    staticArray = null;
+    try {
+      doWhile(0);
+      throw new Error("Expected NPE");
+    } catch (NullPointerException e) {
+    }
+    staticArray = new int[5];
+    staticArray[4] = 1;
+    assertEquals(4, doWhile(-2));
+    assertEquals(4, doWhile(0));
+    assertEquals(4, doWhile(2));
+    try {
+      doWhile(1);
+      throw new Error("Expected IOOBE");
+    } catch (IndexOutOfBoundsException e) {
+    }
+
+    System.out.println("passed");
   }
 }
diff --git a/test/625-checker-licm-regressions/src/Main.java b/test/625-checker-licm-regressions/src/Main.java
index cc1e07c..f372b1c 100644
--- a/test/625-checker-licm-regressions/src/Main.java
+++ b/test/625-checker-licm-regressions/src/Main.java
@@ -47,14 +47,83 @@
     } while (j < arr.length);
   }
 
+  //
+  // Similar situation as in foo(), but now a proper induction value
+  // is assigned to the field inside the do-while loop.
+  //
+  /// CHECK-START: void Main.bar(int[]) licm (before)
+  /// CHECK-DAG: LoadClass      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: StaticFieldSet loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: NullCheck      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: ArrayLength    loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START: void Main.bar(int[]) licm (after)
+  /// CHECK-DAG: LoadClass      loop:none
+  /// CHECK-DAG: StaticFieldSet loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: NullCheck      loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: ArrayLength    loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START: void Main.bar(int[]) licm (after)
+  /// CHECK-NOT: LoadClass      loop:{{B\d+}} outer_loop:none
+  static void bar(int[] arr) {
+    int j = 0;
+    do {
+      j++;
+      sA = j;
+    } while (j < arr.length);
+  }
+
+  //
+  // Similar situation as in bar(), but now an explicit catch
+  // statement may need the latest value of local j.
+  //
+  /// CHECK-START: int Main.catcher(int[]) licm (before)
+  /// CHECK-DAG: NullCheck   loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>      outer_loop:none
+  //
+  /// CHECK-START: int Main.catcher(int[]) licm (after)
+  /// CHECK-DAG: NullCheck   loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: ArrayLength loop:<<Loop>>      outer_loop:none
+  static int catcher(int[] arr) {
+    int j = 0;
+    try {
+      do {
+        j++;
+      } while (j < arr.length);
+    } catch (NullPointerException e) {
+      return -j;  // flag exception with negative value
+    }
+    return j;
+  }
+
   public static void main(String[] args) {
     sA = 0;
     try {
       foo(null);
-    } catch (Exception e) {
+      throw new Error("Expected NPE");
+    } catch (NullPointerException e) {
     }
     expectEquals(1, sA);
 
+    sA = 0;
+    try {
+      bar(null);
+      throw new Error("Expected NPE");
+    } catch (NullPointerException e) {
+    }
+    expectEquals(1, sA);
+
+    for (int i = 0; i < 5; i++) {
+      sA = 0;
+      bar(new int[i]);
+      expectEquals(i == 0 ? 1 : i, sA);
+    }
+
+    expectEquals(-1, catcher(null));
+    for (int i = 0; i < 5; i++) {
+      expectEquals(i == 0 ? 1 : i, catcher(new int[i]));
+    }
+
     System.out.println("passed");
   }