blob: ed4eb62502788d4b5df02de50355fb37f8a05145 [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 DivTest {
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() {
divInt();
divLong();
}
private static void divInt() {
expectEquals(0, $noinline$IntDivBy18(0));
expectEquals(0, $noinline$IntDivBy18(1));
expectEquals(0, $noinline$IntDivBy18(-1));
expectEquals(1, $noinline$IntDivBy18(18));
expectEquals(-1, $noinline$IntDivBy18(-18));
expectEquals(3, $noinline$IntDivBy18(65));
expectEquals(-3, $noinline$IntDivBy18(-65));
expectEquals(0, $noinline$IntDivByMinus18(0));
expectEquals(0, $noinline$IntDivByMinus18(1));
expectEquals(0, $noinline$IntDivByMinus18(-1));
expectEquals(-1, $noinline$IntDivByMinus18(18));
expectEquals(1, $noinline$IntDivByMinus18(-18));
expectEquals(-3, $noinline$IntDivByMinus18(65));
expectEquals(3, $noinline$IntDivByMinus18(-65));
expectEquals(0, $noinline$IntDivBy7(0));
expectEquals(0, $noinline$IntDivBy7(1));
expectEquals(0, $noinline$IntDivBy7(-1));
expectEquals(1, $noinline$IntDivBy7(7));
expectEquals(-1, $noinline$IntDivBy7(-7));
expectEquals(3, $noinline$IntDivBy7(22));
expectEquals(-3, $noinline$IntDivBy7(-22));
expectEquals(0, $noinline$IntDivByMinus7(0));
expectEquals(0, $noinline$IntDivByMinus7(1));
expectEquals(0, $noinline$IntDivByMinus7(-1));
expectEquals(-1, $noinline$IntDivByMinus7(7));
expectEquals(1, $noinline$IntDivByMinus7(-7));
expectEquals(-3, $noinline$IntDivByMinus7(22));
expectEquals(3, $noinline$IntDivByMinus7(-22));
expectEquals(0, $noinline$IntDivBy6(0));
expectEquals(0, $noinline$IntDivBy6(1));
expectEquals(0, $noinline$IntDivBy6(-1));
expectEquals(1, $noinline$IntDivBy6(6));
expectEquals(-1, $noinline$IntDivBy6(-6));
expectEquals(3, $noinline$IntDivBy6(19));
expectEquals(-3, $noinline$IntDivBy6(-19));
expectEquals(0, $noinline$IntDivByMinus6(0));
expectEquals(0, $noinline$IntDivByMinus6(1));
expectEquals(0, $noinline$IntDivByMinus6(-1));
expectEquals(-1, $noinline$IntDivByMinus6(6));
expectEquals(1, $noinline$IntDivByMinus6(-6));
expectEquals(-3, $noinline$IntDivByMinus6(19));
expectEquals(3, $noinline$IntDivByMinus6(-19));
}
// 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 DivTest.$noinline$IntDivBy18(int) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #34
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
private static int $noinline$IntDivBy18(int v) {
int r = v / 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 DivTest.$noinline$IntDivByMinus18(int) disassembly (after)
/// CHECK: asr x{{\d+}}, x{{\d+}}, #34
/// CHECK-NEXT: add w{{\d+}}, w{{\d+}}, w{{\d+}}, lsr #31
private static int $noinline$IntDivByMinus18(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 DivTest.$noinline$IntDivBy7(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
private static int $noinline$IntDivBy7(int v) {
int r = v / 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 DivTest.$noinline$IntDivByMinus7(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
private static int $noinline$IntDivByMinus7(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 DivTest.$noinline$IntDivBy6(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$IntDivBy6(int v) {
int r = v / 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 DivTest.$noinline$IntDivByMinus6(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$IntDivByMinus6(int v) {
int r = v / -6;
return r;
}
private static void divLong() {
expectEquals(0L, $noinline$LongDivBy18(0L));
expectEquals(0L, $noinline$LongDivBy18(1L));
expectEquals(0L, $noinline$LongDivBy18(-1L));
expectEquals(1L, $noinline$LongDivBy18(18L));
expectEquals(-1L, $noinline$LongDivBy18(-18L));
expectEquals(3L, $noinline$LongDivBy18(65L));
expectEquals(-3L, $noinline$LongDivBy18(-65L));
expectEquals(0L, $noinline$LongDivByMinus18(0L));
expectEquals(0L, $noinline$LongDivByMinus18(1L));
expectEquals(0L, $noinline$LongDivByMinus18(-1L));
expectEquals(-1L, $noinline$LongDivByMinus18(18L));
expectEquals(1L, $noinline$LongDivByMinus18(-18L));
expectEquals(-3L, $noinline$LongDivByMinus18(65L));
expectEquals(3L, $noinline$LongDivByMinus18(-65L));
expectEquals(0L, $noinline$LongDivBy7(0L));
expectEquals(0L, $noinline$LongDivBy7(1L));
expectEquals(0L, $noinline$LongDivBy7(-1L));
expectEquals(1L, $noinline$LongDivBy7(7L));
expectEquals(-1L, $noinline$LongDivBy7(-7L));
expectEquals(3L, $noinline$LongDivBy7(22L));
expectEquals(-3L, $noinline$LongDivBy7(-22L));
expectEquals(0L, $noinline$LongDivByMinus7(0L));
expectEquals(0L, $noinline$LongDivByMinus7(1L));
expectEquals(0L, $noinline$LongDivByMinus7(-1L));
expectEquals(-1L, $noinline$LongDivByMinus7(7L));
expectEquals(1L, $noinline$LongDivByMinus7(-7L));
expectEquals(-3L, $noinline$LongDivByMinus7(22L));
expectEquals(3L, $noinline$LongDivByMinus7(-22L));
expectEquals(0L, $noinline$LongDivBy6(0L));
expectEquals(0L, $noinline$LongDivBy6(1L));
expectEquals(0L, $noinline$LongDivBy6(-1L));
expectEquals(1L, $noinline$LongDivBy6(6L));
expectEquals(-1L, $noinline$LongDivBy6(-6L));
expectEquals(3L, $noinline$LongDivBy6(19L));
expectEquals(-3L, $noinline$LongDivBy6(-19L));
expectEquals(0L, $noinline$LongDivByMinus6(0L));
expectEquals(0L, $noinline$LongDivByMinus6(1L));
expectEquals(0L, $noinline$LongDivByMinus6(-1L));
expectEquals(-1L, $noinline$LongDivByMinus6(6L));
expectEquals(1L, $noinline$LongDivByMinus6(-6L));
expectEquals(-3L, $noinline$LongDivByMinus6(19L));
expectEquals(3L, $noinline$LongDivByMinus6(-19L));
expectEquals(0L, $noinline$LongDivBy100(0L));
expectEquals(0L, $noinline$LongDivBy100(1L));
expectEquals(0L, $noinline$LongDivBy100(-1L));
expectEquals(1L, $noinline$LongDivBy100(100L));
expectEquals(-1L, $noinline$LongDivBy100(-100L));
expectEquals(3L, $noinline$LongDivBy100(301L));
expectEquals(-3L, $noinline$LongDivBy100(-301L));
expectEquals(0L, $noinline$LongDivByMinus100(0L));
expectEquals(0L, $noinline$LongDivByMinus100(1L));
expectEquals(0L, $noinline$LongDivByMinus100(-1L));
expectEquals(-1L, $noinline$LongDivByMinus100(100L));
expectEquals(1L, $noinline$LongDivByMinus100(-100L));
expectEquals(-3L, $noinline$LongDivByMinus100(301L));
expectEquals(3L, $noinline$LongDivByMinus100(-301L));
}
// 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 DivTest.$noinline$LongDivBy18(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
private static long $noinline$LongDivBy18(long v) {
long r = v / 18L;
return r;
}
/// CHECK-START-ARM64: long DivTest.$noinline$LongDivByMinus18(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
private static long $noinline$LongDivByMinus18(long v) {
long r = v / -18L;
return r;
}
/// CHECK-START-ARM64: long DivTest.$noinline$LongDivBy7(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
private static long $noinline$LongDivBy7(long v) {
long r = v / 7L;
return r;
}
/// CHECK-START-ARM64: long DivTest.$noinline$LongDivByMinus7(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
private static long $noinline$LongDivByMinus7(long v) {
long r = v / -7L;
return r;
}
/// CHECK-START-ARM64: long DivTest.$noinline$LongDivBy6(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
private static long $noinline$LongDivBy6(long v) {
long r = v / 6L;
return r;
}
/// CHECK-START-ARM64: long DivTest.$noinline$LongDivByMinus6(long) disassembly (after)
/// CHECK: smulh x{{\d+}}, x{{\d+}}, x{{\d+}}
/// CHECK-NEXT: add x{{\d+}}, x{{\d+}}, x{{\d+}}, lsr #63
private static long $noinline$LongDivByMinus6(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 DivTest.$noinline$LongDivBy100(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
private static long $noinline$LongDivBy100(long v) {
long r = v / 100L;
return r;
}
// A test to check 'subs' and 'add_shift' are optimized into 'subs' and 'cinc'.
//
/// CHECK-START-ARM64: long DivTest.$noinline$LongDivByMinus100(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
private static long $noinline$LongDivByMinus100(long v) {
long r = v / -100L;
return r;
}
}