blob: 261a5f46609c9cbd0a2149274502655f2218e571 [file] [log] [blame]
/*
* Copyright (C) 2020 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 {
private static void expectEquals(long expected, long result) {
if (expected != result) {
throw new Error("Expected: " + expected + ", found: " + result);
}
}
private static void remInt() {
expectEquals(1L << 32, $noinline$IntRemBy3(3));
expectEquals((3L << 32) | 6, $noinline$IntRemBy7(27));
expectEquals((1L << 32) | 1, $noinline$IntRemBy12(13));
expectEquals((1L << 32) | 1, $noinline$IntRemBy12A(13));
}
// A test case to check:
// BCE detects the optimized 'v % 3' and eliminates bounds checks.
//
/// CHECK-START: long Main.$noinline$IntRemBy3(int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: long Main.$noinline$IntRemBy3(int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
private static long $noinline$IntRemBy3(int v) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 3;
int r = v % 3;
return ((long)q << 32) | values[r];
} else {
return -1;
}
}
// A test case to check:
// BCE detects the optimized 'v % 7' and eliminates bounds checks.
//
/// CHECK-START: long Main.$noinline$IntRemBy7(int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: long Main.$noinline$IntRemBy7(int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
private static long $noinline$IntRemBy7(int v) {
int[] values = {0, 1, 2, 3, 4, 5, 6};
if (v > 0) {
int q = v / 7;
int r = v % 7;
return ((long)q << 32) | values[r];
} else {
return -1;
}
}
// A test case to check:
// BCE detects the optimized 'v % 12' and eliminates bounds checks.
//
/// CHECK-START: long Main.$noinline$IntRemBy12(int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: long Main.$noinline$IntRemBy12(int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
private static long $noinline$IntRemBy12(int v) {
int[] values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
if (v > 0) {
int q = v / 12;
int r = v % 12;
return ((long)q << 32) | values[r];
} else {
return -1;
}
}
// A test case to check:
// BCE detects the optimized 'v % 12' and eliminates bounds checks.
//
/// CHECK-START: long Main.$noinline$IntRemBy12A(int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: long Main.$noinline$IntRemBy12A(int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
private static long $noinline$IntRemBy12A(int v) {
int[] values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
if (v > 0) {
int q = v / 12;
int t = q * 12;
int r = v - t;
return ((long)q << 32) | values[r];
} else {
return -1;
}
}
// A test case to check:
// BCE detects the optimized 'v % Integer.MAX_VALUE' and eliminates bounds checks.
//
/// CHECK-START: int Main.$noinline$IntRemByMaxInt(int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$IntRemByMaxInt(int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
private static int $noinline$IntRemByMaxInt(int v) {
int[] values = new int[Integer.MAX_VALUE];
if (v > 0) {
int q = v / Integer.MAX_VALUE;
int r = v % Integer.MAX_VALUE;
return values[v % Integer.MAX_VALUE] + q;
} else {
return -1;
}
}
// A test case to check:
// BCE detects the optimized 'v % Integer.MIN_VALUE' and eliminates bounds checks.
//
/// CHECK-START: int Main.$noinline$IntRemByMinInt(int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$IntRemByMinInt(int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK-NOT: BoundsCheck
/// CHECK: ArrayGet
private static int $noinline$IntRemByMinInt(int v) {
int[] values = new int[Integer.MAX_VALUE];
if (v > 0) {
int q = v / Integer.MIN_VALUE;
int t = q * Integer.MIN_VALUE;
int r = v - t;
return values[r - 1];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem01(int, int) BCE (before)
/// CHECK: Mul
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem01(int, int) BCE (after)
/// CHECK: Mul
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem01(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int a = v * 10;
int b = s - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem02(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem02(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem02(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int a = q * s;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem03(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem03(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem03(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int a = q + s;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem04(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem04(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem04(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int t = q << s;
int a = q + t;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem05(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem05(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem05(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int t = s << 1;
int a = q + t;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem06(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem06(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem06(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int a = q * 11;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem07(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem07(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem07(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int t = q << 1;
int a = s + t;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem08(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem08(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem08(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int t = q << 31;
int a = q + t;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem09(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem09(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Add
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem09(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int t = q << 1;
int a = q + t;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem10(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem10(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem10(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int t = q << s;
int a = t - q;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem11(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem11(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem11(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int t = s << 1;
int a = t - q;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem12(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem12(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem12(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int t = q << 1;
int a = t - s;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem13(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem13(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Shl
/// CHECK-NEXT: Sub
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem13(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int t = q << 31;
int a = t - q;
int b = v - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem14(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem14(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem14(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int a = v / 10;
int b = s - a;
return values[b];
} else {
return -1;
}
}
// A test case to check:
// Bounds checks are not eliminated if the checked value is not an optimized HDiv+HRem.
//
/// CHECK-START: int Main.$noinline$NoRem15(int, int) BCE (before)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
//
/// CHECK-START: int Main.$noinline$NoRem15(int, int) BCE (after)
/// CHECK: Div
/// CHECK-NEXT: Mul
/// CHECK-NEXT: Sub
/// CHECK-NEXT: BoundsCheck
/// CHECK-NEXT: ArrayGet
private static int $noinline$NoRem15(int v, int s) {
int[] values = {0, 1, 2};
if (v > 0) {
int q = v / 10;
int a = q * 10;
int b = s - a;
return values[b];
} else {
return -1;
}
}
/// CHECK-START: int Main.$noinline$noRemNonConst(int, int) BCE (after)
/// CHECK: BoundsCheck
private static int $noinline$noRemNonConst(int v, int s) {
// Regression test for compiler crash, b/169669115.
int[] values = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
if (v > 0) {
int q = v / s; // Non-constant divisor.
int a = q * 10; // Constant unrelated to the divisor above.
int b = s - a;
return values[b];
} else {
return -1;
}
}
public static void main(String args[]) {
remInt();
}
}