Fix issue with propagating partial values

We would incorrectly not propagate or calculate partial read values
sometimes in the presence of loops. This fixes that issue by correctly
interpreting merged-unknowns as being phis when before escapes and
propagating uses of removed reads when needed.

Test: ./test.py --host
Test: ./art/tools/compile-jar.py --dex2oat `which dex2oatd64`  --profile-line 'HSLcom/android/textclassifier/common/statsd/GenerateLinksLogger;->logGenerateLinks(Ljava/lang/CharSequence;Landroid/view/textclassifier/TextLinks;Ljava/lang/String;JLcom/google/common/base/Optional;Lcom/google/common/base/Optional;)V' --arch arm64 ~/GoogleExtServices.apk -j1  --runtime-arg -verbose:compiler  --dump-stats
Bug: 183554067
Change-Id: I7f6e99934237174922ef2da2b77092e74cfb6a77
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 1ea2ece..c4279c7 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -2833,7 +2833,7 @@
   std::replace_if(
       phi_placeholder_replacements_.begin(),
       phi_placeholder_replacements_.end(),
-      [](const Value& val) { return val.IsPureUnknown(); },
+      [](const Value& val) { return !val.IsDefault() && !val.IsInstruction(); },
       Value::Invalid());
 }
 
@@ -2978,7 +2978,7 @@
       }
 
       ReplaceInput(to_replace);
-      RemoveInput(to_remove);
+      RemoveAndReplaceInputs(to_remove);
       CreateConstructorFences(constructor_fences);
       PredicateInstructions(to_predicate);
 
@@ -3092,7 +3092,7 @@
       }
     }
 
-    void RemoveInput(const ScopedArenaVector<HInstruction*>& to_remove) {
+    void RemoveAndReplaceInputs(const ScopedArenaVector<HInstruction*>& to_remove) {
       for (HInstruction* ins : to_remove) {
         if (ins->GetBlock() == nullptr) {
           // Already dealt with.
@@ -3100,6 +3100,30 @@
         }
         DCHECK(BeforeAllEscapes(ins->GetBlock())) << *ins;
         if (ins->IsInstanceFieldGet() || ins->IsInstanceFieldSet()) {
+          bool instruction_has_users =
+              ins->IsInstanceFieldGet() && (!ins->GetUses().empty() || !ins->GetEnvUses().empty());
+          if (instruction_has_users) {
+            // Make sure any remaining users of read are replaced.
+            HInstruction* replacement =
+                helper_->lse_->GetPartialValueAt(OriginalNewInstance(), ins);
+            // NB ReplaceInput will remove a use from the list so this is
+            // guaranteed to finish eventually.
+            while (!ins->GetUses().empty()) {
+              const HUseListNode<HInstruction*>& use = ins->GetUses().front();
+              use.GetUser()->ReplaceInput(replacement, use.GetIndex());
+            }
+            while (!ins->GetEnvUses().empty()) {
+              const HUseListNode<HEnvironment*>& use = ins->GetEnvUses().front();
+              use.GetUser()->ReplaceInput(replacement, use.GetIndex());
+            }
+          } else {
+            DCHECK(ins->GetUses().empty())
+                << "Instruction has users!\n"
+                << ins->DumpWithArgs() << "\nUsers are " << ins->GetUses();
+            DCHECK(ins->GetEnvUses().empty())
+                << "Instruction has users!\n"
+                << ins->DumpWithArgs() << "\nUsers are " << ins->GetEnvUses();
+          }
           ins->GetBlock()->RemoveInstruction(ins);
         } else {
           // Can only be obj == other, obj != other, obj == obj (!?) or, obj != obj (!?)
@@ -3554,9 +3578,8 @@
     info = field_infos_[loc_off];
     DCHECK(loc->GetIndex() == nullptr);
     Value value = ReplacementOrValue(heap_values_for_[old_pred->GetBlockId()][loc_off].value);
-    if (value.NeedsLoopPhi()) {
+    if (value.NeedsLoopPhi() || value.IsMergedUnknown()) {
       Value repl = phi_placeholder_replacements_[PhiPlaceholderIndex(value.GetPhiPlaceholder())];
-      DCHECK(!repl.IsUnknown());
       DCHECK(repl.IsDefault() || repl.IsInvalid() || repl.IsInstruction())
           << repl << " from " << value << " pred is " << old_pred->GetBlockId();
       if (!repl.IsInvalid()) {