CF backend: Fix removeUnneededLoadsAndStores()

When the input classfile contains a local variable ending between a
value moving to the stack (e.g. by GetField) and the value being
consumed (e.g. by CheckCast), removeUnneededLoadsAndStores() must not
remove the local read.

Change-Id: I6ed022556c068e8b5196d926247f0e00f1b13cd5
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index 8dd9162..d945dea 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -231,7 +231,7 @@
             store.outValue().removeUser(load);
             // Remove the store.
             it.previous();
-            it.remove();
+            it.removeOrReplaceByDebugLocalRead();
             // Remove the load.
             it.next();
             it.remove();
diff --git a/src/test/java/com/android/tools/r8/cf/UnneededLoadStoreDebugInfoTest.java b/src/test/java/com/android/tools/r8/cf/UnneededLoadStoreDebugInfoTest.java
new file mode 100644
index 0000000..63f131e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/UnneededLoadStoreDebugInfoTest.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2018, 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.cf;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer;
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.R8;
+import com.android.tools.r8.R8Command;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class UnneededLoadStoreDebugInfoTest extends TestBase {
+
+  private static final String CLASS_NAME = "UnneededLoadStoreDebugInfoTest";
+  private static final String DESCRIPTOR = "L" + CLASS_NAME + ";";
+
+  public static class Dump implements Opcodes {
+
+    public static byte[] dump() {
+      ClassWriter cw = new ClassWriter(0);
+      MethodVisitor mv;
+
+      cw.visit(V1_8, ACC_PUBLIC + ACC_SUPER, CLASS_NAME, null, "java/lang/Object", null);
+
+      {
+        mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+        mv.visitCode();
+        Label argsStart = new Label();
+        mv.visitLabel(argsStart);
+        mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+        Label argsEnd = new Label();
+        mv.visitLabel(argsEnd);
+        mv.visitTypeInsn(CHECKCAST, "java/io/PrintStream");
+        mv.visitInsn(POP);
+        mv.visitInsn(RETURN);
+        mv.visitLocalVariable("args", "[Ljava/lang/String;", null, argsStart, argsEnd, 0);
+        mv.visitMaxs(1, 1);
+        mv.visitEnd();
+      }
+      cw.visitEnd();
+
+      return cw.toByteArray();
+    }
+  }
+
+  @Test
+  public void test() throws Exception {
+    Path inputJar = temp.getRoot().toPath().resolve("input.jar");
+    ArchiveConsumer consumer = new ArchiveConsumer(inputJar);
+    consumer.accept(Dump.dump(), DESCRIPTOR, null);
+    consumer.finished(null);
+    ProcessResult runInput = ToolHelper.runJava(inputJar, CLASS_NAME);
+    assertEquals(0, runInput.exitCode);
+    Path outputJar = temp.getRoot().toPath().resolve("output.jar");
+    R8.run(
+        R8Command.builder()
+            .setMode(CompilationMode.DEBUG)
+            .addProgramFiles(inputJar)
+            .addLibraryFiles(ToolHelper.getAndroidJar(ToolHelper.getMinApiLevelForDexVm()))
+            .setProgramConsumer(new ArchiveConsumer(outputJar))
+            .build());
+    ProcessResult runOutput = ToolHelper.runJava(outputJar, CLASS_NAME);
+    assertEquals(runInput.toString(), runOutput.toString());
+  }
+}