diff options
Diffstat (limited to 'test')
| -rwxr-xr-x | test/004-JniTest/build | 28 | ||||
| -rw-r--r-- | test/004-JniTest/expected.txt | 3 | ||||
| -rw-r--r-- | test/004-JniTest/jni_test.cc | 19 | ||||
| -rw-r--r-- | test/004-JniTest/src/Main.java | 17 | ||||
| -rw-r--r-- | test/020-string/expected.txt | 6 | ||||
| -rw-r--r-- | test/020-string/src/Main.java | 45 | ||||
| -rw-r--r-- | test/082-inline-execute/src/Main.java | 2 | ||||
| -rw-r--r-- | test/449-checker-bce/src/Main.java | 74 | ||||
| -rw-r--r-- | test/530-checker-loops/src/Main.java | 849 | ||||
| -rw-r--r-- | test/530-checker-loops2/expected.txt | 0 | ||||
| -rw-r--r-- | test/530-checker-loops2/info.txt | 1 | ||||
| -rw-r--r-- | test/530-checker-loops2/src/Main.java | 999 | ||||
| -rw-r--r-- | test/550-checker-multiply-accumulate/src/Main.java | 215 | ||||
| -rw-r--r-- | test/564-checker-negbitwise/expected.txt | 0 | ||||
| -rw-r--r-- | test/564-checker-negbitwise/info.txt | 1 | ||||
| -rw-r--r-- | test/564-checker-negbitwise/src/Main.java | 207 | ||||
| -rw-r--r-- | test/577-checker-fp2int/expected.txt | 1 | ||||
| -rw-r--r-- | test/577-checker-fp2int/info.txt | 1 | ||||
| -rw-r--r-- | test/577-checker-fp2int/src/Main.java | 122 | ||||
| -rw-r--r-- | test/Android.run-test.mk | 12 |
20 files changed, 1794 insertions, 808 deletions
diff --git a/test/004-JniTest/build b/test/004-JniTest/build new file mode 100755 index 0000000000..e8e9f31ef4 --- /dev/null +++ b/test/004-JniTest/build @@ -0,0 +1,28 @@ +#!/bin/bash +# +# Copyright 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. +# Make us exit on a failure. +# +set -e + +# Hard-wired use of experimental jack. +# TODO: fix this temporary work-around for lambdas, see b/19467889 +export USE_JACK=true +# export JACK_SERVER=false +# export JACK_REPOSITORY="${ANDROID_BUILD_TOP}/prebuilts/sdk/tools/jacks" + +# e.g. /foo/bar/jack-3.10.ALPHA.jar -> 3.10.ALPHA +# export JACK_VERSION="$(find "$JACK_REPOSITORY" -name '*ALPHA*' | sed 's/.*jack-//g' | sed 's/[.]jar//g')" +./default-build "$@" --experimental lambdas diff --git a/test/004-JniTest/expected.txt b/test/004-JniTest/expected.txt index 155c6ae5f3..f7e404d30b 100644 --- a/test/004-JniTest/expected.txt +++ b/test/004-JniTest/expected.txt @@ -55,3 +55,6 @@ Calling method AbstractInterface->JniCallSoftConflictMethod on object of type Co DefaultInterface.JniCallSoftConflictMethod Calling method ConflictInterface->JniCallConflictDefaultMethod on object of type ConcreteClass EXCEPTION OCCURED: java.lang.IncompatibleClassChangeError: Conflicting default method implementations void ConflictInterface.JniCallConflictDefaultMethod() +hi-lambda: λ +hi-default δλ +hi-default δλ diff --git a/test/004-JniTest/jni_test.cc b/test/004-JniTest/jni_test.cc index f632331fe3..2bdf8d1e71 100644 --- a/test/004-JniTest/jni_test.cc +++ b/test/004-JniTest/jni_test.cc @@ -721,3 +721,22 @@ class JniCallDefaultMethodsTest { extern "C" JNIEXPORT void JNICALL Java_Main_testCallDefaultMethods(JNIEnv* env) { JniCallDefaultMethodsTest(env).Test(); } + +static void InvokeSpecificMethod(JNIEnv* env, jobject obj, const char* method) { + jclass lambda_class = env->FindClass("LambdaInterface"); + assert(!env->ExceptionCheck()); + assert(lambda_class != nullptr); + jmethodID method_id = env->GetMethodID(lambda_class, method, "()V"); + assert(!env->ExceptionCheck()); + env->CallVoidMethod(obj, method_id); + assert(!env->ExceptionCheck()); +} + +extern "C" JNIEXPORT void JNICALL Java_Main_testInvokeLambdaDefaultMethod( + JNIEnv* e, jclass, jobject l) { + InvokeSpecificMethod(e, l, "sayHiTwice"); +} + +extern "C" JNIEXPORT void JNICALL Java_Main_testInvokeLambdaMethod(JNIEnv* e, jclass, jobject l) { + InvokeSpecificMethod(e, l, "sayHi"); +} diff --git a/test/004-JniTest/src/Main.java b/test/004-JniTest/src/Main.java index 9f4a8522e7..e0530d8d62 100644 --- a/test/004-JniTest/src/Main.java +++ b/test/004-JniTest/src/Main.java @@ -40,6 +40,10 @@ public class Main { testProxyGetMethodID(); testJniCriticalSectionAndGc(); testCallDefaultMethods(); + String lambda = "λ"; + testInvokeLambdaMethod(() -> { System.out.println("hi-lambda: " + lambda); }); + String def = "δ"; + testInvokeLambdaDefaultMethod(() -> { System.out.println("hi-default " + def + lambda); }); } private static native void testCallDefaultMethods(); @@ -255,6 +259,19 @@ public class Main { } private static native void enterJniCriticalSection(int arraySize, byte[] array0, byte[] array); + + private static native void testInvokeLambdaMethod(LambdaInterface iface); + + private static native void testInvokeLambdaDefaultMethod(LambdaInterface iface); +} + +@FunctionalInterface +interface LambdaInterface { + public void sayHi(); + public default void sayHiTwice() { + sayHi(); + sayHi(); + } } class JniCallNonvirtualTest { diff --git a/test/020-string/expected.txt b/test/020-string/expected.txt index 081fea3a41..76b8929bd7 100644 --- a/test/020-string/expected.txt +++ b/test/020-string/expected.txt @@ -5,3 +5,9 @@ Compare unicode: -65302 Got expected exception subStr is 'uick brown fox jumps over the lazy ' Indexes are: 0:-1:0:43:33:-1:18:13:13:-1:18:18:-1:13:-1:-1:-1 +Got expected exception +Got expected exception +Got expected exception +Got expected exception +Got expected exception +llo And diff --git a/test/020-string/src/Main.java b/test/020-string/src/Main.java index b876e6ad21..710808255c 100644 --- a/test/020-string/src/Main.java +++ b/test/020-string/src/Main.java @@ -25,6 +25,7 @@ public class Main { basicTest(); indexTest(); constructorTest(); + copyTest(); } public static void basicTest() { @@ -117,4 +118,48 @@ public class Main { String s14 = new String(codePoints, 1, 3); String s15 = new String(stringBuilder); } + + public static void copyTest() { + String src = new String("Hello Android"); + char[] dst = new char[7]; + char[] tmp = null; + + try { + src.getChars(2, 9, tmp, 0); + System.out.println("GLITCH: expected exception"); + } catch (NullPointerException npe) { + System.out.println("Got expected exception"); + } + + try { + src.getChars(-1, 9, dst, 0); + System.out.println("GLITCH: expected exception"); + } catch (StringIndexOutOfBoundsException sioobe) { + System.out.println("Got expected exception"); + } + + try { + src.getChars(2, 19, dst, 0); + System.out.println("GLITCH: expected exception"); + } catch (StringIndexOutOfBoundsException sioobe) { + System.out.println("Got expected exception"); + } + + try { + src.getChars(2, 1, dst, 0); + System.out.println("GLITCH: expected exception"); + } catch (StringIndexOutOfBoundsException sioobe) { + System.out.println("Got expected exception"); + } + + try { + src.getChars(2, 10, dst, 0); + System.out.println("GLITCH: expected exception"); + } catch (ArrayIndexOutOfBoundsException aioobe) { + System.out.println("Got expected exception"); + } + + src.getChars(2, 9, dst, 0); + System.out.println(new String(dst)); + } } diff --git a/test/082-inline-execute/src/Main.java b/test/082-inline-execute/src/Main.java index 5b3fa14076..93a9005fe0 100644 --- a/test/082-inline-execute/src/Main.java +++ b/test/082-inline-execute/src/Main.java @@ -1039,6 +1039,7 @@ public class Main { Assert.assertEquals(StrictMath.round(-2.9d), -3l); Assert.assertEquals(StrictMath.round(-3.0d), -3l); Assert.assertEquals(StrictMath.round(0.49999999999999994d), 0l); + Assert.assertEquals(StrictMath.round(9007199254740991.0d), 9007199254740991l); // 2^53 - 1 Assert.assertEquals(StrictMath.round(Double.NaN), (long)+0.0d); Assert.assertEquals(StrictMath.round(Long.MAX_VALUE + 1.0d), Long.MAX_VALUE); Assert.assertEquals(StrictMath.round(Long.MIN_VALUE - 1.0d), Long.MIN_VALUE); @@ -1062,6 +1063,7 @@ public class Main { Assert.assertEquals(StrictMath.round(-3.0f), -3); // 0.4999999701976776123046875 Assert.assertEquals(StrictMath.round(Float.intBitsToFloat(0x3EFFFFFF)), (int)+0.0f); + Assert.assertEquals(StrictMath.round(16777215.0f), 16777215); // 2^24 - 1 Assert.assertEquals(StrictMath.round(Float.NaN), (int)+0.0f); Assert.assertEquals(StrictMath.round(Integer.MAX_VALUE + 1.0f), Integer.MAX_VALUE); Assert.assertEquals(StrictMath.round(Integer.MIN_VALUE - 1.0f), Integer.MIN_VALUE); diff --git a/test/449-checker-bce/src/Main.java b/test/449-checker-bce/src/Main.java index 32bbc5b61d..66e1d92cc2 100644 --- a/test/449-checker-bce/src/Main.java +++ b/test/449-checker-bce/src/Main.java @@ -137,20 +137,16 @@ public class Main { /// CHECK: ArraySet /// CHECK: BoundsCheck /// CHECK: ArraySet - /// CHECK: BoundsCheck - /// CHECK: ArraySet /// CHECK-START: void Main.$opt$noinline$constantIndexing2(int[]) BCE (after) - /// CHECK-NOT: Deoptimize - /// CHECK: BoundsCheck - /// CHECK: ArraySet - /// CHECK: BoundsCheck + /// CHECK: Deoptimize + /// CHECK-NOT: BoundsCheck /// CHECK: ArraySet - /// CHECK: BoundsCheck + /// CHECK-NOT: BoundsCheck /// CHECK: ArraySet - /// CHECK: BoundsCheck + /// CHECK-NOT: BoundsCheck /// CHECK: ArraySet - /// CHECK: BoundsCheck + /// CHECK-NOT: BoundsCheck /// CHECK: ArraySet static void $opt$noinline$constantIndexing2(int[] array) { @@ -158,8 +154,7 @@ public class Main { array[2] = 1; array[3] = 1; array[4] = 1; - array[-1] = 1; // prevents the whole opt on [-1:4] - if (array[1] == 1) { + if (array[1] != 1) { throw new Error(""); } } @@ -173,8 +168,41 @@ public class Main { /// CHECK: ArraySet /// CHECK: BoundsCheck /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet /// CHECK-START: void Main.constantIndexing2b(int[]) BCE (after) + /// CHECK-NOT: Deoptimize + /// CHECK: BoundsCheck + /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet + + static void constantIndexing2b(int[] array) { + array[0] = 6; + array[1] = 6; + array[2] = 6; + array[3] = 6; + array[-1] = 1; // prevents the whole opt on [-1:4] + } + + /// CHECK-START: void Main.constantIndexing2c(int[]) BCE (before) + /// CHECK: BoundsCheck + /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet + /// CHECK: BoundsCheck + /// CHECK: ArraySet + + /// CHECK-START: void Main.constantIndexing2c(int[]) BCE (after) /// CHECK: Deoptimize /// CHECK-NOT: BoundsCheck /// CHECK: ArraySet @@ -185,7 +213,7 @@ public class Main { /// CHECK-NOT: BoundsCheck /// CHECK: ArraySet - static void constantIndexing2b(int[] array) { + static void constantIndexing2c(int[] array) { array[0] = 7; array[1] = 7; array[2] = 7; @@ -440,31 +468,37 @@ public class Main { System.out.println("constant indices 1 failed!"); } + $opt$noinline$constantIndexing2(a6); + if (a6[0] != 0 || a6[1] != 1 || a6[2] != 1 || + a6[3] != 1 || a6[4] != 1 || a6[5] != 11) { + System.out.println("constant indices 2 failed!"); + } + caught = false; try { - $opt$noinline$constantIndexing2(a6); + constantIndexing2b(a6); } catch (ArrayIndexOutOfBoundsException e) { caught = true; } - if (!caught || a6[0] != 0 || a6[1] != 1 || a6[2] != 1 || - a6[3] != 1 || a6[4] != 1 || a6[5] != 11) { - System.out.println("constant indices 2 failed!"); + if (!caught || a6[0] != 6 || a6[1] != 6 || a6[2] != 6 || + a6[3] != 6 || a6[4] != 1 || a6[5] != 11) { + System.out.println("constant indices 2b failed!"); } caught = false; try { - constantIndexing2b(a1); + constantIndexing2c(a1); } catch (ArrayIndexOutOfBoundsException e) { caught = true; } if (!caught || a1[0] != 7) { - System.out.println("constant indices 2b failed!"); + System.out.println("constant indices 2c failed!"); } - constantIndexing2b(a6); + constantIndexing2c(a6); if (a6[0] != 7 || a6[1] != 7 || a6[2] != 7 || a6[3] != 7 || a6[4] != 1 || a6[5] != 11) { - System.out.println("constant indices 2b failed!"); + System.out.println("constant indices 2c failed!"); } int[] b4 = new int[4]; diff --git a/test/530-checker-loops/src/Main.java b/test/530-checker-loops/src/Main.java index deff279f77..d5111b0c14 100644 --- a/test/530-checker-loops/src/Main.java +++ b/test/530-checker-loops/src/Main.java @@ -394,6 +394,34 @@ public class Main { return result; } + /// CHECK-START: int Main.linearForNEArrayLengthUp(int[]) BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.linearForNEArrayLengthUp(int[]) BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int linearForNEArrayLengthUp(int[] x) { + int result = 0; + for (int i = 0; i != x.length; i++) { + result += x[i]; + } + return result; + } + + /// CHECK-START: int Main.linearForNEArrayLengthDown(int[]) BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.linearForNEArrayLengthDown(int[]) BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int linearForNEArrayLengthDown(int[] x) { + int result = 0; + for (int i = x.length - 1; i != -1; i--) { + result += x[i]; + } + return result; + } + /// CHECK-START: int Main.linearDoWhileUp() BCE (before) /// CHECK-DAG: BoundsCheck // @@ -471,7 +499,7 @@ public class Main { // /// CHECK-START: void Main.linearTriangularOnTwoArrayLengths(int) BCE (after) /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize + // TODO: also CHECK-NOT: Deoptimize, see b/27151190 private static void linearTriangularOnTwoArrayLengths(int n) { int[] a = new int[n]; for (int i = 0; i < a.length; i++) { @@ -513,7 +541,7 @@ public class Main { // /// CHECK-START: void Main.linearTriangularOnParameter(int) BCE (after) /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize + // TODO: also CHECK-NOT: Deoptimize, see b/27151190 private static void linearTriangularOnParameter(int n) { int[] a = new int[n]; for (int i = 0; i < n; i++) { @@ -528,22 +556,22 @@ public class Main { } } - /// CHECK-START: void Main.linearTriangularVariations(int) BCE (before) + /// CHECK-START: void Main.linearTriangularVariationsInnerStrict(int) BCE (before) /// CHECK-DAG: BoundsCheck /// CHECK-DAG: BoundsCheck /// CHECK-DAG: BoundsCheck /// CHECK-DAG: BoundsCheck // - /// CHECK-START: void Main.linearTriangularVariations(int) BCE (after) + /// CHECK-START: void Main.linearTriangularVariationsInnerStrict(int) BCE (after) /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static void linearTriangularVariations(int n) { + // TODO: also CHECK-NOT: Deoptimize, see b/27151190 + private static void linearTriangularVariationsInnerStrict(int n) { int[] a = new int[n]; for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { a[j] += 1; } - for (int j = i - 1; j >= 0; j--) { + for (int j = i - 1; j > -1; j--) { a[j] += 1; } for (int j = i; j < n; j++) { @@ -556,6 +584,34 @@ public class Main { verifyTriangular(a); } + /// CHECK-START: void Main.linearTriangularVariationsInnerNonStrict(int) BCE (before) + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.linearTriangularVariationsInnerNonStrict(int) BCE (after) + /// CHECK-NOT: BoundsCheck + // TODO: also CHECK-NOT: Deoptimize, see b/27151190 + private static void linearTriangularVariationsInnerNonStrict(int n) { + int[] a = new int[n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j <= i - 1; j++) { + a[j] += 1; + } + for (int j = i - 1; j >= 0; j--) { + a[j] += 1; + } + for (int j = i; j <= n - 1; j++) { + a[j] += 1; + } + for (int j = n - 1; j >= i; j--) { + a[j] += 1; + } + } + verifyTriangular(a); + } + // Verifier for triangular loops. private static void verifyTriangular(int[] a, int[] b, int m, int n) { expectEquals(n, a.length); @@ -577,596 +633,6 @@ public class Main { } } - /// CHECK-START: void Main.bubble(int[]) BCE (before) - /// CHECK-DAG: BoundsCheck - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: void Main.bubble(int[]) BCE (after) - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static void bubble(int[] a) { - for (int i = a.length; --i >= 0;) { - for (int j = 0; j < i; j++) { - if (a[j] > a[j+1]) { - int tmp = a[j]; - a[j] = a[j+1]; - a[j+1] = tmp; - } - } - } - } - - /// CHECK-START: int Main.periodicIdiom(int) BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.periodicIdiom(int) BCE (after) - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static int periodicIdiom(int tc) { - int[] x = { 1, 3 }; - // Loop with periodic sequence (0, 1). - int k = 0; - int result = 0; - for (int i = 0; i < tc; i++) { - result += x[k]; - k = 1 - k; - } - return result; - } - - /// CHECK-START: int Main.periodicSequence2(int) BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.periodicSequence2(int) BCE (after) - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static int periodicSequence2(int tc) { - int[] x = { 1, 3 }; - // Loop with periodic sequence (0, 1). - int k = 0; - int l = 1; - int result = 0; - for (int i = 0; i < tc; i++) { - result += x[k]; - int t = l; - l = k; - k = t; - } - return result; - } - - /// CHECK-START: int Main.periodicSequence4(int) BCE (before) - /// CHECK-DAG: BoundsCheck - /// CHECK-DAG: BoundsCheck - /// CHECK-DAG: BoundsCheck - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.periodicSequence4(int) BCE (after) - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static int periodicSequence4(int tc) { - int[] x = { 1, 3, 5, 7 }; - // Loop with periodic sequence (0, 1, 2, 3). - int k = 0; - int l = 1; - int m = 2; - int n = 3; - int result = 0; - for (int i = 0; i < tc; i++) { - result += x[k] + x[l] + x[m] + x[n]; // all used at once - int t = n; - n = k; - k = l; - l = m; - m = t; - } - return result; - } - - /// CHECK-START: int Main.justRightUp1() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.justRightUp1() BCE (after) - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static int justRightUp1() { - int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int result = 0; - for (int i = Integer.MAX_VALUE - 10, k = 0; i < Integer.MAX_VALUE; i++) { - result += x[k++]; - } - return result; - } - - /// CHECK-START: int Main.justRightUp2() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.justRightUp2() BCE (after) - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static int justRightUp2() { - int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int result = 0; - for (int i = Integer.MAX_VALUE - 10; i < Integer.MAX_VALUE; i++) { - result += x[i - Integer.MAX_VALUE + 10]; - } - return result; - } - - /// CHECK-START: int Main.justRightUp3() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.justRightUp3() BCE (after) - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static int justRightUp3() { - int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int result = 0; - for (int i = Integer.MAX_VALUE - 10, k = 0; i <= Integer.MAX_VALUE - 1; i++) { - result += x[k++]; - } - return result; - } - - /// CHECK-START: int Main.justOOBUp() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.justOOBUp() BCE (after) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.justOOBUp() BCE (after) - /// CHECK-NOT: Deoptimize - private static int justOOBUp() { - int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int result = 0; - // Infinite loop! - for (int i = Integer.MAX_VALUE - 9, k = 0; i <= Integer.MAX_VALUE; i++) { - result += x[k++]; - } - return result; - } - - /// CHECK-START: int Main.justRightDown1() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.justRightDown1() BCE (after) - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static int justRightDown1() { - int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int result = 0; - for (int i = Integer.MIN_VALUE + 10, k = 0; i > Integer.MIN_VALUE; i--) { - result += x[k++]; - } - return result; - } - - /// CHECK-START: int Main.justRightDown2() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.justRightDown2() BCE (after) - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static int justRightDown2() { - int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int result = 0; - for (int i = Integer.MIN_VALUE + 10; i > Integer.MIN_VALUE; i--) { - result += x[Integer.MAX_VALUE + i]; - } - return result; - } - - /// CHECK-START: int Main.justRightDown3() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.justRightDown3() BCE (after) - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static int justRightDown3() { - int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int result = 0; - for (int i = Integer.MIN_VALUE + 10, k = 0; i >= Integer.MIN_VALUE + 1; i--) { - result += x[k++]; - } - return result; - } - - /// CHECK-START: int Main.justOOBDown() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.justOOBDown() BCE (after) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int Main.justOOBDown() BCE (after) - /// CHECK-NOT: Deoptimize - private static int justOOBDown() { - int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int result = 0; - // Infinite loop! - for (int i = Integer.MIN_VALUE + 9, k = 0; i >= Integer.MIN_VALUE; i--) { - result += x[k++]; - } - return result; - } - - /// CHECK-START: void Main.lowerOOB(int[]) BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: void Main.lowerOOB(int[]) BCE (after) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: void Main.lowerOOB(int[]) BCE (after) - /// CHECK-NOT: Deoptimize - private static void lowerOOB(int[] x) { - // OOB! - for (int i = -1; i < x.length; i++) { - sResult += x[i]; - } - } - - /// CHECK-START: void Main.upperOOB(int[]) BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: void Main.upperOOB(int[]) BCE (after) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: void Main.upperOOB(int[]) BCE (after) - /// CHECK-NOT: Deoptimize - private static void upperOOB(int[] x) { - // OOB! - for (int i = 0; i <= x.length; i++) { - sResult += x[i]; - } - } - - /// CHECK-START: void Main.doWhileUpOOB() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: void Main.doWhileUpOOB() BCE (after) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: void Main.doWhileUpOOB() BCE (after) - /// CHECK-NOT: Deoptimize - private static void doWhileUpOOB() { - int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int i = 0; - // OOB! - do { - sResult += x[i++]; - } while (i <= x.length); - } - - /// CHECK-START: void Main.doWhileDownOOB() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: void Main.doWhileDownOOB() BCE (after) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: void Main.doWhileDownOOB() BCE (after) - /// CHECK-NOT: Deoptimize - private static void doWhileDownOOB() { - int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; - int i = x.length - 1; - // OOB! - do { - sResult += x[i--]; - } while (-1 <= i); - } - - /// CHECK-START: int[] Main.multiply1() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int[] Main.multiply1() BCE (after) - /// CHECK-NOT: BoundsCheck - /// CHECK-NOT: Deoptimize - private static int[] multiply1() { - int[] a = new int[10]; - try { - for (int i = 0; i <= 3; i++) { - for (int j = 0; j <= 3; j++) { - // Range [0,9]: safe. - a[i * j] += 1; - } - } - } catch (Exception e) { - a[0] += 1000; - } - return a; - } - - /// CHECK-START: int[] Main.multiply2() BCE (before) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int[] Main.multiply2() BCE (after) - /// CHECK-DAG: BoundsCheck - // - /// CHECK-START: int[] Main.multiply2() BCE (after) - /// CHECK-NOT: Deoptimize - static int[] multiply2() { - int[] a = new int[10]; - try { - for (int i = -3; i <= 3; i++) { - for (int j = -3; j <= 3; j++) { - // Range [-9,9]: unsafe. - a[i * j] += 1; - } - } - } catch (Exception e) { - a[0] += 1000; - } - return a; - } - - /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (before) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: NullCheck loop:<<Loop>> - /// CHECK-DAG: ArrayLength loop:<<Loop>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - // - /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: Deoptimize loop:none - // - /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after) - /// CHECK-NOT: NullCheck loop:{{B\d+}} - /// CHECK-NOT: ArrayLength loop:{{B\d+}} - /// CHECK-NOT: BoundsCheck loop:{{B\d+}} - private static int linearDynamicBCE1(int[] x, int lo, int hi) { - int result = 0; - for (int i = lo; i < hi; i++) { - sResult += x[i]; - } - return result; - } - - /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (before) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: NullCheck loop:<<Loop>> - /// CHECK-DAG: ArrayLength loop:<<Loop>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - // - /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: Deoptimize loop:none - // - /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after) - /// CHECK-NOT: NullCheck loop:{{B\d+}} - /// CHECK-NOT: ArrayLength loop:{{B\d+}} - /// CHECK-NOT: BoundsCheck loop:{{B\d+}} - private static int linearDynamicBCE2(int[] x, int lo, int hi, int offset) { - int result = 0; - for (int i = lo; i < hi; i++) { - sResult += x[offset + i]; - } - return result; - } - - /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (before) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: NullCheck loop:<<Loop>> - /// CHECK-DAG: ArrayLength loop:<<Loop>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - // - /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: Deoptimize loop:none - // - /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after) - /// CHECK-NOT: NullCheck loop:{{B\d+}} - /// CHECK-NOT: ArrayLength loop:{{B\d+}} - /// CHECK-NOT: BoundsCheck loop:{{B\d+}} - private static int wrapAroundDynamicBCE(int[] x) { - int w = 9; - int result = 0; - for (int i = 0; i < 10; i++) { - result += x[w]; - w = i; - } - return result; - } - - /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (before) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: NullCheck loop:<<Loop>> - /// CHECK-DAG: ArrayLength loop:<<Loop>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - // - /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: Deoptimize loop:none - // - /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after) - /// CHECK-NOT: NullCheck loop:{{B\d+}} - /// CHECK-NOT: ArrayLength loop:{{B\d+}} - /// CHECK-NOT: BoundsCheck loop:{{B\d+}} - private static int periodicDynamicBCE(int[] x) { - int k = 0; - int result = 0; - for (int i = 0; i < 10; i++) { - result += x[k]; - k = 1 - k; - } - return result; - } - - /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: NullCheck loop:<<Loop>> - /// CHECK-DAG: ArrayLength loop:<<Loop>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - // - /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) - /// CHECK-DAG: ArrayGet loop:{{B\d+}} - /// CHECK-DAG: Deoptimize loop:none - // - /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) - /// CHECK-NOT: NullCheck loop:{{B\d+}} - /// CHECK-NOT: ArrayLength loop:{{B\d+}} - /// CHECK-NOT: BoundsCheck loop:{{B\d+}} - static int dynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) { - // This loop could be infinite for hi = max int. Since i is also used - // as subscript, however, dynamic bce can proceed. - int result = 0; - for (int i = lo; i <= hi; i++) { - result += x[i]; - } - return result; - } - - /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - // - /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - // - /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) - /// CHECK-NOT: Deoptimize - static int noDynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) { - // As above, but now the index is not used as subscript, - // and dynamic bce is not applied. - int result = 0; - for (int k = 0, i = lo; i <= hi; i++) { - result += x[k++]; - } - return result; - } - - /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (before) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - // - /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - // - /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after) - /// CHECK-NOT: Deoptimize - static int noDynamicBCEMixedInductionTypes(int[] x, long lo, long hi) { - int result = 0; - // Mix of int and long induction. - int k = 0; - for (long i = lo; i < hi; i++) { - result += x[k++]; - } - return result; - } - - /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (before) - /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> - /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> - // - /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after) - // Order matters: - /// CHECK: Deoptimize loop:<<Loop:B\d+>> - // CHECK-NOT: Goto loop:<<Loop>> - /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> - /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> - /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> - /// CHECK: Goto loop:<<Loop>> - // - /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after) - /// CHECK-DAG: Deoptimize loop:none - static int dynamicBCEAndConstantIndices(int[] x, int[][] a, int lo, int hi) { - // Deliberately test array length on a before the loop so that only bounds checks - // on constant subscripts remain, making them a viable candidate for hoisting. - if (a.length == 0) { - return -1; - } - // Loop that allows BCE on x[i]. - int result = 0; - for (int i = lo; i < hi; i++) { - result += x[i]; - if ((i % 10) != 0) { - // None of the subscripts inside a conditional are removed by dynamic bce, - // making them a candidate for deoptimization based on constant indices. - // Compiler should ensure the array loads are not subsequently hoisted - // "above" the deoptimization "barrier" on the bounds. - a[0][i] = 1; - a[1][i] = 2; - a[99][i] = 3; - } - } - return result; - } - - /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (before) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: ArrayGet loop:<<Loop>> - /// CHECK-DAG: ArrayGet loop:<<Loop>> - /// CHECK-DAG: ArrayGet loop:<<Loop>> - /// CHECK-DAG: ArrayGet loop:<<Loop>> - /// CHECK-DAG: ArrayGet loop:<<Loop>> - /// CHECK-DAG: ArrayGet loop:<<Loop>> - /// CHECK-DAG: ArrayGet loop:<<Loop>> - /// CHECK-DAG: ArrayGet loop:<<Loop>> - // For brevity, just test occurrence of at least one of each in the loop: - /// CHECK-DAG: NullCheck loop:<<Loop>> - /// CHECK-DAG: ArrayLength loop:<<Loop>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - // - /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-NOT: ArrayGet loop:<<Loop>> - // - /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) - /// CHECK-NOT: NullCheck loop:{{B\d+}} - /// CHECK-NOT: ArrayLength loop:{{B\d+}} - /// CHECK-NOT: BoundsCheck loop:{{B\d+}} - // - /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) - /// CHECK-DAG: Deoptimize loop:none - static int dynamicBCEAndConstantIndicesAllPrimTypes(int[] q, - boolean[] r, - byte[] s, - char[] t, - short[] u, - int[] v, - long[] w, - float[] x, - double[] y, int lo, int hi) { - int result = 0; - for (int i = lo; i < hi; i++) { - // All constant index array references can be hoisted out of the loop during BCE on q[i]. - result += q[i] + (r[0] ? 1 : 0) + (int) s[0] + (int) t[0] + (int) u[0] + (int) v[0] + - (int) w[0] + (int) x[0] + (int) y[0]; - } - return result; - } - - /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (before) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: NullCheck loop:<<Loop>> - /// CHECK-DAG: ArrayLength loop:<<Loop>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - /// CHECK-DAG: ArrayGet loop:<<Loop>> - /// CHECK-DAG: NullCheck loop:<<Loop>> - /// CHECK-DAG: ArrayLength loop:<<Loop>> - /// CHECK-DAG: BoundsCheck loop:<<Loop>> - // - /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after) - /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> - /// CHECK-DAG: Deoptimize loop:none - // - /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after) - /// CHECK-NOT: ArrayLength loop:{{B\d+}} - /// CHECK-NOT: BoundsCheck loop:{{B\d+}} - static int dynamicBCEAndConstantIndexRefType(int[] q, Integer[] z, int lo, int hi) { - int result = 0; - for (int i = lo; i < hi; i++) { - // Similar to above, but now implicit call to intValue() may prevent hoisting - // z[0] itself during BCE on q[i]. Therefore, we just check BCE on q[i]. - result += q[i] + z[0]; - } - return result; - } - - // - // Verifier. - // - public static void main(String[] args) { int[] empty = { }; int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; @@ -1232,6 +698,8 @@ public class Main { // Special forms. expectEquals(55, linearForNEUp()); expectEquals(55, linearForNEDown()); + expectEquals(55, linearForNEArrayLengthUp(x)); + expectEquals(55, linearForNEArrayLengthDown(x)); expectEquals(55, linearDoWhileUp()); expectEquals(55, linearDoWhileDown()); expectEquals(55, linearShort()); @@ -1239,191 +707,8 @@ public class Main { linearTriangularOnTwoArrayLengths(10); linearTriangularOnOneArrayLength(10); linearTriangularOnParameter(10); - linearTriangularVariations(10); - - // Sorting. - int[] sort = { 5, 4, 1, 9, 10, 2, 7, 6, 3, 8 }; - bubble(sort); - for (int i = 0; i < 10; i++) { - expectEquals(sort[i], x[i]); - } - - // Periodic adds (1, 3), one at the time. - expectEquals(0, periodicIdiom(-1)); - for (int tc = 0; tc < 32; tc++) { - int expected = (tc >> 1) << 2; - if ((tc & 1) != 0) - expected += 1; - expectEquals(expected, periodicIdiom(tc)); - } - - // Periodic adds (1, 3), one at the time. - expectEquals(0, periodicSequence2(-1)); - for (int tc = 0; tc < 32; tc++) { - int expected = (tc >> 1) << 2; - if ((tc & 1) != 0) - expected += 1; - expectEquals(expected, periodicSequence2(tc)); - } - - // Periodic adds (1, 3, 5, 7), all at once. - expectEquals(0, periodicSequence4(-1)); - for (int tc = 0; tc < 32; tc++) { - expectEquals(tc * 16, periodicSequence4(tc)); - } - - // Large bounds. - expectEquals(55, justRightUp1()); - expectEquals(55, justRightUp2()); - expectEquals(55, justRightUp3()); - expectEquals(55, justRightDown1()); - expectEquals(55, justRightDown2()); - expectEquals(55, justRightDown3()); - sResult = 0; - try { - justOOBUp(); - } catch (ArrayIndexOutOfBoundsException e) { - sResult = 1; - } - expectEquals(1, sResult); - sResult = 0; - try { - justOOBDown(); - } catch (ArrayIndexOutOfBoundsException e) { - sResult = 1; - } - expectEquals(1, sResult); - - // Lower bound goes OOB. - sResult = 0; - try { - lowerOOB(x); - } catch (ArrayIndexOutOfBoundsException e) { - sResult += 1000; - } - expectEquals(1000, sResult); - - // Upper bound goes OOB. - sResult = 0; - try { - upperOOB(x); - } catch (ArrayIndexOutOfBoundsException e) { - sResult += 1000; - } - expectEquals(1055, sResult); - - // Do while up goes OOB. - sResult = 0; - try { - doWhileUpOOB(); - } catch (ArrayIndexOutOfBoundsException e) { - sResult += 1000; - } - expectEquals(1055, sResult); - - // Do while down goes OOB. - sResult = 0; - try { - doWhileDownOOB(); - } catch (ArrayIndexOutOfBoundsException e) { - sResult += 1000; - } - expectEquals(1055, sResult); - - // Multiplication. - { - int[] e1 = { 7, 1, 2, 2, 1, 0, 2, 0, 0, 1 }; - int[] a1 = multiply1(); - for (int i = 0; i < 10; i++) { - expectEquals(a1[i], e1[i]); - } - int[] e2 = { 1001, 0, 0, 1, 0, 0, 1, 0, 0, 1 }; - int[] a2 = multiply2(); - for (int i = 0; i < 10; i++) { - expectEquals(a2[i], e2[i]); - } - } - - // Dynamic BCE. - sResult = 0; - try { - linearDynamicBCE1(x, -1, x.length); - } catch (ArrayIndexOutOfBoundsException e) { - sResult += 1000; - } - expectEquals(1000, sResult); - sResult = 0; - linearDynamicBCE1(x, 0, x.length); - expectEquals(55, sResult); - sResult = 0; - try { - linearDynamicBCE1(x, 0, x.length + 1); - } catch (ArrayIndexOutOfBoundsException e) { - sResult += 1000; - } - expectEquals(1055, sResult); - - // Dynamic BCE with offset. - sResult = 0; - try { - linearDynamicBCE2(x, 0, x.length, -1); - } catch (ArrayIndexOutOfBoundsException e) { - sResult += 1000; - } - expectEquals(1000, sResult); - sResult = 0; - linearDynamicBCE2(x, 0, x.length, 0); - expectEquals(55, sResult); - sResult = 0; - try { - linearDynamicBCE2(x, 0, x.length, 1); - } catch (ArrayIndexOutOfBoundsException e) { - sResult += 1000; - } - expectEquals(1054, sResult); - - // Dynamic BCE candidates. - expectEquals(55, wrapAroundDynamicBCE(x)); - expectEquals(15, periodicDynamicBCE(x)); - expectEquals(55, dynamicBCEPossiblyInfiniteLoop(x, 0, 9)); - expectEquals(55, noDynamicBCEPossiblyInfiniteLoop(x, 0, 9)); - expectEquals(55, noDynamicBCEMixedInductionTypes(x, 0, 10)); - - // Dynamic BCE combined with constant indices. - int[][] a; - a = new int[0][0]; - expectEquals(-1, dynamicBCEAndConstantIndices(x, a, 0, 10)); - a = new int[100][10]; - expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10)); - for (int i = 0; i < 10; i++) { - expectEquals((i % 10) != 0 ? 1 : 0, a[0][i]); - expectEquals((i % 10) != 0 ? 2 : 0, a[1][i]); - expectEquals((i % 10) != 0 ? 3 : 0, a[99][i]); - } - a = new int[2][10]; - sResult = 0; - try { - expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10)); - } catch (ArrayIndexOutOfBoundsException e) { - sResult = 1; - } - expectEquals(1, sResult); - expectEquals(a[0][1], 1); - expectEquals(a[1][1], 2); - - // Dynamic BCE combined with constant indices of all types. - boolean[] x1 = { true }; - byte[] x2 = { 2 }; - char[] x3 = { 3 }; - short[] x4 = { 4 }; - int[] x5 = { 5 }; - long[] x6 = { 6 }; - float[] x7 = { 7 }; - double[] x8 = { 8 }; - expectEquals(415, - dynamicBCEAndConstantIndicesAllPrimTypes(x, x1, x2, x3, x4, x5, x6, x7, x8, 0, 10)); - Integer[] x9 = { 9 }; - expectEquals(145, dynamicBCEAndConstantIndexRefType(x, x9, 0, 10)); + linearTriangularVariationsInnerStrict(10); + linearTriangularVariationsInnerNonStrict(10); } private static void expectEquals(int expected, int result) { diff --git a/test/530-checker-loops2/expected.txt b/test/530-checker-loops2/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/530-checker-loops2/expected.txt diff --git a/test/530-checker-loops2/info.txt b/test/530-checker-loops2/info.txt new file mode 100644 index 0000000000..f5d334d011 --- /dev/null +++ b/test/530-checker-loops2/info.txt @@ -0,0 +1 @@ +Test on loop optimizations. diff --git a/test/530-checker-loops2/src/Main.java b/test/530-checker-loops2/src/Main.java new file mode 100644 index 0000000000..64be1a2be4 --- /dev/null +++ b/test/530-checker-loops2/src/Main.java @@ -0,0 +1,999 @@ +/* + * 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. + */ + +// +// Test on loop optimizations. +// +public class Main { + + static int sResult; + + // + // Various sequence variables used in bound checks. + // + + /// CHECK-START: void Main.bubble(int[]) BCE (before) + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.bubble(int[]) BCE (after) + /// CHECK-NOT: BoundsCheck + // TODO: also CHECK-NOT: Deoptimize, see b/27151190 + private static void bubble(int[] a) { + for (int i = a.length; --i >= 0;) { + for (int j = 0; j < i; j++) { + if (a[j] > a[j+1]) { + int tmp = a[j]; + a[j] = a[j+1]; + a[j+1] = tmp; + } + } + } + } + + /// CHECK-START: int Main.periodicIdiom(int) BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.periodicIdiom(int) BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int periodicIdiom(int tc) { + int[] x = { 1, 3 }; + // Loop with periodic sequence (0, 1). + int k = 0; + int result = 0; + for (int i = 0; i < tc; i++) { + result += x[k]; + k = 1 - k; + } + return result; + } + + /// CHECK-START: int Main.periodicSequence2(int) BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.periodicSequence2(int) BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int periodicSequence2(int tc) { + int[] x = { 1, 3 }; + // Loop with periodic sequence (0, 1). + int k = 0; + int l = 1; + int result = 0; + for (int i = 0; i < tc; i++) { + result += x[k]; + int t = l; + l = k; + k = t; + } + return result; + } + + /// CHECK-START: int Main.periodicSequence4(int) BCE (before) + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.periodicSequence4(int) BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int periodicSequence4(int tc) { + int[] x = { 1, 3, 5, 7 }; + // Loop with periodic sequence (0, 1, 2, 3). + int k = 0; + int l = 1; + int m = 2; + int n = 3; + int result = 0; + for (int i = 0; i < tc; i++) { + result += x[k] + x[l] + x[m] + x[n]; // all used at once + int t = n; + n = k; + k = l; + l = m; + m = t; + } + return result; + } + + /// CHECK-START: int Main.justRightUp1() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justRightUp1() BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int justRightUp1() { + int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int result = 0; + for (int i = Integer.MAX_VALUE - 10, k = 0; i < Integer.MAX_VALUE; i++) { + result += x[k++]; + } + return result; + } + + /// CHECK-START: int Main.justRightUp2() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justRightUp2() BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int justRightUp2() { + int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int result = 0; + for (int i = Integer.MAX_VALUE - 10; i < Integer.MAX_VALUE; i++) { + result += x[i - Integer.MAX_VALUE + 10]; + } + return result; + } + + /// CHECK-START: int Main.justRightUp3() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justRightUp3() BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int justRightUp3() { + int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int result = 0; + for (int i = Integer.MAX_VALUE - 10, k = 0; i <= Integer.MAX_VALUE - 1; i++) { + result += x[k++]; + } + return result; + } + + /// CHECK-START: int Main.justOOBUp() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justOOBUp() BCE (after) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justOOBUp() BCE (after) + /// CHECK-NOT: Deoptimize + private static int justOOBUp() { + int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int result = 0; + // Infinite loop! + for (int i = Integer.MAX_VALUE - 9, k = 0; i <= Integer.MAX_VALUE; i++) { + result += x[k++]; + } + return result; + } + + /// CHECK-START: int Main.justRightDown1() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justRightDown1() BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int justRightDown1() { + int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int result = 0; + for (int i = Integer.MIN_VALUE + 10, k = 0; i > Integer.MIN_VALUE; i--) { + result += x[k++]; + } + return result; + } + + /// CHECK-START: int Main.justRightDown2() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justRightDown2() BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int justRightDown2() { + int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int result = 0; + for (int i = Integer.MIN_VALUE + 10; i > Integer.MIN_VALUE; i--) { + result += x[Integer.MAX_VALUE + i]; + } + return result; + } + + /// CHECK-START: int Main.justRightDown3() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justRightDown3() BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int justRightDown3() { + int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int result = 0; + for (int i = Integer.MIN_VALUE + 10, k = 0; i >= Integer.MIN_VALUE + 1; i--) { + result += x[k++]; + } + return result; + } + + /// CHECK-START: int Main.justOOBDown() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justOOBDown() BCE (after) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int Main.justOOBDown() BCE (after) + /// CHECK-NOT: Deoptimize + private static int justOOBDown() { + int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int result = 0; + // Infinite loop! + for (int i = Integer.MIN_VALUE + 9, k = 0; i >= Integer.MIN_VALUE; i--) { + result += x[k++]; + } + return result; + } + + /// CHECK-START: void Main.lowerOOB(int[]) BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.lowerOOB(int[]) BCE (after) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.lowerOOB(int[]) BCE (after) + /// CHECK-NOT: Deoptimize + private static void lowerOOB(int[] x) { + // OOB! + for (int i = -1; i < x.length; i++) { + sResult += x[i]; + } + } + + /// CHECK-START: void Main.upperOOB(int[]) BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.upperOOB(int[]) BCE (after) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.upperOOB(int[]) BCE (after) + /// CHECK-NOT: Deoptimize + private static void upperOOB(int[] x) { + // OOB! + for (int i = 0; i <= x.length; i++) { + sResult += x[i]; + } + } + + /// CHECK-START: void Main.doWhileUpOOB() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.doWhileUpOOB() BCE (after) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.doWhileUpOOB() BCE (after) + /// CHECK-NOT: Deoptimize + private static void doWhileUpOOB() { + int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int i = 0; + // OOB! + do { + sResult += x[i++]; + } while (i <= x.length); + } + + /// CHECK-START: void Main.doWhileDownOOB() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.doWhileDownOOB() BCE (after) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.doWhileDownOOB() BCE (after) + /// CHECK-NOT: Deoptimize + private static void doWhileDownOOB() { + int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + int i = x.length - 1; + // OOB! + do { + sResult += x[i--]; + } while (-1 <= i); + } + + /// CHECK-START: void Main.hiddenOOB1(int) BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.hiddenOOB1(int) BCE (after) + /// CHECK-DAG: Deoptimize + // + /// CHECK-START: void Main.hiddenOOB1(int) BCE (after) + /// CHECK-NOT: BoundsCheck + private static void hiddenOOB1(int lo) { + int[] a = { 1 } ; + for (int i = lo; i <= 10; i++) { + // Dangerous loop where careless static range analysis would yield strict upper bound + // on index j of 5. When, for instance, lo and thus i = -2147483648, the upper bound + // becomes really positive due to arithmetic wrap-around, causing OOB. + // Dynamic BCE is feasible though, since it checks the range. + for (int j = 4; j < i - 5; j++) { + sResult += a[j - 4]; + } + } + } + + /// CHECK-START: void Main.hiddenOOB2(int) BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.hiddenOOB2(int) BCE (after) + /// CHECK-DAG: Deoptimize + // + /// CHECK-START: void Main.hiddenOOB2(int) BCE (after) + /// CHECK-NOT: BoundsCheck + private static void hiddenOOB2(int hi) { + int[] a = { 1 } ; + for (int i = 0; i < hi; i++) { + // Dangerous loop where careless static range analysis would yield strict lower bound + // on index j of 5. When, for instance, hi and thus i = 2147483647, the upper bound + // becomes really negative due to arithmetic wrap-around, causing OOB. + // Dynamic BCE is feasible though, since it checks the range. + for (int j = 6; j > i + 5; j--) { + sResult += a[j - 6]; + } + } + } + + /// CHECK-START: void Main.hiddenInfiniteOOB() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.hiddenInfiniteOOB() BCE (after) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.hiddenInfiniteOOB() BCE (after) + /// CHECK-NOT: Deoptimize + private static void hiddenInfiniteOOB() { + int[] a = { 11 } ; + for (int i = -1; i <= 0; i++) { + // Dangerous loop where careless static range analysis would yield a safe upper bound + // of -3. In reality, due to arithmetic wrap-around (when i = -1, j <= 2147483647; + // whereas when i = 0, j <= -3), this is an infinite loop that goes OOB. + for (int j = -3; j <= 2147483646 * i - 3; j++) { + sResult += a[j + 3]; + } + } + } + + /// CHECK-START: void Main.hiddenFiniteOOB() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: void Main.hiddenFiniteOOB() BCE (after) + /// CHECK-DAG: Deoptimize + // + /// CHECK-START: void Main.hiddenFiniteOOB() BCE (after) + /// CHECK-NOT: BoundsCheck + private static void hiddenFiniteOOB() { + int[] a = { 111 } ; + for (int i = -1; i <= 0; i++) { + // Dangerous loop similar as above where the loop is now finite, but the + // loop still goes out of bounds for i = -1 due to the large upper bound. + // Dynamic BCE is feasible though, since it checks the range. + for (int j = -4; j < 2147483646 * i - 3; j++) { + sResult += a[j + 4]; + } + } + } + + /// CHECK-START: int[] Main.add() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int[] Main.add() BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int[] add() { + int[] a = new int[10]; + for (int i = 0; i <= 3; i++) { + for (int j = 0; j <= 6; j++) { + a[i + j] += 1; + } + } + return a; + } + + /// CHECK-START: int[] Main.multiply1() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int[] Main.multiply1() BCE (after) + /// CHECK-NOT: BoundsCheck + /// CHECK-NOT: Deoptimize + private static int[] multiply1() { + int[] a = new int[10]; + try { + for (int i = 0; i <= 3; i++) { + for (int j = 0; j <= 3; j++) { + // Range [0,9]: safe. + a[i * j] += 1; + } + } + } catch (Exception e) { + a[0] += 1000; + } + return a; + } + + /// CHECK-START: int[] Main.multiply2() BCE (before) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int[] Main.multiply2() BCE (after) + /// CHECK-DAG: BoundsCheck + // + /// CHECK-START: int[] Main.multiply2() BCE (after) + /// CHECK-NOT: Deoptimize + static int[] multiply2() { + int[] a = new int[10]; + try { + for (int i = -3; i <= 3; i++) { + for (int j = -3; j <= 3; j++) { + // Range [-9,9]: unsafe. + a[i * j] += 1; + } + } + } catch (Exception e) { + a[0] += 1000; + } + return a; + } + + /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (before) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after) + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.linearDynamicBCE1(int[], int, int) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} + private static int linearDynamicBCE1(int[] x, int lo, int hi) { + int result = 0; + for (int i = lo; i < hi; i++) { + sResult += x[i]; + } + return result; + } + + /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (before) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after) + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.linearDynamicBCE2(int[], int, int, int) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} + private static int linearDynamicBCE2(int[] x, int lo, int hi, int offset) { + int result = 0; + for (int i = lo; i < hi; i++) { + sResult += x[offset + i]; + } + return result; + } + + /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (before) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after) + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.wrapAroundDynamicBCE(int[]) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} + private static int wrapAroundDynamicBCE(int[] x) { + int w = 9; + int result = 0; + for (int i = 0; i < 10; i++) { + result += x[w]; + w = i; + } + return result; + } + + /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (before) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after) + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.periodicDynamicBCE(int[]) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} + private static int periodicDynamicBCE(int[] x) { + int k = 0; + int result = 0; + for (int i = 0; i < 10; i++) { + result += x[k]; + k = 1 - k; + } + return result; + } + + /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) + /// CHECK-DAG: ArrayGet loop:{{B\d+}} + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.dynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} + static int dynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) { + // This loop could be infinite for hi = max int. Since i is also used + // as subscript, however, dynamic bce can proceed. + int result = 0; + for (int i = lo; i <= hi; i++) { + result += x[i]; + } + return result; + } + + /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (before) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.noDynamicBCEPossiblyInfiniteLoop(int[], int, int) BCE (after) + /// CHECK-NOT: Deoptimize + static int noDynamicBCEPossiblyInfiniteLoop(int[] x, int lo, int hi) { + // As above, but now the index is not used as subscript, + // and dynamic bce is not applied. + int result = 0; + for (int k = 0, i = lo; i <= hi; i++) { + result += x[k++]; + } + return result; + } + + /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (before) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.noDynamicBCEMixedInductionTypes(int[], long, long) BCE (after) + /// CHECK-NOT: Deoptimize + static int noDynamicBCEMixedInductionTypes(int[] x, long lo, long hi) { + int result = 0; + // Mix of int and long induction. + int k = 0; + for (long i = lo; i < hi; i++) { + result += x[k++]; + } + return result; + } + + /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (before) + /// CHECK-DAG: BoundsCheck loop:<<InnerLoop:B\d+>> + /// CHECK-DAG: ArrayGet loop:<<InnerLoop>> + /// CHECK-DAG: If loop:<<InnerLoop>> + /// CHECK-DAG: If loop:<<OuterLoop:B\d+>> + /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>" + // + /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after) + /// CHECK-DAG: ArrayGet loop:<<InnerLoop:B\d+>> + /// CHECK-DAG: Deoptimize loop:<<OuterLoop:B\d+>> + /// CHECK-EVAL: "<<InnerLoop>>" != "<<OuterLoop>>" + // + /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after) + /// CHECK-NOT: BoundsCheck + // + // No additional top tests were introduced. + /// CHECK-START: int Main.dynamicBCEConstantRange(int[]) BCE (after) + /// CHECK-DAG: If + /// CHECK-DAG: If + /// CHECK-NOT: If + static int dynamicBCEConstantRange(int[] x) { + int result = 0; + for (int i = 2; i <= 6; i++) { + // Range analysis sees that innermost loop is finite and always taken. + for (int j = i - 2; j <= i + 2; j++) { + result += x[j]; + } + } + return result; + } + + /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (before) + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after) + // Order matters: + /// CHECK: Deoptimize loop:<<Loop:B\d+>> + // CHECK-NOT: Goto loop:<<Loop>> + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> + /// CHECK-DAG: {{l\d+}} ArrayGet loop:<<Loop>> + /// CHECK: Goto loop:<<Loop>> + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndices(int[], int[][], int, int) BCE (after) + /// CHECK-DAG: Deoptimize loop:none + static int dynamicBCEAndConstantIndices(int[] x, int[][] a, int lo, int hi) { + // Deliberately test array length on a before the loop so that only bounds checks + // on constant subscripts remain, making them a viable candidate for hoisting. + if (a.length == 0) { + return -1; + } + // Loop that allows BCE on x[i]. + int result = 0; + for (int i = lo; i < hi; i++) { + result += x[i]; + if ((i % 10) != 0) { + // None of the subscripts inside a conditional are removed by dynamic bce, + // making them a candidate for deoptimization based on constant indices. + // Compiler should ensure the array loads are not subsequently hoisted + // "above" the deoptimization "barrier" on the bounds. + a[0][i] = 1; + a[1][i] = 2; + a[99][i] = 3; + } + } + return result; + } + + /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (before) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + // For brevity, just test occurrence of at least one of each in the loop: + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-NOT: ArrayGet loop:<<Loop>> + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) + /// CHECK-NOT: NullCheck loop:{{B\d+}} + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndicesAllPrimTypes(int[], boolean[], byte[], char[], short[], int[], long[], float[], double[], int, int) BCE (after) + /// CHECK-DAG: Deoptimize loop:none + static int dynamicBCEAndConstantIndicesAllPrimTypes(int[] q, + boolean[] r, + byte[] s, + char[] t, + short[] u, + int[] v, + long[] w, + float[] x, + double[] y, int lo, int hi) { + int result = 0; + for (int i = lo; i < hi; i++) { + // All constant index array references can be hoisted out of the loop during BCE on q[i]. + result += q[i] + (r[0] ? 1 : 0) + (int) s[0] + (int) t[0] + (int) u[0] + (int) v[0] + + (int) w[0] + (int) x[0] + (int) y[0]; + } + return result; + } + + /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (before) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + /// CHECK-DAG: ArrayGet loop:<<Loop>> + /// CHECK-DAG: NullCheck loop:<<Loop>> + /// CHECK-DAG: ArrayLength loop:<<Loop>> + /// CHECK-DAG: BoundsCheck loop:<<Loop>> + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after) + /// CHECK-DAG: ArrayGet loop:<<Loop:B\d+>> + /// CHECK-DAG: Deoptimize loop:none + // + /// CHECK-START: int Main.dynamicBCEAndConstantIndexRefType(int[], java.lang.Integer[], int, int) BCE (after) + /// CHECK-NOT: ArrayLength loop:{{B\d+}} + /// CHECK-NOT: BoundsCheck loop:{{B\d+}} + static int dynamicBCEAndConstantIndexRefType(int[] q, Integer[] z, int lo, int hi) { + int result = 0; + for (int i = lo; i < hi; i++) { + // Similar to above, but now implicit call to intValue() may prevent hoisting + // z[0] itself during BCE on q[i]. Therefore, we just check BCE on q[i]. + result += q[i] + z[0]; + } + return result; + } + + // + // Verifier. + // + + public static void main(String[] args) { + // Set to run expensive tests for correctness too. + boolean HEAVY = false; + + int[] x = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; + + // Sorting. + int[] sort = { 5, 4, 1, 9, 10, 2, 7, 6, 3, 8 }; + bubble(sort); + for (int i = 0; i < 10; i++) { + expectEquals(sort[i], x[i]); + } + + // Periodic adds (1, 3), one at the time. + expectEquals(0, periodicIdiom(-1)); + for (int tc = 0; tc < 32; tc++) { + int expected = (tc >> 1) << 2; + if ((tc & 1) != 0) + expected += 1; + expectEquals(expected, periodicIdiom(tc)); + } + + // Periodic adds (1, 3), one at the time. + expectEquals(0, periodicSequence2(-1)); + for (int tc = 0; tc < 32; tc++) { + int expected = (tc >> 1) << 2; + if ((tc & 1) != 0) + expected += 1; + expectEquals(expected, periodicSequence2(tc)); + } + + // Periodic adds (1, 3, 5, 7), all at once. + expectEquals(0, periodicSequence4(-1)); + for (int tc = 0; tc < 32; tc++) { + expectEquals(tc * 16, periodicSequence4(tc)); + } + + // Large bounds. + expectEquals(55, justRightUp1()); + expectEquals(55, justRightUp2()); + expectEquals(55, justRightUp3()); + expectEquals(55, justRightDown1()); + expectEquals(55, justRightDown2()); + expectEquals(55, justRightDown3()); + sResult = 0; + try { + justOOBUp(); + } catch (ArrayIndexOutOfBoundsException e) { + sResult = 1; + } + expectEquals(1, sResult); + sResult = 0; + try { + justOOBDown(); + } catch (ArrayIndexOutOfBoundsException e) { + sResult = 1; + } + expectEquals(1, sResult); + + // Lower bound goes OOB. + sResult = 0; + try { + lowerOOB(x); + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1000, sResult); + + // Upper bound goes OOB. + sResult = 0; + try { + upperOOB(x); + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1055, sResult); + + // Do while up goes OOB. + sResult = 0; + try { + doWhileUpOOB(); + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1055, sResult); + + // Do while down goes OOB. + sResult = 0; + try { + doWhileDownOOB(); + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1055, sResult); + + // Hidden OOB. + sResult = 0; + try { + hiddenOOB1(10); // no OOB + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1, sResult); + sResult = 0; + try { + hiddenOOB1(-2147483648); // OOB + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1001, sResult); + sResult = 0; + try { + hiddenOOB2(1); // no OOB + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1, sResult); + if (HEAVY) { + sResult = 0; + try { + hiddenOOB2(2147483647); // OOB + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1002, sResult); + } + sResult = 0; + try { + hiddenInfiniteOOB(); + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1011, sResult); + sResult = 0; + try { + hiddenFiniteOOB(); + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1111, sResult); + + // Addition. + { + int[] e1 ={ 1, 2, 3, 4, 4, 4, 4, 3, 2, 1 }; + int[] a1 = add(); + for (int i = 0; i < 10; i++) { + expectEquals(a1[i], e1[i]); + } + } + + // Multiplication. + { + int[] e1 = { 7, 1, 2, 2, 1, 0, 2, 0, 0, 1 }; + int[] a1 = multiply1(); + for (int i = 0; i < 10; i++) { + expectEquals(a1[i], e1[i]); + } + int[] e2 = { 1001, 0, 0, 1, 0, 0, 1, 0, 0, 1 }; + int[] a2 = multiply2(); + for (int i = 0; i < 10; i++) { + expectEquals(a2[i], e2[i]); + } + } + + // Dynamic BCE. + sResult = 0; + try { + linearDynamicBCE1(x, -1, x.length); + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1000, sResult); + sResult = 0; + linearDynamicBCE1(x, 0, x.length); + expectEquals(55, sResult); + sResult = 0; + try { + linearDynamicBCE1(x, 0, x.length + 1); + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1055, sResult); + + // Dynamic BCE with offset. + sResult = 0; + try { + linearDynamicBCE2(x, 0, x.length, -1); + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1000, sResult); + sResult = 0; + linearDynamicBCE2(x, 0, x.length, 0); + expectEquals(55, sResult); + sResult = 0; + try { + linearDynamicBCE2(x, 0, x.length, 1); + } catch (ArrayIndexOutOfBoundsException e) { + sResult += 1000; + } + expectEquals(1054, sResult); + + // Dynamic BCE candidates. + expectEquals(55, wrapAroundDynamicBCE(x)); + expectEquals(15, periodicDynamicBCE(x)); + expectEquals(55, dynamicBCEPossiblyInfiniteLoop(x, 0, 9)); + expectEquals(55, noDynamicBCEPossiblyInfiniteLoop(x, 0, 9)); + expectEquals(55, noDynamicBCEMixedInductionTypes(x, 0, 10)); + expectEquals(125, dynamicBCEConstantRange(x)); + + // Dynamic BCE combined with constant indices. + int[][] a; + a = new int[0][0]; + expectEquals(-1, dynamicBCEAndConstantIndices(x, a, 0, 10)); + a = new int[100][10]; + expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10)); + for (int i = 0; i < 10; i++) { + expectEquals((i % 10) != 0 ? 1 : 0, a[0][i]); + expectEquals((i % 10) != 0 ? 2 : 0, a[1][i]); + expectEquals((i % 10) != 0 ? 3 : 0, a[99][i]); + } + a = new int[2][10]; + sResult = 0; + try { + expectEquals(55, dynamicBCEAndConstantIndices(x, a, 0, 10)); + } catch (ArrayIndexOutOfBoundsException e) { + sResult = 1; + } + expectEquals(1, sResult); + expectEquals(a[0][1], 1); + expectEquals(a[1][1], 2); + + // Dynamic BCE combined with constant indices of all types. + boolean[] x1 = { true }; + byte[] x2 = { 2 }; + char[] x3 = { 3 }; + short[] x4 = { 4 }; + int[] x5 = { 5 }; + long[] x6 = { 6 }; + float[] x7 = { 7 }; + double[] x8 = { 8 }; + expectEquals(415, + dynamicBCEAndConstantIndicesAllPrimTypes(x, x1, x2, x3, x4, x5, x6, x7, x8, 0, 10)); + Integer[] x9 = { 9 }; + expectEquals(145, dynamicBCEAndConstantIndexRefType(x, x9, 0, 10)); + } + + private static void expectEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } +} diff --git a/test/550-checker-multiply-accumulate/src/Main.java b/test/550-checker-multiply-accumulate/src/Main.java index 87a89bd9dc..09376a2054 100644 --- a/test/550-checker-multiply-accumulate/src/Main.java +++ b/test/550-checker-multiply-accumulate/src/Main.java @@ -47,7 +47,7 @@ public class Main { /// CHECK: <<Acc:i\d+>> ParameterValue /// CHECK: <<Left:i\d+>> ParameterValue /// CHECK: <<Right:i\d+>> ParameterValue - /// CHECK: <<MulAdd:i\d+>> Arm64MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Add + /// CHECK: <<MulAdd:i\d+>> MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Add /// CHECK: Return [<<MulAdd>>] /// CHECK-START-ARM64: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm64 (after) @@ -57,6 +57,28 @@ public class Main { /// CHECK-START-ARM64: int Main.$opt$noinline$mulAdd(int, int, int) disassembly (after) /// CHECK: madd w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} + /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm (before) + /// CHECK: <<Acc:i\d+>> ParameterValue + /// CHECK: <<Left:i\d+>> ParameterValue + /// CHECK: <<Right:i\d+>> ParameterValue + /// CHECK: <<Mul:i\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Add:i\d+>> Add [<<Acc>>,<<Mul>>] + /// CHECK: Return [<<Add>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm (after) + /// CHECK: <<Acc:i\d+>> ParameterValue + /// CHECK: <<Left:i\d+>> ParameterValue + /// CHECK: <<Right:i\d+>> ParameterValue + /// CHECK: <<MulAdd:i\d+>> MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Add + /// CHECK: Return [<<MulAdd>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) instruction_simplifier_arm (after) + /// CHECK-NOT: Mul + /// CHECK-NOT: Add + + /// CHECK-START-ARM: int Main.$opt$noinline$mulAdd(int, int, int) disassembly (after) + /// CHECK: mla r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} + public static int $opt$noinline$mulAdd(int acc, int left, int right) { if (doThrow) throw new Error(); return acc + left * right; @@ -78,7 +100,7 @@ public class Main { /// CHECK: <<Acc:j\d+>> ParameterValue /// CHECK: <<Left:j\d+>> ParameterValue /// CHECK: <<Right:j\d+>> ParameterValue - /// CHECK: <<MulSub:j\d+>> Arm64MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Sub + /// CHECK: <<MulSub:j\d+>> MultiplyAccumulate [<<Acc>>,<<Left>>,<<Right>>] kind:Sub /// CHECK: Return [<<MulSub>>] /// CHECK-START-ARM64: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm64 (after) @@ -88,6 +110,17 @@ public class Main { /// CHECK-START-ARM64: long Main.$opt$noinline$mulSub(long, long, long) disassembly (after) /// CHECK: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} + /// CHECK-START-ARM: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm (before) + /// CHECK: <<Acc:j\d+>> ParameterValue + /// CHECK: <<Left:j\d+>> ParameterValue + /// CHECK: <<Right:j\d+>> ParameterValue + /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Sub:j\d+>> Sub [<<Acc>>,<<Mul>>] + /// CHECK: Return [<<Sub>>] + + /// CHECK-START-ARM: long Main.$opt$noinline$mulSub(long, long, long) instruction_simplifier_arm (after) + /// CHECK-NOT: MultiplyAccumulate + public static long $opt$noinline$mulSub(long acc, long left, long right) { if (doThrow) throw new Error(); return acc - left * right; @@ -117,7 +150,28 @@ public class Main { /// CHECK: Return [<<Or>>] /// CHECK-START-ARM64: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm64 (after) - /// CHECK-NOT: Arm64MultiplyAccumulate + /// CHECK-NOT: MultiplyAccumulate + + /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm (before) + /// CHECK: <<Acc:i\d+>> ParameterValue + /// CHECK: <<Left:i\d+>> ParameterValue + /// CHECK: <<Right:i\d+>> ParameterValue + /// CHECK: <<Mul:i\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Add:i\d+>> Add [<<Acc>>,<<Mul>>] + /// CHECK: <<Or:i\d+>> Or [<<Mul>>,<<Add>>] + /// CHECK: Return [<<Or>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm (after) + /// CHECK: <<Acc:i\d+>> ParameterValue + /// CHECK: <<Left:i\d+>> ParameterValue + /// CHECK: <<Right:i\d+>> ParameterValue + /// CHECK: <<Mul:i\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Add:i\d+>> Add [<<Acc>>,<<Mul>>] + /// CHECK: <<Or:i\d+>> Or [<<Mul>>,<<Add>>] + /// CHECK: Return [<<Or>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$multipleUses1(int, int, int) instruction_simplifier_arm (after) + /// CHECK-NOT: MultiplyAccumulate public static int $opt$noinline$multipleUses1(int acc, int left, int right) { if (doThrow) throw new Error(); @@ -151,7 +205,30 @@ public class Main { /// CHECK: Return [<<Res>>] /// CHECK-START-ARM64: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm64 (after) - /// CHECK-NOT: Arm64MultiplyAccumulate + /// CHECK-NOT: MultiplyAccumulate + + /// CHECK-START-ARM: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm (before) + /// CHECK: <<Acc:j\d+>> ParameterValue + /// CHECK: <<Left:j\d+>> ParameterValue + /// CHECK: <<Right:j\d+>> ParameterValue + /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Add:j\d+>> Add [<<Acc>>,<<Mul>>] + /// CHECK: <<Sub:j\d+>> Sub [<<Acc>>,<<Mul>>] + /// CHECK: <<Res:j\d+>> Add [<<Add>>,<<Sub>>] + /// CHECK: Return [<<Res>>] + + /// CHECK-START-ARM: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm (after) + /// CHECK: <<Acc:j\d+>> ParameterValue + /// CHECK: <<Left:j\d+>> ParameterValue + /// CHECK: <<Right:j\d+>> ParameterValue + /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Add:j\d+>> Add [<<Acc>>,<<Mul>>] + /// CHECK: <<Sub:j\d+>> Sub [<<Acc>>,<<Mul>>] + /// CHECK: <<Res:j\d+>> Add [<<Add>>,<<Sub>>] + /// CHECK: Return [<<Res>>] + + /// CHECK-START-ARM: long Main.$opt$noinline$multipleUses2(long, long, long) instruction_simplifier_arm (after) + /// CHECK-NOT: MultiplyAccumulate public static long $opt$noinline$multipleUses2(long acc, long left, long right) { @@ -176,7 +253,7 @@ public class Main { /// CHECK-START-ARM64: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm64 (after) /// CHECK: <<Acc:i\d+>> ParameterValue /// CHECK: <<Var:i\d+>> ParameterValue - /// CHECK: <<MulAdd:i\d+>> Arm64MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Add + /// CHECK: <<MulAdd:i\d+>> MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Add /// CHECK: Return [<<MulAdd>>] /// CHECK-START-ARM64: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm64 (after) @@ -186,6 +263,27 @@ public class Main { /// CHECK-START-ARM64: int Main.$opt$noinline$mulPlusOne(int, int) disassembly (after) /// CHECK: madd w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}} + /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm (before) + /// CHECK: <<Acc:i\d+>> ParameterValue + /// CHECK: <<Var:i\d+>> ParameterValue + /// CHECK: <<Const1:i\d+>> IntConstant 1 + /// CHECK: <<Add:i\d+>> Add [<<Var>>,<<Const1>>] + /// CHECK: <<Mul:i\d+>> Mul [<<Acc>>,<<Add>>] + /// CHECK: Return [<<Mul>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm (after) + /// CHECK: <<Acc:i\d+>> ParameterValue + /// CHECK: <<Var:i\d+>> ParameterValue + /// CHECK: <<MulAdd:i\d+>> MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Add + /// CHECK: Return [<<MulAdd>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) instruction_simplifier_arm (after) + /// CHECK-NOT: Mul + /// CHECK-NOT: Add + + /// CHECK-START-ARM: int Main.$opt$noinline$mulPlusOne(int, int) disassembly (after) + /// CHECK: mla r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}} + public static int $opt$noinline$mulPlusOne(int acc, int var) { if (doThrow) throw new Error(); return acc * (var + 1); @@ -207,7 +305,7 @@ public class Main { /// CHECK-START-ARM64: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm64 (after) /// CHECK: <<Acc:j\d+>> ParameterValue /// CHECK: <<Var:j\d+>> ParameterValue - /// CHECK: <<MulSub:j\d+>> Arm64MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Sub + /// CHECK: <<MulSub:j\d+>> MultiplyAccumulate [<<Acc>>,<<Acc>>,<<Var>>] kind:Sub /// CHECK: Return [<<MulSub>>] /// CHECK-START-ARM64: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm64 (after) @@ -217,11 +315,114 @@ public class Main { /// CHECK-START-ARM64: long Main.$opt$noinline$mulMinusOne(long, long) disassembly (after) /// CHECK: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}} + /// CHECK-START-ARM: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm (before) + /// CHECK: <<Acc:j\d+>> ParameterValue + /// CHECK: <<Var:j\d+>> ParameterValue + /// CHECK: <<Const1:j\d+>> LongConstant 1 + /// CHECK: <<Sub:j\d+>> Sub [<<Const1>>,<<Var>>] + /// CHECK: <<Mul:j\d+>> Mul [<<Acc>>,<<Sub>>] + /// CHECK: Return [<<Mul>>] + + /// CHECK-START-ARM: long Main.$opt$noinline$mulMinusOne(long, long) instruction_simplifier_arm (after) + /// CHECK-NOT: MultiplyAccumulate public static long $opt$noinline$mulMinusOne(long acc, long var) { if (doThrow) throw new Error(); return acc * (1 - var); } + /** + * Test basic merging of `MUL+NEG` into `MULNEG`. + */ + + /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm64 (before) + /// CHECK: <<Left:i\d+>> ParameterValue + /// CHECK: <<Right:i\d+>> ParameterValue + /// CHECK: <<Mul:i\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Neg:i\d+>> Neg [<<Mul>>] + /// CHECK: Return [<<Neg>>] + + /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm64 (after) + /// CHECK: <<Left:i\d+>> ParameterValue + /// CHECK: <<Right:i\d+>> ParameterValue + /// CHECK: <<Const0:i\d+>> IntConstant 0 + /// CHECK: <<MulNeg:i\d+>> MultiplyAccumulate [<<Const0>>,<<Left>>,<<Right>>] kind:Sub + /// CHECK: Return [<<MulNeg>>] + + /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm64 (after) + /// CHECK-NOT: Mul + /// CHECK-NOT: Neg + + /// CHECK-START-ARM64: int Main.$opt$noinline$mulNeg(int, int) disassembly (after) + /// CHECK: mneg w{{\d+}}, w{{\d+}}, w{{\d+}} + + /// CHECK-START-ARM: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm (before) + /// CHECK: <<Left:i\d+>> ParameterValue + /// CHECK: <<Right:i\d+>> ParameterValue + /// CHECK: <<Mul:i\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Neg:i\d+>> Neg [<<Mul>>] + /// CHECK: Return [<<Neg>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm (after) + /// CHECK: <<Left:i\d+>> ParameterValue + /// CHECK: <<Right:i\d+>> ParameterValue + /// CHECK: <<Mul:i\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Neg:i\d+>> Neg [<<Mul>>] + /// CHECK: Return [<<Neg>>] + + /// CHECK-START-ARM: int Main.$opt$noinline$mulNeg(int, int) instruction_simplifier_arm (after) + /// CHECK-NOT: MultiplyAccumulate + + public static int $opt$noinline$mulNeg(int left, int right) { + if (doThrow) throw new Error(); + return - (left * right); + } + + /** + * Test basic merging of `MUL+NEG` into `MULNEG`. + */ + + /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm64 (before) + /// CHECK: <<Left:j\d+>> ParameterValue + /// CHECK: <<Right:j\d+>> ParameterValue + /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Neg:j\d+>> Neg [<<Mul>>] + /// CHECK: Return [<<Neg>>] + + /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm64 (after) + /// CHECK: <<Left:j\d+>> ParameterValue + /// CHECK: <<Right:j\d+>> ParameterValue + /// CHECK: <<Const0:j\d+>> LongConstant 0 + /// CHECK: <<MulNeg:j\d+>> MultiplyAccumulate [<<Const0>>,<<Left>>,<<Right>>] kind:Sub + /// CHECK: Return [<<MulNeg>>] + + /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm64 (after) + /// CHECK-NOT: Mul + /// CHECK-NOT: Neg + + /// CHECK-START-ARM64: long Main.$opt$noinline$mulNeg(long, long) disassembly (after) + /// CHECK: mneg x{{\d+}}, x{{\d+}}, x{{\d+}} + + /// CHECK-START-ARM: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm (before) + /// CHECK: <<Left:j\d+>> ParameterValue + /// CHECK: <<Right:j\d+>> ParameterValue + /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Neg:j\d+>> Neg [<<Mul>>] + /// CHECK: Return [<<Neg>>] + + /// CHECK-START-ARM: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm (after) + /// CHECK: <<Left:j\d+>> ParameterValue + /// CHECK: <<Right:j\d+>> ParameterValue + /// CHECK: <<Mul:j\d+>> Mul [<<Left>>,<<Right>>] + /// CHECK: <<Neg:j\d+>> Neg [<<Mul>>] + /// CHECK: Return [<<Neg>>] + + /// CHECK-START-ARM: long Main.$opt$noinline$mulNeg(long, long) instruction_simplifier_arm (after) + /// CHECK-NOT: MultiplyAccumulate + + public static long $opt$noinline$mulNeg(long left, long right) { + if (doThrow) throw new Error(); + return - (left * right); + } public static void main(String[] args) { assertIntEquals(7, $opt$noinline$mulAdd(1, 2, 3)); @@ -230,5 +431,7 @@ public class Main { assertLongEquals(20, $opt$noinline$multipleUses2(10, 11, 12)); assertIntEquals(195, $opt$noinline$mulPlusOne(13, 14)); assertLongEquals(-225, $opt$noinline$mulMinusOne(15, 16)); + assertIntEquals(-306, $opt$noinline$mulNeg(17, 18)); + assertLongEquals(-380, $opt$noinline$mulNeg(19, 20)); } } diff --git a/test/564-checker-negbitwise/expected.txt b/test/564-checker-negbitwise/expected.txt new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/test/564-checker-negbitwise/expected.txt diff --git a/test/564-checker-negbitwise/info.txt b/test/564-checker-negbitwise/info.txt new file mode 100644 index 0000000000..28b9e9e832 --- /dev/null +++ b/test/564-checker-negbitwise/info.txt @@ -0,0 +1 @@ +Test negated bitwise operations simplification on ARM64. diff --git a/test/564-checker-negbitwise/src/Main.java b/test/564-checker-negbitwise/src/Main.java new file mode 100644 index 0000000000..3de7be7161 --- /dev/null +++ b/test/564-checker-negbitwise/src/Main.java @@ -0,0 +1,207 @@ +/* + * 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. + */ + +public class Main { + + // A dummy value to defeat inlining of these routines. + static boolean doThrow = false; + + public static void assertIntEquals(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + public static void assertLongEquals(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + expected + ", found: " + result); + } + } + + /** + * Test merging of `NOT+AND` into `BIC`. + */ + + /// CHECK-START-ARM64: int Main.$opt$noinline$notAnd(int, int) instruction_simplifier_arm64 (before) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<Not:i\d+>> Not [<<Mask>>] + /// CHECK: <<Op:i\d+>> And [<<Base>>,<<Not>>] + /// CHECK: Return [<<Op>>] + + /// CHECK-START-ARM64: int Main.$opt$noinline$notAnd(int, int) instruction_simplifier_arm64 (after) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<NegOp:i\d+>> Arm64BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:And + /// CHECK: Return [<<NegOp>>] + + /// CHECK-START-ARM64: int Main.$opt$noinline$notAnd(int, int) instruction_simplifier_arm64 (after) + /// CHECK-NOT: Not + /// CHECK-NOT: And + + /// CHECK-START-ARM64: int Main.$opt$noinline$notAnd(int, int) disassembly (after) + /// CHECK: bic w{{\d+}}, w{{\d+}}, w{{\d+}} + + public static int $opt$noinline$notAnd(int base, int mask) { + if (doThrow) throw new Error(); + return base & ~mask; + } + + /** + * Test merging of `NOT+ORR` into `ORN`. + */ + + /// CHECK-START-ARM64: long Main.$opt$noinline$notOr(long, long) instruction_simplifier_arm64 (before) + /// CHECK: <<Base:j\d+>> ParameterValue + /// CHECK: <<Mask:j\d+>> ParameterValue + /// CHECK: <<Not:j\d+>> Not [<<Mask>>] + /// CHECK: <<Op:j\d+>> Or [<<Base>>,<<Not>>] + /// CHECK: Return [<<Op>>] + + /// CHECK-START-ARM64: long Main.$opt$noinline$notOr(long, long) instruction_simplifier_arm64 (after) + /// CHECK: <<Base:j\d+>> ParameterValue + /// CHECK: <<Mask:j\d+>> ParameterValue + /// CHECK: <<NegOp:j\d+>> Arm64BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:Or + /// CHECK: Return [<<NegOp>>] + + /// CHECK-START-ARM64: long Main.$opt$noinline$notOr(long, long) instruction_simplifier_arm64 (after) + /// CHECK-NOT: Not + /// CHECK-NOT: Or + + /// CHECK-START-ARM64: long Main.$opt$noinline$notOr(long, long) disassembly (after) + /// CHECK: orn x{{\d+}}, x{{\d+}}, x{{\d+}} + + public static long $opt$noinline$notOr(long base, long mask) { + if (doThrow) throw new Error(); + return base | ~mask; + } + + /** + * Test merging of `NOT+EOR` into `EON`. + */ + + /// CHECK-START-ARM64: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_arm64 (before) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<Not:i\d+>> Not [<<Mask>>] + /// CHECK: <<Op:i\d+>> Xor [<<Base>>,<<Not>>] + /// CHECK: Return [<<Op>>] + + /// CHECK-START-ARM64: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_arm64 (after) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<NegOp:i\d+>> Arm64BitwiseNegatedRight [<<Base>>,<<Mask>>] kind:Xor + /// CHECK: Return [<<NegOp>>] + + /// CHECK-START-ARM64: int Main.$opt$noinline$notXor(int, int) instruction_simplifier_arm64 (after) + /// CHECK-NOT: Not + /// CHECK-NOT: Xor + + /// CHECK-START-ARM64: int Main.$opt$noinline$notXor(int, int) disassembly (after) + /// CHECK: eon w{{\d+}}, w{{\d+}}, w{{\d+}} + + public static int $opt$noinline$notXor(int base, int mask) { + if (doThrow) throw new Error(); + return base ^ ~mask; + } + + /** + * Check that the transformation is also done when the base is a constant. + */ + + /// CHECK-START-ARM64: int Main.$opt$noinline$notXorConstant(int) instruction_simplifier_arm64 (before) + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<Constant:i\d+>> IntConstant + /// CHECK: <<Not:i\d+>> Not [<<Mask>>] + /// CHECK: <<Op:i\d+>> Xor [<<Not>>,<<Constant>>] + /// CHECK: Return [<<Op>>] + + /// CHECK-START-ARM64: int Main.$opt$noinline$notXorConstant(int) instruction_simplifier_arm64 (after) + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<Constant:i\d+>> IntConstant + /// CHECK: <<NegOp:i\d+>> Arm64BitwiseNegatedRight [<<Constant>>,<<Mask>>] kind:Xor + /// CHECK: Return [<<NegOp>>] + + /// CHECK-START-ARM64: int Main.$opt$noinline$notXorConstant(int) instruction_simplifier_arm64 (after) + /// CHECK-NOT: Not + /// CHECK-NOT: Xor + + /// CHECK-START-ARM64: int Main.$opt$noinline$notXorConstant(int) disassembly (after) + /// CHECK: mov <<Reg:w\d+>>, #0xf + /// CHECK: eon w{{\d+}}, <<Reg>>, w{{\d+}} + + public static int $opt$noinline$notXorConstant(int mask) { + if (doThrow) throw new Error(); + return 0xf ^ ~mask; + } + + /** + * Check that no transformation is done when Not has multiple uses. + */ + + /// CHECK-START-ARM64: int Main.$opt$noinline$notAndMultipleUses(int, int) instruction_simplifier_arm64 (before) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<One:i\d+>> IntConstant + /// CHECK: <<Not:i\d+>> Not [<<Mask>>] + /// CHECK: <<Op1:i\d+>> And [<<Not>>,<<One>>] + /// CHECK: <<Op2:i\d+>> And [<<Base>>,<<Not>>] + /// CHECK: <<Add:i\d+>> Add [<<Op1>>,<<Op2>>] + /// CHECK: Return [<<Add>>] + + /// CHECK-START-ARM64: int Main.$opt$noinline$notAndMultipleUses(int, int) instruction_simplifier_arm64 (after) + /// CHECK: <<Base:i\d+>> ParameterValue + /// CHECK: <<Mask:i\d+>> ParameterValue + /// CHECK: <<One:i\d+>> IntConstant + /// CHECK: <<Not:i\d+>> Not [<<Mask>>] + /// CHECK: <<Op1:i\d+>> And [<<Not>>,<<One>>] + /// CHECK: <<Op2:i\d+>> And [<<Base>>,<<Not>>] + /// CHECK: <<Add:i\d+>> Add [<<Op1>>,<<Op2>>] + /// CHECK: Return [<<Add>>] + + /// CHECK-START-ARM64: int Main.$opt$noinline$notAndMultipleUses(int, int) instruction_simplifier_arm64 (after) + /// CHECK-NOT: Arm64BitwiseNegatedRight + + public static int $opt$noinline$notAndMultipleUses(int base, int mask) { + if (doThrow) throw new Error(); + int tmp = ~mask; + return (tmp & 0x1) + (base & tmp); + } + + /** + * Check that no transformation is done when both inputs are Not's. + */ + + // We don't check the instructions before the pass, since if De Morgan's laws + // have been applied then Not/Not/Or is replaced by And/Not. + + /// CHECK-START-ARM64: int Main.$opt$noinline$deMorganOr(int, int) instruction_simplifier_arm64 (after) + /// CHECK-NOT: Arm64BitwiseNegatedRight + + public static int $opt$noinline$deMorganOr(int a, int b) { + if (doThrow) throw new Error(); + return ~a | ~b; + } + + public static void main(String[] args) { + assertIntEquals(0xe, $opt$noinline$notAnd(0xf, 0x1)); + assertLongEquals(~0x0, $opt$noinline$notOr(0xf, 0x1)); + assertIntEquals(~0xe, $opt$noinline$notXor(0xf, 0x1)); + assertIntEquals(~0xe, $opt$noinline$notXorConstant(0x1)); + assertIntEquals(0xe, $opt$noinline$notAndMultipleUses(0xf, 0x1)); + assertIntEquals(~0x1, $opt$noinline$deMorganOr(0x3, 0x1)); + } +} diff --git a/test/577-checker-fp2int/expected.txt b/test/577-checker-fp2int/expected.txt new file mode 100644 index 0000000000..b0aad4deb5 --- /dev/null +++ b/test/577-checker-fp2int/expected.txt @@ -0,0 +1 @@ +passed diff --git a/test/577-checker-fp2int/info.txt b/test/577-checker-fp2int/info.txt new file mode 100644 index 0000000000..d22a0eab9d --- /dev/null +++ b/test/577-checker-fp2int/info.txt @@ -0,0 +1 @@ +Unit test for float/double to raw bits conversions. diff --git a/test/577-checker-fp2int/src/Main.java b/test/577-checker-fp2int/src/Main.java new file mode 100644 index 0000000000..e3f1230beb --- /dev/null +++ b/test/577-checker-fp2int/src/Main.java @@ -0,0 +1,122 @@ +/* + * 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. + */ + +public class Main { + + /// CHECK-START: int Main.f2int(float) instruction_simplifier (before) + /// CHECK-DAG: <<Result:i\d+>> InvokeStaticOrDirect intrinsic:FloatFloatToIntBits + /// CHECK-DAG: Return [<<Result>>] + // + /// CHECK-START: int Main.f2int(float) instruction_simplifier (after) + /// CHECK-DAG: <<Raw:i\d+>> InvokeStaticOrDirect [<<Arg:f\d+>>] intrinsic:FloatFloatToRawIntBits + /// CHECK-DAG: <<Cond:z\d+>> NotEqual [<<Arg>>,<<Arg>>] + /// CHECK-DAG: <<Result:i\d+>> Select [<<Raw>>,{{i\d+}},<<Cond>>] + /// CHECK-DAG: Return [<<Result>>] + private static int f2int(float f) { + return Float.floatToIntBits(f); + } + + /// CHECK-START: long Main.d2long(double) instruction_simplifier (before) + /// CHECK-DAG: <<Result:j\d+>> InvokeStaticOrDirect intrinsic:DoubleDoubleToLongBits + /// CHECK-DAG: Return [<<Result>>] + // + /// CHECK-START: long Main.d2long(double) instruction_simplifier (after) + /// CHECK-DAG: <<Raw:j\d+>> InvokeStaticOrDirect [<<Arg:d\d+>>] intrinsic:DoubleDoubleToRawLongBits + /// CHECK-DAG: <<Cond:z\d+>> NotEqual [<<Arg>>,<<Arg>>] + /// CHECK-DAG: <<Result:j\d+>> Select [<<Raw>>,{{j\d+}},<<Cond>>] + /// CHECK-DAG: Return [<<Result>>] + private static long d2long(double d) { + return Double.doubleToLongBits(d); + } + + public static void main(String args[]) { + // A few distinct numbers. + expectEquals32(0xff800000, f2int(Float.NEGATIVE_INFINITY)); + expectEquals32(0xbf800000, f2int(-1.0f)); + expectEquals32(0x80000000, f2int(-0.0f)); + expectEquals32(0x00000000, f2int(+0.0f)); + expectEquals32(0x3f800000, f2int(+1.0f)); + expectEquals32(0x7f800000, f2int(Float.POSITIVE_INFINITY)); + + // A few others. + for (int i = 0; i <= 100; i++) { + expectEquals32(i, f2int(Float.intBitsToFloat(i))); + } + + // A few NaN numbers. + float[] fvals = { + Float.intBitsToFloat(0x7f800001), + Float.intBitsToFloat(0x7fa00000), + Float.intBitsToFloat(0x7fc00000), + Float.intBitsToFloat(0x7fffffff), + Float.intBitsToFloat(0xff800001), + Float.intBitsToFloat(0xffa00000), + Float.intBitsToFloat(0xffc00000), + Float.intBitsToFloat(0xffffffff) + }; + for (int i = 0; i < fvals.length; i++) { + expectEquals32(0x7fc00000, f2int(fvals[i])); + } + + // A few distinct numbers. + expectEquals64(0xfff0000000000000L, d2long(Double.NEGATIVE_INFINITY)); + expectEquals64(0xbff0000000000000L, d2long(-1.0d)); + expectEquals64(0x8000000000000000L, d2long(-0.0d)); + expectEquals64(0x0000000000000000L, d2long(+0.0d)); + expectEquals64(0x3ff0000000000000L, d2long(+1.0d)); + expectEquals64(0x7ff0000000000000L, d2long(Double.POSITIVE_INFINITY)); + + // A few others. + for (long l = 0; l <= 100; l++) { + expectEquals64(l, d2long(Double.longBitsToDouble(l))); + } + + // A few NaN numbers. + double[] dvals = { + Double.longBitsToDouble(0x7ff0000000000001L), + Double.longBitsToDouble(0x7ff4000000000000L), + Double.longBitsToDouble(0x7ff8000000000000L), + Double.longBitsToDouble(0x7fffffffffffffffL), + Double.longBitsToDouble(0xfff0000000000001L), + Double.longBitsToDouble(0xfff4000000000000L), + Double.longBitsToDouble(0xfff8000000000000L), + Double.longBitsToDouble(0xffffffffffffffffL) + }; + for (int i = 0; i < dvals.length; i++) { + expectEquals64(0x7ff8000000000000L, d2long(dvals[i])); + } + + System.out.println("passed"); + } + + private static void expectEquals32(int expected, int result) { + if (expected != result) { + throw new Error("Expected: " + + Integer.toHexString(expected) + + ", found: " + + Integer.toHexString(result)); + } + } + + private static void expectEquals64(long expected, long result) { + if (expected != result) { + throw new Error("Expected: " + + Long.toHexString(expected) + + ", found: " + + Long.toHexString(result)); + } + } +} diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk index 364be59919..167ad859d2 100644 --- a/test/Android.run-test.mk +++ b/test/Android.run-test.mk @@ -220,6 +220,18 @@ ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES), $(COMPILER_TYPES),$(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ $(IMAGE_TYPES), $(PICTEST_TYPES), $(DEBUGGABLE_TYPES), $(ART_TEST_RUN_TEST_SKIP), $(ALL_ADDRESS_SIZES)) + +# Disable 097-duplicate-method while investigation (broken by latest Jack release, b/27358065) +TEST_ART_BROKEN_ALL_TARGET_TESTS := \ + 097-duplicate-method + +ART_TEST_KNOWN_BROKEN += $(call all-run-test-names,$(TARGET_TYPES),$(RUN_TYPES),$(PREBUILD_TYPES), \ + $(COMPILER_TYPES), $(RELOCATE_TYPES),$(TRACE_TYPES),$(GC_TYPES),$(JNI_TYPES), \ + $(IMAGE_TYPES),$(PICTEST_TYPES),$(DEBUGGABLE_TYPES), $(TEST_ART_BROKEN_ALL_TARGET_TESTS), \ + $(ALL_ADDRESS_SIZES)) + +TEST_ART_BROKEN_ALL_TARGET_TESTS := + # Tests that are timing sensitive and flaky on heavily loaded systems. TEST_ART_TIMING_SENSITIVE_RUN_TESTS := \ 002-sleep \ |