Reland: 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: I5c9c3e6abdc817aba3f469a395bdde9b72d76b6d
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 e87b29b..348fd02 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 205ae64..71f2a66 100644 --- a/src/test/debugTestResources/Locals.java +++ b/src/test/debugTestResources/Locals.java
@@ -346,6 +346,13 @@ return c + d; } + 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(); @@ -369,5 +376,6 @@ System.out.println(localConstant(true)); System.out.println(localConstantBis(true)); System.out.println(localTriggeringCSE()); + 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 177efbe..c86581f 100644 --- a/src/test/java/com/android/tools/r8/debug/LocalsTest.java +++ b/src/test/java/com/android/tools/r8/debug/LocalsTest.java
@@ -648,4 +648,37 @@ checkLocal("d", Value.createInt(5)), 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, 350), + checkLocal("a", Value.createInt(1)), + checkLocal("b", Value.createInt(2)), + checkLocal("c", Value.createInt(6)), + stepOver(), + checkLine(SOURCE_FILE, 351), + checkLocal("a", Value.createInt(3)), + checkLocal("b", Value.createInt(2)), + checkLocal("c", Value.createInt(6)), + stepOver(), + checkLine(SOURCE_FILE, 352), + checkLocal("a", Value.createInt(3)), + checkLocal("b", Value.createInt(8)), + checkLocal("c", Value.createInt(6)), + stepOver(), + checkLine(SOURCE_FILE, 353), + 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); + } + +}