Propagate type information in member value propagation and field load elimination

Change-Id: I81d8475ccc75f5086e9a62d7429e934bd48a1953
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 4ea2cf4..c8bd65d 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
@@ -222,7 +222,7 @@
       setValueRangeFromProguardRule(lookup.rule, current.outValue());
       return false;
     }
-    affectedValues.add(replacement.outValue());
+    affectedValues.addAll(current.outValue().affectedValues());
     if (lookup.type == RuleType.ASSUME_NO_SIDE_EFFECTS) {
       iterator.replaceCurrentInstruction(replacement);
     } else {
@@ -309,7 +309,7 @@
                 code, constant, current.outValue().getTypeLattice(), current.getLocalInfo());
       }
 
-      affectedValues.add(replacement.outValue());
+      affectedValues.addAll(current.outValue().affectedValues());
       current.outValue().replaceUsers(replacement.outValue());
       current.setOutValue(null);
       replacement.setPosition(current.getPosition());
@@ -366,7 +366,7 @@
     if (!appView.appInfo().isPinned(target.field)) {
       ConstInstruction replacement = target.valueAsConstInstruction(code, current.dest(), appView);
       if (replacement != null) {
-        affectedValues.add(replacement.outValue());
+        affectedValues.addAll(current.outValue().affectedValues());
         iterator.replaceCurrentInstruction(replacement);
         if (replacement.isDexItemBasedConstString()) {
           code.method.getMutableOptimizationInfo().markUseIdentifierNameString();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
index b50496e..5e73129 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexEncodedField;
 import com.android.tools.r8.graph.DexEncodedMethod;
 import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
 import com.android.tools.r8.ir.code.BasicBlock;
 import com.android.tools.r8.ir.code.DominatorTree;
 import com.android.tools.r8.ir.code.FieldInstruction;
@@ -20,11 +21,13 @@
 import com.android.tools.r8.ir.code.StaticGet;
 import com.android.tools.r8.ir.code.StaticPut;
 import com.android.tools.r8.ir.code.Value;
+import com.google.common.collect.Sets;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.Set;
 
 /**
  * Eliminate redundant field loads.
@@ -40,6 +43,9 @@
   private final IRCode code;
   private final DominatorTree dominatorTree;
 
+  // Values that may require type propagation.
+  private final Set<Value> affectedValues = Sets.newIdentityHashSet();
+
   // Maps keeping track of fields that have an already loaded value at basic block entry.
   private final Map<BasicBlock, Map<FieldAndObject, FieldInstruction>> activeInstanceFieldsAtEntry =
       new IdentityHashMap<>();
@@ -163,6 +169,9 @@
       }
       propagateActiveFieldsFrom(block);
     }
+    if (!affectedValues.isEmpty()) {
+      new TypeAnalysis(appView).narrowing(affectedValues);
+    }
     assert code.isConsistentSSA();
   }
 
@@ -238,7 +247,8 @@
 
   private void eliminateRedundantRead(
       InstructionListIterator it, FieldInstruction redundant, FieldInstruction active) {
-    redundant.outValue().replaceUsers(active.value());
+    affectedValues.addAll(redundant.value().affectedValues());
+    redundant.value().replaceUsers(active.value());
     it.removeOrReplaceByDebugLocalRead();
     active.value().uniquePhiUsers().forEach(Phi::removeTrivialPhi);
   }