blob: 1d041b8f0d985f4a52e3d364366553c0b19352e9 [file] [log] [blame]
// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
public class AssociativeLongTest extends TestBase {
private static final String EXPECTED_RESULT =
StringUtils.lines(
"Associative",
"7",
"47",
"-9223372036854775804",
"-9223372036854775803",
"12",
"252",
"-6",
"0",
"2",
"2",
"2",
"0",
"3",
"43",
"9223372036854775807",
"-9223372036854775805",
"3",
"43",
"9223372036854775806",
"-9223372036854775807",
"Shift",
"64",
"1344",
"-32",
"0",
"0",
"1",
"288230376151711743",
"-288230376151711744",
"0",
"1",
"288230376151711743",
"288230376151711744",
"Sub",
"-1",
"-41",
"-9223372036854775806",
"-9223372036854775807",
"-3",
"37",
"9223372036854775802",
"9223372036854775803",
"Mixed",
"3",
"43",
"-9223372036854775808",
"-9223372036854775807",
"3",
"-37",
"-9223372036854775802",
"-9223372036854775803",
"3",
"43",
"-9223372036854775808",
"-9223372036854775807",
"1",
"41",
"9223372036854775806",
"9223372036854775807",
"Double Associative",
"12",
"52",
"84",
"1764",
"2",
"2",
"7",
"47",
"4",
"44",
"Double Shift",
"128",
"2688",
"0",
"0",
"0",
"0",
"Double Sub",
"-1",
"-41",
"-10",
"30",
"Double Mixed",
"-4",
"36",
"7",
"-33",
"-4",
"36",
"5",
"45");
private final TestParameters parameters;
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withCfRuntimes().withDexRuntimes().withAllApiLevels().build();
}
public AssociativeLongTest(TestParameters parameters) {
this.parameters = parameters;
}
@Test
public void testD8() throws Exception {
testForRuntime(parameters)
.addProgramClasses(Main.class)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
@Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
.addProgramClasses(Main.class)
.addKeepMainRule(Main.class)
.enableInliningAnnotations()
.setMinApi(parameters)
.compile()
.inspect(this::inspect)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
private void inspect(CodeInspector inspector) {
ClassSubject clazz = inspector.clazz(Main.class);
for (FoundMethodSubject method :
clazz.allMethods(m -> m.getParameters().size() > 0 && m.getParameter(0).is("long"))) {
assertEquals(
1,
method
.streamInstructions()
.filter(i -> i.isLongArithmeticBinop() || i.isLongLogicalBinop())
.count());
}
}
public static class Main {
public static void main(String[] args) {
simple();
doubleOps();
}
@NeverInline
private static void simple() {
// Associative + * & | ^.
System.out.println("Associative");
add(2);
add(42);
add(Long.MAX_VALUE);
add(Long.MIN_VALUE);
mul(2);
mul(42);
mul(Long.MAX_VALUE);
mul(Long.MIN_VALUE);
and(2);
and(42);
and(Long.MAX_VALUE);
and(Long.MIN_VALUE);
or(2);
or(42);
or(Long.MAX_VALUE);
or(Long.MIN_VALUE);
xor(2);
xor(42);
xor(Long.MAX_VALUE);
xor(Long.MIN_VALUE);
// Shift composition.
System.out.println("Shift");
shl(2);
shl(42);
shl(Long.MAX_VALUE);
shl(Long.MIN_VALUE);
shr(2);
shr(42);
shr(Long.MAX_VALUE);
shr(Long.MIN_VALUE);
ushr(2);
ushr(42);
ushr(Long.MAX_VALUE);
ushr(Long.MIN_VALUE);
// Special for -.
System.out.println("Sub");
sub(2);
sub(42);
sub(Long.MAX_VALUE);
sub(Long.MIN_VALUE);
sub2(2);
sub2(42);
sub2(Long.MAX_VALUE);
sub2(Long.MIN_VALUE);
// Mixed for + and -.
System.out.println("Mixed");
addSub(2);
addSub(42);
addSub(Long.MAX_VALUE);
addSub(Long.MIN_VALUE);
subAdd(2);
subAdd(42);
subAdd(Long.MAX_VALUE);
subAdd(Long.MIN_VALUE);
addSub2(2);
addSub2(42);
addSub2(Long.MAX_VALUE);
addSub2(Long.MIN_VALUE);
subAdd2(2);
subAdd2(42);
subAdd2(Long.MAX_VALUE);
subAdd2(Long.MIN_VALUE);
}
@NeverInline
private static void doubleOps() {
// Associative + * & | ^.
System.out.println("Double Associative");
addDouble(2);
addDouble(42);
mulDouble(2);
mulDouble(42);
andDouble(2);
andDouble(42);
orDouble(2);
orDouble(42);
xorDouble(2);
xorDouble(42);
// Shift composition.
System.out.println("Double Shift");
shlDouble(2);
shlDouble(42);
shrDouble(2);
shrDouble(42);
ushrDouble(2);
ushrDouble(42);
// Special for -.
System.out.println("Double Sub");
subDouble(2);
subDouble(42);
sub2Double(2);
sub2Double(42);
// Mixed for + and -.
System.out.println("Double Mixed");
addSubDouble(2);
addSubDouble(42);
subAddDouble(2);
subAddDouble(42);
addSub2Double(2);
addSub2Double(42);
subAdd2Double(2);
subAdd2Double(42);
}
@NeverInline
public static void add(long x) {
System.out.println(3L + x + 2L);
}
@NeverInline
public static void mul(long x) {
System.out.println(3L * x * 2L);
}
@NeverInline
public static void and(long x) {
System.out.println(3L & x & 2L);
}
@NeverInline
public static void or(long x) {
System.out.println(3L | x | 2L);
}
@NeverInline
public static void xor(long x) {
System.out.println(3L ^ x ^ 2L);
}
@NeverInline
public static void shl(long x) {
System.out.println(x << 2L << 3L);
}
@NeverInline
public static void shr(long x) {
System.out.println(x >> 2L >> 3L);
}
@NeverInline
public static void ushr(long x) {
System.out.println(x >>> 2L >>> 3L);
}
@NeverInline
public static void sub(long x) {
System.out.println(3L - x - 2L);
}
@NeverInline
public static void sub2(long x) {
System.out.println(x - 3L - 2L);
}
@NeverInline
public static void addSub(long x) {
System.out.println(3L + x - 2L);
}
@NeverInline
public static void addSub2(long x) {
System.out.println(x + 3L - 2L);
}
@NeverInline
public static void subAdd(long x) {
System.out.println(3L - x + 2L);
}
@NeverInline
public static void subAdd2(long x) {
System.out.println(x - 3L + 2L);
}
@NeverInline
public static void addDouble(long x) {
System.out.println(3L + x + 2L + 5);
}
@NeverInline
public static void mulDouble(long x) {
System.out.println(3L * x * 2L * 7L);
}
@NeverInline
public static void andDouble(long x) {
System.out.println(3L & x & 2L & 7L);
}
@NeverInline
public static void orDouble(long x) {
System.out.println(3L | x | 2L | 7L);
}
@NeverInline
public static void xorDouble(long x) {
System.out.println(3L ^ x ^ 2L ^ 7L);
}
@NeverInline
public static void shlDouble(long x) {
System.out.println(x << 2L << 3L << 1L);
}
@NeverInline
public static void shrDouble(long x) {
System.out.println(x >> 2L >> 3L >> 1L);
}
@NeverInline
public static void ushrDouble(long x) {
System.out.println(x >>> 2L >>> 3L >>> 1L);
}
@NeverInline
public static void subDouble(long x) {
System.out.println(3L - x - 2L);
}
@NeverInline
public static void sub2Double(long x) {
System.out.println(x - 3L - 2L - 7L);
}
@NeverInline
public static void addSubDouble(long x) {
System.out.println(3L + x - 2L - 7L);
}
@NeverInline
public static void addSub2Double(long x) {
System.out.println(x + 3L - 2L - 7L);
}
@NeverInline
public static void subAddDouble(long x) {
System.out.println(3L - x + 2L + 4L);
}
@NeverInline
public static void subAdd2Double(long x) {
System.out.println(x - 3L + 2L + 4L);
}
}
}