Rewrite unused static-get instructions in dead code remover

Change-Id: Idd812693d188d7ee68d3d4e7d9473c51d61a2beb
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
index 1a401f7..b533145 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -790,18 +790,26 @@
   public Instruction getConstantReturn(
       AppView<AppInfoWithLiveness> appView,
       IRCode code,
-      ProgramMethod method,
       Position position,
       TypeAndLocalInfoSupplier info) {
     assert rewrittenReturnInfo != null;
     assert rewrittenReturnInfo.hasSingleValue();
-    assert rewrittenReturnInfo.getSingleValue().isMaterializableInContext(appView, method);
     Instruction instruction =
         rewrittenReturnInfo.getSingleValue().createMaterializingInstruction(appView, code, info);
     instruction.setPosition(position);
     return instruction;
   }
 
+  public boolean verifyConstantReturnAccessibleInContext(
+      AppView<AppInfoWithLiveness> appView, ProgramMethod method, GraphLens codeLens) {
+    SingleValue rewrittenSingleValue =
+        rewrittenReturnInfo
+            .getSingleValue()
+            .rewrittenWithLens(appView, appView.graphLens(), codeLens);
+    assert rewrittenSingleValue.isMaterializableInContext(appView, method);
+    return true;
+  }
+
   public DexMethod rewriteMethod(ProgramMethod method, DexItemFactory dexItemFactory) {
     if (isEmpty()) {
       return method.getReference();
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
index 2ad1f65..e1ed280 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
@@ -34,6 +34,7 @@
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Set;
+import java.util.function.Consumer;
 
 public class BasicBlockInstructionListIterator implements InstructionListIterator {
 
@@ -350,8 +351,11 @@
   }
 
   @Override
-  public boolean replaceCurrentInstructionByInitClassIfPossible(
-      AppView<AppInfoWithLiveness> appView, IRCode code, DexType type) {
+  public boolean removeOrReplaceCurrentInstructionByInitClassIfPossible(
+      AppView<AppInfoWithLiveness> appView,
+      IRCode code,
+      DexType type,
+      Consumer<InitClass> consumer) {
     Instruction toBeReplaced = current;
     assert toBeReplaced != null;
     assert toBeReplaced.isStaticFieldInstruction() || toBeReplaced.isInvokeStatic();
@@ -377,7 +381,9 @@
     DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(type));
     if (clazz != null) {
       Value dest = code.createValue(TypeElement.getInt());
-      replaceCurrentInstruction(new InitClass(dest, clazz.type));
+      InitClass initClass = new InitClass(dest, clazz.type);
+      replaceCurrentInstruction(initClass);
+      consumer.accept(initClass);
     }
     return true;
   }
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
index a68da1a..21b9df5 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
@@ -19,6 +19,7 @@
 import java.util.ListIterator;
 import java.util.NoSuchElementException;
 import java.util.Set;
+import java.util.function.Consumer;
 
 public class IRCodeInstructionListIterator implements InstructionListIterator {
 
@@ -62,9 +63,13 @@
   }
 
   @Override
-  public boolean replaceCurrentInstructionByInitClassIfPossible(
-      AppView<AppInfoWithLiveness> appView, IRCode code, DexType type) {
-    return instructionIterator.replaceCurrentInstructionByInitClassIfPossible(appView, code, type);
+  public boolean removeOrReplaceCurrentInstructionByInitClassIfPossible(
+      AppView<AppInfoWithLiveness> appView,
+      IRCode code,
+      DexType type,
+      Consumer<InitClass> consumer) {
+    return instructionIterator.removeOrReplaceCurrentInstructionByInitClassIfPossible(
+        appView, code, type, consumer);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
index bc6bec6..f1eab89 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
@@ -15,10 +15,12 @@
 import com.android.tools.r8.graph.ProgramMethod;
 import com.android.tools.r8.ir.analysis.type.TypeElement;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.ConsumerUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.google.common.collect.Sets;
 import java.util.ListIterator;
 import java.util.Set;
+import java.util.function.Consumer;
 
 public interface InstructionListIterator
     extends InstructionIterator, ListIterator<Instruction>, PreviousUntilIterator<Instruction> {
@@ -109,8 +111,17 @@
 
   boolean replaceCurrentInstructionByNullCheckIfPossible(AppView<?> appView, ProgramMethod context);
 
-  boolean replaceCurrentInstructionByInitClassIfPossible(
-      AppView<AppInfoWithLiveness> appView, IRCode code, DexType type);
+  default boolean removeOrReplaceCurrentInstructionByInitClassIfPossible(
+      AppView<AppInfoWithLiveness> appView, IRCode code, DexType type) {
+    return removeOrReplaceCurrentInstructionByInitClassIfPossible(
+        appView, code, type, ConsumerUtils.emptyConsumer());
+  }
+
+  boolean removeOrReplaceCurrentInstructionByInitClassIfPossible(
+      AppView<AppInfoWithLiveness> appView,
+      IRCode code,
+      DexType type,
+      Consumer<InitClass> consumer);
 
   void replaceCurrentInstructionWithConstClass(
       AppView<?> appView, IRCode code, DexType type, DebugLocalInfo localInfo);
diff --git a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
index 37d45df..ffb5d2b 100644
--- a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
@@ -18,6 +18,7 @@
 import com.google.common.collect.Sets;
 import java.util.ListIterator;
 import java.util.Set;
+import java.util.function.Consumer;
 
 public class LinearFlowInstructionListIterator implements InstructionListIterator {
 
@@ -86,9 +87,13 @@
   }
 
   @Override
-  public boolean replaceCurrentInstructionByInitClassIfPossible(
-      AppView<AppInfoWithLiveness> appView, IRCode code, DexType type) {
-    return currentBlockIterator.replaceCurrentInstructionByInitClassIfPossible(appView, code, type);
+  public boolean removeOrReplaceCurrentInstructionByInitClassIfPossible(
+      AppView<AppInfoWithLiveness> appView,
+      IRCode code,
+      DexType type,
+      Consumer<InitClass> consumer) {
+    return currentBlockIterator.removeOrReplaceCurrentInstructionByInitClassIfPossible(
+        appView, code, type, consumer);
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index b1292dc..a52190d 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -401,11 +401,12 @@
                               .toTypeElement(appView);
                         }
                       };
+                  prototypeChanges.verifyConstantReturnAccessibleInContext(
+                      appView.withLiveness(), method, graphLens);
                   constantReturnMaterializingInstruction =
                       prototypeChanges.getConstantReturn(
                           appView.withLiveness(),
                           code,
-                          method,
                           invoke.getPosition(),
                           typeAndLocalInfo);
                   if (invoke.outValue().hasLocalInfo()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
index 04ba47d..5dbfaba 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DeadCodeRemover.java
@@ -14,11 +14,13 @@
 import com.android.tools.r8.ir.code.CatchHandlers.CatchHandler;
 import com.android.tools.r8.ir.code.CheckCast;
 import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.InitClass;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.Phi;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Iterators;
@@ -134,6 +136,23 @@
         if (current.isInvoke() && !current.outValue().isUsed()) {
           current.setOutValue(null);
         }
+        if (current.isStaticGet() && !current.outValue().isUsed() && appView.hasLiveness()) {
+          Box<InitClass> initClass = new Box<>();
+          if (iterator.removeOrReplaceCurrentInstructionByInitClassIfPossible(
+              appView.withLiveness(),
+              code,
+              current.asStaticGet().getField().getHolderType(),
+              initClass::set)) {
+            if (initClass.isSet()) {
+              // Apply dead code remover to the new init-class instruction.
+              current = iterator.previous();
+              assert current == initClass.get();
+            } else {
+              // Instruction removed.
+              continue;
+            }
+          }
+        }
       }
       DeadInstructionResult deadInstructionResult = current.canBeDeadCode(appView, code);
       if (deadInstructionResult.isNotDead()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 2c185bf..785c461 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -1099,7 +1099,7 @@
         return false;
       }
     } else if (invoke.isInvokeStatic()) {
-      if (!iterator.replaceCurrentInstructionByInitClassIfPossible(
+      if (!iterator.removeOrReplaceCurrentInstructionByInitClassIfPossible(
           appView, code, resolvedMethod.getHolderType())) {
         return false;
       }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 755f334..4807cda 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -246,7 +246,7 @@
         iterator.replaceCurrentInstructionByNullCheckIfPossible(appView, code.context());
       } else if (current.isStaticGet()) {
         StaticGet staticGet = current.asStaticGet();
-        iterator.replaceCurrentInstructionByInitClassIfPossible(
+        iterator.removeOrReplaceCurrentInstructionByInitClassIfPossible(
             appView, code, staticGet.getField().holder);
       }
       replacement.setPosition(position);
@@ -333,7 +333,7 @@
         if (invoke.isInvokeMethodWithReceiver()) {
           iterator.replaceCurrentInstructionByNullCheckIfPossible(appView, context);
         } else if (invoke.isInvokeStatic() && singleTarget != null) {
-          iterator.replaceCurrentInstructionByInitClassIfPossible(
+          iterator.removeOrReplaceCurrentInstructionByInitClassIfPossible(
               appView, code, singleTarget.getHolderType());
         }
 
@@ -440,7 +440,7 @@
           iterator.replaceCurrentInstructionByNullCheckIfPossible(appView, context);
         } else {
           assert current.isStaticGet();
-          iterator.replaceCurrentInstructionByInitClassIfPossible(
+          iterator.removeOrReplaceCurrentInstructionByInitClassIfPossible(
               appView, code, target.getHolderType());
         }
 
@@ -491,7 +491,8 @@
       return;
     }
 
-    iterator.replaceCurrentInstructionByInitClassIfPossible(appView, code, field.getHolderType());
+    iterator.removeOrReplaceCurrentInstructionByInitClassIfPossible(
+        appView, code, field.getHolderType());
   }
 
   /**
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
index 5987d3c..15f68fc 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
@@ -183,8 +183,7 @@
         Lists.newArrayList(
             "STATIC: String SimpleWithSideEffects.bar(String)",
             "STATIC: String SimpleWithSideEffects.foo()",
-            "STATIC: String TrivialTestClass.next()",
-            "SimpleWithSideEffects SimpleWithSideEffects.INSTANCE"),
+            "STATIC: String TrivialTestClass.next()"),
         references(clazz, "testSimpleWithSideEffects", "void"));
 
     ClassSubject simpleWithSideEffects = inspector.clazz(SimpleWithSideEffects.class);
@@ -315,8 +314,7 @@
         Lists.newArrayList(
             "STATIC: String movetohost.CandidateOkSideEffects.bar(String)",
             "STATIC: String movetohost.CandidateOkSideEffects.foo()",
-            "STATIC: String movetohost.MoveToHostTestClass.next()",
-            "movetohost.CandidateOkSideEffects movetohost.HostOkSideEffects.INSTANCE"),
+            "STATIC: String movetohost.MoveToHostTestClass.next()"),
         references(clazz, "testOkSideEffects", "void"));
 
     assertThat(inspector.clazz(HostOkSideEffects.class), isPresent());
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
index b05928d..24f1672 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.BasicBlockIterator;
 import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.InitClass;
 import com.android.tools.r8.ir.code.Instruction;
 import com.android.tools.r8.ir.code.InstructionListIterator;
 import com.android.tools.r8.ir.code.InvokeMethod;
@@ -34,6 +35,7 @@
 import java.util.List;
 import java.util.ListIterator;
 import java.util.Set;
+import java.util.function.Consumer;
 import org.junit.Test;
 
 public class RegisterMoveSchedulerTest {
@@ -84,8 +86,11 @@
     }
 
     @Override
-    public boolean replaceCurrentInstructionByInitClassIfPossible(
-        AppView<AppInfoWithLiveness> appView, IRCode code, DexType type) {
+    public boolean removeOrReplaceCurrentInstructionByInitClassIfPossible(
+        AppView<AppInfoWithLiveness> appView,
+        IRCode code,
+        DexType type,
+        Consumer<InitClass> consumer) {
       throw new Unimplemented();
     }