Remove DebugLocalWrite when it is possible
- It allows to D8 to generate smaller code in debug mode. It save about
12k on framework and 46k on GMSCore v10.
Bug: 66161160
Change-Id: Ic9169ca1d89cc990c779f026ad9f60cb4f23e568
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 454d6cd..7248df3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -1441,6 +1441,23 @@
}
}
+ // TODO(mikaelpeltier) Manage that from and to instruction do not belong to the same block.
+ private boolean hasLineChangeBetween(Instruction from, Instruction to) {
+ if (from.getBlock() != to.getBlock()) {
+ return true;
+ }
+ InstructionListIterator iterator = from.getBlock().listIterator(from);
+ while (iterator.hasNext()) {
+ Instruction instruction = iterator.next();
+ if (instruction == to) {
+ return false;
+ } else if (instruction.isDebugPosition()) {
+ return true;
+ }
+ }
+ throw new Unreachable();
+ }
+
public void simplifyDebugLocals(IRCode code) {
for (BasicBlock block : code.blocks) {
for (Phi phi : block.getPhis()) {
@@ -1451,6 +1468,26 @@
}
}
}
+
+ InstructionIterator iterator = code.instructionIterator();
+ while (iterator.hasNext()) {
+ Instruction instruction = iterator.next();
+ if (instruction.isDebugLocalWrite()) {
+ assert instruction.inValues().size() == 1;
+ Value inValue = instruction.inValues().get(0);
+ if (inValue.definition != null &&
+ !inValue.definition.isConstNumber() &&
+ !hasLineChangeBetween(inValue.definition, instruction) &&
+ inValue.getLocalInfo() == null &&
+ inValue.numberOfAllUsers() == 1) {
+ inValue.setLocalInfo(instruction.outValue().getLocalInfo());
+ instruction.moveDebugValues(inValue.definition);
+ instruction.outValue().replaceUsers(inValue);
+ instruction.clearDebugValues();
+ iterator.remove();
+ }
+ }
+ }
}
}
diff --git a/src/test/debugTestResources/Locals.java b/src/test/debugTestResources/Locals.java
index 1221234..a474c1e 100644
--- a/src/test/debugTestResources/Locals.java
+++ b/src/test/debugTestResources/Locals.java
@@ -338,6 +338,13 @@
return result;
}
+ public static int intAddition(int a, int b, int c) {
+ a += b;
+ b += c;
+ c = a + b;
+ return c;
+ }
+
public static void main(String[] args) {
noLocals();
unusedLocals();
@@ -360,5 +367,6 @@
regression65066975(false);
System.out.println(localConstant(true));
System.out.println(localConstantBis(true));
+ System.out.println(intAddition(1, 2, 6));
}
}
diff --git a/src/test/java/com/android/tools/r8/debug/LocalsTest.java b/src/test/java/com/android/tools/r8/debug/LocalsTest.java
index 9b0a888..b6cf308 100644
--- a/src/test/java/com/android/tools/r8/debug/LocalsTest.java
+++ b/src/test/java/com/android/tools/r8/debug/LocalsTest.java
@@ -608,4 +608,37 @@
checkNoLocal("result2"),
run());
}
+
+ /**
+ * Companion test with dex inspection
+ * {@link com.android.tools.r8.debuginfo.CodeGeneratorTestRunner#test2AddrInstruction}
+ */
+ @Test
+ public void testLocalUsedBy2AddrInstruction() throws Throwable {
+ final String className = "Locals";
+ final String methodName = "intAddition";
+ runDebugTest(className,
+ breakpoint(className, methodName),
+ run(),
+ checkLine(SOURCE_FILE, 342),
+ checkLocal("a", Value.createInt(1)),
+ checkLocal("b", Value.createInt(2)),
+ checkLocal("c", Value.createInt(6)),
+ stepOver(),
+ checkLine(SOURCE_FILE, 343),
+ checkLocal("a", Value.createInt(3)),
+ checkLocal("b", Value.createInt(2)),
+ checkLocal("c", Value.createInt(6)),
+ stepOver(),
+ checkLine(SOURCE_FILE, 344),
+ checkLocal("a", Value.createInt(3)),
+ checkLocal("b", Value.createInt(8)),
+ checkLocal("c", Value.createInt(6)),
+ stepOver(),
+ checkLine(SOURCE_FILE, 345),
+ checkLocal("a", Value.createInt(3)),
+ checkLocal("b", Value.createInt(8)),
+ checkLocal("c", Value.createInt(11)),
+ run());
+ }
}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTest.java b/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTest.java
new file mode 100644
index 0000000..a586502
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTest.java
@@ -0,0 +1,18 @@
+// Copyright (c) 2017, 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.debuginfo;
+
+public class CodeGeneratorTest {
+
+ public static int intAddition(int a, int b, int c) {
+ a += b;
+ b += c;
+ c = a + b;
+ return c;
+ }
+
+ public static void main(String[] args) {
+ System.out.print(intAddition(1, 2, 6));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTestRunner.java
new file mode 100644
index 0000000..062a4d3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debuginfo/CodeGeneratorTestRunner.java
@@ -0,0 +1,43 @@
+// Copyright (c) 2017, 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.debuginfo;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.code.AddInt;
+import com.android.tools.r8.code.AddInt2Addr;
+import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.code.Return;
+import com.android.tools.r8.utils.AndroidApp;
+import org.junit.Test;
+
+public class CodeGeneratorTestRunner extends DebugInfoTestBase {
+
+ /**
+ * Companion test checking the behavior when attached to a debugger
+ * {@link com.android.tools.r8.debug.LocalsTest#testLocalUsedBy2AddrInstruction}
+ */
+ @Test
+ public void test2AddrInstruction() throws Exception {
+ Class clazz = CodeGeneratorTest.class;
+
+ AndroidApp d8App = compileWithD8(clazz);
+ AndroidApp dxApp = getDxCompiledSources();
+
+ String expected = "11";
+ assertEquals(expected, runOnJava(clazz));
+ assertEquals(expected, runOnArt(d8App, clazz.getCanonicalName()));
+ assertEquals(expected, runOnArt(dxApp, clazz.getCanonicalName()));
+
+ DebugInfoInspector inspector = inspectMethod(d8App, clazz, "int", "intAddition", "int", "int",
+ "int");
+ Instruction[] instructions = inspector.getMethod().getCode().asDexCode().instructions;
+ assertTrue(instructions[0] instanceof AddInt2Addr);
+ assertTrue(instructions[1] instanceof AddInt2Addr);
+ assertTrue(instructions[2] instanceof AddInt);
+ assertTrue(instructions[3] instanceof Return);
+ }
+
+}