blob: f7117ec935f43d3aaa81c4c85f8bf97001e0ad50 [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 RemTest {
private static void expectEquals(int expected, int result) {
if (expected != result) {
throw new Error("Expected: " + expected + ", found: " + result);
}
}
private static void expectEquals(long expected, long result) {
if (expected != result) {
throw new Error("Expected: " + expected + ", found: " + result);
}
}
public static void main() {
remInt();
remLong();
}
private static void remInt() {
expectEquals(0, $noinline$IntRemBy18(0));
expectEquals(1, $noinline$IntRemBy18(1));
expectEquals(-1, $noinline$IntRemBy18(-1));
expectEquals(0, $noinline$IntRemBy18(18));
expectEquals(0, $noinline$IntRemBy18(-18));
expectEquals(11, $noinline$IntRemBy18(65));
expectEquals(-11, $noinline$IntRemBy18(-65));
expectEquals(0, $noinline$IntALenRemBy18(new int[0]));
expectEquals(1, $noinline$IntALenRemBy18(new int[1]));
expectEquals(0, $noinline$IntALenRemBy18(new int[18]));
expectEquals(11, $noinline$IntALenRemBy18(new int[65]));
expectEquals(0, $noinline$IntRemByMinus18(0));
expectEquals(1, $noinline$IntRemByMinus18(1));
expectEquals(-1, $noinline$IntRemByMinus18(-1));
expectEquals(0, $noinline$IntRemByMinus18(18));
expectEquals(0, $noinline$IntRemByMinus18(-18));
expectEquals(11, $noinline$IntRemByMinus18(65));
expectEquals(-11, $noinline$IntRemByMinus18(-65));
expectEquals(0, $noinline$IntRemBy7(0));
expectEquals(1, $noinline$IntRemBy7(1));
expectEquals(-1, $noinline$IntRemBy7(-1));
expectEquals(0, $noinline$IntRemBy7(7));
expectEquals(0, $noinline$IntRemBy7(-7));
expectEquals(1, $noinline$IntRemBy7(22));
expectEquals(-1, $noinline$IntRemBy7(-22));
expectEquals(0, $noinline$IntALenRemBy7(new int[0]));
expectEquals(1, $noinline$IntALenRemBy7(new int[1]));
expectEquals(0, $noinline$IntALenRemBy7(new int[7]));
expectEquals(1, $noinline$IntALenRemBy7(new int[22]));
expectEquals(0, $noinline$IntRemByMinus7(0));
expectEquals(1, $noinline$IntRemByMinus7(1));
expectEquals(-1, $noinline$IntRemByMinus7(-1));
expectEquals(0, $noinline$IntRemByMinus7(7));
expectEquals(0, $noinline$IntRemByMinus7(-7));
expectEquals(1, $noinline$IntRemByMinus7(22));
expectEquals(-1, $noinline$IntRemByMinus7(-22));
expectEquals(0, $noinline$IntRemBy6(0));
expectEquals(1, $noinline$IntRemBy6(1));
expectEquals(-1, $noinline$IntRemBy6(-1));
expectEquals(0, $noinline$IntRemBy6(6));
expectEquals(0, $noinline$IntRemBy6(-6));
expectEquals(1, $noinline$IntRemBy6(19));
expectEquals(-1, $noinline$IntRemBy6(-19));
expectEquals(0, $noinline$IntALenRemBy6(new int[0]));
expectEquals(1, $noinline$IntALenRemBy6(new int[1]));
expectEquals(0, $noinline$IntALenRemBy6(new int[6]));
expectEquals(1, $noinline$IntALenRemBy6(new int[19]));
expectEquals(0, $noinline$IntRemByMinus6(0));
expectEquals(1, $noinline$IntRemByMinus6(1));
expectEquals(-1, $noinline$IntRemByMinus6(-1));
expectEquals(0, $noinline$IntRemByMinus6(6));
expectEquals(0, $noinline$IntRemByMinus6(-6));
expectEquals(1, $noinline$IntRemByMinus6(19));
expectEquals(-1, $noinline$IntRemByMinus6(-19));
expectEquals(1, $noinline$UnsignedIntRem01(13));
expectEquals(1, $noinline$UnsignedIntRem02(13));
expectEquals(1, $noinline$UnsignedIntRem03(13));
expectEquals(1, $noinline$UnsignedIntRem04(13));
expectEquals(1, $noinline$UnsignedIntRem05(101));
expectEquals(11, $noinline$UnsignedIntRem06(101));
expectEquals(-1, $noinline$SignedIntRem01(-13));
expectEquals(-1, $noinline$SignedIntRem02(-13));
expectEquals(1, $noinline$SignedIntRem03(-13));
expectEquals(1, $noinline$SignedIntRem04(-13, true));
expectEquals(0, $noinline$SignedIntRem05(-12, 0,-13));
expectEquals(-1, $noinline$SignedIntRem06(-13));
}
// A test case to check that 'lsr' and 'asr' are combined into one 'asr'.
// For divisor 18 seen in an MP3 decoding workload there is no need
// to correct the result of get_high(dividend * magic). So there are no
// instructions between 'lsr' and 'asr'. In such a case they can be combined
// into one 'asr'.
//
/// CHECK-START-ARM64: int RemTest.$noinline$IntRemBy18(int) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #34
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
/// CHECK-NEXT: mov w{{\d+}}, #0x12
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$IntRemBy18(int v) {
int r = v % 18;
return r;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM: int RemTest.$noinline$IntALenRemBy18(int[]) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: lsr{{s?}} r{{\d+}}, #2
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #18
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$IntALenRemBy18(int[]) disassembly (after)
/// CHECK: lsr x{{\d+}}, x{{\d+}}, #34
/// CHECK-NEXT: mov w{{\d+}}, #0x12
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$IntALenRemBy18(int[] arr) {
int r = arr.length % 18;
return r;
}
// A test case to check that 'lsr' and 'asr' are combined into one 'asr'.
// Divisor -18 has the same property as divisor 18: no need to correct the
// result of get_high(dividend * magic). So there are no
// instructions between 'lsr' and 'asr'. In such a case they can be combined
// into one 'asr'.
//
/// CHECK-START-ARM64: int RemTest.$noinline$IntRemByMinus18(int) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #34
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
/// CHECK-NEXT: mov w{{\d+}}, #0xffffffee
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$IntRemByMinus18(int v) {
int r = v % -18;
return r;
}
// A test case to check that 'lsr' and 'add' are combined into one 'adds'.
// For divisor 7 seen in the core library the result of get_high(dividend * magic)
// must be corrected by the 'add' instruction.
//
// The test case also checks 'add' and 'add_shift' are optimized into 'adds' and 'cinc'.
//
/// CHECK-START-ARM64: int RemTest.$noinline$IntRemBy7(int) disassembly (after)
/// CHECK: adds x{{\d+}}, x{{\d+}}, x{{\d+}}, lsl #32
/// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #34
/// CHECK-NEXT: cinc w{{\d+}}, w{{\d+}}, mi
/// CHECK-NEXT: mov w{{\d+}}, #0x7
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$IntRemBy7(int v) {
int r = v % 7;
return r;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM: int RemTest.$noinline$IntALenRemBy7(int[]) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: add{{s?}} r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: lsr{{s?}} r{{\d+}}, #2
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #7
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$IntALenRemBy7(int[]) disassembly (after)
/// CHECK: lsr x{{\d+}}, x{{\d+}}, #34
/// CHECK-NEXT: mov w{{\d+}}, #0x7
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$IntALenRemBy7(int[] arr) {
int r = arr.length % 7;
return r;
}
// A test case to check that 'lsr' and 'add' are combined into one 'adds'.
// Divisor -7 has the same property as divisor 7: the result of get_high(dividend * magic)
// must be corrected. In this case it is a 'sub' instruction.
//
// The test case also checks 'sub' and 'add_shift' are optimized into 'subs' and 'cinc'.
//
/// CHECK-START-ARM64: int RemTest.$noinline$IntRemByMinus7(int) disassembly (after)
/// CHECK: subs x{{\d+}}, x{{\d+}}, x{{\d+}}, lsl #32
/// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #34
/// CHECK-NEXT: cinc w{{\d+}}, w{{\d+}}, mi
/// CHECK-NEXT: mov w{{\d+}}, #0xfffffff9
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$IntRemByMinus7(int v) {
int r = v % -7;
return r;
}
// A test case to check that 'asr' is used to get the high 32 bits of the result of
// 'dividend * magic'.
// For divisor 6 seen in the core library there is no need to correct the result of
// get_high(dividend * magic). Also there is no 'asr' before the final 'add' instruction
// which uses only the high 32 bits of the result. In such a case 'asr' getting the high
// 32 bits can be used as well.
//
/// CHECK-START-ARM64: int RemTest.$noinline$IntRemBy6(int) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
/// CHECK-NEXT: mov w{{\d+}}, #0x6
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$IntRemBy6(int v) {
int r = v % 6;
return r;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM: int RemTest.$noinline$IntALenRemBy6(int[]) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$IntALenRemBy6(int[]) disassembly (after)
/// CHECK: lsr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: mov w{{\d+}}, #0x6
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$IntALenRemBy6(int[] arr) {
int r = arr.length % 6;
return r;
}
// A test case to check that 'asr' is used to get the high 32 bits of the result of
// 'dividend * magic'.
// Divisor -6 has the same property as divisor 6: no need to correct the result of
// get_high(dividend * magic) and no 'asr' before the final 'add' instruction
// which uses only the high 32 bits of the result. In such a case 'asr' getting the high
// 32 bits can be used as well.
//
/// CHECK-START-ARM64: int RemTest.$noinline$IntRemByMinus6(int) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
/// CHECK-NEXT: mov w{{\d+}}, #0xfffffffa
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$IntRemByMinus6(int v) {
int r = v % -6;
return r;
}
private static int $noinline$Negate(int v) {
return -v;
}
private static int $noinline$Decrement(int v) {
return v - 1;
}
private static int $noinline$Increment(int v) {
return v + 1;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem01(int) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem01(int) disassembly (after)
/// CHECK: lsr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: mov w{{\d+}}, #0x6
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$UnsignedIntRem01(int v) {
int c = 0;
if (v > 0) {
c = v % 6;
} else {
c = $noinline$Negate(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem02(int) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem02(int) disassembly (after)
/// CHECK: lsr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: mov w{{\d+}}, #0x6
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$UnsignedIntRem02(int v) {
int c = 0;
if (0 < v) {
c = v % 6;
} else {
c = $noinline$Negate(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem03(int) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem03(int) disassembly (after)
/// CHECK: lsr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: mov w{{\d+}}, #0x6
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$UnsignedIntRem03(int v) {
int c = 0;
if (v >= 0) {
c = v % 6;
} else {
c = $noinline$Negate(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem04(int) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem04(int) disassembly (after)
/// CHECK: lsr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: mov w{{\d+}}, #0x6
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$UnsignedIntRem04(int v) {
int c = 0;
if (0 <= v) {
c = v % 6;
} else {
c = $noinline$Negate(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem05(int) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: lsr{{s?}} r{{\d+}}, #2
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #10
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem05(int) disassembly (after)
/// CHECK: lsr x{{\d+}}, x{{\d+}}, #34
/// CHECK-NEXT: mov w{{\d+}}, #0xa
/// CHECK-NEXT: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$UnsignedIntRem05(int v) {
int c = 0;
for(; v > 100; ++c) {
v %= 10;
}
return c;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM: int RemTest.$noinline$UnsignedIntRem06(int) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: lsr{{s?}} r{{\d+}}, r{{\d+}}, #2
/// CHECK: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$UnsignedIntRem06(int) disassembly (after)
/// CHECK: smull x{{\d+}}, w{{\d+}}, w{{\d+}}
/// CHECK-NEXT: lsr x{{\d+}}, x{{\d+}}, #34
/// CHECK: msub w{{\d+}}, w{{\d+}}, w{{\d+}}, w{{\d+}}
private static int $noinline$UnsignedIntRem06(int v) {
if (v < 10) {
v = $noinline$Negate(v); // This is to prevent from using Select.
} else {
v = (v % 10) + (v / 10);
}
return v;
}
// A test case to check that a correcting 'add' is generated for a negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem01(int) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem01(int) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
private static int $noinline$SignedIntRem01(int v) {
int c = 0;
if (v < 0) {
c = v % 6;
} else {
c = $noinline$Decrement(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is generated for a negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem02(int) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem02(int) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
private static int $noinline$SignedIntRem02(int v) {
int c = 0;
if (v <= 0) {
c = v % 6;
} else {
c = $noinline$Decrement(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is generated for signed division.
//
/// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem03(int) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem03(int) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
private static int $noinline$SignedIntRem03(int v) {
boolean positive = (v > 0);
int c = v % 6;
if (!positive) {
c = $noinline$Negate(c); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is generated for signed division.
//
/// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem04(int, boolean) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem04(int, boolean) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
private static int $noinline$SignedIntRem04(int v, boolean apply_rem) {
int c = 0;
boolean positive = (v > 0);
if (apply_rem) {
c = v % 6;
} else {
c = $noinline$Decrement(v); // This is to prevent from using Select.
}
if (!positive) {
c = $noinline$Negate(c); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is generated for signed division.
//
/// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem05(int, int, int) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem05(int, int, int) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
private static int $noinline$SignedIntRem05(int v, int a, int b) {
int c = 0;
if (v < a)
c = $noinline$Increment(c); // This is to prevent from using Select.
if (b < a)
c = $noinline$Increment(c); // This is to prevent from using Select.
if (v > b) {
c = v % 6;
} else {
c = $noinline$Increment(c); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is generated for signed division.
//
/// CHECK-START-ARM: int RemTest.$noinline$SignedIntRem06(int) disassembly (after)
/// CHECK: smull r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
/// CHECK-NEXT: sub r{{\d+}}, r{{\d+}}, asr #31
/// CHECK-NEXT: mov{{s?}} r{{\d+}}, #6
/// CHECK-NEXT: mls r{{\d+}}, r{{\d+}}, r{{\d+}}, r{{\d+}}
//
/// CHECK-START-ARM64: int RemTest.$noinline$SignedIntRem06(int) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #32
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
private static int $noinline$SignedIntRem06(int v) {
int c = v % 6;
if (v > 0) {
c = $noinline$Negate(c); // This is to prevent from using Select.
}
return c;
}
private static void remLong() {
expectEquals(0L, $noinline$LongRemBy18(0L));
expectEquals(1L, $noinline$LongRemBy18(1L));
expectEquals(-1L, $noinline$LongRemBy18(-1L));
expectEquals(0L, $noinline$LongRemBy18(18L));
expectEquals(0L, $noinline$LongRemBy18(-18L));
expectEquals(11L, $noinline$LongRemBy18(65L));
expectEquals(-11L, $noinline$LongRemBy18(-65L));
expectEquals(0L, $noinline$LongRemByMinus18(0L));
expectEquals(1L, $noinline$LongRemByMinus18(1L));
expectEquals(-1L, $noinline$LongRemByMinus18(-1L));
expectEquals(0L, $noinline$LongRemByMinus18(18L));
expectEquals(0L, $noinline$LongRemByMinus18(-18L));
expectEquals(11L, $noinline$LongRemByMinus18(65L));
expectEquals(-11L, $noinline$LongRemByMinus18(-65L));
expectEquals(0L, $noinline$LongRemBy7(0L));
expectEquals(1L, $noinline$LongRemBy7(1L));
expectEquals(-1L, $noinline$LongRemBy7(-1L));
expectEquals(0L, $noinline$LongRemBy7(7L));
expectEquals(0L, $noinline$LongRemBy7(-7L));
expectEquals(1L, $noinline$LongRemBy7(22L));
expectEquals(-1L, $noinline$LongRemBy7(-22L));
expectEquals(0L, $noinline$LongRemByMinus7(0L));
expectEquals(1L, $noinline$LongRemByMinus7(1L));
expectEquals(-1L, $noinline$LongRemByMinus7(-1L));
expectEquals(0L, $noinline$LongRemByMinus7(7L));
expectEquals(0L, $noinline$LongRemByMinus7(-7L));
expectEquals(1L, $noinline$LongRemByMinus7(22L));
expectEquals(-1L, $noinline$LongRemByMinus7(-22L));
expectEquals(0L, $noinline$LongRemBy6(0L));
expectEquals(1L, $noinline$LongRemBy6(1L));
expectEquals(-1L, $noinline$LongRemBy6(-1L));
expectEquals(0L, $noinline$LongRemBy6(6L));
expectEquals(0L, $noinline$LongRemBy6(-6L));
expectEquals(1L, $noinline$LongRemBy6(19L));
expectEquals(-1L, $noinline$LongRemBy6(-19L));
expectEquals(0L, $noinline$LongRemByMinus6(0L));
expectEquals(1L, $noinline$LongRemByMinus6(1L));
expectEquals(-1L, $noinline$LongRemByMinus6(-1L));
expectEquals(0L, $noinline$LongRemByMinus6(6L));
expectEquals(0L, $noinline$LongRemByMinus6(-6L));
expectEquals(1L, $noinline$LongRemByMinus6(19L));
expectEquals(-1L, $noinline$LongRemByMinus6(-19L));
expectEquals(0L, $noinline$LongRemBy100(0L));
expectEquals(1L, $noinline$LongRemBy100(1L));
expectEquals(-1L, $noinline$LongRemBy100(-1L));
expectEquals(0L, $noinline$LongRemBy100(100L));
expectEquals(0L, $noinline$LongRemBy100(-100L));
expectEquals(1L, $noinline$LongRemBy100(101L));
expectEquals(-1L, $noinline$LongRemBy100(-101L));
expectEquals(0L, $noinline$LongRemByMinus100(0L));
expectEquals(1L, $noinline$LongRemByMinus100(1L));
expectEquals(-1L, $noinline$LongRemByMinus100(-1L));
expectEquals(0L, $noinline$LongRemByMinus100(100L));
expectEquals(0L, $noinline$LongRemByMinus100(-100L));
expectEquals(1L, $noinline$LongRemByMinus100(101L));
expectEquals(-1L, $noinline$LongRemByMinus100(-101L));
expectEquals(1L, $noinline$UnsignedLongRem01(13L));
expectEquals(1L, $noinline$UnsignedLongRem02(13L));
expectEquals(1L, $noinline$UnsignedLongRem03(13L));
expectEquals(1L, $noinline$UnsignedLongRem04(13L));
expectEquals(1L, $noinline$UnsignedLongRem05(101L));
expectEquals(11L, $noinline$UnsignedLongRem06(101L));
expectEquals(-1L, $noinline$SignedLongRem01(-13L));
expectEquals(-1L, $noinline$SignedLongRem02(-13L));
expectEquals(1L, $noinline$SignedLongRem03(-13L));
expectEquals(1L, $noinline$SignedLongRem04(-13L, true));
expectEquals(0L, $noinline$SignedLongRem05(-12L, 0L,-13L));
expectEquals(-1L, $noinline$SignedLongRem06(-13L));
}
// Test cases for Int64 HDiv/HRem to check that optimizations implemented for Int32 are not
// used for Int64. The same divisors 18, -18, 7, -7, 6 and -6 are used.
/// CHECK-START-ARM64: long RemTest.$noinline$LongRemBy18(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0x12
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$LongRemBy18(long v) {
long r = v % 18L;
return r;
}
/// CHECK-START-ARM64: long RemTest.$noinline$LongRemByMinus18(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0xffffffffffffffee
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$LongRemByMinus18(long v) {
long r = v % -18L;
return r;
}
/// CHECK-START-ARM64: long RemTest.$noinline$LongRemBy7(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #1
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0x7
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$LongRemBy7(long v) {
long r = v % 7L;
return r;
}
/// CHECK-START-ARM64: long RemTest.$noinline$LongRemByMinus7(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #1
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0xfffffffffffffff9
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$LongRemByMinus7(long v) {
long r = v % -7L;
return r;
}
/// CHECK-START-ARM64: long RemTest.$noinline$LongRemBy6(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0x6
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$LongRemBy6(long v) {
long r = v % 6L;
return r;
}
/// CHECK-START-ARM64: long RemTest.$noinline$LongRemByMinus6(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0xfffffffffffffffa
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$LongRemByMinus6(long v) {
long r = v % -6L;
return r;
}
// A test to check 'add' and 'add_shift' are optimized into 'adds' and 'cinc'.
//
/// CHECK-START-ARM64: long RemTest.$noinline$LongRemBy100(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: adds x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #6
/// CHECK-NEXT: cinc x{{\d+}}, x{{\d+}}, mi
/// CHECK-NEXT: mov x{{\d+}}, #0x64
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$LongRemBy100(long v) {
long r = v % 100L;
return r;
}
// A test to check 'sub' and 'add_shift' are optimized into 'subs' and 'cinc'.
//
/// CHECK-START-ARM64: long RemTest.$noinline$LongRemByMinus100(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: subs x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: asr x{{\d+}}, x{{\d+}}, #6
/// CHECK-NEXT: cinc x{{\d+}}, x{{\d+}}, mi
/// CHECK-NEXT: mov x{{\d+}}, #0xffffffffffffff9c
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$LongRemByMinus100(long v) {
long r = v % -100L;
return r;
}
private static long $noinline$Negate(long v) {
return -v;
}
private static long $noinline$Decrement(long v) {
return v - 1;
}
private static long $noinline$Increment(long v) {
return v + 1;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem01(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: mov x{{\d+}}, #0x6
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$UnsignedLongRem01(long v) {
long c = 0;
if (v > 0) {
c = v % 6;
} else {
c = $noinline$Negate(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem02(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: mov x{{\d+}}, #0x6
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$UnsignedLongRem02(long v) {
long c = 0;
if (0 < v) {
c = v % 6;
} else {
c = $noinline$Negate(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem03(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: mov x{{\d+}}, #0x6
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$UnsignedLongRem03(long v) {
long c = 0;
if (v >= 0) {
c = v % 6;
} else {
c = $noinline$Negate(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem04(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: mov x{{\d+}}, #0x6
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$UnsignedLongRem04(long v) {
long c = 0;
if (0 <= v) {
c = v % 6;
} else {
c = $noinline$Negate(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem05(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: lsr x{{\d+}}, x{{\d+}}, #2
/// CHECK-NEXT: mov x{{\d+}}, #0xa
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$UnsignedLongRem05(long v) {
long c = 0;
for(; v > 100; ++c) {
v %= 10;
}
return c;
}
// A test case to check that a correcting 'add' is not generated for a non-negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM64: long RemTest.$noinline$UnsignedLongRem06(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: lsr x{{\d+}}, x{{\d+}}, #2
/// CHECK: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$UnsignedLongRem06(long v) {
if (v < 10) {
v = $noinline$Negate(v); // This is to prevent from using Select.
} else {
v = (v % 10) + (v / 10);
}
return v;
}
// A test case to check that a correcting 'add' is generated for a negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem01(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0x6
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$SignedLongRem01(long v) {
long c = 0;
if (v < 0) {
c = v % 6;
} else {
c = $noinline$Decrement(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is generated for a negative
// dividend and a positive divisor.
//
/// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem02(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0x6
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$SignedLongRem02(long v) {
long c = 0;
if (v <= 0) {
c = v % 6;
} else {
c = $noinline$Decrement(v); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is generated for signed division.
//
/// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem03(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0x6
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$SignedLongRem03(long v) {
boolean positive = (v > 0);
long c = v % 6;
if (!positive) {
c = $noinline$Negate(c); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is generated for signed division.
//
/// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem04(long, boolean) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0x6
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$SignedLongRem04(long v, boolean apply_rem) {
long c = 0;
boolean positive = (v > 0);
if (apply_rem) {
c = v % 6;
} else {
c = $noinline$Decrement(v); // This is to prevent from using Select.
}
if (!positive) {
c = $noinline$Negate(c); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is generated for signed division.
//
/// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem05(long, long, long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0x6
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$SignedLongRem05(long v, long a, long b) {
long c = 0;
if (v < a)
c = $noinline$Increment(c); // This is to prevent from using Select.
if (b < a)
c = $noinline$Increment(c); // This is to prevent from using Select.
if (v > b) {
c = v % 6;
} else {
c = $noinline$Increment(c); // This is to prevent from using Select.
}
return c;
}
// A test case to check that a correcting 'add' is generated for signed division.
//
/// CHECK-START-ARM64: long RemTest.$noinline$SignedLongRem06(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
/// CHECK-NEXT: mov x{{\d+}}, #0x6
/// CHECK-NEXT: msub x{{\d+}}, x{{\d+}}, x{{\d+}}, x{{\d+}}
private static long $noinline$SignedLongRem06(long v) {
long c = v % 6;
if (v > 0) {
c = $noinline$Negate(c); // This is to prevent from using Select.
}
return c;
}
}