Extend char conversion tests for StringBuilder optimizer
Bug: b/384844007
Change-Id: Ieea67366da780d48649b66e9c44c172a27a08d74
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/B384844007Test.java b/src/test/java/com/android/tools/r8/ir/optimize/string/B384844007Test.java
deleted file mode 100644
index 748e0c2..0000000
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/B384844007Test.java
+++ /dev/null
@@ -1,68 +0,0 @@
-// Copyright (c) 2024, 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.optimize.string;
-
-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 org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class B384844007Test extends TestBase {
-
- @Parameter(0)
- public TestParameters parameters;
-
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
- }
-
- private static final String EXPECTED_OUTPUT = StringUtils.lines("i = 65523");
-
- @Test
- public void testJvm() throws Exception {
- parameters.assumeJvmTestParameters();
- testForJvm(parameters)
- .addInnerClasses(getClass())
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED_OUTPUT);
- }
-
- @Test
- public void testD8() throws Exception {
- parameters.assumeDexRuntime();
- testForD8(parameters.getBackend())
- .addInnerClasses(getClass())
- .setMinApi(parameters)
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED_OUTPUT);
- }
-
- @Test
- public void testR8() throws Exception {
- testForR8(parameters.getBackend())
- .addInnerClasses(getClass())
- .addKeepMainRule(TestClass.class)
- .setMinApi(parameters)
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED_OUTPUT);
- }
-
- static class TestClass {
-
- public static void main(String[] args) {
- int i = -13;
- char c = (char) i;
- i = c;
- System.out.println("i = " + i);
- }
- }
-}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderWithCharConversionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderWithCharConversionTest.java
new file mode 100644
index 0000000..b83eb50
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringBuilderWithCharConversionTest.java
@@ -0,0 +1,140 @@
+// Copyright (c) 2024, 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.optimize.string;
+
+import static org.junit.Assert.assertTrue;
+
+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 org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class StringBuilderWithCharConversionTest extends TestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ private static final String EXPECTED_OUTPUT =
+ StringUtils.lines("i = 65523", "i = 13", "i = 65535", "i = 65535", "i = 32767", "i = 32768");
+
+ @Test
+ public void testJvm() throws Exception {
+ parameters.assumeJvmTestParameters();
+ testForJvm(parameters)
+ .addInnerClasses(getClass())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ parameters.assumeDexRuntime();
+ testForD8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .setMinApi(parameters)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters)
+ .enableInliningAnnotations()
+ .run(parameters.getRuntime(), TestClass.class)
+ .inspect(
+ inspector -> {
+ for (int i = 1; i < 6; i++) {
+ assertTrue(
+ inspector
+ .clazz(TestClass.class)
+ .uniqueMethodWithOriginalName("f" + i)
+ .streamInstructions()
+ .noneMatch(
+ instruction ->
+ instruction.isConstNumber() || instruction.isNumberConversion()));
+ }
+ })
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ static class TestClass {
+
+ @NeverInline
+ public static void f1() {
+ int i = -13;
+ char c = (char) i;
+ i = c;
+ System.out.println("i = " + i);
+ }
+
+ @NeverInline
+ public static void f2() {
+ int i = 13;
+ char c = (char) i;
+ i = c;
+ System.out.println("i = " + i);
+ }
+
+ @NeverInline
+ public static void f3() {
+ // 7------07------07------07------0
+ int i = 0b00000000000000001111111111111111;
+ char c = (char) i;
+ i = c;
+ System.out.println("i = " + i);
+ }
+
+ @NeverInline
+ public static void f4() {
+ // 7------07------07------07------0
+ int i = 0b00000000000000011111111111111111;
+ char c = (char) i;
+ i = c;
+ System.out.println("i = " + i);
+ }
+
+ @NeverInline
+ public static void f5() {
+ // 7------07------07------07------0
+ int i = 0b00000000000000000111111111111111;
+ char c = (char) i;
+ i = c;
+ System.out.println("i = " + i);
+ }
+
+ @NeverInline
+ public static void f6() {
+ // 7------07------07------07------0
+ int i = 0b00000000000000001000000000000000;
+ char c = (char) i;
+ i = c;
+ System.out.println("i = " + i);
+ }
+
+ public static void main(String[] args) {
+ f1();
+ f2();
+ f3();
+ f4();
+ f5();
+ f6();
+ }
+ }
+}
diff --git a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
index 7ad1a8f..4c0102e 100644
--- a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
+++ b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
@@ -29,6 +29,7 @@
import com.android.tools.r8.cf.code.CfNew;
import com.android.tools.r8.cf.code.CfNewArray;
import com.android.tools.r8.cf.code.CfNop;
+import com.android.tools.r8.cf.code.CfNumberConversion;
import com.android.tools.r8.cf.code.CfPosition;
import com.android.tools.r8.cf.code.CfReturn;
import com.android.tools.r8.cf.code.CfReturnVoid;
@@ -216,6 +217,11 @@
}
@Override
+ public boolean isNumberConversion() {
+ return instruction instanceof CfNumberConversion;
+ }
+
+ @Override
public boolean isGoto() {
return instruction instanceof CfGoto;
}
diff --git a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
index fee7623..90d28b3 100644
--- a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
+++ b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/DexInstructionSubject.java
@@ -49,9 +49,15 @@
import com.android.tools.r8.dex.code.DexDivIntLit8;
import com.android.tools.r8.dex.code.DexDivLong;
import com.android.tools.r8.dex.code.DexDivLong2Addr;
+import com.android.tools.r8.dex.code.DexDoubleToFloat;
+import com.android.tools.r8.dex.code.DexDoubleToInt;
+import com.android.tools.r8.dex.code.DexDoubleToLong;
import com.android.tools.r8.dex.code.DexFillArrayData;
import com.android.tools.r8.dex.code.DexFilledNewArray;
import com.android.tools.r8.dex.code.DexFilledNewArrayRange;
+import com.android.tools.r8.dex.code.DexFloatToDouble;
+import com.android.tools.r8.dex.code.DexFloatToInt;
+import com.android.tools.r8.dex.code.DexFloatToLong;
import com.android.tools.r8.dex.code.DexGoto;
import com.android.tools.r8.dex.code.DexIfEq;
import com.android.tools.r8.dex.code.DexIfEqz;
@@ -74,6 +80,12 @@
import com.android.tools.r8.dex.code.DexIgetWide;
import com.android.tools.r8.dex.code.DexInstanceOf;
import com.android.tools.r8.dex.code.DexInstruction;
+import com.android.tools.r8.dex.code.DexIntToByte;
+import com.android.tools.r8.dex.code.DexIntToChar;
+import com.android.tools.r8.dex.code.DexIntToDouble;
+import com.android.tools.r8.dex.code.DexIntToFloat;
+import com.android.tools.r8.dex.code.DexIntToLong;
+import com.android.tools.r8.dex.code.DexIntToShort;
import com.android.tools.r8.dex.code.DexInvokeCustom;
import com.android.tools.r8.dex.code.DexInvokeCustomRange;
import com.android.tools.r8.dex.code.DexInvokeDirect;
@@ -94,6 +106,9 @@
import com.android.tools.r8.dex.code.DexIputObject;
import com.android.tools.r8.dex.code.DexIputShort;
import com.android.tools.r8.dex.code.DexIputWide;
+import com.android.tools.r8.dex.code.DexLongToDouble;
+import com.android.tools.r8.dex.code.DexLongToFloat;
+import com.android.tools.r8.dex.code.DexLongToInt;
import com.android.tools.r8.dex.code.DexMonitorEnter;
import com.android.tools.r8.dex.code.DexMonitorExit;
import com.android.tools.r8.dex.code.DexMove;
@@ -413,6 +428,25 @@
}
@Override
+ public boolean isNumberConversion() {
+ return instruction instanceof DexIntToByte
+ || instruction instanceof DexIntToShort
+ || instruction instanceof DexIntToLong
+ || instruction instanceof DexIntToChar
+ || instruction instanceof DexIntToDouble
+ || instruction instanceof DexIntToFloat
+ || instruction instanceof DexLongToInt
+ || instruction instanceof DexLongToFloat
+ || instruction instanceof DexLongToDouble
+ || instruction instanceof DexFloatToInt
+ || instruction instanceof DexFloatToLong
+ || instruction instanceof DexFloatToDouble
+ || instruction instanceof DexDoubleToInt
+ || instruction instanceof DexDoubleToLong
+ || instruction instanceof DexDoubleToFloat;
+ }
+
+ @Override
public boolean isGoto() {
return instruction instanceof DexGoto;
diff --git a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
index 983751f..49dffcd 100644
--- a/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
+++ b/src/test/testbase/java/com/android/tools/r8/utils/codeinspector/InstructionSubject.java
@@ -94,6 +94,8 @@
boolean isConstClass(String type);
+ boolean isNumberConversion();
+
boolean isGoto();
boolean isPop();