Revert^2 "Partial Load Store Elimination"

This reverts commit 47ac53100303e7e864b7f6d65f17b23088ccf1d6.

There was a bug in LSE where we would incorrectly record the
shadow$_monitor_ field as not having a default initial value. This
caused partial LSE to be unable to compile the Object.identityHashCode
function, causing crashes. This issue was fixed in a parent CL. Also
updated all Offsets in LSE_test to be outside of the object header
regardless of configuration.

Test: ./test.py --host
Bug: 67037140

Reason for revert: Fixed issue with shadow$_monitor_ field and offsets

Change-Id: I4fb2afff4d410da818db38ed833927dfc0f6be33
diff --git a/compiler/optimizing/load_store_elimination_test.cc b/compiler/optimizing/load_store_elimination_test.cc
index 9904192..9b000a1 100644
--- a/compiler/optimizing/load_store_elimination_test.cc
+++ b/compiler/optimizing/load_store_elimination_test.cc
@@ -14,38 +14,99 @@
  * limitations under the License.
  */
 
-#include <tuple>
+#include "load_store_elimination.h"
 
+#include <initializer_list>
+#include <memory>
+#include <tuple>
+#include <variant>
+
+#include "base/iteration_range.h"
 #include "compilation_kind.h"
+#include "dex/dex_file_types.h"
+#include "entrypoints/quick/quick_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
 #include "gtest/gtest.h"
 #include "handle_scope.h"
 #include "load_store_analysis.h"
-#include "load_store_elimination.h"
 #include "nodes.h"
+#include "optimizing/data_type.h"
+#include "optimizing/instruction_simplifier.h"
+#include "optimizing/optimizing_compiler_stats.h"
 #include "optimizing_unit_test.h"
-
-#include "gtest/gtest.h"
+#include "scoped_thread_state_change.h"
 
 namespace art {
 
-class LoadStoreEliminationTest : public OptimizingUnitTest {
+struct InstructionDumper {
  public:
-  AdjacencyListGraph SetupFromAdjacencyList(
-      const std::string_view entry_name,
-      const std::string_view exit_name,
-      const std::vector<AdjacencyListGraph::Edge>& adj) {
+  HInstruction* ins_;
+};
+
+bool operator==(const InstructionDumper& a, const InstructionDumper& b) {
+  return a.ins_ == b.ins_;
+}
+bool operator!=(const InstructionDumper& a, const InstructionDumper& b) {
+  return !(a == b);
+}
+
+std::ostream& operator<<(std::ostream& os, const InstructionDumper& id) {
+  if (id.ins_ == nullptr) {
+    return os << "NULL";
+  } else {
+    return os << "(" << id.ins_ << "): " << id.ins_->DumpWithArgs();
+  }
+}
+
+#define CHECK_SUBROUTINE_FAILURE() \
+  do {                             \
+    if (HasFatalFailure()) {       \
+      return;                      \
+    }                              \
+  } while (false)
+
+#define EXPECT_INS_EQ(a, b) EXPECT_EQ(InstructionDumper{a}, InstructionDumper{b})
+#define EXPECT_INS_REMOVED(a) EXPECT_TRUE(IsRemoved(a)) << "Not removed: " << (InstructionDumper{a})
+#define EXPECT_INS_RETAINED(a) EXPECT_FALSE(IsRemoved(a)) << "Removed: " << (InstructionDumper{a})
+#define ASSERT_INS_EQ(a, b) ASSERT_EQ(InstructionDumper{a}, InstructionDumper{b})
+#define ASSERT_INS_REMOVED(a) ASSERT_TRUE(IsRemoved(a)) << "Not removed: " << (InstructionDumper{a})
+#define ASSERT_INS_RETAINED(a) ASSERT_FALSE(IsRemoved(a)) << "Removed: " << (InstructionDumper{a})
+
+template <typename SuperTest>
+class LoadStoreEliminationTestBase : public SuperTest, public OptimizingUnitTestHelper {
+ public:
+  void SetUp() override {
+    SuperTest::SetUp();
+    gLogVerbosity.compiler = true;
+  }
+
+  void TearDown() override {
+    SuperTest::TearDown();
+    gLogVerbosity.compiler = false;
+  }
+
+  AdjacencyListGraph SetupFromAdjacencyList(const std::string_view entry_name,
+                                            const std::string_view exit_name,
+                                            const std::vector<AdjacencyListGraph::Edge>& adj) {
     return AdjacencyListGraph(graph_, GetAllocator(), entry_name, exit_name, adj);
   }
 
-  void PerformLSE() {
+  void PerformLSE(bool with_partial = true) {
     graph_->BuildDominatorTree();
-    LoadStoreElimination lse(graph_, /*stats=*/ nullptr);
-    lse.Run();
+    LoadStoreElimination lse(graph_, /*stats=*/nullptr);
+    lse.Run(with_partial);
     std::ostringstream oss;
     EXPECT_TRUE(CheckGraphSkipRefTypeInfoChecks(oss)) << oss.str();
   }
 
+  void PerformLSEWithPartial() {
+    PerformLSE(true);
+  }
+
+  void PerformLSENoPartial() {
+    PerformLSE(false);
+  }
+
   // Create instructions shared among tests.
   void CreateEntryBlockInstructions() {
     HInstruction* c1 = graph_->GetIntConstant(1);
@@ -108,9 +169,7 @@
   }
 
   void CreateEnvForSuspendCheck() {
-    ArenaVector<HInstruction*> current_locals({array_, i_, j_},
-                                              GetAllocator()->Adapter(kArenaAllocInstruction));
-    ManuallyBuildEnvFor(suspend_check_, &current_locals);
+    ManuallyBuildEnvFor(suspend_check_, {array_, i_, j_});
   }
 
   // Create the diamond-shaped CFG:
@@ -153,15 +212,15 @@
     DCHECK(block != nullptr);
     DCHECK(array != nullptr);
     DCHECK(index != nullptr);
-    HInstruction* vload = new (GetAllocator()) HVecLoad(
-        GetAllocator(),
-        array,
-        index,
-        DataType::Type::kInt32,
-        SideEffects::ArrayReadOfType(DataType::Type::kInt32),
-        4,
-        /*is_string_char_at*/ false,
-        kNoDexPc);
+    HInstruction* vload =
+        new (GetAllocator()) HVecLoad(GetAllocator(),
+                                      array,
+                                      index,
+                                      DataType::Type::kInt32,
+                                      SideEffects::ArrayReadOfType(DataType::Type::kInt32),
+                                      4,
+                                      /*is_string_char_at*/ false,
+                                      kNoDexPc);
     block->InsertInstructionBefore(vload, block->GetLastInstruction());
     return vload;
   }
@@ -179,22 +238,19 @@
     DCHECK(index != nullptr);
     if (vdata == nullptr) {
       HInstruction* c1 = graph_->GetIntConstant(1);
-      vdata = new (GetAllocator()) HVecReplicateScalar(GetAllocator(),
-                                                       c1,
-                                                       DataType::Type::kInt32,
-                                                       4,
-                                                       kNoDexPc);
+      vdata = new (GetAllocator())
+          HVecReplicateScalar(GetAllocator(), c1, DataType::Type::kInt32, 4, kNoDexPc);
       block->InsertInstructionBefore(vdata, block->GetLastInstruction());
     }
-    HInstruction* vstore = new (GetAllocator()) HVecStore(
-        GetAllocator(),
-        array,
-        index,
-        vdata,
-        DataType::Type::kInt32,
-        SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
-        4,
-        kNoDexPc);
+    HInstruction* vstore =
+        new (GetAllocator()) HVecStore(GetAllocator(),
+                                       array,
+                                       index,
+                                       vdata,
+                                       DataType::Type::kInt32,
+                                       SideEffects::ArrayWriteOfType(DataType::Type::kInt32),
+                                       4,
+                                       kNoDexPc);
     block->InsertInstructionBefore(vstore, block->GetLastInstruction());
     return vstore;
   }
@@ -225,34 +281,153 @@
     if (data == nullptr) {
       data = graph_->GetIntConstant(1);
     }
-    HInstruction* store = new (GetAllocator()) HArraySet(array,
-                                                         index,
-                                                         data,
-                                                         DataType::Type::kInt32,
-                                                         0);
+    HInstruction* store =
+        new (GetAllocator()) HArraySet(array, index, data, DataType::Type::kInt32, 0);
     block->InsertInstructionBefore(store, block->GetLastInstruction());
     return store;
   }
 
   void InitGraphAndParameters() {
     InitGraph();
-    AddParameter(new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
-                                                      dex::TypeIndex(0),
-                                                      0,
-                                                      DataType::Type::kInt32));
+    AddParameter(new (GetAllocator()) HParameterValue(
+        graph_->GetDexFile(), dex::TypeIndex(0), 0, DataType::Type::kInt32));
     array_ = parameters_.back();
-    AddParameter(new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
-                                                      dex::TypeIndex(1),
-                                                      1,
-                                                      DataType::Type::kInt32));
+    AddParameter(new (GetAllocator()) HParameterValue(
+        graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kInt32));
     i_ = parameters_.back();
-    AddParameter(new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
-                                                      dex::TypeIndex(1),
-                                                      2,
-                                                      DataType::Type::kInt32));
+    AddParameter(new (GetAllocator()) HParameterValue(
+        graph_->GetDexFile(), dex::TypeIndex(1), 2, DataType::Type::kInt32));
     j_ = parameters_.back();
   }
 
+  void ManuallyBuildEnvFor(HInstruction* ins, const std::initializer_list<HInstruction*>& env) {
+    ArenaVector<HInstruction*> current_locals(env, GetAllocator()->Adapter(kArenaAllocInstruction));
+    OptimizingUnitTestHelper::ManuallyBuildEnvFor(ins, &current_locals);
+  }
+
+  HLoadClass* MakeClassLoad(std::optional<dex::TypeIndex> ti = std::nullopt) {
+    return new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
+                                           ti ? *ti : dex::TypeIndex(class_idx_++),
+                                           graph_->GetDexFile(),
+                                           /* klass= */ null_klass_,
+                                           /* is_referrers_class= */ false,
+                                           /* dex_pc= */ 0,
+                                           /* needs_access_check= */ false);
+  }
+
+  HNewInstance* MakeNewInstance(HInstruction* cls, uint32_t dex_pc = 0u) {
+    EXPECT_TRUE(cls->IsLoadClass() || cls->IsClinitCheck()) << *cls;
+    HLoadClass* load =
+        cls->IsLoadClass() ? cls->AsLoadClass() : cls->AsClinitCheck()->GetLoadClass();
+    return new (GetAllocator()) HNewInstance(cls,
+                                             dex_pc,
+                                             load->GetTypeIndex(),
+                                             graph_->GetDexFile(),
+                                             /* finalizable= */ false,
+                                             QuickEntrypointEnum::kQuickAllocObjectInitialized);
+  }
+
+  HInstanceFieldSet* MakeIFieldSet(HInstruction* inst,
+                                   HInstruction* data,
+                                   MemberOffset off,
+                                   uint32_t dex_pc = 0u) {
+    return new (GetAllocator()) HInstanceFieldSet(inst,
+                                                  data,
+                                                  /* field= */ nullptr,
+                                                  /* field_type= */ data->GetType(),
+                                                  /* field_offset= */ off,
+                                                  /* is_volatile= */ false,
+                                                  /* field_idx= */ 0,
+                                                  /* declaring_class_def_index= */ 0,
+                                                  graph_->GetDexFile(),
+                                                  dex_pc);
+  }
+
+  HInstanceFieldGet* MakeIFieldGet(HInstruction* inst,
+                                   DataType::Type type,
+                                   MemberOffset off,
+                                   uint32_t dex_pc = 0u) {
+    return new (GetAllocator()) HInstanceFieldGet(inst,
+                                                  /* field= */ nullptr,
+                                                  /* field_type= */ type,
+                                                  /* field_offset= */ off,
+                                                  /* is_volatile= */ false,
+                                                  /* field_idx= */ 0,
+                                                  /* declaring_class_def_index= */ 0,
+                                                  graph_->GetDexFile(),
+                                                  dex_pc);
+  }
+
+  HInvokeStaticOrDirect* MakeInvoke(DataType::Type return_type,
+                                    const std::vector<HInstruction*>& args) {
+    MethodReference method_reference{/* file= */ &graph_->GetDexFile(), /* index= */ method_idx_++};
+    HInvokeStaticOrDirect* res = new (GetAllocator())
+        HInvokeStaticOrDirect(GetAllocator(),
+                              args.size(),
+                              return_type,
+                              /* dex_pc= */ 0,
+                              method_reference,
+                              /* resolved_method= */ nullptr,
+                              HInvokeStaticOrDirect::DispatchInfo{},
+                              InvokeType::kStatic,
+                              /* resolved_method_reference= */ method_reference,
+                              HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+    for (auto [ins, idx] : ZipCount(MakeIterationRange(args))) {
+      res->SetRawInputAt(idx, ins);
+    }
+    return res;
+  }
+
+  HPhi* MakePhi(const std::vector<HInstruction*>& ins) {
+    EXPECT_GE(ins.size(), 2u) << "Phi requires at least 2 inputs";
+    HPhi* phi =
+        new (GetAllocator()) HPhi(GetAllocator(), kNoRegNumber, ins.size(), ins[0]->GetType());
+    for (auto [i, idx] : ZipCount(MakeIterationRange(ins))) {
+      phi->SetRawInputAt(idx, i);
+    }
+    return phi;
+  }
+
+  void SetupExit(HBasicBlock* exit) {
+    exit->AddInstruction(new (GetAllocator()) HExit());
+  }
+
+  dex::TypeIndex DefaultTypeIndexForType(DataType::Type type) {
+    switch (type) {
+      case DataType::Type::kBool:
+        return dex::TypeIndex(1);
+      case DataType::Type::kUint8:
+      case DataType::Type::kInt8:
+        return dex::TypeIndex(2);
+      case DataType::Type::kUint16:
+      case DataType::Type::kInt16:
+        return dex::TypeIndex(3);
+      case DataType::Type::kUint32:
+      case DataType::Type::kInt32:
+        return dex::TypeIndex(4);
+      case DataType::Type::kUint64:
+      case DataType::Type::kInt64:
+        return dex::TypeIndex(5);
+      case DataType::Type::kReference:
+        return dex::TypeIndex(6);
+      case DataType::Type::kFloat32:
+        return dex::TypeIndex(7);
+      case DataType::Type::kFloat64:
+        return dex::TypeIndex(8);
+      case DataType::Type::kVoid:
+        EXPECT_TRUE(false) << "No type for void!";
+        return dex::TypeIndex(1000);
+    }
+  }
+
+  // Creates a parameter. The instruction is automatically added to the entry-block
+  HParameterValue* MakeParam(DataType::Type type, std::optional<dex::TypeIndex> ti = std::nullopt) {
+    HParameterValue* val = new (GetAllocator()) HParameterValue(
+        graph_->GetDexFile(), ti ? *ti : DefaultTypeIndexForType(type), param_count_++, type);
+    graph_->GetEntryBlock()->AddInstruction(val);
+    return val;
+  }
+
   HBasicBlock* pre_header_;
   HBasicBlock* loop_;
 
@@ -264,6 +439,208 @@
   HInstruction* suspend_check_;
 
   HPhi* phi_;
+
+  size_t param_count_ = 0;
+  size_t class_idx_ = 42;
+  uint32_t method_idx_ = 100;
+
+  ScopedNullHandle<mirror::Class> null_klass_;
+};
+
+class LoadStoreEliminationTest : public LoadStoreEliminationTestBase<CommonCompilerTest> {};
+
+enum class TestOrder { kSameAsAlloc, kReverseOfAlloc };
+std::ostream& operator<<(std::ostream& os, const TestOrder& ord) {
+  switch (ord) {
+    case TestOrder::kSameAsAlloc:
+      return os << "SameAsAlloc";
+    case TestOrder::kReverseOfAlloc:
+      return os << "ReverseOfAlloc";
+  }
+}
+
+class OrderDependentTestGroup
+    : public LoadStoreEliminationTestBase<CommonCompilerTestWithParam<TestOrder>> {};
+
+// Various configs we can use for testing. Currently used in PartialComparison tests.
+struct PartialComparisonKind {
+ public:
+  enum class Type : uint8_t { kEquals, kNotEquals };
+  enum class Target : uint8_t { kNull, kValue, kSelf };
+  enum class Position : uint8_t { kLeft, kRight };
+
+  const Type type_;
+  const Target target_;
+  const Position position_;
+
+  bool IsDefinitelyFalse() const {
+    return !IsPossiblyTrue();
+  }
+  bool IsPossiblyFalse() const {
+    return !IsDefinitelyTrue();
+  }
+  bool IsDefinitelyTrue() const {
+    if (target_ == Target::kSelf) {
+      return type_ == Type::kEquals;
+    } else if (target_ == Target::kNull) {
+      return type_ == Type::kNotEquals;
+    } else {
+      return false;
+    }
+  }
+  bool IsPossiblyTrue() const {
+    if (target_ == Target::kSelf) {
+      return type_ == Type::kEquals;
+    } else if (target_ == Target::kNull) {
+      return type_ == Type::kNotEquals;
+    } else {
+      return true;
+    }
+  }
+  std::ostream& Dump(std::ostream& os) const {
+    os << "PartialComparisonKind{" << (type_ == Type::kEquals ? "kEquals" : "kNotEquals") << ", "
+       << (target_ == Target::kNull ? "kNull" : (target_ == Target::kSelf ? "kSelf" : "kValue"))
+       << ", " << (position_ == Position::kLeft ? "kLeft" : "kRight") << "}";
+    return os;
+  }
+};
+
+std::ostream& operator<<(std::ostream& os, const PartialComparisonKind& comp) {
+  return comp.Dump(os);
+}
+
+class PartialComparisonTestGroup
+    : public LoadStoreEliminationTestBase<CommonCompilerTestWithParam<PartialComparisonKind>> {
+ public:
+  enum class ComparisonPlacement {
+    kBeforeEscape,
+    kInEscape,
+    kAfterEscape,
+  };
+  void CheckFinalInstruction(HInstruction* ins, ComparisonPlacement placement) {
+    using Target = PartialComparisonKind::Target;
+    using Type = PartialComparisonKind::Type;
+    using Position = PartialComparisonKind::Position;
+    PartialComparisonKind kind = GetParam();
+    if (ins->IsIntConstant()) {
+      if (kind.IsDefinitelyTrue()) {
+        EXPECT_TRUE(ins->AsIntConstant()->IsTrue()) << kind << " " << *ins;
+      } else if (kind.IsDefinitelyFalse()) {
+        EXPECT_TRUE(ins->AsIntConstant()->IsFalse()) << kind << " " << *ins;
+      } else {
+        EXPECT_EQ(placement, ComparisonPlacement::kBeforeEscape);
+        EXPECT_EQ(kind.target_, Target::kValue);
+        // We are before escape so value is not the object
+        if (kind.type_ == Type::kEquals) {
+          EXPECT_TRUE(ins->AsIntConstant()->IsFalse()) << kind << " " << *ins;
+        } else {
+          EXPECT_TRUE(ins->AsIntConstant()->IsTrue()) << kind << " " << *ins;
+        }
+      }
+      return;
+    }
+    EXPECT_NE(placement, ComparisonPlacement::kBeforeEscape)
+        << "For comparisons before escape we should always be able to transform into a constant."
+        << " Instead we got:" << std::endl << ins->DumpWithArgs();
+    if (placement == ComparisonPlacement::kInEscape) {
+      // Should be the same type.
+      ASSERT_TRUE(ins->IsEqual() || ins->IsNotEqual()) << *ins;
+      HInstruction* other = kind.position_ == Position::kLeft ? ins->AsBinaryOperation()->GetRight()
+                                                              : ins->AsBinaryOperation()->GetLeft();
+      if (kind.target_ == Target::kSelf) {
+        EXPECT_INS_EQ(ins->AsBinaryOperation()->GetLeft(), ins->AsBinaryOperation()->GetRight())
+            << " ins is: " << *ins;
+      } else if (kind.target_ == Target::kNull) {
+        EXPECT_INS_EQ(other, graph_->GetNullConstant()) << " ins is: " << *ins;
+      } else {
+        EXPECT_TRUE(other->IsStaticFieldGet()) << " ins is: " << *ins;
+      }
+      if (kind.type_ == Type::kEquals) {
+        EXPECT_TRUE(ins->IsEqual()) << *ins;
+      } else {
+        EXPECT_TRUE(ins->IsNotEqual()) << *ins;
+      }
+    } else {
+      ASSERT_EQ(placement, ComparisonPlacement::kAfterEscape);
+      if (kind.type_ == Type::kEquals) {
+        // obj == <anything> can only be true if (1) it's obj == obj or (2) obj has escaped.
+        ASSERT_TRUE(ins->IsAnd()) << ins->DumpWithArgs();
+        EXPECT_TRUE(ins->InputAt(1)->IsEqual()) << ins->DumpWithArgs();
+      } else {
+        // obj != <anything> is true if (2) obj has escaped.
+        ASSERT_TRUE(ins->IsOr()) << ins->DumpWithArgs();
+        EXPECT_TRUE(ins->InputAt(1)->IsNotEqual()) << ins->DumpWithArgs();
+      }
+      // Check the first part of AND is the obj-has-escaped
+      ASSERT_TRUE(ins->InputAt(0)->IsNotEqual()) << ins->DumpWithArgs();
+      EXPECT_TRUE(ins->InputAt(0)->InputAt(0)->IsPhi()) << ins->DumpWithArgs();
+      EXPECT_TRUE(ins->InputAt(0)->InputAt(1)->IsNullConstant()) << ins->DumpWithArgs();
+      // Check the second part of AND is the eq other
+      EXPECT_INS_EQ(ins->InputAt(1)->InputAt(kind.position_ == Position::kLeft ? 0 : 1),
+                    ins->InputAt(0)->InputAt(0))
+          << ins->DumpWithArgs();
+    }
+  }
+
+  struct ComparisonInstructions {
+    void AddSetup(HBasicBlock* blk) const {
+      for (HInstruction* i : setup_instructions_) {
+        blk->AddInstruction(i);
+      }
+    }
+
+    void AddEnvironment(HEnvironment* env) const {
+      for (HInstruction* i : setup_instructions_) {
+        if (i->NeedsEnvironment()) {
+          i->CopyEnvironmentFrom(env);
+        }
+      }
+    }
+
+    const std::vector<HInstruction*> setup_instructions_;
+    HInstruction* const cmp_;
+  };
+
+  ComparisonInstructions GetComparisonInstructions(HInstruction* partial) {
+    PartialComparisonKind kind = GetParam();
+    std::vector<HInstruction*> setup;
+    HInstruction* target_other;
+    switch (kind.target_) {
+      case PartialComparisonKind::Target::kSelf:
+        target_other = partial;
+        break;
+      case PartialComparisonKind::Target::kNull:
+        target_other = graph_->GetNullConstant();
+        break;
+      case PartialComparisonKind::Target::kValue: {
+        HInstruction* cls = MakeClassLoad();
+        HInstruction* static_read =
+            new (GetAllocator()) HStaticFieldGet(cls,
+                                                 /* field= */ nullptr,
+                                                 DataType::Type::kReference,
+                                                 /* field_offset= */ MemberOffset(40),
+                                                 /* is_volatile= */ false,
+                                                 /* field_idx= */ 0,
+                                                 /* declaring_class_def_index= */ 0,
+                                                 graph_->GetDexFile(),
+                                                 /* dex_pc= */ 0);
+        setup.push_back(cls);
+        setup.push_back(static_read);
+        target_other = static_read;
+        break;
+      }
+    }
+    HInstruction* target_left;
+    HInstruction* target_right;
+    std::tie(target_left, target_right) = kind.position_ == PartialComparisonKind::Position::kLeft
+                                              ? std::pair{partial, target_other}
+                                              : std::pair{target_other, partial};
+    HInstruction* cmp =
+        kind.type_ == PartialComparisonKind::Type::kEquals
+            ? static_cast<HInstruction*>(new (GetAllocator()) HEqual(target_left, target_right))
+            : static_cast<HInstruction*>(new (GetAllocator()) HNotEqual(target_left, target_right));
+    return {setup, cmp};
+  }
 };
 
 TEST_F(LoadStoreEliminationTest, ArrayGetSetElimination) {
@@ -669,10 +1046,8 @@
 
   // Add another array parameter that may alias with `array_`.
   // Note: We're not adding it to the suspend check environment.
-  AddParameter(new (GetAllocator()) HParameterValue(graph_->GetDexFile(),
-                                                    dex::TypeIndex(0),
-                                                    3,
-                                                    DataType::Type::kInt32));
+  AddParameter(new (GetAllocator()) HParameterValue(
+      graph_->GetDexFile(), dex::TypeIndex(0), 3, DataType::Type::kInt32));
   HInstruction* array2 = parameters_.back();
 
   HInstruction* c0 = graph_->GetIntConstant(0);
@@ -931,43 +1306,14 @@
   HInstruction* suspend_check = new (GetAllocator()) HSuspendCheck();
   entry->AddInstruction(suspend_check);
   entry->AddInstruction(new (GetAllocator()) HGoto());
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(suspend_check, &current_locals);
+  ManuallyBuildEnvFor(suspend_check, {});
 
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* const_fence = new (GetAllocator()) HConstructorFence(new_inst, 0, GetAllocator());
-  HInstruction* set_field = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                   graph_->GetIntConstant(33),
-                                                                   nullptr,
-                                                                   DataType::Type::kReference,
-                                                                   MemberOffset(32),
-                                                                   false,
-                                                                   0,
-                                                                   0,
-                                                                   graph_->GetDexFile(),
-                                                                   0);
-  HInstruction* get_field = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                   nullptr,
-                                                                   DataType::Type::kReference,
-                                                                   mirror::Object::ClassOffset(),
-                                                                   false,
-                                                                   0,
-                                                                   0,
-                                                                   graph_->GetDexFile(),
-                                                                   0);
+  HInstruction* set_field = MakeIFieldSet(new_inst, graph_->GetIntConstant(33), MemberOffset(32));
+  HInstruction* get_field =
+      MakeIFieldGet(new_inst, DataType::Type::kReference, mirror::Object::ClassOffset());
   HInstruction* return_val = new (GetAllocator()) HReturn(get_field);
   main->AddInstruction(cls);
   main->AddInstruction(new_inst);
@@ -978,17 +1324,17 @@
   cls->CopyEnvironmentFrom(suspend_check->GetEnvironment());
   new_inst->CopyEnvironmentFrom(suspend_check->GetEnvironment());
 
-  exit->AddInstruction(new (GetAllocator()) HExit());
+  SetupExit(exit);
 
   graph_->ClearDominanceInformation();
   PerformLSE();
 
-  EXPECT_TRUE(IsRemoved(new_inst));
-  EXPECT_TRUE(IsRemoved(const_fence));
-  EXPECT_TRUE(IsRemoved(get_field));
-  EXPECT_TRUE(IsRemoved(set_field));
-  EXPECT_FALSE(IsRemoved(cls));
-  EXPECT_EQ(cls, return_val->InputAt(0));
+  EXPECT_INS_REMOVED(new_inst);
+  EXPECT_INS_REMOVED(const_fence);
+  EXPECT_INS_REMOVED(get_field);
+  EXPECT_INS_REMOVED(set_field);
+  EXPECT_INS_RETAINED(cls);
+  EXPECT_INS_EQ(cls, return_val->InputAt(0));
 }
 
 // Object o = new Obj();
@@ -1011,43 +1357,14 @@
   HInstruction* suspend_check = new (GetAllocator()) HSuspendCheck();
   entry->AddInstruction(suspend_check);
   entry->AddInstruction(new (GetAllocator()) HGoto());
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(suspend_check, &current_locals);
+  ManuallyBuildEnvFor(suspend_check, {});
 
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* const_fence = new (GetAllocator()) HConstructorFence(new_inst, 0, GetAllocator());
-  HInstruction* set_field = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                   graph_->GetIntConstant(33),
-                                                                   nullptr,
-                                                                   DataType::Type::kReference,
-                                                                   MemberOffset(32),
-                                                                   false,
-                                                                   0,
-                                                                   0,
-                                                                   graph_->GetDexFile(),
-                                                                   0);
-  HInstruction* get_field = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                   nullptr,
-                                                                   DataType::Type::kInt32,
-                                                                   mirror::Object::MonitorOffset(),
-                                                                   false,
-                                                                   0,
-                                                                   0,
-                                                                   graph_->GetDexFile(),
-                                                                   0);
+  HInstruction* set_field = MakeIFieldSet(new_inst, graph_->GetIntConstant(33), MemberOffset(32));
+  HInstruction* get_field =
+      MakeIFieldGet(new_inst, DataType::Type::kInt32, mirror::Object::MonitorOffset());
   HInstruction* return_val = new (GetAllocator()) HReturn(get_field);
   main->AddInstruction(cls);
   main->AddInstruction(new_inst);
@@ -1058,17 +1375,17 @@
   cls->CopyEnvironmentFrom(suspend_check->GetEnvironment());
   new_inst->CopyEnvironmentFrom(suspend_check->GetEnvironment());
 
-  exit->AddInstruction(new (GetAllocator()) HExit());
+  SetupExit(exit);
 
   graph_->ClearDominanceInformation();
   PerformLSE();
 
-  EXPECT_TRUE(IsRemoved(new_inst));
-  EXPECT_TRUE(IsRemoved(const_fence));
-  EXPECT_TRUE(IsRemoved(get_field));
-  EXPECT_TRUE(IsRemoved(set_field));
-  EXPECT_FALSE(IsRemoved(cls));
-  EXPECT_EQ(graph_->GetIntConstant(0), return_val->InputAt(0));
+  EXPECT_INS_REMOVED(new_inst);
+  EXPECT_INS_REMOVED(const_fence);
+  EXPECT_INS_REMOVED(get_field);
+  EXPECT_INS_REMOVED(set_field);
+  EXPECT_INS_RETAINED(cls);
+  EXPECT_INS_EQ(graph_->GetIntConstant(0), return_val->InputAt(0));
 }
 
 // void DO_CAL() {
@@ -1083,7 +1400,8 @@
 //   return t;
 // }
 TEST_F(LoadStoreEliminationTest, ArrayLoopOverlap) {
-  CreateGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blocks(graph_,
                             GetAllocator(),
                             "entry",
@@ -1114,8 +1432,7 @@
   loop_pre_header->AddInstruction(alloc_w);
   loop_pre_header->AddInstruction(pre_header_goto);
   // environment
-  ArenaVector<HInstruction*> alloc_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(alloc_w, &alloc_locals);
+  ManuallyBuildEnvFor(alloc_w, {});
 
   // loop-start
   HPhi* i_phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
@@ -1140,44 +1457,18 @@
   t_phi->AddInput(zero_const);
 
   // environment
-  ArenaVector<HInstruction*> suspend_locals({ alloc_w, i_phi, t_phi },
-                                            GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(suspend, &suspend_locals);
+  ManuallyBuildEnvFor(suspend, { alloc_w, i_phi, t_phi });
 
   // BODY
   HInstruction* last_i = new (GetAllocator()) HSub(DataType::Type::kInt32, i_phi, one_const);
   HInstruction* last_get =
       new (GetAllocator()) HArrayGet(alloc_w, last_i, DataType::Type::kInt32, 0);
-  HInvoke* body_value = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            2,
-                            DataType::Type::kInt32,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  body_value->SetRawInputAt(0, last_get);
-  body_value->SetRawInputAt(1, one_const);
+  HInvoke* body_value = MakeInvoke(DataType::Type::kInt32, { last_get, one_const });
   HInstruction* body_set =
       new (GetAllocator()) HArraySet(alloc_w, i_phi, body_value, DataType::Type::kInt32, 0);
   HInstruction* body_get =
       new (GetAllocator()) HArrayGet(alloc_w, i_phi, DataType::Type::kInt32, 0);
-  HInvoke* t_next = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            2,
-                            DataType::Type::kInt32,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  t_next->SetRawInputAt(0, body_get);
-  t_next->SetRawInputAt(1, t_phi);
+  HInvoke* t_next = MakeInvoke(DataType::Type::kInt32, { body_get, t_phi });
   HInstruction* i_next = new (GetAllocator()) HAdd(DataType::Type::kInt32, i_phi, one_const);
   HInstruction* body_goto = new (GetAllocator()) HGoto();
   loop_body->AddInstruction(last_i);
@@ -1199,8 +1490,7 @@
   loop_post->AddInstruction(return_inst);
 
   // exit
-  HInstruction* exit_inst = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_inst);
+  SetupExit(exit);
 
   graph_->ClearDominanceInformation();
   graph_->ClearLoopInformation();
@@ -1211,18 +1501,17 @@
   // back into the array.
   if (IsRemoved(last_get)) {
     // If we were able to remove the previous read the entire array should be removable.
-    EXPECT_TRUE(IsRemoved(body_set));
-    EXPECT_TRUE(IsRemoved(alloc_w));
+    EXPECT_INS_REMOVED(body_set);
+    EXPECT_INS_REMOVED(alloc_w);
   } else {
     // This is the branch we actually take for now. If we rely on being able to
     // read the array we'd better remember to write to it as well.
-    EXPECT_FALSE(IsRemoved(body_set));
+    EXPECT_INS_RETAINED(body_set);
   }
   // The last 'get' should always be removable.
-  EXPECT_TRUE(IsRemoved(body_get));
+  EXPECT_INS_REMOVED(body_get);
 }
 
-
 // void DO_CAL2() {
 //   int i = 1;
 //   int[] w = new int[80];
@@ -1239,7 +1528,8 @@
 //   return t;
 // }
 TEST_F(LoadStoreEliminationTest, ArrayLoopOverlap2) {
-  CreateGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blocks(graph_,
                             GetAllocator(),
                             "entry",
@@ -1270,8 +1560,7 @@
   loop_pre_header->AddInstruction(alloc_w);
   loop_pre_header->AddInstruction(pre_header_goto);
   // environment
-  ArenaVector<HInstruction*> alloc_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(alloc_w, &alloc_locals);
+  ManuallyBuildEnvFor(alloc_w, {});
 
   // loop-start
   HPhi* i_phi = new (GetAllocator()) HPhi(GetAllocator(), 0, 0, DataType::Type::kInt32);
@@ -1296,50 +1585,24 @@
   t_phi->AddInput(zero_const);
 
   // environment
-  ArenaVector<HInstruction*> suspend_locals({ alloc_w, i_phi, t_phi },
-                                            GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(suspend, &suspend_locals);
+  ManuallyBuildEnvFor(suspend, { alloc_w, i_phi, t_phi });
 
   // BODY
   HInstruction* last_i = new (GetAllocator()) HSub(DataType::Type::kInt32, i_phi, one_const);
-  HInstruction* last_get_1, *last_get_2, *last_get_3;
-  HInstruction* body_value_1, *body_value_2, *body_value_3;
-  HInstruction* body_set_1, *body_set_2, *body_set_3;
-  HInstruction* body_get_1, *body_get_2, *body_get_3;
-  HInstruction* t_next_1, *t_next_2, *t_next_3;
+  HInstruction *last_get_1, *last_get_2, *last_get_3;
+  HInstruction *body_value_1, *body_value_2, *body_value_3;
+  HInstruction *body_set_1, *body_set_2, *body_set_3;
+  HInstruction *body_get_1, *body_get_2, *body_get_3;
+  HInstruction *t_next_1, *t_next_2, *t_next_3;
   auto make_instructions = [&](HInstruction* last_t_value) {
     HInstruction* last_get =
         new (GetAllocator()) HArrayGet(alloc_w, last_i, DataType::Type::kInt32, 0);
-    HInvoke* body_value = new (GetAllocator())
-        HInvokeStaticOrDirect(GetAllocator(),
-                              2,
-                              DataType::Type::kInt32,
-                              0,
-                              { nullptr, 0 },
-                              nullptr,
-                              {},
-                              InvokeType::kStatic,
-                              { nullptr, 0 },
-                              HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-    body_value->SetRawInputAt(0, last_get);
-    body_value->SetRawInputAt(1, one_const);
+    HInvoke* body_value = MakeInvoke(DataType::Type::kInt32, { last_get, one_const });
     HInstruction* body_set =
         new (GetAllocator()) HArraySet(alloc_w, i_phi, body_value, DataType::Type::kInt32, 0);
     HInstruction* body_get =
         new (GetAllocator()) HArrayGet(alloc_w, i_phi, DataType::Type::kInt32, 0);
-    HInvoke* t_next = new (GetAllocator())
-        HInvokeStaticOrDirect(GetAllocator(),
-                              2,
-                              DataType::Type::kInt32,
-                              0,
-                              { nullptr, 0 },
-                              nullptr,
-                              {},
-                              InvokeType::kStatic,
-                              { nullptr, 0 },
-                              HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-    t_next->SetRawInputAt(0, body_get);
-    t_next->SetRawInputAt(1, last_t_value);
+    HInvoke* t_next = MakeInvoke(DataType::Type::kInt32, { body_get, last_t_value });
     loop_body->AddInstruction(last_get);
     loop_body->AddInstruction(body_value);
     loop_body->AddInstruction(body_set);
@@ -1372,8 +1635,7 @@
   loop_post->AddInstruction(return_inst);
 
   // exit
-  HInstruction* exit_inst = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_inst);
+  SetupExit(exit);
 
   graph_->ClearDominanceInformation();
   graph_->ClearLoopInformation();
@@ -1384,28 +1646,29 @@
   // back into the array.
   if (IsRemoved(last_get_1)) {
     // If we were able to remove the previous read the entire array should be removable.
-    EXPECT_TRUE(IsRemoved(body_set_1));
-    EXPECT_TRUE(IsRemoved(body_set_2));
-    EXPECT_TRUE(IsRemoved(body_set_3));
-    EXPECT_TRUE(IsRemoved(last_get_1));
-    EXPECT_TRUE(IsRemoved(last_get_2));
-    EXPECT_TRUE(IsRemoved(alloc_w));
+    EXPECT_INS_REMOVED(body_set_1);
+    EXPECT_INS_REMOVED(body_set_2);
+    EXPECT_INS_REMOVED(body_set_3);
+    EXPECT_INS_REMOVED(last_get_1);
+    EXPECT_INS_REMOVED(last_get_2);
+    EXPECT_INS_REMOVED(alloc_w);
   } else {
     // This is the branch we actually take for now. If we rely on being able to
     // read the array we'd better remember to write to it as well.
-    EXPECT_FALSE(IsRemoved(body_set_3));
+    EXPECT_INS_RETAINED(body_set_3);
   }
   // The last 'get' should always be removable.
-  EXPECT_TRUE(IsRemoved(body_get_1));
-  EXPECT_TRUE(IsRemoved(body_get_2));
-  EXPECT_TRUE(IsRemoved(body_get_3));
+  EXPECT_INS_REMOVED(body_get_1);
+  EXPECT_INS_REMOVED(body_get_2);
+  EXPECT_INS_REMOVED(body_get_3);
   // shadowed writes should always be removed
-  EXPECT_TRUE(IsRemoved(body_set_1));
-  EXPECT_TRUE(IsRemoved(body_set_2));
+  EXPECT_INS_REMOVED(body_set_1);
+  EXPECT_INS_REMOVED(body_set_2);
 }
 
 TEST_F(LoadStoreEliminationTest, ArrayNonLoopPhi) {
-  CreateGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blocks(graph_,
                             GetAllocator(),
                             "entry",
@@ -1428,10 +1691,9 @@
   HInstruction* zero_const = graph_->GetConstant(DataType::Type::kInt32, 0);
   HInstruction* one_const = graph_->GetConstant(DataType::Type::kInt32, 1);
   HInstruction* two_const = graph_->GetConstant(DataType::Type::kInt32, 2);
-  HInstruction* param = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 0, DataType::Type::kBool);
+  HInstruction* param = MakeParam(DataType::Type::kBool);
+
   HInstruction* entry_goto = new (GetAllocator()) HGoto();
-  entry->AddInstruction(param);
   entry->AddInstruction(entry_goto);
 
   HInstruction* alloc_w = new (GetAllocator()) HNewArray(zero_const, two_const, 0, 0);
@@ -1439,22 +1701,10 @@
   start->AddInstruction(alloc_w);
   start->AddInstruction(branch);
   // environment
-  ArenaVector<HInstruction*> alloc_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(alloc_w, &alloc_locals);
+  ManuallyBuildEnvFor(alloc_w, {});
 
   // left
-  HInvoke* left_value = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kInt32,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  left_value->SetRawInputAt(0, zero_const);
+  HInvoke* left_value = MakeInvoke(DataType::Type::kInt32, { zero_const });
   HInstruction* left_set_1 =
       new (GetAllocator()) HArraySet(alloc_w, zero_const, left_value, DataType::Type::kInt32, 0);
   HInstruction* left_set_2 =
@@ -1464,23 +1714,10 @@
   left->AddInstruction(left_set_1);
   left->AddInstruction(left_set_2);
   left->AddInstruction(left_goto);
-  ArenaVector<HInstruction*> left_locals({ alloc_w },
-                                         GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(left_value, &alloc_locals);
+  ManuallyBuildEnvFor(left_value, { alloc_w });
 
   // right
-  HInvoke* right_value = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kInt32,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  right_value->SetRawInputAt(0, one_const);
+  HInvoke* right_value = MakeInvoke(DataType::Type::kInt32, { one_const });
   HInstruction* right_set_1 =
       new (GetAllocator()) HArraySet(alloc_w, zero_const, right_value, DataType::Type::kInt32, 0);
   HInstruction* right_set_2 =
@@ -1490,9 +1727,7 @@
   right->AddInstruction(right_set_1);
   right->AddInstruction(right_set_2);
   right->AddInstruction(right_goto);
-  ArenaVector<HInstruction*> right_locals({ alloc_w },
-                                          GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(right_value, &alloc_locals);
+  ManuallyBuildEnvFor(right_value, { alloc_w });
 
   // ret
   HInstruction* read_1 =
@@ -1507,27 +1742,27 @@
   ret->AddInstruction(return_inst);
 
   // exit
-  HInstruction* exit_inst = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_inst);
+  SetupExit(exit);
 
   graph_->ClearDominanceInformation();
   graph_->ClearLoopInformation();
   PerformLSE();
 
-  EXPECT_TRUE(IsRemoved(read_1));
-  EXPECT_TRUE(IsRemoved(read_2));
-  EXPECT_TRUE(IsRemoved(left_set_1));
-  EXPECT_TRUE(IsRemoved(left_set_2));
-  EXPECT_TRUE(IsRemoved(right_set_1));
-  EXPECT_TRUE(IsRemoved(right_set_2));
-  EXPECT_TRUE(IsRemoved(alloc_w));
+  EXPECT_INS_REMOVED(read_1);
+  EXPECT_INS_REMOVED(read_2);
+  EXPECT_INS_REMOVED(left_set_1);
+  EXPECT_INS_REMOVED(left_set_2);
+  EXPECT_INS_REMOVED(right_set_1);
+  EXPECT_INS_REMOVED(right_set_2);
+  EXPECT_INS_REMOVED(alloc_w);
 
-  EXPECT_FALSE(IsRemoved(left_value));
-  EXPECT_FALSE(IsRemoved(right_value));
+  EXPECT_INS_RETAINED(left_value);
+  EXPECT_INS_RETAINED(right_value);
 }
 
 TEST_F(LoadStoreEliminationTest, ArrayMergeDefault) {
-  CreateGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blocks(graph_,
                             GetAllocator(),
                             "entry",
@@ -1550,10 +1785,9 @@
   HInstruction* zero_const = graph_->GetConstant(DataType::Type::kInt32, 0);
   HInstruction* one_const = graph_->GetConstant(DataType::Type::kInt32, 1);
   HInstruction* two_const = graph_->GetConstant(DataType::Type::kInt32, 2);
-  HInstruction* param = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 0, DataType::Type::kBool);
+  HInstruction* param = MakeParam(DataType::Type::kBool);
   HInstruction* entry_goto = new (GetAllocator()) HGoto();
-  entry->AddInstruction(param);
+
   entry->AddInstruction(entry_goto);
 
   HInstruction* alloc_w = new (GetAllocator()) HNewArray(zero_const, two_const, 0, 0);
@@ -1562,7 +1796,7 @@
   start->AddInstruction(branch);
   // environment
   ArenaVector<HInstruction*> alloc_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(alloc_w, &alloc_locals);
+  ManuallyBuildEnvFor(alloc_w, {});
 
   // left
   HInstruction* left_set_1 =
@@ -1597,20 +1831,19 @@
   ret->AddInstruction(return_inst);
 
   // exit
-  HInstruction* exit_inst = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_inst);
+  SetupExit(exit);
 
   graph_->ClearDominanceInformation();
   graph_->ClearLoopInformation();
   PerformLSE();
 
-  EXPECT_TRUE(IsRemoved(read_1));
-  EXPECT_TRUE(IsRemoved(read_2));
-  EXPECT_TRUE(IsRemoved(left_set_1));
-  EXPECT_TRUE(IsRemoved(left_set_2));
-  EXPECT_TRUE(IsRemoved(right_set_1));
-  EXPECT_TRUE(IsRemoved(right_set_2));
-  EXPECT_TRUE(IsRemoved(alloc_w));
+  EXPECT_INS_REMOVED(read_1);
+  EXPECT_INS_REMOVED(read_2);
+  EXPECT_INS_REMOVED(left_set_1);
+  EXPECT_INS_REMOVED(left_set_2);
+  EXPECT_INS_REMOVED(right_set_1);
+  EXPECT_INS_REMOVED(right_set_2);
+  EXPECT_INS_REMOVED(alloc_w);
 }
 
 // // ENTRY
@@ -1651,22 +1884,22 @@
   CreateGraph();
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit",
-                                                 { { "entry", "bswitch" },
-                                                   { "bswitch", "case1" },
-                                                   { "bswitch", "case2" },
-                                                   { "bswitch", "case3" },
-                                                   { "case1", "breturn" },
-                                                   { "case2", "breturn" },
-                                                   { "case3", "loop_pre_header" },
-                                                   { "loop_pre_header", "loop_header" },
-                                                   { "loop_header", "loop_body" },
-                                                   { "loop_body", "loop_if_left" },
-                                                   { "loop_body", "loop_if_right" },
-                                                   { "loop_if_left", "loop_end" },
-                                                   { "loop_if_right", "loop_end" },
-                                                   { "loop_end", "loop_header" },
-                                                   { "loop_header", "breturn" },
-                                                   { "breturn", "exit" } }));
+                                                 {{"entry", "bswitch"},
+                                                  {"bswitch", "case1"},
+                                                  {"bswitch", "case2"},
+                                                  {"bswitch", "case3"},
+                                                  {"case1", "breturn"},
+                                                  {"case2", "breturn"},
+                                                  {"case3", "loop_pre_header"},
+                                                  {"loop_pre_header", "loop_header"},
+                                                  {"loop_header", "loop_body"},
+                                                  {"loop_body", "loop_if_left"},
+                                                  {"loop_body", "loop_if_right"},
+                                                  {"loop_if_left", "loop_end"},
+                                                  {"loop_if_right", "loop_end"},
+                                                  {"loop_end", "loop_header"},
+                                                  {"loop_header", "breturn"},
+                                                  {"breturn", "exit"}}));
 #define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
   GET_BLOCK(entry);
   GET_BLOCK(bswitch);
@@ -1683,104 +1916,41 @@
   GET_BLOCK(loop_if_right);
   GET_BLOCK(loop_end);
 #undef GET_BLOCK
-  HInstruction* switch_val = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kInt32);
+  HInstruction* switch_val = MakeParam(DataType::Type::kInt32);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
   HInstruction* c3 = graph_->GetIntConstant(3);
   HInstruction* c5 = graph_->GetIntConstant(5);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* entry_goto = new (GetAllocator()) HGoto();
-  entry->AddInstruction(switch_val);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(entry_goto);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
 
   HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, switch_val);
   bswitch->AddInstruction(switch_inst);
 
-  HInstruction* write_c1 = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                  c1,
-                                                                  nullptr,
-                                                                  DataType::Type::kInt32,
-                                                                  MemberOffset(32),
-                                                                  false,
-                                                                  0,
-                                                                  0,
-                                                                  graph_->GetDexFile(),
-                                                                  0);
-  HInstruction* call_c1 = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+  HInstruction* write_c1 = MakeIFieldSet(new_inst, c1, MemberOffset(32));
+  HInstruction* call_c1 = MakeInvoke(DataType::Type::kVoid, { new_inst });
   HInstruction* goto_c1 = new (GetAllocator()) HGoto();
-  call_c1->AsInvoke()->SetRawInputAt(0, new_inst);
   case1->AddInstruction(write_c1);
   case1->AddInstruction(call_c1);
   case1->AddInstruction(goto_c1);
   call_c1->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_c2 = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                  c2,
-                                                                  nullptr,
-                                                                  DataType::Type::kInt32,
-                                                                  MemberOffset(32),
-                                                                  false,
-                                                                  0,
-                                                                  0,
-                                                                  graph_->GetDexFile(),
-                                                                  0);
-  HInstruction* call_c2 = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+  HInstruction* write_c2 = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* call_c2 = MakeInvoke(DataType::Type::kVoid, { new_inst });
   HInstruction* goto_c2 = new (GetAllocator()) HGoto();
-  call_c2->AsInvoke()->SetRawInputAt(0, new_inst);
   case2->AddInstruction(write_c2);
   case2->AddInstruction(call_c2);
   case2->AddInstruction(goto_c2);
   call_c2->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_c3 = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                  c3,
-                                                                  nullptr,
-                                                                  DataType::Type::kInt32,
-                                                                  MemberOffset(32),
-                                                                  false,
-                                                                  0,
-                                                                  0,
-                                                                  graph_->GetDexFile(),
-                                                                  0);
+  HInstruction* write_c3 = MakeIFieldSet(new_inst, c3, MemberOffset(32));
   HInstruction* goto_c3 = new (GetAllocator()) HGoto();
   case3->AddInstruction(write_c3);
   case3->AddInstruction(goto_c3);
@@ -1789,17 +1959,7 @@
   loop_pre_header->AddInstruction(goto_preheader);
 
   HInstruction* suspend_check_header = new (GetAllocator()) HSuspendCheck();
-  HInstruction* call_loop_header = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            0,
-                            DataType::Type::kBool,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+  HInstruction* call_loop_header = MakeInvoke(DataType::Type::kBool, {});
   HInstruction* if_loop_header = new (GetAllocator()) HIf(call_loop_header);
   loop_header->AddInstruction(suspend_check_header);
   loop_header->AddInstruction(call_loop_header);
@@ -1807,17 +1967,7 @@
   call_loop_header->CopyEnvironmentFrom(cls->GetEnvironment());
   suspend_check_header->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* call_loop_body = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            0,
-                            DataType::Type::kBool,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+  HInstruction* call_loop_body = MakeInvoke(DataType::Type::kBool, {});
   HInstruction* if_loop_body = new (GetAllocator()) HIf(call_loop_body);
   loop_body->AddInstruction(call_loop_body);
   loop_body->AddInstruction(if_loop_body);
@@ -1826,16 +1976,7 @@
   HInstruction* goto_loop_left = new (GetAllocator()) HGoto();
   loop_if_left->AddInstruction(goto_loop_left);
 
-  HInstruction* write_loop_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                          c5,
-                                                                          nullptr,
-                                                                          DataType::Type::kInt32,
-                                                                          MemberOffset(32),
-                                                                          false,
-                                                                          0,
-                                                                          0,
-                                                                          graph_->GetDexFile(),
-                                                                          0);
+  HInstruction* write_loop_right = MakeIFieldSet(new_inst, c5, MemberOffset(32));
   HInstruction* goto_loop_right = new (GetAllocator()) HGoto();
   loop_if_right->AddInstruction(write_loop_right);
   loop_if_right->AddInstruction(goto_loop_right);
@@ -1843,31 +1984,23 @@
   HInstruction* goto_loop_end = new (GetAllocator()) HGoto();
   loop_end->AddInstruction(goto_loop_end);
 
-  HInstruction* read_bottom = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
   breturn->AddInstruction(read_bottom);
   breturn->AddInstruction(return_exit);
 
-  HInstruction* exit_ins = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_ins);
+  SetupExit(exit);
+
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
-  PerformLSE();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSENoPartial();
 
-  EXPECT_FALSE(IsRemoved(read_bottom));
-  EXPECT_FALSE(IsRemoved(write_c1));
-  EXPECT_FALSE(IsRemoved(write_c2));
-  EXPECT_FALSE(IsRemoved(write_c3));
-  // EXPECT_FALSE(IsRemoved(write_loop_left));
-  EXPECT_FALSE(IsRemoved(write_loop_right));
+  EXPECT_INS_RETAINED(read_bottom);
+  EXPECT_INS_RETAINED(write_c1);
+  EXPECT_INS_RETAINED(write_c2);
+  EXPECT_INS_RETAINED(write_c3);
+  EXPECT_INS_RETAINED(write_loop_right);
 }
 
 // // ENTRY
@@ -1887,7 +2020,8 @@
 // EXIT
 // return PHI(foo_l, foo_r)
 TEST_F(LoadStoreEliminationTest, PartialLoadElimination) {
-  InitGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit_REAL",
                                                  { { "entry", "left" },
@@ -1899,99 +2033,37 @@
   HBasicBlock* left = blks.Get("left");
   HBasicBlock* right = blks.Get("right");
   HBasicBlock* exit = blks.Get("exit");
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
-  entry->AddInstruction(bool_value);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(if_inst);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_left = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                    c1,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(32),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
-  HInstruction* call_left = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  HInstruction* read_left = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                   nullptr,
-                                                                   DataType::Type::kInt32,
-                                                                   MemberOffset(16),
-                                                                   false,
-                                                                   0,
-                                                                   0,
-                                                                   graph_->GetDexFile(),
-                                                                   0);
+  HInstruction* write_left = MakeIFieldSet(new_inst, c1, MemberOffset(32));
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* read_left = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(16));
   HInstruction* goto_left = new (GetAllocator()) HGoto();
-  call_left->AsInvoke()->SetRawInputAt(0, new_inst);
   left->AddInstruction(write_left);
   left->AddInstruction(call_left);
   left->AddInstruction(read_left);
   left->AddInstruction(goto_left);
   call_left->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c2,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(16),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
-  HInstruction* read_right = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(16),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(16));
+  HInstruction* read_right = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(16));
   HInstruction* goto_right = new (GetAllocator()) HGoto();
   right->AddInstruction(write_right);
   right->AddInstruction(read_right);
   right->AddInstruction(goto_right);
 
-  HInstruction* phi_final =
-      new (GetAllocator()) HPhi(GetAllocator(), 12, 2, DataType::Type::kInt32);
-  phi_final->SetRawInputAt(0, read_left);
-  phi_final->SetRawInputAt(1, read_right);
+  HInstruction* phi_final = MakePhi({read_left, read_right});
   HInstruction* return_exit = new (GetAllocator()) HReturn(phi_final);
   exit->AddPhi(phi_final->AsPhi());
   exit->AddInstruction(return_exit);
@@ -2022,10 +2094,10 @@
 // }
 // EXIT
 // return obj.field
-// TODO We eventually want to be able to eliminate the right write along with the final read but
-// will need either new blocks or new instructions.
+// This test runs with partial LSE disabled.
 TEST_F(LoadStoreEliminationTest, PartialLoadPreserved) {
-  InitGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit_REAL",
                                                  { { "entry", "left" },
@@ -2037,93 +2109,42 @@
   HBasicBlock* left = blks.Get("left");
   HBasicBlock* right = blks.Get("right");
   HBasicBlock* exit = blks.Get("exit");
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
-  entry->AddInstruction(bool_value);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(if_inst);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_left = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                    c1,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(32),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
-  HInstruction* call_left = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+  HInstruction* write_left = MakeIFieldSet(new_inst, c1, MemberOffset(32));
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
   HInstruction* goto_left = new (GetAllocator()) HGoto();
-  call_left->AsInvoke()->SetRawInputAt(0, new_inst);
   left->AddInstruction(write_left);
   left->AddInstruction(call_left);
   left->AddInstruction(goto_left);
   call_left->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c2,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
   HInstruction* goto_right = new (GetAllocator()) HGoto();
   right->AddInstruction(write_right);
   right->AddInstruction(goto_right);
 
-  HInstruction* read_bottom = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
   exit->AddInstruction(read_bottom);
   exit->AddInstruction(return_exit);
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
-  PerformLSE();
+  PerformLSENoPartial();
 
-  ASSERT_FALSE(IsRemoved(read_bottom));
-  ASSERT_FALSE(IsRemoved(write_right));
+  EXPECT_INS_RETAINED(read_bottom) << *read_bottom;
+  EXPECT_INS_RETAINED(write_right) << *write_right;
 }
 
 // // ENTRY
@@ -2144,10 +2165,10 @@
 // }
 // EXIT
 // return obj.field
-// TODO We eventually want to be able to eliminate the right write along with the final read but
-// will need either new blocks or new instructions.
+// NB This test is for non-partial LSE flow. Normally the obj.field writes will be removed
 TEST_F(LoadStoreEliminationTest, PartialLoadPreserved2) {
-  InitGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit_REAL",
                                                  { { "entry", "left" },
@@ -2166,60 +2187,24 @@
   HBasicBlock* right_second = blks.Get("right_second");
   HBasicBlock* right_end = blks.Get("right_end");
   HBasicBlock* exit = blks.Get("exit");
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
-  HInstruction* bool_value_2 = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 2, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* bool_value_2 = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
   HInstruction* c3 = graph_->GetIntConstant(3);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
-  entry->AddInstruction(bool_value);
-  entry->AddInstruction(bool_value_2);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(if_inst);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_left = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                    c1,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(32),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
-  HInstruction* call_left = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+  HInstruction* write_left = MakeIFieldSet(new_inst, c1, MemberOffset(32));
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
   HInstruction* goto_left = new (GetAllocator()) HGoto();
-  call_left->AsInvoke()->SetRawInputAt(0, new_inst);
   left->AddInstruction(write_left);
   left->AddInstruction(call_left);
   left->AddInstruction(goto_left);
@@ -2228,30 +2213,12 @@
   HInstruction* right_if = new (GetAllocator()) HIf(bool_value_2);
   right_start->AddInstruction(right_if);
 
-  HInstruction* write_right_first = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                           c2,
-                                                                           nullptr,
-                                                                           DataType::Type::kInt32,
-                                                                           MemberOffset(32),
-                                                                           false,
-                                                                           0,
-                                                                           0,
-                                                                           graph_->GetDexFile(),
-                                                                           0);
+  HInstruction* write_right_first = MakeIFieldSet(new_inst, c2, MemberOffset(32));
   HInstruction* goto_right_first = new (GetAllocator()) HGoto();
   right_first->AddInstruction(write_right_first);
   right_first->AddInstruction(goto_right_first);
 
-  HInstruction* write_right_second = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                            c3,
-                                                                            nullptr,
-                                                                            DataType::Type::kInt32,
-                                                                            MemberOffset(32),
-                                                                            false,
-                                                                            0,
-                                                                            0,
-                                                                            graph_->GetDexFile(),
-                                                                            0);
+  HInstruction* write_right_second = MakeIFieldSet(new_inst, c3, MemberOffset(32));
   HInstruction* goto_right_second = new (GetAllocator()) HGoto();
   right_second->AddInstruction(write_right_second);
   right_second->AddInstruction(goto_right_second);
@@ -2259,25 +2226,17 @@
   HInstruction* goto_right_end = new (GetAllocator()) HGoto();
   right_end->AddInstruction(goto_right_end);
 
-  HInstruction* read_bottom = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
   exit->AddInstruction(read_bottom);
   exit->AddInstruction(return_exit);
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
-  PerformLSE();
+  PerformLSENoPartial();
 
-  ASSERT_FALSE(IsRemoved(read_bottom));
-  EXPECT_FALSE(IsRemoved(write_right_first));
-  EXPECT_FALSE(IsRemoved(write_right_second));
+  EXPECT_INS_RETAINED(read_bottom);
+  EXPECT_INS_RETAINED(write_right_first);
+  EXPECT_INS_RETAINED(write_right_second);
 }
 
 // // ENTRY
@@ -2296,14 +2255,15 @@
 // ELIMINATE
 // return obj.field
 TEST_F(LoadStoreEliminationTest, PartialLoadElimination2) {
-  InitGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit",
-                                                 { { "entry", "left" },
-                                                   { "entry", "right" },
-                                                   { "left", "breturn"},
-                                                   { "right", "breturn" },
-                                                   { "breturn", "exit" } }));
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
 #define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
   GET_BLOCK(entry);
   GET_BLOCK(exit);
@@ -2311,98 +2271,1888 @@
   GET_BLOCK(left);
   GET_BLOCK(right);
 #undef GET_BLOCK
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
-  entry->AddInstruction(bool_value);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(if_inst);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* call_left = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  HInstruction* write_left = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                    c1,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(32),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* write_left = MakeIFieldSet(new_inst, c1, MemberOffset(32));
   HInstruction* goto_left = new (GetAllocator()) HGoto();
-  call_left->AsInvoke()->SetRawInputAt(0, new_inst);
   left->AddInstruction(call_left);
   left->AddInstruction(write_left);
   left->AddInstruction(goto_left);
   call_left->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c2,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
   HInstruction* goto_right = new (GetAllocator()) HGoto();
   right->AddInstruction(write_right);
   right->AddInstruction(goto_right);
 
-  HInstruction* read_bottom = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
   breturn->AddInstruction(read_bottom);
   breturn->AddInstruction(return_exit);
 
-  HInstruction* exit_instruction = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_instruction);
+  SetupExit(exit);
+
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
   PerformLSE();
 
-  EXPECT_TRUE(IsRemoved(read_bottom));
-  EXPECT_TRUE(IsRemoved(write_right));
-  EXPECT_FALSE(IsRemoved(write_left));
-  EXPECT_FALSE(IsRemoved(call_left));
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_RETAINED(write_left);
+  EXPECT_INS_RETAINED(call_left);
+}
+
+class PatternMatchGraphVisitor : public HGraphVisitor {
+ private:
+  struct HandlerWrapper {
+   public:
+    virtual ~HandlerWrapper() {}
+    virtual void operator()(HInstruction* h) = 0;
+  };
+
+  template <HInstruction::InstructionKind kKind, typename F>
+  struct KindWrapper;
+
+#define GEN_HANDLER(nm, unused)                                                         \
+  template <typename F>                                                                 \
+  struct KindWrapper<HInstruction::InstructionKind::k##nm, F> : public HandlerWrapper { \
+   public:                                                                              \
+    explicit KindWrapper(F f) : f_(f) {}                                                \
+    void operator()(HInstruction* h) override {                                         \
+      if constexpr (std::is_invocable_v<F, H##nm*>) {                                   \
+        f_(h->As##nm());                                                                \
+      } else {                                                                          \
+        LOG(FATAL) << "Incorrect call with " << #nm;                                    \
+      }                                                                                 \
+    }                                                                                   \
+                                                                                        \
+   private:                                                                             \
+    F f_;                                                                               \
+  };
+
+  FOR_EACH_CONCRETE_INSTRUCTION(GEN_HANDLER)
+#undef GEN_HANDLER
+
+  template <typename F>
+  std::unique_ptr<HandlerWrapper> GetWrapper(HInstruction::InstructionKind kind, F f) {
+    switch (kind) {
+#define GEN_GETTER(nm, unused)               \
+  case HInstruction::InstructionKind::k##nm: \
+    return std::unique_ptr<HandlerWrapper>(  \
+        new KindWrapper<HInstruction::InstructionKind::k##nm, F>(f));
+      FOR_EACH_CONCRETE_INSTRUCTION(GEN_GETTER)
+#undef GEN_GETTER
+      default:
+        LOG(FATAL) << "Unable to handle kind " << kind;
+        return nullptr;
+    }
+  }
+
+ public:
+  template <typename... Inst>
+  explicit PatternMatchGraphVisitor(HGraph* graph, Inst... handlers) : HGraphVisitor(graph) {
+    FillHandlers(handlers...);
+  }
+
+  void VisitInstruction(HInstruction* instruction) override {
+    auto& h = handlers_[instruction->GetKind()];
+    if (h.get() != nullptr) {
+      (*h)(instruction);
+    }
+  }
+
+ private:
+  template <typename Func>
+  constexpr HInstruction::InstructionKind GetKind() {
+#define CHECK_INST(nm, unused)                       \
+    if constexpr (std::is_invocable_v<Func, H##nm*>) { \
+      return HInstruction::InstructionKind::k##nm;     \
+    }
+    FOR_EACH_CONCRETE_INSTRUCTION(CHECK_INST);
+#undef CHECK_INST
+    static_assert(!std::is_invocable_v<Func, HInstruction*>,
+                  "Use on generic HInstruction not allowed");
+#define STATIC_ASSERT_ABSTRACT(nm, unused) && !std::is_invocable_v<Func, H##nm*>
+    static_assert(true FOR_EACH_ABSTRACT_INSTRUCTION(STATIC_ASSERT_ABSTRACT),
+                  "Must not be abstract instruction");
+#undef STATIC_ASSERT_ABSTRACT
+#define STATIC_ASSERT_CONCRETE(nm, unused) || std::is_invocable_v<Func, H##nm*>
+    static_assert(false FOR_EACH_CONCRETE_INSTRUCTION(STATIC_ASSERT_CONCRETE),
+                  "Must be a concrete instruction");
+#undef STATIC_ASSERT_CONCRETE
+    return HInstruction::InstructionKind::kLastInstructionKind;
+  }
+  template <typename First>
+  void FillHandlers(First h1) {
+    HInstruction::InstructionKind type = GetKind<First>();
+    CHECK_NE(type, HInstruction::kLastInstructionKind)
+        << "Unknown instruction kind. Only concrete ones please.";
+    handlers_[type] = GetWrapper(type, h1);
+  }
+
+  template <typename First, typename... Inst>
+  void FillHandlers(First h1, Inst... handlers) {
+    FillHandlers(h1);
+    FillHandlers<Inst...>(handlers...);
+  }
+
+  std::array<std::unique_ptr<HandlerWrapper>, HInstruction::InstructionKind::kLastInstructionKind>
+      handlers_;
+};
+
+template <typename... Target>
+std::tuple<std::vector<Target*>...> FindAllInstructions(
+    HGraph* graph,
+    std::variant<std::nullopt_t, HBasicBlock*, std::initializer_list<HBasicBlock*>> blks =
+        std::nullopt) {
+  std::tuple<std::vector<Target*>...> res;
+  PatternMatchGraphVisitor vis(
+      graph, [&](Target* t) { std::get<std::vector<Target*>>(res).push_back(t); }...);
+
+  if (std::holds_alternative<std::initializer_list<HBasicBlock*>>(blks)) {
+    for (HBasicBlock* blk : std::get<std::initializer_list<HBasicBlock*>>(blks)) {
+      vis.VisitBasicBlock(blk);
+    }
+  } else if (std::holds_alternative<std::nullopt_t>(blks)) {
+    vis.VisitInsertionOrder();
+  } else {
+    vis.VisitBasicBlock(std::get<HBasicBlock*>(blks));
+  }
+  return res;
+}
+
+template <typename... Target>
+std::tuple<Target*...> FindSingleInstructions(
+    HGraph* graph,
+    std::variant<std::nullopt_t, HBasicBlock*, std::initializer_list<HBasicBlock*>> blks =
+        std::nullopt) {
+  std::tuple<Target*...> res;
+  PatternMatchGraphVisitor vis(graph, [&](Target* t) {
+    EXPECT_EQ(std::get<Target*>(res), nullptr)
+        << *std::get<Target*>(res) << " already found but found " << *t << "!";
+    std::get<Target*>(res) = t;
+  }...);
+  if (std::holds_alternative<std::initializer_list<HBasicBlock*>>(blks)) {
+    for (HBasicBlock* blk : std::get<std::initializer_list<HBasicBlock*>>(blks)) {
+      vis.VisitBasicBlock(blk);
+    }
+  } else if (std::holds_alternative<std::nullopt_t>(blks)) {
+    vis.VisitInsertionOrder();
+  } else {
+    vis.VisitBasicBlock(std::get<HBasicBlock*>(blks));
+  }
+  return res;
+}
+
+template <typename Target>
+Target* FindSingleInstruction(
+    HGraph* graph,
+    std::variant<std::nullopt_t, HBasicBlock*, std::initializer_list<HBasicBlock*>> blks =
+        std::nullopt) {
+  return std::get<Target*>(FindSingleInstructions<Target>(graph, blks));
+}
+
+template<typename Iter, typename Func>
+typename Iter::value_type FindOrNull(Iter begin, Iter end, Func func) {
+  static_assert(std::is_pointer_v<typename Iter::value_type>);
+  auto it = std::find_if(begin, end, func);
+  if (it == end) {
+    return nullptr;
+  } else {
+    return *it;
+  }
+}
+
+// // ENTRY
+// Obj new_inst = new Obj();
+// new_inst.foo = 12;
+// Obj obj;
+// Obj out;
+// int first;
+// if (param0) {
+//   // ESCAPE_ROUTE
+//   if (param1) {
+//     // LEFT_START
+//     if (param2) {
+//       // LEFT_LEFT
+//       obj = new_inst;
+//     } else {
+//       // LEFT_RIGHT
+//       obj = obj_param;
+//     }
+//     // LEFT_MERGE
+//     // technically the phi is enough to cause an escape but might as well be
+//     // thorough.
+//     // obj = phi[new_inst, param]
+//     escape(obj);
+//     out = obj;
+//   } else {
+//     // RIGHT
+//     out = obj_param;
+//   }
+//   // EXIT
+//   // Can't do anything with this since we don't have good tracking for the heap-locations
+//   // out = phi[param, phi[new_inst, param]]
+//   first = out.foo
+// } else {
+//   new_inst.foo = 15;
+//   first = 13;
+// }
+// // first = phi[out.foo, 13]
+// return first + new_inst.foo;
+TEST_F(LoadStoreEliminationTest, PartialPhiPropagation) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "escape_route"},
+                                                  {"entry", "noescape_route"},
+                                                  {"escape_route", "left"},
+                                                  {"escape_route", "right"},
+                                                  {"left", "left_left"},
+                                                  {"left", "left_right"},
+                                                  {"left_left", "left_merge"},
+                                                  {"left_right", "left_merge"},
+                                                  {"left_merge", "escape_end"},
+                                                  {"right", "escape_end"},
+                                                  {"escape_end", "breturn"},
+                                                  {"noescape_route", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+  GET_BLOCK(left_left);
+  GET_BLOCK(left_right);
+  GET_BLOCK(left_merge);
+  GET_BLOCK(escape_end);
+  GET_BLOCK(escape_route);
+  GET_BLOCK(noescape_route);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(escape_end, {left_merge, right});
+  EnsurePredecessorOrder(left_merge, {left_left, left_right});
+  EnsurePredecessorOrder(breturn, {escape_end, noescape_route});
+  HInstruction* param0 = MakeParam(DataType::Type::kBool);
+  HInstruction* param1 = MakeParam(DataType::Type::kBool);
+  HInstruction* param2 = MakeParam(DataType::Type::kBool);
+  HInstruction* obj_param = MakeParam(DataType::Type::kReference);
+  HInstruction* c12 = graph_->GetIntConstant(12);
+  HInstruction* c13 = graph_->GetIntConstant(13);
+  HInstruction* c15 = graph_->GetIntConstant(15);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* store = MakeIFieldSet(new_inst, c12, MemberOffset(32));
+  HInstruction* if_param0 = new (GetAllocator()) HIf(param0);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(store);
+  entry->AddInstruction(if_param0);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* store_noescape = MakeIFieldSet(new_inst, c15, MemberOffset(32));
+  noescape_route->AddInstruction(store_noescape);
+  noescape_route->AddInstruction(new (GetAllocator()) HGoto());
+
+  escape_route->AddInstruction(new (GetAllocator()) HIf(param1));
+
+  HInstruction* if_left = new (GetAllocator()) HIf(param2);
+  left->AddInstruction(if_left);
+
+  HInstruction* goto_left_left = new (GetAllocator()) HGoto();
+  left_left->AddInstruction(goto_left_left);
+
+  HInstruction* goto_left_right = new (GetAllocator()) HGoto();
+  left_right->AddInstruction(goto_left_right);
+
+  HPhi* left_phi = MakePhi({obj_param, new_inst});
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { left_phi });
+  HInstruction* goto_left_merge = new (GetAllocator()) HGoto();
+  left_merge->AddPhi(left_phi);
+  left_merge->AddInstruction(call_left);
+  left_merge->AddInstruction(goto_left_merge);
+  left_phi->SetCanBeNull(true);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(goto_right);
+
+  HPhi* escape_end_phi = MakePhi({left_phi, obj_param});
+  HInstruction* read_escape_end =
+      MakeIFieldGet(escape_end_phi, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* goto_escape_end = new (GetAllocator()) HGoto();
+  escape_end->AddPhi(escape_end_phi);
+  escape_end->AddInstruction(read_escape_end);
+  escape_end->AddInstruction(goto_escape_end);
+
+  HPhi* return_phi = MakePhi({read_escape_end, c13});
+  HInstruction* read_exit = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* add_exit = new (GetAllocator()) HAdd(DataType::Type::kInt32, return_phi, read_exit);
+  HInstruction* return_exit = new (GetAllocator()) HReturn(add_exit);
+  breturn->AddPhi(return_phi);
+  breturn->AddInstruction(read_exit);
+  breturn->AddInstruction(add_exit);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_);
+  std::vector<HPhi*> all_return_phis;
+  std::tie(all_return_phis) = FindAllInstructions<HPhi>(graph_, breturn);
+  EXPECT_EQ(all_return_phis.size(), 3u);
+  EXPECT_INS_RETAINED(return_phi);
+  EXPECT_TRUE(std::find(all_return_phis.begin(), all_return_phis.end(), return_phi) !=
+              all_return_phis.end());
+  HPhi* instance_phi =
+      FindOrNull(all_return_phis.begin(), all_return_phis.end(), [&](HPhi* phi) {
+        return phi != return_phi && phi->GetType() == DataType::Type::kReference;
+      });
+  ASSERT_NE(instance_phi, nullptr);
+  HPhi* value_phi = FindOrNull(all_return_phis.begin(), all_return_phis.end(), [&](HPhi* phi) {
+    return phi != return_phi && phi->GetType() == DataType::Type::kInt32;
+  });
+  ASSERT_NE(value_phi, nullptr);
+  EXPECT_INS_EQ(
+      instance_phi->InputAt(0),
+      FindSingleInstruction<HNewInstance>(graph_, escape_route->GetSinglePredecessor()));
+  // Check materialize block
+  EXPECT_INS_EQ(FindSingleInstruction<HInstanceFieldSet>(
+                    graph_, escape_route->GetSinglePredecessor())
+                    ->InputAt(1),
+                c12);
+
+  EXPECT_INS_EQ(instance_phi->InputAt(1), graph_->GetNullConstant());
+  EXPECT_INS_EQ(value_phi->InputAt(0), graph_->GetIntConstant(0));
+  EXPECT_INS_EQ(value_phi->InputAt(1), c15);
+  EXPECT_INS_REMOVED(store_noescape);
+  EXPECT_INS_EQ(pred_get->GetTarget(), instance_phi);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue(), value_phi);
+}
+
+// // ENTRY
+// // To be moved
+// // NB Order important. By having alloc and store of obj1 before obj2 that
+// // ensure we'll build the materialization for obj1 first (just due to how
+// // we iterate.)
+// obj1 = new Obj();
+// obj2 = new Obj(); // has env[obj1]
+// // Swap the order of these
+// obj1.foo = param_obj1;
+// obj2.foo = param_obj2;
+// if (param1) {
+//   // LEFT
+//   obj2.foo = obj1;
+//   if (param2) {
+//     // LEFT_LEFT
+//     escape(obj2);
+//   } else {}
+// } else {}
+// return select(param3, obj1.foo, obj2.foo);
+// EXIT
+TEST_P(OrderDependentTestGroup, PredicatedUse) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "left_left"},
+                                                  {"left", "left_right"},
+                                                  {"left_left", "left_end"},
+                                                  {"left_right", "left_end"},
+                                                  {"left_end", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(right);
+  GET_BLOCK(left);
+  GET_BLOCK(left_left);
+  GET_BLOCK(left_right);
+  GET_BLOCK(left_end);
+#undef GET_BLOCK
+  TestOrder order = GetParam();
+  EnsurePredecessorOrder(breturn, {left_end, right});
+  EnsurePredecessorOrder(left_end, {left_left, left_right});
+  HInstruction* param1 = MakeParam(DataType::Type::kBool);
+  HInstruction* param2 = MakeParam(DataType::Type::kBool);
+  HInstruction* param3 = MakeParam(DataType::Type::kBool);
+  HInstruction* param_obj1 = MakeParam(DataType::Type::kReference);
+  HInstruction* param_obj2 = MakeParam(DataType::Type::kReference);
+
+  HInstruction* cls1 = MakeClassLoad();
+  HInstruction* cls2 = MakeClassLoad();
+  HInstruction* new_inst1 = MakeNewInstance(cls1);
+  HInstruction* new_inst2 = MakeNewInstance(cls2);
+  HInstruction* store1 = MakeIFieldSet(new_inst1, param_obj1, MemberOffset(32));
+  HInstruction* store2 = MakeIFieldSet(new_inst2, param_obj2, MemberOffset(32));
+  HInstruction* null_const = graph_->GetNullConstant();
+  HInstruction* if_inst = new (GetAllocator()) HIf(param1);
+  entry->AddInstruction(cls1);
+  entry->AddInstruction(cls2);
+  entry->AddInstruction(new_inst1);
+  entry->AddInstruction(new_inst2);
+  if (order == TestOrder::kSameAsAlloc) {
+    entry->AddInstruction(store1);
+    entry->AddInstruction(store2);
+  } else {
+    entry->AddInstruction(store2);
+    entry->AddInstruction(store1);
+  }
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls1, {});
+  cls2->CopyEnvironmentFrom(cls1->GetEnvironment());
+  new_inst1->CopyEnvironmentFrom(cls1->GetEnvironment());
+  new_inst2->CopyEnvironmentFrom(cls1->GetEnvironment());
+
+  // This is the escape of new_inst1
+  HInstruction* store_left = MakeIFieldSet(new_inst2, new_inst1, MemberOffset(32));
+  HInstruction* if_left = new (GetAllocator()) HIf(param2);
+  left->AddInstruction(store_left);
+  left->AddInstruction(if_left);
+
+  HInstruction* call_left_left = MakeInvoke(DataType::Type::kVoid, { new_inst2 });
+  HInstruction* goto_left_left = new (GetAllocator()) HGoto();
+  left_left->AddInstruction(call_left_left);
+  left_left->AddInstruction(goto_left_left);
+  call_left_left->CopyEnvironmentFrom(new_inst2->GetEnvironment());
+
+  left_right->AddInstruction(new (GetAllocator()) HGoto());
+  left_end->AddInstruction(new (GetAllocator()) HGoto());
+
+  right->AddInstruction(new (GetAllocator()) HGoto());
+
+  // Used to distinguish the pred-gets without having to dig through the
+  // multiple phi layers.
+  constexpr uint32_t kRead1DexPc = 10;
+  constexpr uint32_t kRead2DexPc = 20;
+  HInstruction* read1 =
+      MakeIFieldGet(new_inst1, DataType::Type::kReference, MemberOffset(32), kRead1DexPc);
+  read1->SetReferenceTypeInfo(
+      ReferenceTypeInfo::CreateUnchecked(graph_->GetHandleCache()->GetObjectClassHandle(), false));
+  HInstruction* read2 =
+      MakeIFieldGet(new_inst2, DataType::Type::kReference, MemberOffset(32), kRead2DexPc);
+  read2->SetReferenceTypeInfo(
+      ReferenceTypeInfo::CreateUnchecked(graph_->GetHandleCache()->GetObjectClassHandle(), false));
+  HInstruction* sel_return = new (GetAllocator()) HSelect(param3, read1, read2, 0);
+  HInstruction* return_exit = new (GetAllocator()) HReturn(sel_return);
+  breturn->AddInstruction(read1);
+  breturn->AddInstruction(read2);
+  breturn->AddInstruction(sel_return);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_RETAINED(call_left_left);
+  EXPECT_INS_REMOVED(read1);
+  EXPECT_INS_REMOVED(read2);
+  EXPECT_INS_REMOVED(new_inst1);
+  EXPECT_INS_REMOVED(new_inst2);
+  EXPECT_TRUE(new_inst1->GetUses().empty()) << *new_inst1 << " " << new_inst1->GetUses();
+  EXPECT_TRUE(new_inst2->GetUses().empty()) << *new_inst2 << " " << new_inst2->GetUses();
+  EXPECT_INS_RETAINED(sel_return);
+  // Make sure the selector is the same
+  EXPECT_INS_EQ(sel_return->InputAt(2), param3);
+  std::vector<HPredicatedInstanceFieldGet*> pred_gets;
+  std::tie(pred_gets) = FindAllInstructions<HPredicatedInstanceFieldGet>(graph_, breturn);
+  HPredicatedInstanceFieldGet* pred1 = FindOrNull(pred_gets.begin(), pred_gets.end(), [&](auto i) {
+    return i->GetDexPc() == kRead1DexPc;
+  });
+  HPredicatedInstanceFieldGet* pred2 = FindOrNull(pred_gets.begin(), pred_gets.end(), [&](auto i) {
+    return i->GetDexPc() == kRead2DexPc;
+  });
+  ASSERT_NE(pred1, nullptr);
+  ASSERT_NE(pred2, nullptr);
+  EXPECT_INS_EQ(sel_return->InputAt(0), pred2);
+  EXPECT_INS_EQ(sel_return->InputAt(1), pred1);
+  // Check targets
+  EXPECT_TRUE(pred1->GetTarget()->IsPhi()) << pred1->DumpWithArgs();
+  EXPECT_TRUE(pred2->GetTarget()->IsPhi()) << pred2->DumpWithArgs();
+  HInstruction* mat1 = FindSingleInstruction<HNewInstance>(graph_, left->GetSinglePredecessor());
+  HInstruction* mat2 =
+      FindSingleInstruction<HNewInstance>(graph_, left_left->GetSinglePredecessor());
+  EXPECT_INS_EQ(pred1->GetTarget()->InputAt(0), mat1);
+  EXPECT_INS_EQ(pred1->GetTarget()->InputAt(1), null_const);
+  EXPECT_TRUE(pred2->GetTarget()->InputAt(0)->IsPhi()) << pred2->DumpWithArgs();
+  EXPECT_INS_EQ(pred2->GetTarget()->InputAt(0)->InputAt(0), mat2);
+  EXPECT_INS_EQ(pred2->GetTarget()->InputAt(0)->InputAt(1), null_const);
+  EXPECT_INS_EQ(pred2->GetTarget()->InputAt(1), null_const);
+  // Check default values.
+  EXPECT_TRUE(pred1->GetDefaultValue()->IsPhi()) << pred1->DumpWithArgs();
+  EXPECT_TRUE(pred2->GetDefaultValue()->IsPhi()) << pred2->DumpWithArgs();
+  EXPECT_INS_EQ(pred1->GetDefaultValue()->InputAt(0), null_const);
+  EXPECT_INS_EQ(pred1->GetDefaultValue()->InputAt(1), param_obj1);
+  EXPECT_TRUE(pred2->GetDefaultValue()->InputAt(0)->IsPhi()) << pred2->DumpWithArgs();
+  EXPECT_INS_EQ(pred2->GetDefaultValue()->InputAt(0)->InputAt(0), null_const);
+  EXPECT_INS_EQ(pred2->GetDefaultValue()->InputAt(0)->InputAt(1), mat1);
+  EXPECT_INS_EQ(pred2->GetDefaultValue()->InputAt(1), param_obj2);
+}
+
+// // ENTRY
+// // To be moved
+// // NB Order important. By having alloc and store of obj1 before obj2 that
+// // ensure we'll build the materialization for obj1 first (just due to how
+// // we iterate.)
+// obj1 = new Obj();
+// obj.foo = 12;
+// obj2 = new Obj(); // has env[obj1]
+// obj2.foo = 15;
+// if (param1) {
+//   // LEFT
+//   // Need to update env to nullptr
+//   escape(obj1/2);
+//   if (param2) {
+//     // LEFT_LEFT
+//     escape(obj2/1);
+//   } else {}
+// } else {}
+// return obj1.foo + obj2.foo;
+// EXIT
+TEST_P(OrderDependentTestGroup, PredicatedEnvUse) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "left_left"},
+                                                  {"left", "left_right"},
+                                                  {"left_left", "left_end"},
+                                                  {"left_right", "left_end"},
+                                                  {"left_end", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(right);
+  GET_BLOCK(left);
+  GET_BLOCK(left_left);
+  GET_BLOCK(left_right);
+  GET_BLOCK(left_end);
+#undef GET_BLOCK
+  TestOrder order = GetParam();
+  EnsurePredecessorOrder(breturn, {left_end, right});
+  EnsurePredecessorOrder(left_end, {left_left, left_right});
+  HInstruction* param1 = MakeParam(DataType::Type::kBool);
+  HInstruction* param2 = MakeParam(DataType::Type::kBool);
+  HInstruction* c12 = graph_->GetIntConstant(12);
+  HInstruction* c15 = graph_->GetIntConstant(15);
+
+  HInstruction* cls1 = MakeClassLoad();
+  HInstruction* cls2 = MakeClassLoad();
+  HInstruction* new_inst1 = MakeNewInstance(cls1);
+  HInstruction* store1 = MakeIFieldSet(new_inst1, c12, MemberOffset(32));
+  HInstruction* new_inst2 = MakeNewInstance(cls2);
+  HInstruction* store2 = MakeIFieldSet(new_inst2, c15, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(param1);
+  entry->AddInstruction(cls1);
+  entry->AddInstruction(cls2);
+  entry->AddInstruction(new_inst1);
+  entry->AddInstruction(store1);
+  entry->AddInstruction(new_inst2);
+  entry->AddInstruction(store2);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls1, {});
+  cls2->CopyEnvironmentFrom(cls1->GetEnvironment());
+  new_inst1->CopyEnvironmentFrom(cls1->GetEnvironment());
+  ManuallyBuildEnvFor(new_inst2, {new_inst1});
+
+  HInstruction* first_inst = new_inst1;
+  HInstruction* second_inst = new_inst2;
+
+  if (order == TestOrder::kReverseOfAlloc) {
+    std::swap(first_inst, second_inst);
+  }
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { first_inst });
+  HInstruction* if_left = new (GetAllocator()) HIf(param2);
+  left->AddInstruction(call_left);
+  left->AddInstruction(if_left);
+  call_left->CopyEnvironmentFrom(new_inst2->GetEnvironment());
+
+  HInstruction* call_left_left = MakeInvoke(DataType::Type::kVoid, { second_inst });
+  HInstruction* goto_left_left = new (GetAllocator()) HGoto();
+  left_left->AddInstruction(call_left_left);
+  left_left->AddInstruction(goto_left_left);
+  call_left_left->CopyEnvironmentFrom(new_inst2->GetEnvironment());
+
+  left_right->AddInstruction(new (GetAllocator()) HGoto());
+  left_end->AddInstruction(new (GetAllocator()) HGoto());
+
+  right->AddInstruction(new (GetAllocator()) HGoto());
+
+  HInstruction* read1 = MakeIFieldGet(new_inst1, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* read2 = MakeIFieldGet(new_inst2, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* add_return = new (GetAllocator()) HAdd(DataType::Type::kInt32, read1, read2);
+  HInstruction* return_exit = new (GetAllocator()) HReturn(add_return);
+  breturn->AddInstruction(read1);
+  breturn->AddInstruction(read2);
+  breturn->AddInstruction(add_return);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  HNewInstance* moved_new_inst1;
+  HInstanceFieldSet* moved_set1;
+  HNewInstance* moved_new_inst2;
+  HInstanceFieldSet* moved_set2;
+  HBasicBlock* first_mat_block = left->GetSinglePredecessor();
+  HBasicBlock* second_mat_block = left_left->GetSinglePredecessor();
+  if (order == TestOrder::kReverseOfAlloc) {
+    std::swap(first_mat_block, second_mat_block);
+  }
+  std::tie(moved_new_inst1, moved_set1) =
+      FindSingleInstructions<HNewInstance, HInstanceFieldSet>(graph_, first_mat_block);
+  std::tie(moved_new_inst2, moved_set2) =
+      FindSingleInstructions<HNewInstance, HInstanceFieldSet>(graph_, second_mat_block);
+  std::vector<HPredicatedInstanceFieldGet*> pred_gets;
+  std::vector<HPhi*> phis;
+  std::tie(pred_gets, phis) = FindAllInstructions<HPredicatedInstanceFieldGet, HPhi>(graph_);
+  EXPECT_NE(moved_new_inst1, nullptr);
+  EXPECT_NE(moved_new_inst2, nullptr);
+  EXPECT_NE(moved_set1, nullptr);
+  EXPECT_NE(moved_set2, nullptr);
+  EXPECT_INS_EQ(moved_set1->InputAt(1), c12);
+  EXPECT_INS_EQ(moved_set2->InputAt(1), c15);
+  EXPECT_INS_RETAINED(call_left);
+  EXPECT_INS_RETAINED(call_left_left);
+  EXPECT_INS_REMOVED(store1);
+  EXPECT_INS_REMOVED(store2);
+  EXPECT_INS_REMOVED(read1);
+  EXPECT_INS_REMOVED(read2);
+  EXPECT_INS_EQ(moved_new_inst2->GetEnvironment()->GetInstructionAt(0),
+                order == TestOrder::kSameAsAlloc
+                    ? moved_new_inst1
+                    : static_cast<HInstruction*>(graph_->GetNullConstant()));
+}
+
+// // ENTRY
+// obj1 = new Obj1();
+// obj2 = new Obj2();
+// val1 = 3;
+// val2 = 13;
+// // The exact order the stores are written affects what the order we perform
+// // partial LSE on the values
+// obj1/2.field = val1/2;
+// obj2/1.field = val2/1;
+// if (parameter_value) {
+//   // LEFT
+//   escape(obj1);
+//   escape(obj2);
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj1.field = 2;
+//   obj2.field = 12;
+// }
+// EXIT
+// predicated-ELIMINATE
+// return obj1.field + obj2.field
+TEST_P(OrderDependentTestGroup, FieldSetOrderEnv) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  TestOrder order = GetParam();
+  EnsurePredecessorOrder(breturn, {left, right});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c12 = graph_->GetIntConstant(12);
+  HInstruction* c13 = graph_->GetIntConstant(13);
+
+  HInstruction* cls1 = MakeClassLoad();
+  HInstruction* cls2 = MakeClassLoad();
+  HInstruction* new_inst1 = MakeNewInstance(cls1);
+  HInstruction* new_inst2 = MakeNewInstance(cls2);
+  HInstruction* write_entry1 = MakeIFieldSet(new_inst1, c3, MemberOffset(32));
+  HInstruction* write_entry2 = MakeIFieldSet(new_inst2, c13, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls1);
+  entry->AddInstruction(cls2);
+  entry->AddInstruction(new_inst1);
+  entry->AddInstruction(new_inst2);
+  if (order == TestOrder::kSameAsAlloc) {
+    entry->AddInstruction(write_entry1);
+    entry->AddInstruction(write_entry2);
+  } else {
+    entry->AddInstruction(write_entry2);
+    entry->AddInstruction(write_entry1);
+  }
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls1, {});
+  cls2->CopyEnvironmentFrom(cls1->GetEnvironment());
+  new_inst1->CopyEnvironmentFrom(cls1->GetEnvironment());
+  ManuallyBuildEnvFor(new_inst2, {new_inst1});
+
+  HInstruction* call_left1 = MakeInvoke(DataType::Type::kVoid, { new_inst1 });
+  HInstruction* call_left2 = MakeInvoke(DataType::Type::kVoid, { new_inst2 });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left1);
+  left->AddInstruction(call_left2);
+  left->AddInstruction(goto_left);
+  call_left1->CopyEnvironmentFrom(cls1->GetEnvironment());
+  call_left2->CopyEnvironmentFrom(cls1->GetEnvironment());
+
+  HInstruction* write_right1 = MakeIFieldSet(new_inst1, c2, MemberOffset(32));
+  HInstruction* write_right2 = MakeIFieldSet(new_inst2, c12, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right1);
+  right->AddInstruction(write_right2);
+  right->AddInstruction(goto_right);
+
+  HInstruction* read_bottom1 = MakeIFieldGet(new_inst1, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* read_bottom2 = MakeIFieldGet(new_inst2, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* combine =
+      new (GetAllocator()) HAdd(DataType::Type::kInt32, read_bottom1, read_bottom2);
+  HInstruction* return_exit = new (GetAllocator()) HReturn(combine);
+  breturn->AddInstruction(read_bottom1);
+  breturn->AddInstruction(read_bottom2);
+  breturn->AddInstruction(combine);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(write_entry1);
+  EXPECT_INS_REMOVED(write_entry2);
+  EXPECT_INS_REMOVED(read_bottom1);
+  EXPECT_INS_REMOVED(read_bottom2);
+  EXPECT_INS_REMOVED(write_right1);
+  EXPECT_INS_REMOVED(write_right2);
+  EXPECT_INS_RETAINED(call_left1);
+  EXPECT_INS_RETAINED(call_left2);
+  std::vector<HPhi*> merges;
+  std::vector<HPredicatedInstanceFieldGet*> pred_gets;
+  std::vector<HNewInstance*> materializations;
+  std::tie(merges, pred_gets) =
+      FindAllInstructions<HPhi, HPredicatedInstanceFieldGet>(graph_, breturn);
+  std::tie(materializations) = FindAllInstructions<HNewInstance>(graph_);
+  ASSERT_EQ(merges.size(), 4u);
+  ASSERT_EQ(pred_gets.size(), 2u);
+  ASSERT_EQ(materializations.size(), 2u);
+  HPhi* merge_value_return1 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->InputAt(1) == c2;
+  });
+  HPhi* merge_value_return2 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->InputAt(1) == c12;
+  });
+  HNewInstance* mat_alloc1 = FindOrNull(materializations.begin(),
+                                        materializations.end(),
+                                        [&](HNewInstance* n) { return n->InputAt(0) == cls1; });
+  HNewInstance* mat_alloc2 = FindOrNull(materializations.begin(),
+                                        materializations.end(),
+                                        [&](HNewInstance* n) { return n->InputAt(0) == cls2; });
+  ASSERT_NE(mat_alloc1, nullptr);
+  ASSERT_NE(mat_alloc2, nullptr);
+  HPhi* merge_alloc1 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference && p->InputAt(0) == mat_alloc1;
+  });
+  HPhi* merge_alloc2 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference && p->InputAt(0) == mat_alloc2;
+  });
+  ASSERT_NE(merge_alloc1, nullptr);
+  HPredicatedInstanceFieldGet* pred_get1 =
+      FindOrNull(pred_gets.begin(), pred_gets.end(), [&](HPredicatedInstanceFieldGet* pg) {
+        return pg->GetTarget() == merge_alloc1;
+      });
+  ASSERT_NE(merge_alloc2, nullptr);
+  HPredicatedInstanceFieldGet* pred_get2 =
+      FindOrNull(pred_gets.begin(), pred_gets.end(), [&](HPredicatedInstanceFieldGet* pg) {
+        return pg->GetTarget() == merge_alloc2;
+      });
+  ASSERT_NE(merge_value_return1, nullptr);
+  ASSERT_NE(merge_value_return2, nullptr);
+  EXPECT_INS_EQ(merge_alloc1->InputAt(1), graph_->GetNullConstant());
+  EXPECT_INS_EQ(merge_alloc2->InputAt(1), graph_->GetNullConstant());
+  ASSERT_NE(pred_get1, nullptr);
+  EXPECT_INS_EQ(pred_get1->GetTarget(), merge_alloc1);
+  EXPECT_INS_EQ(pred_get1->GetDefaultValue(), merge_value_return1)
+      << " pred-get is: " << *pred_get1;
+  EXPECT_INS_EQ(merge_value_return1->InputAt(0), graph_->GetIntConstant(0))
+      << " merge val is: " << *merge_value_return1;
+  EXPECT_INS_EQ(merge_value_return1->InputAt(1), c2) << " merge val is: " << *merge_value_return1;
+  ASSERT_NE(pred_get2, nullptr);
+  EXPECT_INS_EQ(pred_get2->GetTarget(), merge_alloc2);
+  EXPECT_INS_EQ(pred_get2->GetDefaultValue(), merge_value_return2)
+      << " pred-get is: " << *pred_get2;
+  EXPECT_INS_EQ(merge_value_return2->InputAt(0), graph_->GetIntConstant(0))
+      << " merge val is: " << *merge_value_return1;
+  EXPECT_INS_EQ(merge_value_return2->InputAt(1), c12) << " merge val is: " << *merge_value_return1;
+  EXPECT_INS_EQ(mat_alloc2->GetEnvironment()->GetInstructionAt(0), mat_alloc1);
+}
+
+// // TODO We can compile this better if we are better able to understand lifetimes.
+// // ENTRY
+// obj1 = new Obj1();
+// obj2 = new Obj2();
+// // The exact order the stores are written affects what the order we perform
+// // partial LSE on the values
+// obj{1,2}.var = param_obj;
+// obj{2,1}.var = param_obj;
+// if (param_1) {
+//   // EARLY_RETURN
+//   return;
+// }
+// // escape of obj1
+// obj2.var = obj1;
+// if (param_2) {
+//   // escape of obj2 with a materialization that uses obj1
+//   escape(obj2);
+// }
+// // EXIT
+// return;
+TEST_P(OrderDependentTestGroup, MaterializationMovedUse) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "early_return"},
+                                                  {"early_return", "exit"},
+                                                  {"entry", "escape_1"},
+                                                  {"escape_1", "escape_2"},
+                                                  {"escape_1", "escape_1_crit_break"},
+                                                  {"escape_1_crit_break", "exit"},
+                                                  {"escape_2", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(early_return);
+  GET_BLOCK(escape_1);
+  GET_BLOCK(escape_1_crit_break);
+  GET_BLOCK(escape_2);
+#undef GET_BLOCK
+  TestOrder order = GetParam();
+  HInstruction* param_1 = MakeParam(DataType::Type::kBool);
+  HInstruction* param_2 = MakeParam(DataType::Type::kBool);
+  HInstruction* param_obj = MakeParam(DataType::Type::kReference);
+
+  HInstruction* cls1 = MakeClassLoad();
+  HInstruction* cls2 = MakeClassLoad();
+  HInstruction* new_inst1 = MakeNewInstance(cls1);
+  HInstruction* new_inst2 = MakeNewInstance(cls2);
+  HInstruction* write_entry1 = MakeIFieldSet(new_inst1, param_obj, MemberOffset(32));
+  HInstruction* write_entry2 = MakeIFieldSet(new_inst2, param_obj, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(param_1);
+  entry->AddInstruction(cls1);
+  entry->AddInstruction(cls2);
+  entry->AddInstruction(new_inst1);
+  entry->AddInstruction(new_inst2);
+  if (order == TestOrder::kSameAsAlloc) {
+    entry->AddInstruction(write_entry1);
+    entry->AddInstruction(write_entry2);
+  } else {
+    entry->AddInstruction(write_entry2);
+    entry->AddInstruction(write_entry1);
+  }
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls1, {});
+  cls2->CopyEnvironmentFrom(cls1->GetEnvironment());
+  new_inst1->CopyEnvironmentFrom(cls1->GetEnvironment());
+  new_inst2->CopyEnvironmentFrom(cls1->GetEnvironment());
+
+  early_return->AddInstruction(new (GetAllocator()) HReturnVoid());
+
+  HInstruction* escape_1_set = MakeIFieldSet(new_inst2, new_inst1, MemberOffset(32));
+  HInstruction* escape_1_if = new (GetAllocator()) HIf(param_2);
+  escape_1->AddInstruction(escape_1_set);
+  escape_1->AddInstruction(escape_1_if);
+
+  escape_1_crit_break->AddInstruction(new (GetAllocator()) HReturnVoid());
+
+  HInstruction* escape_2_call = MakeInvoke(DataType::Type::kVoid, {new_inst2});
+  HInstruction* escape_2_return = new (GetAllocator()) HReturnVoid();
+  escape_2->AddInstruction(escape_2_call);
+  escape_2->AddInstruction(escape_2_return);
+  escape_2_call->CopyEnvironmentFrom(cls1->GetEnvironment());
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(new_inst1);
+  EXPECT_INS_REMOVED(new_inst2);
+  EXPECT_INS_REMOVED(write_entry1);
+  EXPECT_INS_REMOVED(write_entry2);
+  EXPECT_INS_REMOVED(escape_1_set);
+  EXPECT_INS_RETAINED(escape_2_call);
+
+  HInstruction* obj1_mat =
+      FindSingleInstruction<HNewInstance>(graph_, escape_1->GetSinglePredecessor());
+  HInstruction* obj1_set =
+      FindSingleInstruction<HInstanceFieldSet>(graph_, escape_1->GetSinglePredecessor());
+  HInstruction* obj2_mat =
+      FindSingleInstruction<HNewInstance>(graph_, escape_2->GetSinglePredecessor());
+  HInstruction* obj2_set =
+      FindSingleInstruction<HInstanceFieldSet>(graph_, escape_2->GetSinglePredecessor());
+  ASSERT_TRUE(obj1_mat != nullptr);
+  ASSERT_TRUE(obj2_mat != nullptr);
+  ASSERT_TRUE(obj1_set != nullptr);
+  ASSERT_TRUE(obj2_set != nullptr);
+  EXPECT_INS_EQ(obj1_set->InputAt(0), obj1_mat);
+  EXPECT_INS_EQ(obj1_set->InputAt(1), param_obj);
+  EXPECT_INS_EQ(obj2_set->InputAt(0), obj2_mat);
+  EXPECT_INS_EQ(obj2_set->InputAt(1), obj1_mat);
+}
+
+INSTANTIATE_TEST_SUITE_P(LoadStoreEliminationTest,
+                         OrderDependentTestGroup,
+                         testing::Values(TestOrder::kSameAsAlloc, TestOrder::kReverseOfAlloc));
+
+// // ENTRY
+// // To be moved
+// obj = new Obj();
+// obj.foo = 12;
+// if (parameter_value) {
+//   // LEFT
+//   escape(obj);
+// } else {}
+// EXIT
+TEST_F(LoadStoreEliminationTest, MovePredicatedAlloc) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"right", "breturn"},
+                                                  {"left", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {left, right});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c12 = graph_->GetIntConstant(12);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* store = MakeIFieldSet(new_inst, c12, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(store);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  right->AddInstruction(new (GetAllocator()) HGoto());
+
+  HInstruction* return_exit = new (GetAllocator()) HReturnVoid();
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  HNewInstance* moved_new_inst = nullptr;
+  HInstanceFieldSet* moved_set = nullptr;
+  std::tie(moved_new_inst, moved_set) =
+      FindSingleInstructions<HNewInstance, HInstanceFieldSet>(graph_);
+  EXPECT_NE(moved_new_inst, nullptr);
+  EXPECT_NE(moved_set, nullptr);
+  EXPECT_INS_RETAINED(call_left);
+  // store removed or moved.
+  EXPECT_NE(store->GetBlock(), entry);
+  // New-inst removed or moved.
+  EXPECT_NE(new_inst->GetBlock(), entry);
+  EXPECT_INS_EQ(moved_set->InputAt(0), moved_new_inst);
+  EXPECT_INS_EQ(moved_set->InputAt(1), c12);
+}
+
+// // ENTRY
+// // To be moved
+// obj = new Obj();
+// obj.foo = 12;
+// if (parameter_value) {
+//   // LEFT
+//   escape(obj);
+// }
+// EXIT
+// int a = obj.foo;
+// obj.foo = 13;
+// noescape();
+// int b = obj.foo;
+// obj.foo = 14;
+// noescape();
+// int c = obj.foo;
+// obj.foo = 15;
+// noescape();
+// return a + b + c
+TEST_F(LoadStoreEliminationTest, MutiPartialLoadStore) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"right", "breturn"},
+                                                  {"left", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {left, right});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c12 = graph_->GetIntConstant(12);
+  HInstruction* c13 = graph_->GetIntConstant(13);
+  HInstruction* c14 = graph_->GetIntConstant(14);
+  HInstruction* c15 = graph_->GetIntConstant(15);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* store = MakeIFieldSet(new_inst, c12, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(store);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(goto_right);
+
+  HInstruction* a_val = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* a_reset = MakeIFieldSet(new_inst, c13, MemberOffset(32));
+  HInstruction* a_noescape = MakeInvoke(DataType::Type::kVoid, {});
+  HInstruction* b_val = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* b_reset = MakeIFieldSet(new_inst, c14, MemberOffset(32));
+  HInstruction* b_noescape = MakeInvoke(DataType::Type::kVoid, {});
+  HInstruction* c_val = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* c_reset = MakeIFieldSet(new_inst, c15, MemberOffset(32));
+  HInstruction* c_noescape = MakeInvoke(DataType::Type::kVoid, {});
+  HInstruction* add_1_exit = new (GetAllocator()) HAdd(DataType::Type::kInt32, a_val, b_val);
+  HInstruction* add_2_exit = new (GetAllocator()) HAdd(DataType::Type::kInt32, c_val, add_1_exit);
+  HInstruction* return_exit = new (GetAllocator()) HReturn(add_2_exit);
+  breturn->AddInstruction(a_val);
+  breturn->AddInstruction(a_reset);
+  breturn->AddInstruction(a_noescape);
+  breturn->AddInstruction(b_val);
+  breturn->AddInstruction(b_reset);
+  breturn->AddInstruction(b_noescape);
+  breturn->AddInstruction(c_val);
+  breturn->AddInstruction(c_reset);
+  breturn->AddInstruction(c_noescape);
+  breturn->AddInstruction(add_1_exit);
+  breturn->AddInstruction(add_2_exit);
+  breturn->AddInstruction(return_exit);
+  ManuallyBuildEnvFor(a_noescape, {new_inst, a_val});
+  ManuallyBuildEnvFor(b_noescape, {new_inst, a_val, b_val});
+  ManuallyBuildEnvFor(c_noescape, {new_inst, a_val, b_val, c_val});
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  HNewInstance* moved_new_inst = nullptr;
+  HInstanceFieldSet* moved_set = nullptr;
+  std::tie(moved_new_inst, moved_set) =
+      FindSingleInstructions<HNewInstance, HInstanceFieldSet>(graph_, left->GetSinglePredecessor());
+  std::vector<HPredicatedInstanceFieldGet*> pred_gets;
+  std::vector<HInstanceFieldSet*> pred_sets;
+  std::vector<HPhi*> return_phis;
+  std::tie(return_phis, pred_gets, pred_sets) =
+      FindAllInstructions<HPhi, HPredicatedInstanceFieldGet, HInstanceFieldSet>(graph_, breturn);
+  ASSERT_EQ(return_phis.size(), 2u);
+  HPhi* inst_phi = return_phis[0];
+  HPhi* val_phi = return_phis[1];
+  if (inst_phi->GetType() != DataType::Type::kReference) {
+    std::swap(inst_phi, val_phi);
+  }
+  ASSERT_NE(moved_new_inst, nullptr);
+  EXPECT_INS_EQ(inst_phi->InputAt(0), moved_new_inst);
+  EXPECT_INS_EQ(inst_phi->InputAt(1), graph_->GetNullConstant());
+  EXPECT_INS_EQ(val_phi->InputAt(0), graph_->GetIntConstant(0));
+  EXPECT_EQ(val_phi->InputAt(1), c12);
+  ASSERT_EQ(pred_gets.size(), 3u);
+  ASSERT_EQ(pred_gets.size(), pred_sets.size());
+  std::vector<HInstruction*> set_values{c13, c14, c15};
+  std::vector<HInstruction*> get_values{val_phi, c13, c14};
+  ASSERT_NE(moved_set, nullptr);
+  EXPECT_INS_EQ(moved_set->InputAt(0), moved_new_inst);
+  EXPECT_INS_EQ(moved_set->InputAt(1), c12);
+  EXPECT_INS_RETAINED(call_left);
+  // store removed or moved.
+  EXPECT_NE(store->GetBlock(), entry);
+  // New-inst removed or moved.
+  EXPECT_NE(new_inst->GetBlock(), entry);
+  for (auto [get, val] : ZipLeft(MakeIterationRange(pred_gets), MakeIterationRange(get_values))) {
+    EXPECT_INS_EQ(get->GetDefaultValue(), val);
+  }
+  for (auto [set, val] : ZipLeft(MakeIterationRange(pred_sets), MakeIterationRange(set_values))) {
+    EXPECT_INS_EQ(set->InputAt(1), val);
+    EXPECT_TRUE(set->GetIsPredicatedSet()) << *set;
+  }
+  EXPECT_INS_RETAINED(a_noescape);
+  EXPECT_INS_RETAINED(b_noescape);
+  EXPECT_INS_RETAINED(c_noescape);
+  EXPECT_INS_EQ(add_1_exit->InputAt(0), pred_gets[0]);
+  EXPECT_INS_EQ(add_1_exit->InputAt(1), pred_gets[1]);
+  EXPECT_INS_EQ(add_2_exit->InputAt(0), pred_gets[2]);
+
+  EXPECT_EQ(a_noescape->GetEnvironment()->Size(), 2u);
+  EXPECT_INS_EQ(a_noescape->GetEnvironment()->GetInstructionAt(0), inst_phi);
+  EXPECT_INS_EQ(a_noescape->GetEnvironment()->GetInstructionAt(1), pred_gets[0]);
+  EXPECT_EQ(b_noescape->GetEnvironment()->Size(), 3u);
+  EXPECT_INS_EQ(b_noescape->GetEnvironment()->GetInstructionAt(0), inst_phi);
+  EXPECT_INS_EQ(b_noescape->GetEnvironment()->GetInstructionAt(1), pred_gets[0]);
+  EXPECT_INS_EQ(b_noescape->GetEnvironment()->GetInstructionAt(2), pred_gets[1]);
+  EXPECT_EQ(c_noescape->GetEnvironment()->Size(), 4u);
+  EXPECT_INS_EQ(c_noescape->GetEnvironment()->GetInstructionAt(0), inst_phi);
+  EXPECT_INS_EQ(c_noescape->GetEnvironment()->GetInstructionAt(1), pred_gets[0]);
+  EXPECT_INS_EQ(c_noescape->GetEnvironment()->GetInstructionAt(2), pred_gets[1]);
+  EXPECT_INS_EQ(c_noescape->GetEnvironment()->GetInstructionAt(3), pred_gets[2]);
+}
+
+// // ENTRY
+// // To be moved
+// obj = new Obj();
+// obj.foo = 12;
+// int a = obj.foo;
+// obj.foo = 13;
+// noescape();
+// int b = obj.foo;
+// obj.foo = 14;
+// noescape();
+// int c = obj.foo;
+// obj.foo = 15;
+// noescape();
+// if (parameter_value) {
+//   // LEFT
+//   escape(obj);
+// }
+// EXIT
+// return a + b + c + obj.foo
+TEST_F(LoadStoreEliminationTest, MutiPartialLoadStore2) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  // Need to have an actual entry block since we check env-layout and the way we
+  // add constants would screw this up otherwise.
+  AdjacencyListGraph blks(SetupFromAdjacencyList("start",
+                                                 "exit",
+                                                 {{"start", "entry"},
+                                                  {"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"right", "breturn"},
+                                                  {"left", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(start);
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {left, right});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c12 = graph_->GetIntConstant(12);
+  HInstruction* c13 = graph_->GetIntConstant(13);
+  HInstruction* c14 = graph_->GetIntConstant(14);
+  HInstruction* c15 = graph_->GetIntConstant(15);
+
+  HInstruction* start_suspend = new (GetAllocator()) HSuspendCheck();
+  HInstruction* start_goto = new (GetAllocator()) HGoto();
+
+  start->AddInstruction(start_suspend);
+  start->AddInstruction(start_goto);
+  ManuallyBuildEnvFor(start_suspend, {});
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* store = MakeIFieldSet(new_inst, c12, MemberOffset(32));
+
+  HInstruction* a_val = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* a_reset = MakeIFieldSet(new_inst, c13, MemberOffset(32));
+  HInstruction* a_noescape = MakeInvoke(DataType::Type::kVoid, {});
+  HInstruction* b_val = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* b_reset = MakeIFieldSet(new_inst, c14, MemberOffset(32));
+  HInstruction* b_noescape = MakeInvoke(DataType::Type::kVoid, {});
+  HInstruction* c_val = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* c_reset = MakeIFieldSet(new_inst, c15, MemberOffset(32));
+  HInstruction* c_noescape = MakeInvoke(DataType::Type::kVoid, {});
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(store);
+  entry->AddInstruction(a_val);
+  entry->AddInstruction(a_reset);
+  entry->AddInstruction(a_noescape);
+  entry->AddInstruction(b_val);
+  entry->AddInstruction(b_reset);
+  entry->AddInstruction(b_noescape);
+  entry->AddInstruction(c_val);
+  entry->AddInstruction(c_reset);
+  entry->AddInstruction(c_noescape);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+  ManuallyBuildEnvFor(a_noescape, {new_inst, a_val});
+  ManuallyBuildEnvFor(b_noescape, {new_inst, a_val, b_val});
+  ManuallyBuildEnvFor(c_noescape, {new_inst, a_val, b_val, c_val});
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(c_noescape->GetEnvironment());
+
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(goto_right);
+
+  HInstruction* val_exit = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* add_1_exit = new (GetAllocator()) HAdd(DataType::Type::kInt32, a_val, b_val);
+  HInstruction* add_2_exit = new (GetAllocator()) HAdd(DataType::Type::kInt32, c_val, add_1_exit);
+  HInstruction* add_3_exit =
+      new (GetAllocator()) HAdd(DataType::Type::kInt32, val_exit, add_2_exit);
+  HInstruction* return_exit = new (GetAllocator()) HReturn(add_3_exit);
+  breturn->AddInstruction(val_exit);
+  breturn->AddInstruction(add_1_exit);
+  breturn->AddInstruction(add_2_exit);
+  breturn->AddInstruction(add_3_exit);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  HNewInstance* moved_new_inst = nullptr;
+  HInstanceFieldSet* moved_set = nullptr;
+  std::tie(moved_new_inst, moved_set) =
+      FindSingleInstructions<HNewInstance, HInstanceFieldSet>(graph_, left->GetSinglePredecessor());
+  std::vector<HPredicatedInstanceFieldGet*> pred_gets;
+  std::vector<HInstanceFieldSet*> pred_sets;
+  std::vector<HPhi*> return_phis;
+  std::tie(return_phis, pred_gets, pred_sets) =
+      FindAllInstructions<HPhi, HPredicatedInstanceFieldGet, HInstanceFieldSet>(graph_, breturn);
+  ASSERT_EQ(return_phis.size(), 2u);
+  HPhi* inst_phi = return_phis[0];
+  HPhi* val_phi = return_phis[1];
+  if (inst_phi->GetType() != DataType::Type::kReference) {
+    std::swap(inst_phi, val_phi);
+  }
+  ASSERT_NE(moved_new_inst, nullptr);
+  EXPECT_INS_EQ(inst_phi->InputAt(0), moved_new_inst);
+  EXPECT_INS_EQ(inst_phi->InputAt(1), graph_->GetNullConstant());
+  EXPECT_INS_EQ(val_phi->InputAt(0), graph_->GetIntConstant(0));
+  EXPECT_INS_EQ(val_phi->InputAt(1), c15);
+  ASSERT_EQ(pred_gets.size(), 1u);
+  ASSERT_EQ(pred_sets.size(), 0u);
+  ASSERT_NE(moved_set, nullptr);
+  EXPECT_INS_EQ(moved_set->InputAt(0), moved_new_inst);
+  EXPECT_INS_EQ(moved_set->InputAt(1), c15);
+  EXPECT_INS_RETAINED(call_left);
+  // store removed or moved.
+  EXPECT_NE(store->GetBlock(), entry);
+  // New-inst removed or moved.
+  EXPECT_NE(new_inst->GetBlock(), entry);
+  EXPECT_INS_REMOVED(a_val);
+  EXPECT_INS_REMOVED(b_val);
+  EXPECT_INS_REMOVED(c_val);
+  EXPECT_INS_RETAINED(a_noescape);
+  EXPECT_INS_RETAINED(b_noescape);
+  EXPECT_INS_RETAINED(c_noescape);
+  EXPECT_INS_EQ(add_1_exit->InputAt(0), c12);
+  EXPECT_INS_EQ(add_1_exit->InputAt(1), c13);
+  EXPECT_INS_EQ(add_2_exit->InputAt(0), c14);
+  EXPECT_INS_EQ(add_2_exit->InputAt(1), add_1_exit);
+  EXPECT_INS_EQ(add_3_exit->InputAt(0), pred_gets[0]);
+  EXPECT_INS_EQ(pred_gets[0]->GetDefaultValue(), val_phi);
+  EXPECT_INS_EQ(add_3_exit->InputAt(1), add_2_exit);
+  EXPECT_EQ(a_noescape->GetEnvironment()->Size(), 2u);
+  EXPECT_INS_EQ(a_noescape->GetEnvironment()->GetInstructionAt(0), graph_->GetNullConstant());
+  EXPECT_INS_EQ(a_noescape->GetEnvironment()->GetInstructionAt(1), c12);
+  EXPECT_EQ(b_noescape->GetEnvironment()->Size(), 3u);
+  EXPECT_INS_EQ(b_noescape->GetEnvironment()->GetInstructionAt(0), graph_->GetNullConstant());
+  EXPECT_INS_EQ(b_noescape->GetEnvironment()->GetInstructionAt(1), c12);
+  EXPECT_INS_EQ(b_noescape->GetEnvironment()->GetInstructionAt(2), c13);
+  EXPECT_EQ(c_noescape->GetEnvironment()->Size(), 4u);
+  EXPECT_INS_EQ(c_noescape->GetEnvironment()->GetInstructionAt(0), graph_->GetNullConstant());
+  EXPECT_INS_EQ(c_noescape->GetEnvironment()->GetInstructionAt(1), c12);
+  EXPECT_INS_EQ(c_noescape->GetEnvironment()->GetInstructionAt(2), c13);
+  EXPECT_INS_EQ(c_noescape->GetEnvironment()->GetInstructionAt(3), c14);
+}
+
+// // ENTRY
+// // To be moved
+// obj = new Obj();
+// // Transforms required for creation non-trivial and unimportant
+// if (parameter_value) {
+//   obj.foo = 10
+// } else {
+//   obj.foo = 12;
+// }
+// if (parameter_value_2) {
+//   escape(obj);
+// }
+// EXIT
+TEST_F(LoadStoreEliminationTest, MovePredicatedAlloc2) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left_set"},
+                                                  {"entry", "right_set"},
+                                                  {"left_set", "merge_crit_break"},
+                                                  {"right_set", "merge_crit_break"},
+                                                  {"merge_crit_break", "merge"},
+                                                  {"merge", "escape"},
+                                                  {"escape", "breturn"},
+                                                  {"merge", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left_set);
+  GET_BLOCK(right_set);
+  GET_BLOCK(merge);
+  GET_BLOCK(merge_crit_break);
+  GET_BLOCK(escape);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {merge, escape});
+  EnsurePredecessorOrder(merge_crit_break, {left_set, right_set});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* bool_value_2 = MakeParam(DataType::Type::kBool);
+  HInstruction* c10 = graph_->GetIntConstant(10);
+  HInstruction* c12 = graph_->GetIntConstant(12);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* store_left = MakeIFieldSet(new_inst, c10, MemberOffset(32));
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left_set->AddInstruction(store_left);
+  left_set->AddInstruction(goto_left);
+
+  HInstruction* store_right = MakeIFieldSet(new_inst, c12, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right_set->AddInstruction(store_right);
+  right_set->AddInstruction(goto_right);
+
+  merge_crit_break->AddInstruction(new (GetAllocator()) HGoto());
+  HInstruction* if_merge = new (GetAllocator()) HIf(bool_value_2);
+  merge->AddInstruction(if_merge);
+
+  HInstruction* escape_instruction = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* escape_goto = new (GetAllocator()) HGoto();
+  escape->AddInstruction(escape_instruction);
+  escape->AddInstruction(escape_goto);
+  escape_instruction->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* return_exit = new (GetAllocator()) HReturnVoid();
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  HNewInstance* moved_new_inst;
+  HInstanceFieldSet* moved_set;
+  std::tie(moved_new_inst, moved_set) =
+      FindSingleInstructions<HNewInstance, HInstanceFieldSet>(graph_);
+  HPhi* merge_phi = FindSingleInstruction<HPhi>(graph_, merge_crit_break);
+  HPhi* alloc_phi = FindSingleInstruction<HPhi>(graph_, breturn);
+  EXPECT_INS_EQ(moved_new_inst, moved_set->InputAt(0));
+  ASSERT_NE(alloc_phi, nullptr);
+  EXPECT_EQ(alloc_phi->InputAt(0), graph_->GetNullConstant())
+      << alloc_phi->GetBlock()->GetPredecessors()[0]->GetBlockId() << " " << *alloc_phi;
+  EXPECT_TRUE(alloc_phi->InputAt(1)->IsNewInstance()) << *alloc_phi;
+  ASSERT_NE(merge_phi, nullptr);
+  EXPECT_EQ(merge_phi->InputCount(), 2u);
+  EXPECT_INS_EQ(merge_phi->InputAt(0), c10);
+  EXPECT_INS_EQ(merge_phi->InputAt(1), c12);
+  EXPECT_TRUE(merge_phi->GetUses().HasExactlyOneElement());
+  EXPECT_INS_EQ(merge_phi->GetUses().front().GetUser(), moved_set);
+  EXPECT_INS_RETAINED(escape_instruction);
+  EXPECT_INS_EQ(escape_instruction->InputAt(0), moved_new_inst);
+  // store removed or moved.
+  EXPECT_NE(store_left->GetBlock(), left_set);
+  EXPECT_NE(store_right->GetBlock(), left_set);
+  // New-inst removed or moved.
+  EXPECT_NE(new_inst->GetBlock(), entry);
+}
+
+// // ENTRY
+// // To be moved
+// obj = new Obj();
+// switch(args) {
+//   default:
+//     return obj.a;
+//   case b:
+//     obj.a = 5; break;
+//   case c:
+//     obj.b = 4; break;
+// }
+// escape(obj);
+// return obj.a;
+// EXIT
+TEST_F(LoadStoreEliminationTest, MovePredicatedAlloc3) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "early_return"},
+                                                  {"entry", "set_one"},
+                                                  {"entry", "set_two"},
+                                                  {"early_return", "exit"},
+                                                  {"set_one", "escape"},
+                                                  {"set_two", "escape"},
+                                                  {"escape", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(escape);
+  GET_BLOCK(early_return);
+  GET_BLOCK(set_one);
+  GET_BLOCK(set_two);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(escape, {set_one, set_two});
+  HInstruction* int_val = MakeParam(DataType::Type::kInt32);
+  HInstruction* c0 = graph_->GetIntConstant(0);
+  HInstruction* c4 = graph_->GetIntConstant(4);
+  HInstruction* c5 = graph_->GetIntConstant(5);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, int_val);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(switch_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* store_one = MakeIFieldSet(new_inst, c4, MemberOffset(32));
+  HInstruction* goto_one = new (GetAllocator()) HGoto();
+  set_one->AddInstruction(store_one);
+  set_one->AddInstruction(goto_one);
+
+  HInstruction* store_two = MakeIFieldSet(new_inst, c5, MemberOffset(32));
+  HInstruction* goto_two = new (GetAllocator()) HGoto();
+  set_two->AddInstruction(store_two);
+  set_two->AddInstruction(goto_two);
+
+  HInstruction* read_early = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_early = new (GetAllocator()) HReturn(read_early);
+  early_return->AddInstruction(read_early);
+  early_return->AddInstruction(return_early);
+
+  HInstruction* escape_instruction = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* read_escape = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_escape = new (GetAllocator()) HReturn(read_escape);
+  escape->AddInstruction(escape_instruction);
+  escape->AddInstruction(read_escape);
+  escape->AddInstruction(return_escape);
+  escape_instruction->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  // Each escaping switch path gets its own materialization block.
+  // Blocks:
+  //   early_return(5) -> [exit(4)]
+  //   entry(3) -> [early_return(5), <Unnamed>(9), <Unnamed>(10)]
+  //   escape(8) -> [exit(4)]
+  //   exit(4) -> []
+  //   set_one(6) -> [escape(8)]
+  //   set_two(7) -> [escape(8)]
+  //   <Unnamed>(10) -> [set_two(7)]
+  //   <Unnamed>(9) -> [set_one(6)]
+  HBasicBlock* materialize_one = set_one->GetSinglePredecessor();
+  HBasicBlock* materialize_two = set_two->GetSinglePredecessor();
+  HNewInstance* materialization_ins_one =
+      FindSingleInstruction<HNewInstance>(graph_, materialize_one);
+  HNewInstance* materialization_ins_two =
+      FindSingleInstruction<HNewInstance>(graph_, materialize_two);
+  HPhi* new_phi = FindSingleInstruction<HPhi>(graph_, escape);
+  EXPECT_NE(materialization_ins_one, nullptr);
+  EXPECT_NE(materialization_ins_two, nullptr);
+  EXPECT_EQ(materialization_ins_one, new_phi->InputAt(0))
+      << *materialization_ins_one << " vs " << *new_phi;
+  EXPECT_EQ(materialization_ins_two, new_phi->InputAt(1))
+      << *materialization_ins_two << " vs " << *new_phi;
+
+  EXPECT_INS_RETAINED(escape_instruction);
+  EXPECT_INS_RETAINED(read_escape);
+  EXPECT_EQ(read_escape->InputAt(0), new_phi) << *new_phi << " vs " << *read_escape->InputAt(0);
+  EXPECT_EQ(store_one->InputAt(0), materialization_ins_one);
+  EXPECT_EQ(store_two->InputAt(0), materialization_ins_two);
+  EXPECT_EQ(escape_instruction->InputAt(0), new_phi);
+  EXPECT_INS_REMOVED(read_early);
+  EXPECT_EQ(return_early->InputAt(0), c0);
+}
+
+// // ENTRY
+// // To be moved
+// obj = new Obj();
+// switch(args) {
+//   case a:
+//     // set_one_and_escape
+//     obj.a = 5;
+//     escape(obj);
+//     // FALLTHROUGH
+//   case c:
+//     // set_two
+//     obj.a = 4; break;
+//   default:
+//     return obj.a;
+// }
+// escape(obj);
+// return obj.a;
+// EXIT
+TEST_F(LoadStoreEliminationTest, MovePredicatedAlloc4) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  // Break the critical edge between entry and set_two with the
+  // set_two_critical_break node. Graph simplification would do this for us if
+  // we didn't do it manually. This way we have a nice-name for debugging and
+  // testing.
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "early_return"},
+                                                  {"entry", "set_one_and_escape"},
+                                                  {"entry", "set_two_critical_break"},
+                                                  {"set_two_critical_break", "set_two"},
+                                                  {"early_return", "exit"},
+                                                  {"set_one_and_escape", "set_two"},
+                                                  {"set_two", "escape"},
+                                                  {"escape", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(escape);
+  GET_BLOCK(early_return);
+  GET_BLOCK(set_one_and_escape);
+  GET_BLOCK(set_two);
+  GET_BLOCK(set_two_critical_break);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(set_two, {set_one_and_escape, set_two_critical_break});
+  HInstruction* int_val = MakeParam(DataType::Type::kInt32);
+  HInstruction* c0 = graph_->GetIntConstant(0);
+  HInstruction* c4 = graph_->GetIntConstant(4);
+  HInstruction* c5 = graph_->GetIntConstant(5);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, int_val);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(switch_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* store_one = MakeIFieldSet(new_inst, c4, MemberOffset(32));
+  HInstruction* escape_one = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_one = new (GetAllocator()) HGoto();
+  set_one_and_escape->AddInstruction(store_one);
+  set_one_and_escape->AddInstruction(escape_one);
+  set_one_and_escape->AddInstruction(goto_one);
+  escape_one->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_crit_break = new (GetAllocator()) HGoto();
+  set_two_critical_break->AddInstruction(goto_crit_break);
+
+  HInstruction* store_two = MakeIFieldSet(new_inst, c5, MemberOffset(32));
+  HInstruction* goto_two = new (GetAllocator()) HGoto();
+  set_two->AddInstruction(store_two);
+  set_two->AddInstruction(goto_two);
+
+  HInstruction* read_early = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_early = new (GetAllocator()) HReturn(read_early);
+  early_return->AddInstruction(read_early);
+  early_return->AddInstruction(return_early);
+
+  HInstruction* escape_instruction = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* read_escape = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_escape = new (GetAllocator()) HReturn(read_escape);
+  escape->AddInstruction(escape_instruction);
+  escape->AddInstruction(read_escape);
+  escape->AddInstruction(return_escape);
+  escape_instruction->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(read_early);
+  EXPECT_EQ(return_early->InputAt(0), c0);
+  // Each escaping switch path gets its own materialization block.
+  // Blocks:
+  //   early_return(5) -> [exit(4)]
+  //   entry(3) -> [early_return(5), <Unnamed>(10), <Unnamed>(11)]
+  //   escape(9) -> [exit(4)]
+  //   exit(4) -> []
+  //   set_one_and_escape(6) -> [set_two(8)]
+  //   set_two(8) -> [escape(9)]
+  //   set_two_critical_break(7) -> [set_two(8)]
+  //   <Unnamed>(11) -> [set_two_critical_break(7)]
+  //   <Unnamed>(10) -> [set_one_and_escape(6)]
+  HBasicBlock* materialize_one = set_one_and_escape->GetSinglePredecessor();
+  HBasicBlock* materialize_two = set_two_critical_break->GetSinglePredecessor();
+  HNewInstance* materialization_ins_one =
+      FindSingleInstruction<HNewInstance>(graph_, materialize_one);
+  HNewInstance* materialization_ins_two =
+      FindSingleInstruction<HNewInstance>(graph_, materialize_two);
+  HPhi* new_phi = FindSingleInstruction<HPhi>(graph_, set_two);
+  ASSERT_NE(new_phi, nullptr);
+  ASSERT_NE(materialization_ins_one, nullptr);
+  ASSERT_NE(materialization_ins_two, nullptr);
+  EXPECT_INS_EQ(materialization_ins_one, new_phi->InputAt(0));
+  EXPECT_INS_EQ(materialization_ins_two, new_phi->InputAt(1));
+
+  EXPECT_INS_EQ(store_one->InputAt(0), materialization_ins_one);
+  EXPECT_INS_EQ(store_two->InputAt(0), new_phi) << *store_two << " vs " << *new_phi;
+  EXPECT_INS_EQ(escape_instruction->InputAt(0), new_phi);
+  EXPECT_INS_RETAINED(escape_one);
+  EXPECT_INS_EQ(escape_one->InputAt(0), materialization_ins_one);
+  EXPECT_INS_RETAINED(escape_instruction);
+  EXPECT_INS_RETAINED(read_escape);
+  EXPECT_EQ(read_escape->InputAt(0), new_phi) << *new_phi << " vs " << *read_escape->InputAt(0);
+}
+
+// // ENTRY
+// // To be moved
+// obj = new Obj();
+// switch(args) {
+//   case a:
+//     // set_one
+//     obj.a = 5;
+//     // nb passthrough
+//   case c:
+//     // set_two_and_escape
+//     obj.a += 4;
+//     escape(obj);
+//     break;
+//   default:
+//     obj.a = 10;
+// }
+// return obj.a;
+// EXIT
+TEST_F(LoadStoreEliminationTest, MovePredicatedAlloc5) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  // Break the critical edge between entry and set_two with the
+  // set_two_critical_break node. Graph simplification would do this for us if
+  // we didn't do it manually. This way we have a nice-name for debugging and
+  // testing.
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "set_noescape"},
+                                                  {"entry", "set_one"},
+                                                  {"entry", "set_two_critical_break"},
+                                                  {"set_two_critical_break", "set_two_and_escape"},
+                                                  {"set_noescape", "breturn"},
+                                                  {"set_one", "set_two_and_escape"},
+                                                  {"set_two_and_escape", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(set_noescape);
+  GET_BLOCK(set_one);
+  GET_BLOCK(set_two_and_escape);
+  GET_BLOCK(set_two_critical_break);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(set_two_and_escape, {set_one, set_two_critical_break});
+  EnsurePredecessorOrder(breturn, {set_two_and_escape, set_noescape});
+  HInstruction* int_val = MakeParam(DataType::Type::kInt32);
+  HInstruction* c0 = graph_->GetIntConstant(0);
+  HInstruction* c4 = graph_->GetIntConstant(4);
+  HInstruction* c5 = graph_->GetIntConstant(5);
+  HInstruction* c10 = graph_->GetIntConstant(10);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, int_val);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(switch_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* store_one = MakeIFieldSet(new_inst, c5, MemberOffset(32));
+  HInstruction* goto_one = new (GetAllocator()) HGoto();
+  set_one->AddInstruction(store_one);
+  set_one->AddInstruction(goto_one);
+
+  HInstruction* goto_crit_break = new (GetAllocator()) HGoto();
+  set_two_critical_break->AddInstruction(goto_crit_break);
+
+  HInstruction* get_two = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* add_two = new (GetAllocator()) HAdd(DataType::Type::kInt32, get_two, c4);
+  HInstruction* store_two = MakeIFieldSet(new_inst, add_two, MemberOffset(32));
+  HInstruction* escape_two = MakeInvoke(DataType::Type::kVoid, {new_inst});
+  HInstruction* goto_two = new (GetAllocator()) HGoto();
+  set_two_and_escape->AddInstruction(get_two);
+  set_two_and_escape->AddInstruction(add_two);
+  set_two_and_escape->AddInstruction(store_two);
+  set_two_and_escape->AddInstruction(escape_two);
+  set_two_and_escape->AddInstruction(goto_two);
+  escape_two->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* store_noescape = MakeIFieldSet(new_inst, c10, MemberOffset(32));
+  HInstruction* goto_noescape = new (GetAllocator()) HGoto();
+  set_noescape->AddInstruction(store_noescape);
+  set_noescape->AddInstruction(goto_noescape);
+
+  HInstruction* read_breturn = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_breturn = new (GetAllocator()) HReturn(read_breturn);
+  breturn->AddInstruction(read_breturn);
+  breturn->AddInstruction(return_breturn);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  // Normal LSE can get rid of these two.
+  EXPECT_INS_REMOVED(store_one);
+  EXPECT_INS_REMOVED(get_two);
+  EXPECT_INS_RETAINED(add_two);
+  EXPECT_TRUE(add_two->InputAt(0)->IsPhi());
+  EXPECT_INS_EQ(add_two->InputAt(0)->InputAt(0), c5);
+  EXPECT_INS_EQ(add_two->InputAt(0)->InputAt(1), c0);
+  EXPECT_INS_EQ(add_two->InputAt(1), c4);
+
+  HBasicBlock* materialize_one = set_one->GetSinglePredecessor();
+  HBasicBlock* materialize_two = set_two_critical_break->GetSinglePredecessor();
+  HNewInstance* materialization_ins_one =
+      FindSingleInstruction<HNewInstance>(graph_, materialize_one);
+  HNewInstance* materialization_ins_two =
+      FindSingleInstruction<HNewInstance>(graph_, materialize_two);
+  std::vector<HPhi*> phis;
+  std::tie(phis) = FindAllInstructions<HPhi>(graph_, set_two_and_escape);
+  HPhi* new_phi = FindOrNull(
+      phis.begin(), phis.end(), [&](auto p) { return p->GetType() == DataType::Type::kReference; });
+  ASSERT_NE(new_phi, nullptr);
+  ASSERT_NE(materialization_ins_one, nullptr);
+  ASSERT_NE(materialization_ins_two, nullptr);
+  EXPECT_INS_EQ(materialization_ins_one, new_phi->InputAt(0));
+  EXPECT_INS_EQ(materialization_ins_two, new_phi->InputAt(1));
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  EXPECT_TRUE(pred_get->GetTarget()->IsPhi());
+  EXPECT_INS_EQ(pred_get->GetTarget()->InputAt(0), new_phi);
+  EXPECT_INS_EQ(pred_get->GetTarget()->InputAt(1), graph_->GetNullConstant());
+
+  EXPECT_INS_EQ(pred_get->GetDefaultValue()->InputAt(0), c0);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue()->InputAt(1), c10);
 }
 
 // // ENTRY
@@ -2421,117 +4171,59 @@
 // }
 // EXIT
 TEST_F(LoadStoreEliminationTest, PartialLoadElimination3) {
-  InitGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blks(SetupFromAdjacencyList(
       "entry",
       "exit",
-      { { "entry", "left" }, { "entry", "right" }, { "left", "exit" }, { "right", "exit" } }));
+      {{"entry", "left"}, {"entry", "right"}, {"left", "exit"}, {"right", "exit"}}));
 #define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
   GET_BLOCK(entry);
   GET_BLOCK(exit);
   GET_BLOCK(left);
   GET_BLOCK(right);
 #undef GET_BLOCK
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
-  entry->AddInstruction(bool_value);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(if_inst);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_left = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                    c1,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(32),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
-  HInstruction* call_left = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  HInstruction* read_left = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                   nullptr,
-                                                                   DataType::Type::kInt32,
-                                                                   MemberOffset(32),
-                                                                   false,
-                                                                   0,
-                                                                   0,
-                                                                   graph_->GetDexFile(),
-                                                                   0);
+  HInstruction* write_left = MakeIFieldSet(new_inst, c1, MemberOffset(32));
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* read_left = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_left = new (GetAllocator()) HReturn(read_left);
-  call_left->AsInvoke()->SetRawInputAt(0, new_inst);
   left->AddInstruction(write_left);
   left->AddInstruction(call_left);
   left->AddInstruction(read_left);
   left->AddInstruction(return_left);
   call_left->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c2,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
-  HInstruction* read_right = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(32),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* read_right = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_right = new (GetAllocator()) HReturn(read_right);
   right->AddInstruction(write_right);
   right->AddInstruction(read_right);
   right->AddInstruction(return_right);
 
-  HInstruction* exit_instruction = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_instruction);
+  SetupExit(exit);
+
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
   PerformLSE();
 
-  EXPECT_TRUE(IsRemoved(read_right));
-  EXPECT_TRUE(IsRemoved(write_right));
-  EXPECT_FALSE(IsRemoved(write_left));
-  EXPECT_FALSE(IsRemoved(call_left));
-  EXPECT_FALSE(IsRemoved(read_left));
+  EXPECT_INS_REMOVED(read_right);
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_RETAINED(write_left);
+  EXPECT_INS_RETAINED(call_left);
+  EXPECT_INS_RETAINED(read_left);
 }
 
 // // ENTRY
@@ -2556,17 +4248,18 @@
 // }
 // EXIT
 TEST_F(LoadStoreEliminationTest, PartialLoadElimination4) {
-  InitGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit",
-                                                 { { "entry", "entry_post" },
-                                                   { "entry_post", "right" },
-                                                   { "right", "exit" },
-                                                   { "entry_post", "left_pre" },
-                                                   { "left_pre", "left_loop" },
-                                                   { "left_loop", "left_loop" },
-                                                   { "left_loop", "left_finish" },
-                                                   { "left_finish", "exit" } }));
+                                                 {{"entry", "entry_post"},
+                                                  {"entry_post", "right"},
+                                                  {"right", "exit"},
+                                                  {"entry_post", "left_pre"},
+                                                  {"left_pre", "left_loop"},
+                                                  {"left_loop", "left_loop"},
+                                                  {"left_loop", "left_finish"},
+                                                  {"left_finish", "exit"}}));
 #define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
   GET_BLOCK(entry);
   GET_BLOCK(entry_post);
@@ -2580,75 +4273,32 @@
   if (left_loop->GetSuccessors()[0] != left_finish) {
     left_loop->SwapSuccessors();
   }
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
   HInstruction* c3 = graph_->GetIntConstant(3);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* goto_entry = new (GetAllocator()) HGoto();
-  entry->AddInstruction(bool_value);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(goto_entry);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
 
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
   entry_post->AddInstruction(if_inst);
 
-  HInstruction* write_left_pre = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                        c1,
-                                                                        nullptr,
-                                                                        DataType::Type::kInt32,
-                                                                        MemberOffset(32),
-                                                                        false,
-                                                                        0,
-                                                                        0,
-                                                                        graph_->GetDexFile(),
-                                                                        0);
+  HInstruction* write_left_pre = MakeIFieldSet(new_inst, c1, MemberOffset(32));
   HInstruction* goto_left_pre = new (GetAllocator()) HGoto();
   left_pre->AddInstruction(write_left_pre);
   left_pre->AddInstruction(goto_left_pre);
 
   HInstruction* suspend_left_loop = new (GetAllocator()) HSuspendCheck();
-  HInstruction* call_left_loop = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kBool,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  HInstruction* write_left_loop = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                         c3,
-                                                                         nullptr,
-                                                                         DataType::Type::kInt32,
-                                                                         MemberOffset(32),
-                                                                         false,
-                                                                         0,
-                                                                         0,
-                                                                         graph_->GetDexFile(),
-                                                                         0);
+  HInstruction* call_left_loop = MakeInvoke(DataType::Type::kBool, { new_inst });
+  HInstruction* write_left_loop = MakeIFieldSet(new_inst, c3, MemberOffset(32));
   HInstruction* if_left_loop = new (GetAllocator()) HIf(call_left_loop);
-  call_left_loop->AsInvoke()->SetRawInputAt(0, new_inst);
   left_loop->AddInstruction(suspend_left_loop);
   left_loop->AddInstruction(call_left_loop);
   left_loop->AddInstruction(write_left_loop);
@@ -2656,55 +4306,30 @@
   suspend_left_loop->CopyEnvironmentFrom(cls->GetEnvironment());
   call_left_loop->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* read_left_end = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                       nullptr,
-                                                                       DataType::Type::kInt32,
-                                                                       MemberOffset(32),
-                                                                       false,
-                                                                       0,
-                                                                       0,
-                                                                       graph_->GetDexFile(),
-                                                                       0);
+  HInstruction* read_left_end = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_left_end = new (GetAllocator()) HReturn(read_left_end);
   left_finish->AddInstruction(read_left_end);
   left_finish->AddInstruction(return_left_end);
 
-  HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c2,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
-  HInstruction* read_right = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(32),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* read_right = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_right = new (GetAllocator()) HReturn(read_right);
   right->AddInstruction(write_right);
   right->AddInstruction(read_right);
   right->AddInstruction(return_right);
 
-  HInstruction* exit_instruction = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_instruction);
+  SetupExit(exit);
+
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
   PerformLSE();
 
-  EXPECT_FALSE(IsRemoved(write_left_pre));
-  EXPECT_TRUE(IsRemoved(read_right));
-  EXPECT_TRUE(IsRemoved(write_right));
-  EXPECT_FALSE(IsRemoved(write_left_loop));
-  EXPECT_FALSE(IsRemoved(call_left_loop));
-  EXPECT_TRUE(IsRemoved(read_left_end));
+  EXPECT_INS_RETAINED(write_left_pre);
+  EXPECT_INS_REMOVED(read_right);
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_RETAINED(write_left_loop);
+  EXPECT_INS_RETAINED(call_left_loop);
+  EXPECT_INS_REMOVED(read_left_end);
 }
 
 // // ENTRY
@@ -2725,14 +4350,15 @@
 // ELIMINATE
 // return obj.field
 TEST_F(LoadStoreEliminationTest, PartialLoadElimination5) {
-  InitGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit",
-                                                 { { "entry", "left" },
-                                                   { "entry", "right" },
-                                                   { "left", "breturn" },
-                                                   { "right", "breturn" },
-                                                   { "breturn", "exit" } }));
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
 #define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
   GET_BLOCK(entry);
   GET_BLOCK(exit);
@@ -2740,112 +4366,51 @@
   GET_BLOCK(left);
   GET_BLOCK(right);
 #undef GET_BLOCK
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
-  entry->AddInstruction(bool_value);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(if_inst);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* call_left = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  HInstruction* write_left = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                    c1,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(32),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* write_left = MakeIFieldSet(new_inst, c1, MemberOffset(32));
   HInstruction* goto_left = new (GetAllocator()) HGoto();
-  call_left->AsInvoke()->SetRawInputAt(0, new_inst);
   left->AddInstruction(call_left);
   left->AddInstruction(write_left);
   left->AddInstruction(goto_left);
   call_left->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c2,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
-  HInstruction* call_right = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            0,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* call_right = MakeInvoke(DataType::Type::kVoid, {});
   HInstruction* goto_right = new (GetAllocator()) HGoto();
   right->AddInstruction(write_right);
   right->AddInstruction(call_right);
   right->AddInstruction(goto_right);
   call_right->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* read_bottom = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
   breturn->AddInstruction(read_bottom);
   breturn->AddInstruction(return_exit);
 
-  HInstruction* exit_instruction = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_instruction);
+  SetupExit(exit);
+
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
   PerformLSE();
 
-  EXPECT_TRUE(IsRemoved(read_bottom));
-  EXPECT_TRUE(IsRemoved(write_right));
-  EXPECT_FALSE(IsRemoved(write_left));
-  EXPECT_FALSE(IsRemoved(call_left));
-  EXPECT_FALSE(IsRemoved(call_right));
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_RETAINED(write_left);
+  EXPECT_INS_RETAINED(call_left);
+  EXPECT_INS_RETAINED(call_right);
 }
 
 // // ENTRY
@@ -2866,16 +4431,17 @@
 // }
 // EXIT
 // ELIMINATE
-// return obj.field
+// return obj.fid
 TEST_F(LoadStoreEliminationTest, PartialLoadElimination6) {
-  InitGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit",
-                                                 { { "entry", "left" },
-                                                   { "entry", "right" },
-                                                   { "left", "breturn" },
-                                                   { "right", "breturn" },
-                                                   { "breturn", "exit" } }));
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
 #define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
   GET_BLOCK(entry);
   GET_BLOCK(exit);
@@ -2883,138 +4449,59 @@
   GET_BLOCK(left);
   GET_BLOCK(right);
 #undef GET_BLOCK
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
   HInstruction* c3 = graph_->GetIntConstant(3);
   HInstruction* c5 = graph_->GetIntConstant(5);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
-  HInstruction* write_entry = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c3,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
-  HInstruction* call_entry = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            0,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_entry = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* call_entry = MakeInvoke(DataType::Type::kVoid, {});
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
-  entry->AddInstruction(bool_value);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(write_entry);
   entry->AddInstruction(call_entry);
   entry->AddInstruction(if_inst);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
   call_entry->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_left_start = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                          c5,
-                                                                          nullptr,
-                                                                          DataType::Type::kInt32,
-                                                                          MemberOffset(32),
-                                                                          false,
-                                                                          0,
-                                                                          0,
-                                                                          graph_->GetDexFile(),
-                                                                          0);
-  HInstruction* call_left = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  HInstruction* write_left = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                    c1,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(32),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
+  HInstruction* write_left_start = MakeIFieldSet(new_inst, c5, MemberOffset(32));
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* write_left = MakeIFieldSet(new_inst, c1, MemberOffset(32));
   HInstruction* goto_left = new (GetAllocator()) HGoto();
-  call_left->AsInvoke()->SetRawInputAt(0, new_inst);
   left->AddInstruction(write_left_start);
   left->AddInstruction(call_left);
   left->AddInstruction(write_left);
   left->AddInstruction(goto_left);
   call_left->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c2,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
   HInstruction* goto_right = new (GetAllocator()) HGoto();
   right->AddInstruction(write_right);
   right->AddInstruction(goto_right);
 
-  HInstruction* read_bottom = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
   breturn->AddInstruction(read_bottom);
   breturn->AddInstruction(return_exit);
 
-  HInstruction* exit_instruction = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_instruction);
+  SetupExit(exit);
+
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
   PerformLSE();
 
-  EXPECT_TRUE(IsRemoved(read_bottom));
-  EXPECT_TRUE(IsRemoved(write_right));
-  EXPECT_TRUE(IsRemoved(write_entry));
-  EXPECT_FALSE(IsRemoved(write_left_start));
-  EXPECT_FALSE(IsRemoved(write_left));
-  EXPECT_FALSE(IsRemoved(call_left));
-  EXPECT_FALSE(IsRemoved(call_entry));
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_REMOVED(write_entry);
+  EXPECT_INS_RETAINED(write_left_start);
+  EXPECT_INS_RETAINED(write_left);
+  EXPECT_INS_RETAINED(call_left);
+  EXPECT_INS_RETAINED(call_entry);
 }
 
 // // ENTRY
@@ -3038,18 +4525,19 @@
 // return obj.field;
 // EXIT
 TEST_F(LoadStoreEliminationTest, PartialLoadPreserved3) {
-  InitGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit",
-                                                 { { "entry", "entry_post" },
-                                                   { "entry_post", "right" },
-                                                   { "right", "return_block" },
-                                                   { "entry_post", "left_pre" },
-                                                   { "left_pre", "left_loop" },
-                                                   { "left_loop", "left_loop_post" },
-                                                   { "left_loop_post", "left_loop" },
-                                                   { "left_loop", "return_block" },
-                                                   { "return_block", "exit" } }));
+                                                 {{"entry", "entry_post"},
+                                                  {"entry_post", "right"},
+                                                  {"right", "return_block"},
+                                                  {"entry_post", "left_pre"},
+                                                  {"left_pre", "left_loop"},
+                                                  {"left_loop", "left_loop_post"},
+                                                  {"left_loop_post", "left_loop"},
+                                                  {"left_loop", "return_block"},
+                                                  {"return_block", "exit"}}));
 #define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
   GET_BLOCK(entry);
   GET_BLOCK(entry_post);
@@ -3064,123 +4552,63 @@
   if (left_loop->GetSuccessors()[0] != return_block) {
     left_loop->SwapSuccessors();
   }
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
   HInstruction* c3 = graph_->GetIntConstant(3);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* goto_entry = new (GetAllocator()) HGoto();
-  entry->AddInstruction(bool_value);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(goto_entry);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
 
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
   entry_post->AddInstruction(if_inst);
 
-  HInstruction* write_left_pre = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                        c1,
-                                                                        nullptr,
-                                                                        DataType::Type::kInt32,
-                                                                        MemberOffset(32),
-                                                                        false,
-                                                                        0,
-                                                                        0,
-                                                                        graph_->GetDexFile(),
-                                                                        0);
+  HInstruction* write_left_pre = MakeIFieldSet(new_inst, c1, MemberOffset(32));
   HInstruction* goto_left_pre = new (GetAllocator()) HGoto();
   left_pre->AddInstruction(write_left_pre);
   left_pre->AddInstruction(goto_left_pre);
 
   HInstruction* suspend_left_loop = new (GetAllocator()) HSuspendCheck();
-  HInstruction* call_left_loop = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kBool,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+  HInstruction* call_left_loop = MakeInvoke(DataType::Type::kBool, { new_inst });
   HInstruction* if_left_loop = new (GetAllocator()) HIf(call_left_loop);
-  call_left_loop->AsInvoke()->SetRawInputAt(0, new_inst);
   left_loop->AddInstruction(suspend_left_loop);
   left_loop->AddInstruction(call_left_loop);
   left_loop->AddInstruction(if_left_loop);
   suspend_left_loop->CopyEnvironmentFrom(cls->GetEnvironment());
   call_left_loop->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_left_loop = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                         c3,
-                                                                         nullptr,
-                                                                         DataType::Type::kInt32,
-                                                                         MemberOffset(32),
-                                                                         false,
-                                                                         0,
-                                                                         0,
-                                                                         graph_->GetDexFile(),
-                                                                         0);
+  HInstruction* write_left_loop = MakeIFieldSet(new_inst, c3, MemberOffset(32));
   HInstruction* goto_left_loop = new (GetAllocator()) HGoto();
   left_loop_post->AddInstruction(write_left_loop);
   left_loop_post->AddInstruction(goto_left_loop);
 
-  HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c2,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
   HInstruction* goto_right = new (GetAllocator()) HGoto();
   right->AddInstruction(write_right);
   right->AddInstruction(goto_right);
 
-  HInstruction* read_return = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* read_return = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_final = new (GetAllocator()) HReturn(read_return);
   return_block->AddInstruction(read_return);
   return_block->AddInstruction(return_final);
 
-  HInstruction* exit_instruction = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_instruction);
+  SetupExit(exit);
+
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
-  PerformLSE();
+  PerformLSENoPartial();
 
-  EXPECT_FALSE(IsRemoved(write_left_pre));
-  EXPECT_FALSE(IsRemoved(read_return));
-  EXPECT_FALSE(IsRemoved(write_right));
-  EXPECT_FALSE(IsRemoved(write_left_loop));
-  EXPECT_FALSE(IsRemoved(call_left_loop));
+  EXPECT_INS_RETAINED(write_left_pre) << *write_left_pre;
+  EXPECT_INS_RETAINED(read_return) << *read_return;
+  EXPECT_INS_RETAINED(write_right) << *write_right;
+  EXPECT_INS_RETAINED(write_left_loop) << *write_left_loop;
+  EXPECT_INS_RETAINED(call_left_loop) << *call_left_loop;
 }
 
 // // ENTRY
@@ -3205,17 +4633,18 @@
 // return obj.field;
 // EXIT
 TEST_F(LoadStoreEliminationTest, PartialLoadPreserved4) {
-  InitGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit",
-                                                 { { "entry", "entry_post" },
-                                                   { "entry_post", "right" },
-                                                   { "right", "return_block" },
-                                                   { "entry_post", "left_pre" },
-                                                   { "left_pre", "left_loop" },
-                                                   { "left_loop", "left_loop" },
-                                                   { "left_loop", "return_block" },
-                                                   { "return_block", "exit" } }));
+                                                 {{"entry", "entry_post"},
+                                                  {"entry_post", "right"},
+                                                  {"right", "return_block"},
+                                                  {"entry_post", "left_pre"},
+                                                  {"left_pre", "left_loop"},
+                                                  {"left_loop", "left_loop"},
+                                                  {"left_loop", "return_block"},
+                                                  {"return_block", "exit"}}));
 #define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
   GET_BLOCK(entry);
   GET_BLOCK(entry_post);
@@ -3229,73 +4658,31 @@
   if (left_loop->GetSuccessors()[0] != return_block) {
     left_loop->SwapSuccessors();
   }
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
   HInstruction* c3 = graph_->GetIntConstant(3);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* goto_entry = new (GetAllocator()) HGoto();
-  entry->AddInstruction(bool_value);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(goto_entry);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
 
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
   entry_post->AddInstruction(if_inst);
 
-  HInstruction* write_left_pre = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                        c1,
-                                                                        nullptr,
-                                                                        DataType::Type::kInt32,
-                                                                        MemberOffset(32),
-                                                                        false,
-                                                                        0,
-                                                                        0,
-                                                                        graph_->GetDexFile(),
-                                                                        0);
+  HInstruction* write_left_pre = MakeIFieldSet(new_inst, c1, MemberOffset(32));
   HInstruction* goto_left_pre = new (GetAllocator()) HGoto();
   left_pre->AddInstruction(write_left_pre);
   left_pre->AddInstruction(goto_left_pre);
 
   HInstruction* suspend_left_loop = new (GetAllocator()) HSuspendCheck();
-  HInstruction* call_left_loop = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            0,
-                            DataType::Type::kBool,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  HInstruction* write_left_loop = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                         c3,
-                                                                         nullptr,
-                                                                         DataType::Type::kInt32,
-                                                                         MemberOffset(32),
-                                                                         false,
-                                                                         0,
-                                                                         0,
-                                                                         graph_->GetDexFile(),
-                                                                         0);
+  HInstruction* call_left_loop = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* write_left_loop = MakeIFieldSet(new_inst, c3, MemberOffset(32));
   HInstruction* if_left_loop = new (GetAllocator()) HIf(call_left_loop);
   left_loop->AddInstruction(suspend_left_loop);
   left_loop->AddInstruction(call_left_loop);
@@ -3304,59 +4691,31 @@
   suspend_left_loop->CopyEnvironmentFrom(cls->GetEnvironment());
   call_left_loop->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c2,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
-  HInstruction* call_right = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kBool,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* call_right = MakeInvoke(DataType::Type::kBool, { new_inst });
   HInstruction* goto_right = new (GetAllocator()) HGoto();
-  call_right->AsInvoke()->SetRawInputAt(0, new_inst);
   right->AddInstruction(write_right);
   right->AddInstruction(call_right);
   right->AddInstruction(goto_right);
   call_right->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* read_return = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* read_return = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_final = new (GetAllocator()) HReturn(read_return);
   return_block->AddInstruction(read_return);
   return_block->AddInstruction(return_final);
 
-  HInstruction* exit_instruction = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_instruction);
+  SetupExit(exit);
+
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
-  PerformLSE();
+  PerformLSENoPartial();
 
-  EXPECT_FALSE(IsRemoved(read_return));
-  EXPECT_FALSE(IsRemoved(write_right));
-  EXPECT_FALSE(IsRemoved(write_left_loop));
-  EXPECT_FALSE(IsRemoved(call_left_loop));
-  EXPECT_TRUE(IsRemoved(write_left_pre));
-  EXPECT_FALSE(IsRemoved(call_right));
+  EXPECT_INS_RETAINED(read_return);
+  EXPECT_INS_RETAINED(write_right);
+  EXPECT_INS_RETAINED(write_left_loop);
+  EXPECT_INS_RETAINED(call_left_loop);
+  EXPECT_INS_REMOVED(write_left_pre);
+  EXPECT_INS_RETAINED(call_right);
 }
 
 // // ENTRY
@@ -3379,14 +4738,15 @@
 // ELIMINATE
 // return obj.field
 TEST_F(LoadStoreEliminationTest, PartialLoadPreserved5) {
-  InitGraph();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit",
-                                                 { { "entry", "left" },
-                                                   { "entry", "right" },
-                                                   { "left", "breturn" },
-                                                   { "right", "breturn" },
-                                                   { "breturn", "exit" } }));
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
 #define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
   GET_BLOCK(entry);
   GET_BLOCK(exit);
@@ -3394,67 +4754,23 @@
   GET_BLOCK(left);
   GET_BLOCK(right);
 #undef GET_BLOCK
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
-  entry->AddInstruction(bool_value);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(if_inst);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* call_left = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  HInstruction* write_left = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                    c1,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(32),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
-  HInstruction* call2_left = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            0,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* write_left = MakeIFieldSet(new_inst, c1, MemberOffset(32));
+  HInstruction* call2_left = MakeInvoke(DataType::Type::kVoid, {});
   HInstruction* goto_left = new (GetAllocator()) HGoto();
-  call_left->AsInvoke()->SetRawInputAt(0, new_inst);
   left->AddInstruction(call_left);
   left->AddInstruction(write_left);
   left->AddInstruction(call2_left);
@@ -3462,57 +4778,30 @@
   call_left->CopyEnvironmentFrom(cls->GetEnvironment());
   call2_left->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c2,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
-  HInstruction* call_right = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            0,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* call_right = MakeInvoke(DataType::Type::kVoid, {});
   HInstruction* goto_right = new (GetAllocator()) HGoto();
   right->AddInstruction(write_right);
   right->AddInstruction(call_right);
   right->AddInstruction(goto_right);
   call_right->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* read_bottom = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
   breturn->AddInstruction(read_bottom);
   breturn->AddInstruction(return_exit);
 
-  HInstruction* exit_instruction = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_instruction);
+  SetupExit(exit);
+
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
-  PerformLSE();
+  PerformLSENoPartial();
 
-  EXPECT_FALSE(IsRemoved(read_bottom));
-  EXPECT_FALSE(IsRemoved(write_right));
-  EXPECT_FALSE(IsRemoved(write_left));
-  EXPECT_FALSE(IsRemoved(call_left));
-  EXPECT_FALSE(IsRemoved(call_right));
+  EXPECT_INS_RETAINED(read_bottom);
+  EXPECT_INS_RETAINED(write_right);
+  EXPECT_INS_RETAINED(write_left);
+  EXPECT_INS_RETAINED(call_left);
+  EXPECT_INS_RETAINED(call_right);
 }
 
 // // ENTRY
@@ -3534,14 +4823,14 @@
 // ELIMINATE
 // return obj.field
 TEST_F(LoadStoreEliminationTest, PartialLoadPreserved6) {
-  InitGraph();
+  CreateGraph();
   AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
                                                  "exit",
-                                                 { { "entry", "left" },
-                                                   { "entry", "right" },
-                                                   { "left", "breturn" },
-                                                   { "right", "breturn" },
-                                                   { "breturn", "exit" } }));
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
 #define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
   GET_BLOCK(entry);
   GET_BLOCK(exit);
@@ -3549,125 +4838,3090 @@
   GET_BLOCK(left);
   GET_BLOCK(right);
 #undef GET_BLOCK
-  HInstruction* bool_value = new (GetAllocator())
-      HParameterValue(graph_->GetDexFile(), dex::TypeIndex(1), 1, DataType::Type::kBool);
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
   HInstruction* c1 = graph_->GetIntConstant(1);
   HInstruction* c2 = graph_->GetIntConstant(2);
   HInstruction* c3 = graph_->GetIntConstant(3);
-  HInstruction* cls = new (GetAllocator()) HLoadClass(graph_->GetCurrentMethod(),
-                                                      dex::TypeIndex(10),
-                                                      graph_->GetDexFile(),
-                                                      ScopedNullHandle<mirror::Class>(),
-                                                      false,
-                                                      0,
-                                                      false);
-  HInstruction* new_inst =
-      new (GetAllocator()) HNewInstance(cls,
-                                        0,
-                                        dex::TypeIndex(10),
-                                        graph_->GetDexFile(),
-                                        false,
-                                        QuickEntrypointEnum::kQuickAllocObjectInitialized);
-  HInstruction* write_entry = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c3,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
-  HInstruction* call_entry = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            0,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_entry = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* call_entry = MakeInvoke(DataType::Type::kVoid, {});
   HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
-  entry->AddInstruction(bool_value);
   entry->AddInstruction(cls);
   entry->AddInstruction(new_inst);
   entry->AddInstruction(write_entry);
   entry->AddInstruction(call_entry);
   entry->AddInstruction(if_inst);
-  ArenaVector<HInstruction*> current_locals({}, GetAllocator()->Adapter(kArenaAllocInstruction));
-  ManuallyBuildEnvFor(cls, &current_locals);
+  ManuallyBuildEnvFor(cls, {});
   new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
   call_entry->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* call_left = new (GetAllocator())
-      HInvokeStaticOrDirect(GetAllocator(),
-                            1,
-                            DataType::Type::kVoid,
-                            0,
-                            { nullptr, 0 },
-                            nullptr,
-                            {},
-                            InvokeType::kStatic,
-                            { nullptr, 0 },
-                            HInvokeStaticOrDirect::ClinitCheckRequirement::kNone);
-  HInstruction* write_left = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                    c1,
-                                                                    nullptr,
-                                                                    DataType::Type::kInt32,
-                                                                    MemberOffset(32),
-                                                                    false,
-                                                                    0,
-                                                                    0,
-                                                                    graph_->GetDexFile(),
-                                                                    0);
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* write_left = MakeIFieldSet(new_inst, c1, MemberOffset(32));
   HInstruction* goto_left = new (GetAllocator()) HGoto();
-  call_left->AsInvoke()->SetRawInputAt(0, new_inst);
   left->AddInstruction(call_left);
   left->AddInstruction(write_left);
   left->AddInstruction(goto_left);
   call_left->CopyEnvironmentFrom(cls->GetEnvironment());
 
-  HInstruction* write_right = new (GetAllocator()) HInstanceFieldSet(new_inst,
-                                                                     c2,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
   HInstruction* goto_right = new (GetAllocator()) HGoto();
   right->AddInstruction(write_right);
   right->AddInstruction(goto_right);
 
-  HInstruction* read_bottom = new (GetAllocator()) HInstanceFieldGet(new_inst,
-                                                                     nullptr,
-                                                                     DataType::Type::kInt32,
-                                                                     MemberOffset(32),
-                                                                     false,
-                                                                     0,
-                                                                     0,
-                                                                     graph_->GetDexFile(),
-                                                                     0);
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
   HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
   breturn->AddInstruction(read_bottom);
   breturn->AddInstruction(return_exit);
 
-  HInstruction* exit_instruction = new (GetAllocator()) HExit();
-  exit->AddInstruction(exit_instruction);
+  SetupExit(exit);
+
   // PerformLSE expects this to be empty.
   graph_->ClearDominanceInformation();
+
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSENoPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_RETAINED(write_entry);
+  EXPECT_INS_RETAINED(write_left);
+  EXPECT_INS_RETAINED(call_left);
+  EXPECT_INS_RETAINED(call_entry);
+}
+
+// // ENTRY
+// // MOVED TO MATERIALIZATION BLOCK
+// obj = new Obj();
+// ELIMINATE, moved to materialization block. Kept by escape.
+// obj.field = 3;
+// // Make sure this graph isn't broken
+// if (obj ==/!= (STATIC.VALUE|obj|null)) {
+//   // partial_BLOCK
+//   // REMOVE (either from unreachable or normal PHI creation)
+//   obj.field = 4;
+// }
+// if (parameter_value) {
+//   // LEFT
+//   // DO NOT ELIMINATE
+//   escape(obj);
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj.field = 2;
+// }
+// EXIT
+// PREDICATED GET
+// return obj.field
+TEST_P(PartialComparisonTestGroup, PartialComparisonBeforeCohort) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "critical_break"},
+                                                  {"entry", "partial"},
+                                                  {"partial", "merge"},
+                                                  {"critical_break", "merge"},
+                                                  {"merge", "left"},
+                                                  {"merge", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(merge);
+  GET_BLOCK(partial);
+  GET_BLOCK(critical_break);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c4 = graph_->GetIntConstant(4);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_entry = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  ComparisonInstructions cmp_instructions = GetComparisonInstructions(new_inst);
+  HInstruction* if_inst = new (GetAllocator()) HIf(cmp_instructions.cmp_);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_entry);
+  cmp_instructions.AddSetup(entry);
+  entry->AddInstruction(cmp_instructions.cmp_);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  cmp_instructions.AddEnvironment(cls->GetEnvironment());
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_partial = MakeIFieldSet(new_inst, c4, MemberOffset(32));
+  HInstruction* goto_partial = new (GetAllocator()) HGoto();
+  partial->AddInstruction(write_partial);
+  partial->AddInstruction(goto_partial);
+
+  HInstruction* goto_crit_break = new (GetAllocator()) HGoto();
+  critical_break->AddInstruction(goto_crit_break);
+
+  HInstruction* if_merge = new (GetAllocator()) HIf(bool_value);
+  merge->AddInstruction(if_merge);
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right);
+  right->AddInstruction(goto_right);
+
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  std::vector<HPhi*> merges;
+  HPredicatedInstanceFieldGet* pred_get;
+  HInstanceFieldSet* init_set;
+  std::tie(pred_get, init_set) =
+      FindSingleInstructions<HPredicatedInstanceFieldGet, HInstanceFieldSet>(graph_);
+  std::tie(merges) = FindAllInstructions<HPhi>(graph_);
+  ASSERT_EQ(merges.size(), 3u);
+  HPhi* merge_value_return = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->GetBlock() == breturn;
+  });
+  HPhi* merge_value_top = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->GetBlock() != breturn;
+  });
+  HPhi* merge_alloc = FindOrNull(merges.begin(), merges.end(), [](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference;
+  });
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(write_entry);
+  EXPECT_INS_REMOVED(write_partial);
+  EXPECT_INS_RETAINED(call_left);
+  CheckFinalInstruction(if_inst->InputAt(0), ComparisonPlacement::kBeforeEscape);
+  EXPECT_INS_EQ(init_set->InputAt(1), merge_value_top);
+  EXPECT_INS_EQ(pred_get->GetTarget(), merge_alloc);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue(), merge_value_return);
+}
+
+// // ENTRY
+// // MOVED TO MATERIALIZATION BLOCK
+// obj = new Obj();
+// ELIMINATE, moved to materialization block. Kept by escape.
+// obj.field = 3;
+// // Make sure this graph isn't broken
+// if (parameter_value) {
+//   if (obj ==/!= (STATIC.VALUE|obj|null)) {
+//     // partial_BLOCK
+//     obj.field = 4;
+//   }
+//   // LEFT
+//   // DO NOT ELIMINATE
+//   escape(obj);
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj.field = 2;
+// }
+// EXIT
+// PREDICATED GET
+// return obj.field
+TEST_P(PartialComparisonTestGroup, PartialComparisonInCohortBeforeEscape) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left_begin"},
+                                                  {"left_begin", "partial"},
+                                                  {"left_begin", "left_crit_break"},
+                                                  {"left_crit_break", "left"},
+                                                  {"partial", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(partial);
+  GET_BLOCK(left_begin);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(left_crit_break);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(left, {left_crit_break, partial});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c4 = graph_->GetIntConstant(4);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_entry = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_entry);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  ComparisonInstructions cmp_instructions = GetComparisonInstructions(new_inst);
+  HInstruction* if_left_begin = new (GetAllocator()) HIf(cmp_instructions.cmp_);
+  cmp_instructions.AddSetup(left_begin);
+  left_begin->AddInstruction(cmp_instructions.cmp_);
+  left_begin->AddInstruction(if_left_begin);
+  cmp_instructions.AddEnvironment(cls->GetEnvironment());
+
+  left_crit_break->AddInstruction(new (GetAllocator()) HGoto());
+
+  HInstruction* write_partial = MakeIFieldSet(new_inst, c4, MemberOffset(32));
+  HInstruction* goto_partial = new (GetAllocator()) HGoto();
+  partial->AddInstruction(write_partial);
+  partial->AddInstruction(goto_partial);
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right);
+  right->AddInstruction(goto_right);
+
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  std::vector<HPhi*> merges;
+  HInstanceFieldSet* init_set =
+      FindSingleInstruction<HInstanceFieldSet>(graph_, left_begin->GetSinglePredecessor());
+  HInstanceFieldSet* partial_set = FindSingleInstruction<HInstanceFieldSet>(graph_, partial);
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_);
+  std::tie(merges) = FindAllInstructions<HPhi>(graph_);
+  ASSERT_EQ(merges.size(), 2u);
+  HPhi* merge_value_return = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32;
+  });
+  HPhi* merge_alloc = FindOrNull(merges.begin(), merges.end(), [](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference;
+  });
+  EXPECT_EQ(merge_value_return->GetBlock(), breturn)
+      << blks.GetName(merge_value_return->GetBlock());
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(write_entry);
+  EXPECT_INS_RETAINED(write_partial);
+  EXPECT_INS_RETAINED(call_left);
+  CheckFinalInstruction(if_left_begin->InputAt(0), ComparisonPlacement::kInEscape);
+  EXPECT_INS_EQ(init_set->InputAt(1), c3);
+  EXPECT_INS_EQ(partial_set->InputAt(0), init_set->InputAt(0));
+  EXPECT_INS_EQ(partial_set->InputAt(1), c4);
+  EXPECT_INS_EQ(pred_get->GetTarget(), merge_alloc);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue(), merge_value_return);
+}
+
+// // ENTRY
+// // MOVED TO MATERIALIZATION BLOCK
+// obj = new Obj();
+// ELIMINATE, moved to materialization block. Kept by escape.
+// obj.field = 3;
+// // Make sure this graph isn't broken
+// if (parameter_value) {
+//   // LEFT
+//   // DO NOT ELIMINATE
+//   escape(obj);
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj.field = 2;
+// }
+// if (obj ==/!= (STATIC.VALUE|obj|null)) {
+//   // partial_BLOCK
+//   obj.field = 4;
+// }
+// EXIT
+// PREDICATED GET
+// return obj.field
+TEST_P(PartialComparisonTestGroup, PartialComparisonAfterCohort) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "merge"},
+                                                  {"right", "merge"},
+                                                  {"merge", "critical_break"},
+                                                  {"critical_break", "breturn"},
+                                                  {"merge", "partial"},
+                                                  {"partial", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(partial);
+  GET_BLOCK(critical_break);
+  GET_BLOCK(merge);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {critical_break, partial});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c4 = graph_->GetIntConstant(4);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_entry = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_entry);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right);
+  right->AddInstruction(goto_right);
+
+  ComparisonInstructions cmp_instructions = GetComparisonInstructions(new_inst);
+  HInstruction* if_merge = new (GetAllocator()) HIf(cmp_instructions.cmp_);
+  cmp_instructions.AddSetup(merge);
+  merge->AddInstruction(cmp_instructions.cmp_);
+  merge->AddInstruction(if_merge);
+  cmp_instructions.AddEnvironment(cls->GetEnvironment());
+
+  HInstanceFieldSet* write_partial = MakeIFieldSet(new_inst, c4, MemberOffset(32));
+  HInstruction* goto_partial = new (GetAllocator()) HGoto();
+  partial->AddInstruction(write_partial);
+  partial->AddInstruction(goto_partial);
+
+  HInstruction* goto_crit_break = new (GetAllocator()) HGoto();
+  critical_break->AddInstruction(goto_crit_break);
+
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  std::vector<HPhi*> merges;
+  HInstanceFieldSet* init_set =
+      FindSingleInstruction<HInstanceFieldSet>(graph_, left->GetSinglePredecessor());
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_);
+  std::tie(merges) = FindAllInstructions<HPhi>(graph_);
+  ASSERT_EQ(merges.size(), 3u);
+  HPhi* merge_value_return = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->GetBlock() == breturn;
+  });
+  HPhi* merge_alloc = FindOrNull(merges.begin(), merges.end(), [](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference;
+  });
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(write_entry);
+  EXPECT_INS_RETAINED(write_partial);
+  EXPECT_TRUE(write_partial->GetIsPredicatedSet());
+  EXPECT_INS_RETAINED(call_left);
+  CheckFinalInstruction(if_merge->InputAt(0), ComparisonPlacement::kAfterEscape);
+  EXPECT_INS_EQ(init_set->InputAt(1), c3);
+  ASSERT_TRUE(write_partial->InputAt(0)->IsPhi());
+  EXPECT_INS_EQ(write_partial->InputAt(0)->AsPhi()->InputAt(0), init_set->InputAt(0));
+  EXPECT_INS_EQ(write_partial->InputAt(1), c4);
+  EXPECT_INS_EQ(pred_get->GetTarget(), merge_alloc);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue(), merge_value_return);
+}
+
+// // ENTRY
+// // MOVED TO MATERIALIZATION BLOCK
+// obj = new Obj();
+// ELIMINATE, moved to materialization block. Kept by escape.
+// obj.field = 3;
+// // Make sure this graph isn't broken
+// if (parameter_value) {
+//   // LEFT
+//   // DO NOT ELIMINATE
+//   escape(obj);
+//   if (obj ==/!= (STATIC.VALUE|obj|null)) {
+//     // partial_BLOCK
+//     obj.field = 4;
+//   }
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj.field = 2;
+// }
+// EXIT
+// PREDICATED GET
+// return obj.field
+TEST_P(PartialComparisonTestGroup, PartialComparisonInCohortAfterEscape) {
+  PartialComparisonKind kind = GetParam();
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"left", "partial"},
+                                                  {"partial", "left_end"},
+                                                  {"left", "left_crit_break"},
+                                                  {"left_crit_break", "left_end"},
+                                                  {"left_end", "breturn"},
+                                                  {"entry", "right"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(partial);
+  GET_BLOCK(left_end);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(left_crit_break);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c4 = graph_->GetIntConstant(4);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_entry = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_entry);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  ComparisonInstructions cmp_instructions = GetComparisonInstructions(new_inst);
+  HInstruction* if_left = new (GetAllocator()) HIf(cmp_instructions.cmp_);
+  left->AddInstruction(call_left);
+  cmp_instructions.AddSetup(left);
+  left->AddInstruction(cmp_instructions.cmp_);
+  left->AddInstruction(if_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+  cmp_instructions.AddEnvironment(cls->GetEnvironment());
+  if (if_left->AsIf()->IfTrueSuccessor() != partial) {
+    left->SwapSuccessors();
+  }
+
+  HInstruction* write_partial = MakeIFieldSet(new_inst, c4, MemberOffset(32));
+  HInstruction* goto_partial = new (GetAllocator()) HGoto();
+  partial->AddInstruction(write_partial);
+  partial->AddInstruction(goto_partial);
+
+  HInstruction* goto_left_crit_break = new (GetAllocator()) HGoto();
+  left_crit_break->AddInstruction(goto_left_crit_break);
+
+  HInstruction* goto_left_end = new (GetAllocator()) HGoto();
+  left_end->AddInstruction(goto_left_end);
+
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right);
+  right->AddInstruction(goto_right);
+
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  std::vector<HPhi*> merges;
+  std::vector<HInstanceFieldSet*> sets;
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_);
+  std::tie(merges, sets) = FindAllInstructions<HPhi, HInstanceFieldSet>(graph_);
+  ASSERT_EQ(merges.size(), 2u);
+  ASSERT_EQ(sets.size(), 2u);
+  HInstanceFieldSet* init_set = FindOrNull(sets.begin(), sets.end(), [&](HInstanceFieldSet* s) {
+    return s->GetBlock()->GetSingleSuccessor() == left;
+  });
+  EXPECT_INS_EQ(init_set->InputAt(1), c3);
+  HPhi* merge_value_return = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->GetBlock() == breturn;
+  });
+  HPhi* merge_alloc = FindOrNull(merges.begin(), merges.end(), [](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference;
+  });
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(write_entry);
+  if (kind.IsPossiblyTrue()) {
+    EXPECT_INS_RETAINED(write_partial);
+    EXPECT_TRUE(std::find(sets.begin(), sets.end(), write_partial) != sets.end());
+  }
+  EXPECT_INS_RETAINED(call_left);
+  CheckFinalInstruction(if_left->InputAt(0), ComparisonPlacement::kInEscape);
+  EXPECT_INS_EQ(pred_get->GetTarget(), merge_alloc);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue(), merge_value_return);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+    LoadStoreEliminationTest,
+    PartialComparisonTestGroup,
+    testing::Values(PartialComparisonKind{PartialComparisonKind::Type::kEquals,
+                                          PartialComparisonKind::Target::kNull,
+                                          PartialComparisonKind::Position::kLeft},
+                    PartialComparisonKind{PartialComparisonKind::Type::kEquals,
+                                          PartialComparisonKind::Target::kNull,
+                                          PartialComparisonKind::Position::kRight},
+                    PartialComparisonKind{PartialComparisonKind::Type::kEquals,
+                                          PartialComparisonKind::Target::kValue,
+                                          PartialComparisonKind::Position::kLeft},
+                    PartialComparisonKind{PartialComparisonKind::Type::kEquals,
+                                          PartialComparisonKind::Target::kValue,
+                                          PartialComparisonKind::Position::kRight},
+                    PartialComparisonKind{PartialComparisonKind::Type::kEquals,
+                                          PartialComparisonKind::Target::kSelf,
+                                          PartialComparisonKind::Position::kLeft},
+                    PartialComparisonKind{PartialComparisonKind::Type::kNotEquals,
+                                          PartialComparisonKind::Target::kNull,
+                                          PartialComparisonKind::Position::kLeft},
+                    PartialComparisonKind{PartialComparisonKind::Type::kNotEquals,
+                                          PartialComparisonKind::Target::kNull,
+                                          PartialComparisonKind::Position::kRight},
+                    PartialComparisonKind{PartialComparisonKind::Type::kNotEquals,
+                                          PartialComparisonKind::Target::kSelf,
+                                          PartialComparisonKind::Position::kLeft},
+                    PartialComparisonKind{PartialComparisonKind::Type::kNotEquals,
+                                          PartialComparisonKind::Target::kValue,
+                                          PartialComparisonKind::Position::kLeft},
+                    PartialComparisonKind{PartialComparisonKind::Type::kNotEquals,
+                                          PartialComparisonKind::Target::kValue,
+                                          PartialComparisonKind::Position::kRight}));
+
+// // ENTRY
+// obj = new Obj();
+// if (parameter_value) {
+//   // LEFT
+//   escape(obj);
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj.field = 2;
+// }
+// EXIT
+// predicated-ELIMINATE
+// obj.field = 3;
+TEST_F(LoadStoreEliminationTest, PredicatedStore1) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  InitGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {left, right});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* null_const = graph_->GetNullConstant();
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right);
+  right->AddInstruction(goto_right);
+
+  HInstruction* write_bottom = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturnVoid();
+  breturn->AddInstruction(write_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_RETAINED(write_bottom);
+  EXPECT_TRUE(write_bottom->AsInstanceFieldSet()->GetIsPredicatedSet());
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_RETAINED(call_left);
+  HPhi* merge_alloc = FindSingleInstruction<HPhi>(graph_, breturn);
+  ASSERT_NE(merge_alloc, nullptr);
+  EXPECT_TRUE(merge_alloc->InputAt(0)->IsNewInstance()) << *merge_alloc;
+  EXPECT_EQ(merge_alloc->InputAt(0)->InputAt(0), cls) << *merge_alloc << " cls? " << *cls;
+  EXPECT_EQ(merge_alloc->InputAt(1), null_const);
+}
+
+// // ENTRY
+// obj = new Obj();
+// obj.field = 3;
+// if (parameter_value) {
+//   // LEFT
+//   escape(obj);
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj.field = 2;
+// }
+// // MERGE
+// if (second_param) {
+//   // NON_ESCAPE
+//   obj.field = 1;
+//   noescape();
+// }
+// EXIT
+// predicated-ELIMINATE
+// obj.field = 4;
+TEST_F(LoadStoreEliminationTest, PredicatedStore2) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "merge"},
+                                                  {"right", "merge"},
+                                                  {"merge", "non_escape"},
+                                                  {"non_escape", "breturn"},
+                                                  {"merge", "merge_crit_break"},
+                                                  {"merge_crit_break", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+  GET_BLOCK(merge);
+  GET_BLOCK(merge_crit_break);
+  GET_BLOCK(non_escape);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(merge, {left, right});
+  EnsurePredecessorOrder(breturn, {merge_crit_break, non_escape});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* bool_value2 = MakeParam(DataType::Type::kBool);
+  HInstruction* null_const = graph_->GetNullConstant();
+  HInstruction* c1 = graph_->GetIntConstant(3);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c4 = graph_->GetIntConstant(4);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_entry = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_entry);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right);
+  right->AddInstruction(goto_right);
+
+  HInstruction* merge_if = new (GetAllocator()) HIf(bool_value2);
+  merge->AddInstruction(merge_if);
+
+  merge_crit_break->AddInstruction(new (GetAllocator()) HGoto());
+
+  HInstruction* write_non_escape = MakeIFieldSet(new_inst, c1, MemberOffset(32));
+  HInstruction* non_escape_call = MakeInvoke(DataType::Type::kVoid, {});
+  HInstruction* non_escape_goto = new (GetAllocator()) HGoto();
+  non_escape->AddInstruction(write_non_escape);
+  non_escape->AddInstruction(non_escape_call);
+  non_escape->AddInstruction(non_escape_goto);
+  non_escape_call->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_bottom = MakeIFieldSet(new_inst, c4, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturnVoid();
+  breturn->AddInstruction(write_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_RETAINED(write_bottom);
+  EXPECT_TRUE(write_bottom->AsInstanceFieldSet()->GetIsPredicatedSet()) << *write_bottom;
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_RETAINED(call_left);
+  HInstanceFieldSet* pred_set = FindSingleInstruction<HInstanceFieldSet>(graph_, breturn);
+  HPhi* merge_alloc = FindSingleInstruction<HPhi>(graph_);
+  ASSERT_NE(merge_alloc, nullptr);
+  EXPECT_TRUE(merge_alloc->InputAt(0)->IsNewInstance()) << *merge_alloc;
+  EXPECT_INS_EQ(merge_alloc->InputAt(0)->InputAt(0), cls) << " phi is: " << *merge_alloc;
+  EXPECT_INS_EQ(merge_alloc->InputAt(1), null_const);
+  ASSERT_NE(pred_set, nullptr);
+  EXPECT_TRUE(pred_set->GetIsPredicatedSet()) << *pred_set;
+  EXPECT_INS_EQ(pred_set->InputAt(0), merge_alloc);
+}
+
+// // ENTRY
+// obj = new Obj();
+// obj.field = 3;
+// if (parameter_value) {
+//   // LEFT
+//   escape(obj);
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj.field = 2;
+// }
+// EXIT
+// predicated-ELIMINATE
+// return obj.field
+TEST_F(LoadStoreEliminationTest, PredicatedLoad1) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {left, right});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* null_const = graph_->GetNullConstant();
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_entry = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_entry);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right);
+  right->AddInstruction(goto_right);
+
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_RETAINED(call_left);
+  std::vector<HPhi*> merges;
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  std::tie(merges) = FindAllInstructions<HPhi>(graph_, breturn);
+  ASSERT_EQ(merges.size(), 2u);
+  HPhi* merge_value_return = FindOrNull(
+      merges.begin(), merges.end(), [](HPhi* p) { return p->GetType() == DataType::Type::kInt32; });
+  HPhi* merge_alloc = FindOrNull(merges.begin(), merges.end(), [](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference;
+  });
+  ASSERT_NE(merge_alloc, nullptr);
+  EXPECT_TRUE(merge_alloc->InputAt(0)->IsNewInstance()) << *merge_alloc;
+  EXPECT_EQ(merge_alloc->InputAt(0)->InputAt(0), cls) << *merge_alloc << " cls? " << *cls;
+  EXPECT_EQ(merge_alloc->InputAt(1), null_const);
+  ASSERT_NE(pred_get, nullptr);
+  EXPECT_INS_EQ(pred_get->GetTarget(), merge_alloc);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue(), merge_value_return) << " pred-get is: " << *pred_get;
+  EXPECT_INS_EQ(merge_value_return->InputAt(0), graph_->GetIntConstant(0))
+      << " merge val is: " << *merge_value_return;
+  EXPECT_INS_EQ(merge_value_return->InputAt(1), c2) << " merge val is: " << *merge_value_return;
+}
+
+// // ENTRY
+// obj1 = new Obj1();
+// obj2 = new Obj2();
+// obj1.field = 3;
+// obj2.field = 13;
+// if (parameter_value) {
+//   // LEFT
+//   escape(obj1);
+//   escape(obj2);
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj1.field = 2;
+//   obj2.field = 12;
+// }
+// EXIT
+// predicated-ELIMINATE
+// return obj1.field + obj2.field
+TEST_F(LoadStoreEliminationTest, MultiPredicatedLoad1) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {left, right});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c12 = graph_->GetIntConstant(12);
+  HInstruction* c13 = graph_->GetIntConstant(13);
+
+  HInstruction* cls1 = MakeClassLoad();
+  HInstruction* cls2 = MakeClassLoad();
+  HInstruction* new_inst1 = MakeNewInstance(cls1);
+  HInstruction* new_inst2 = MakeNewInstance(cls2);
+  HInstruction* write_entry1 = MakeIFieldSet(new_inst1, c3, MemberOffset(32));
+  HInstruction* write_entry2 = MakeIFieldSet(new_inst2, c13, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls1);
+  entry->AddInstruction(cls2);
+  entry->AddInstruction(new_inst1);
+  entry->AddInstruction(new_inst2);
+  entry->AddInstruction(write_entry1);
+  entry->AddInstruction(write_entry2);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls1, {});
+  cls2->CopyEnvironmentFrom(cls1->GetEnvironment());
+  new_inst1->CopyEnvironmentFrom(cls1->GetEnvironment());
+  new_inst2->CopyEnvironmentFrom(cls1->GetEnvironment());
+
+  HInstruction* call_left1 = MakeInvoke(DataType::Type::kVoid, { new_inst1 });
+  HInstruction* call_left2 = MakeInvoke(DataType::Type::kVoid, { new_inst2 });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left1);
+  left->AddInstruction(call_left2);
+  left->AddInstruction(goto_left);
+  call_left1->CopyEnvironmentFrom(cls1->GetEnvironment());
+  call_left2->CopyEnvironmentFrom(cls1->GetEnvironment());
+
+  HInstruction* write_right1 = MakeIFieldSet(new_inst1, c2, MemberOffset(32));
+  HInstruction* write_right2 = MakeIFieldSet(new_inst2, c12, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right1);
+  right->AddInstruction(write_right2);
+  right->AddInstruction(goto_right);
+
+  HInstruction* read_bottom1 = MakeIFieldGet(new_inst1, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* read_bottom2 = MakeIFieldGet(new_inst2, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* combine =
+      new (GetAllocator()) HAdd(DataType::Type::kInt32, read_bottom1, read_bottom2);
+  HInstruction* return_exit = new (GetAllocator()) HReturn(combine);
+  breturn->AddInstruction(read_bottom1);
+  breturn->AddInstruction(read_bottom2);
+  breturn->AddInstruction(combine);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(read_bottom1);
+  EXPECT_INS_REMOVED(read_bottom2);
+  EXPECT_INS_REMOVED(write_right1);
+  EXPECT_INS_REMOVED(write_right2);
+  EXPECT_INS_RETAINED(call_left1);
+  EXPECT_INS_RETAINED(call_left2);
+  std::vector<HPhi*> merges;
+  std::vector<HPredicatedInstanceFieldGet*> pred_gets;
+  std::tie(merges, pred_gets) =
+      FindAllInstructions<HPhi, HPredicatedInstanceFieldGet>(graph_, breturn);
+  ASSERT_EQ(merges.size(), 4u);
+  ASSERT_EQ(pred_gets.size(), 2u);
+  HPhi* merge_value_return1 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->InputAt(1) == c2;
+  });
+  HPhi* merge_value_return2 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->InputAt(1) == c12;
+  });
+  HPhi* merge_alloc1 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference &&
+           p->InputAt(0)->IsNewInstance() &&
+           p->InputAt(0)->InputAt(0) == cls1;
+  });
+  HPhi* merge_alloc2 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference &&
+           p->InputAt(0)->IsNewInstance() &&
+           p->InputAt(0)->InputAt(0) == cls2;
+  });
+  ASSERT_NE(merge_alloc1, nullptr);
+  ASSERT_NE(merge_alloc2, nullptr);
+  EXPECT_EQ(merge_alloc1->InputAt(1), graph_->GetNullConstant());
+  EXPECT_EQ(merge_alloc2->InputAt(1), graph_->GetNullConstant());
+  HPredicatedInstanceFieldGet* pred_get1 =
+      FindOrNull(pred_gets.begin(), pred_gets.end(), [&](HPredicatedInstanceFieldGet* pg) {
+        return pg->GetTarget() == merge_alloc1;
+      });
+  HPredicatedInstanceFieldGet* pred_get2 =
+      FindOrNull(pred_gets.begin(), pred_gets.end(), [&](HPredicatedInstanceFieldGet* pg) {
+        return pg->GetTarget() == merge_alloc2;
+      });
+  ASSERT_NE(pred_get1, nullptr);
+  EXPECT_INS_EQ(pred_get1->GetTarget(), merge_alloc1);
+  EXPECT_INS_EQ(pred_get1->GetDefaultValue(), merge_value_return1)
+      << " pred-get is: " << *pred_get1;
+  EXPECT_INS_EQ(merge_value_return1->InputAt(0), graph_->GetIntConstant(0))
+      << " merge val is: " << *merge_value_return1;
+  EXPECT_INS_EQ(merge_value_return1->InputAt(1), c2) << " merge val is: " << *merge_value_return1;
+  ASSERT_NE(pred_get2, nullptr);
+  EXPECT_INS_EQ(pred_get2->GetTarget(), merge_alloc2);
+  EXPECT_INS_EQ(pred_get2->GetDefaultValue(), merge_value_return2)
+      << " pred-get is: " << *pred_get2;
+  EXPECT_INS_EQ(merge_value_return2->InputAt(0), graph_->GetIntConstant(0))
+      << " merge val is: " << *merge_value_return1;
+  EXPECT_INS_EQ(merge_value_return2->InputAt(1), c12) << " merge val is: " << *merge_value_return1;
+}
+
+// // ENTRY
+// obj1 = new Obj1();
+// obj2 = new Obj2();
+// obj1.field = 3;
+// obj2.field = 13;
+// if (parameter_value) {
+//   // LEFT
+//   escape(obj1);
+//   // ELIMINATE
+//   obj2.field = 12;
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj1.field = 2;
+//   escape(obj2);
+// }
+// EXIT
+// predicated-ELIMINATE
+// return obj1.field + obj2.field
+TEST_F(LoadStoreEliminationTest, MultiPredicatedLoad2) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {left, right});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c12 = graph_->GetIntConstant(12);
+  HInstruction* c13 = graph_->GetIntConstant(13);
+
+  HInstruction* cls1 = MakeClassLoad();
+  HInstruction* cls2 = MakeClassLoad();
+  HInstruction* new_inst1 = MakeNewInstance(cls1);
+  HInstruction* new_inst2 = MakeNewInstance(cls2);
+  HInstruction* write_entry1 = MakeIFieldSet(new_inst1, c3, MemberOffset(32));
+  HInstruction* write_entry2 = MakeIFieldSet(new_inst2, c13, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls1);
+  entry->AddInstruction(cls2);
+  entry->AddInstruction(new_inst1);
+  entry->AddInstruction(new_inst2);
+  entry->AddInstruction(write_entry1);
+  entry->AddInstruction(write_entry2);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls1, {});
+  cls2->CopyEnvironmentFrom(cls1->GetEnvironment());
+  new_inst1->CopyEnvironmentFrom(cls1->GetEnvironment());
+  new_inst2->CopyEnvironmentFrom(cls1->GetEnvironment());
+
+  HInstruction* call_left1 = MakeInvoke(DataType::Type::kVoid, { new_inst1 });
+  HInstruction* write_left2 = MakeIFieldSet(new_inst2, c12, MemberOffset(32));
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left1);
+  left->AddInstruction(write_left2);
+  left->AddInstruction(goto_left);
+  call_left1->CopyEnvironmentFrom(cls1->GetEnvironment());
+
+  HInstruction* write_right1 = MakeIFieldSet(new_inst1, c2, MemberOffset(32));
+  HInstruction* call_right2 = MakeInvoke(DataType::Type::kVoid, { new_inst2 });
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right1);
+  right->AddInstruction(call_right2);
+  right->AddInstruction(goto_right);
+  call_right2->CopyEnvironmentFrom(cls1->GetEnvironment());
+
+  HInstruction* read_bottom1 = MakeIFieldGet(new_inst1, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* read_bottom2 = MakeIFieldGet(new_inst2, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* combine =
+      new (GetAllocator()) HAdd(DataType::Type::kInt32, read_bottom1, read_bottom2);
+  HInstruction* return_exit = new (GetAllocator()) HReturn(combine);
+  breturn->AddInstruction(read_bottom1);
+  breturn->AddInstruction(read_bottom2);
+  breturn->AddInstruction(combine);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(read_bottom1);
+  EXPECT_INS_REMOVED(read_bottom2);
+  EXPECT_INS_REMOVED(write_right1);
+  EXPECT_INS_REMOVED(write_left2);
+  EXPECT_INS_RETAINED(call_left1);
+  EXPECT_INS_RETAINED(call_right2);
+  std::vector<HPhi*> merges;
+  std::vector<HPredicatedInstanceFieldGet*> pred_gets;
+  std::tie(merges, pred_gets) =
+      FindAllInstructions<HPhi, HPredicatedInstanceFieldGet>(graph_, breturn);
+  ASSERT_EQ(merges.size(), 4u);
+  ASSERT_EQ(pred_gets.size(), 2u);
+  HPhi* merge_value_return1 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->InputAt(1) == c2;
+  });
+  HPhi* merge_value_return2 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->InputAt(0) == c12;
+  });
+  HPhi* merge_alloc1 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference && p->InputAt(1)->IsNullConstant();
+  });
+  HPhi* merge_alloc2 = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference && p->InputAt(0)->IsNullConstant();
+  });
+  ASSERT_NE(merge_alloc1, nullptr);
+  ASSERT_NE(merge_alloc2, nullptr);
+  EXPECT_TRUE(merge_alloc1->InputAt(0)->IsNewInstance()) << *merge_alloc1;
+  EXPECT_INS_EQ(merge_alloc1->InputAt(0)->InputAt(0), cls1) << *merge_alloc1;
+  EXPECT_INS_EQ(merge_alloc1->InputAt(1), graph_->GetNullConstant());
+  EXPECT_TRUE(merge_alloc2->InputAt(1)->IsNewInstance()) << *merge_alloc2;
+  EXPECT_INS_EQ(merge_alloc2->InputAt(1)->InputAt(0), cls2) << *merge_alloc2;
+  EXPECT_INS_EQ(merge_alloc2->InputAt(0), graph_->GetNullConstant());
+  HPredicatedInstanceFieldGet* pred_get1 =
+      FindOrNull(pred_gets.begin(), pred_gets.end(), [&](HPredicatedInstanceFieldGet* pg) {
+        return pg->GetTarget() == merge_alloc1;
+      });
+  HPredicatedInstanceFieldGet* pred_get2 =
+      FindOrNull(pred_gets.begin(), pred_gets.end(), [&](HPredicatedInstanceFieldGet* pg) {
+        return pg->GetTarget() == merge_alloc2;
+      });
+  ASSERT_NE(pred_get1, nullptr);
+  EXPECT_INS_EQ(pred_get1->GetTarget(), merge_alloc1);
+  EXPECT_INS_EQ(pred_get1->GetDefaultValue(), merge_value_return1)
+      << " pred-get is: " << *pred_get1;
+  EXPECT_INS_EQ(merge_value_return1->InputAt(0), graph_->GetIntConstant(0))
+      << " merge val is: " << *merge_value_return1;
+  EXPECT_INS_EQ(merge_value_return1->InputAt(1), c2) << " merge val is: " << *merge_value_return1;
+  ASSERT_NE(pred_get2, nullptr);
+  EXPECT_INS_EQ(pred_get2->GetTarget(), merge_alloc2);
+  EXPECT_INS_EQ(pred_get2->GetDefaultValue(), merge_value_return2)
+      << " pred-get is: " << *pred_get2;
+  EXPECT_INS_EQ(merge_value_return2->InputAt(1), graph_->GetIntConstant(0))
+      << " merge val is: " << *merge_value_return1;
+  EXPECT_INS_EQ(merge_value_return2->InputAt(0), c12) << " merge val is: " << *merge_value_return1;
+}
+
+// Based on structure seen in `java.util.List
+// java.util.Collections.checkedList(java.util.List, java.lang.Class)`
+// Incorrect accounting would cause attempts to materialize both obj1 and obj2
+// in each of the materialization blocks.
+// // ENTRY
+// Obj obj;
+// if (param1) {
+//   // needs to be moved after param2 check
+//   obj1 = new Obj1();
+//   obj1.foo = 33;
+//   if (param2) {
+//     return obj1.foo;
+//   }
+//   obj = obj1;
+// } else {
+//   obj2 = new Obj2();
+//   obj2.foo = 44;
+//   if (param2) {
+//     return obj2.foo;
+//   }
+//   obj = obj2;
+// }
+// EXIT
+// // obj = PHI[obj1, obj2]
+// // NB The phi acts as an escape for both obj1 and obj2 meaning as far as the
+// // LSA is concerned the escape frontier is left_crit_break->breturn and
+// // right_crit_break->breturn for both even though only one of the objects is
+// // actually live at each edge.
+// // TODO In the future we really should track liveness through PHIs which would
+// // allow us to entirely remove the allocation in this test.
+// return obj.foo;
+TEST_F(LoadStoreEliminationTest, MultiPredicatedLoad3) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"left", "left_end"},
+                                                  {"left_end", "breturn"},
+                                                  {"left", "left_exit_early"},
+                                                  {"left_exit_early", "exit"},
+                                                  {"entry", "right"},
+                                                  {"right", "right_end"},
+                                                  {"right_end", "breturn"},
+                                                  {"right", "right_exit_early"},
+                                                  {"right_exit_early", "exit"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(left_end);
+  GET_BLOCK(left_exit_early);
+  GET_BLOCK(right);
+  GET_BLOCK(right_end);
+  GET_BLOCK(right_exit_early);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {left_end, right_end});
+  HInstruction* param1 = MakeParam(DataType::Type::kBool);
+  HInstruction* param2 = MakeParam(DataType::Type::kBool);
+  HInstruction* c33 = graph_->GetIntConstant(33);
+  HInstruction* c44 = graph_->GetIntConstant(44);
+
+  HInstruction* if_inst = new (GetAllocator()) HIf(param1);
+  entry->AddInstruction(if_inst);
+
+  HInstruction* cls1 = MakeClassLoad();
+  HInstruction* new_inst1 = MakeNewInstance(cls1);
+  HInstruction* write1 = MakeIFieldSet(new_inst1, c33, MemberOffset(32));
+  HInstruction* if_left = new (GetAllocator()) HIf(param2);
+  left->AddInstruction(cls1);
+  left->AddInstruction(new_inst1);
+  left->AddInstruction(write1);
+  left->AddInstruction(if_left);
+  ManuallyBuildEnvFor(cls1, {});
+  new_inst1->CopyEnvironmentFrom(cls1->GetEnvironment());
+
+  left_end->AddInstruction(new (GetAllocator()) HGoto());
+
+  HInstruction* early_exit_left_read =
+      MakeIFieldGet(new_inst1, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* early_exit_left_return = new (GetAllocator()) HReturn(early_exit_left_read);
+  left_exit_early->AddInstruction(early_exit_left_read);
+  left_exit_early->AddInstruction(early_exit_left_return);
+
+  HInstruction* cls2 = MakeClassLoad();
+  HInstruction* new_inst2 = MakeNewInstance(cls2);
+  HInstruction* write2 = MakeIFieldSet(new_inst2, c44, MemberOffset(32));
+  HInstruction* if_right = new (GetAllocator()) HIf(param2);
+  right->AddInstruction(cls2);
+  right->AddInstruction(new_inst2);
+  right->AddInstruction(write2);
+  right->AddInstruction(if_right);
+  cls2->CopyEnvironmentFrom(cls1->GetEnvironment());
+  new_inst2->CopyEnvironmentFrom(cls2->GetEnvironment());
+
+  right_end->AddInstruction(new (GetAllocator()) HGoto());
+
+  HInstruction* early_exit_right_read =
+      MakeIFieldGet(new_inst2, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* early_exit_right_return = new (GetAllocator()) HReturn(early_exit_right_read);
+  right_exit_early->AddInstruction(early_exit_right_read);
+  right_exit_early->AddInstruction(early_exit_right_return);
+
+  HPhi* bottom_phi = MakePhi({new_inst1, new_inst2});
+  HInstruction* read_bottom = MakeIFieldGet(bottom_phi, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddPhi(bottom_phi);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(early_exit_left_read);
+  EXPECT_INS_REMOVED(early_exit_right_read);
+  EXPECT_INS_RETAINED(bottom_phi);
+  EXPECT_INS_RETAINED(read_bottom);
+  EXPECT_INS_EQ(early_exit_left_return->InputAt(0), c33);
+  EXPECT_INS_EQ(early_exit_right_return->InputAt(0), c44);
+  // These assert there is only 1 HNewInstance in the given blocks.
+  HNewInstance* moved_ni1 =
+      FindSingleInstruction<HNewInstance>(graph_, left_end->GetSinglePredecessor());
+  HNewInstance* moved_ni2 =
+      FindSingleInstruction<HNewInstance>(graph_, right_end->GetSinglePredecessor());
+  ASSERT_NE(moved_ni1, nullptr);
+  ASSERT_NE(moved_ni2, nullptr);
+  EXPECT_INS_EQ(bottom_phi->InputAt(0), moved_ni1);
+  EXPECT_INS_EQ(bottom_phi->InputAt(1), moved_ni2);
+}
+
+// Based on structure seen in `java.util.Set java.util.Collections$UnmodifiableMap.entrySet()`
+// We end up having to update a PHI generated by normal LSE.
+// // ENTRY
+// Obj obj_init = param_obj.BAR;
+// if (param1) {
+//   Obj other = new Obj();
+//   other.foo = 42;
+//   if (param2) {
+//     return other.foo;
+//   } else {
+//     param_obj.BAR = other;
+//   }
+// } else { }
+// EXIT
+// LSE Turns this into PHI[obj_init, other]
+// read_bottom = param_obj.BAR;
+// // won't be changed. The escape happens with .BAR set so this is in escaping cohort.
+// return read_bottom.foo;
+TEST_F(LoadStoreEliminationTest, MultiPredicatedLoad4) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"left", "left_early_return"},
+                                                  {"left_early_return", "exit"},
+                                                  {"left", "left_write_escape"},
+                                                  {"left_write_escape", "breturn"},
+                                                  {"entry", "right"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(left_early_return);
+  GET_BLOCK(left_write_escape);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  MemberOffset foo_offset = MemberOffset(32);
+  MemberOffset bar_offset = MemberOffset(20);
+  EnsurePredecessorOrder(breturn, {left_write_escape, right});
+  HInstruction* c42 = graph_->GetIntConstant(42);
+  HInstruction* param1 = MakeParam(DataType::Type::kBool);
+  HInstruction* param2 = MakeParam(DataType::Type::kBool);
+  HInstruction* param_obj = MakeParam(DataType::Type::kReference);
+
+  HInstruction* get_initial = MakeIFieldGet(param_obj, DataType::Type::kReference, bar_offset);
+  HInstruction* if_inst = new (GetAllocator()) HIf(param1);
+  entry->AddInstruction(get_initial);
+  entry->AddInstruction(if_inst);
+
+  HInstruction* cls1 = MakeClassLoad();
+  HInstruction* new_inst1 = MakeNewInstance(cls1);
+  HInstruction* write1 = MakeIFieldSet(new_inst1, c42, foo_offset);
+  HInstruction* if_left = new (GetAllocator()) HIf(param2);
+  left->AddInstruction(cls1);
+  left->AddInstruction(new_inst1);
+  left->AddInstruction(write1);
+  left->AddInstruction(if_left);
+  ManuallyBuildEnvFor(cls1, {});
+  new_inst1->CopyEnvironmentFrom(cls1->GetEnvironment());
+
+  HInstruction* read_early_return = MakeIFieldGet(new_inst1, DataType::Type::kInt32, foo_offset);
+  HInstruction* return_early = new (GetAllocator()) HReturn(read_early_return);
+  left_early_return->AddInstruction(read_early_return);
+  left_early_return->AddInstruction(return_early);
+
+  HInstruction* write_escape = MakeIFieldSet(param_obj, new_inst1, bar_offset);
+  HInstruction* write_goto = new (GetAllocator()) HGoto();
+  left_write_escape->AddInstruction(write_escape);
+  left_write_escape->AddInstruction(write_goto);
+
+  right->AddInstruction(new (GetAllocator()) HGoto());
+
+  HInstruction* read_bottom = MakeIFieldGet(param_obj, DataType::Type::kReference, bar_offset);
+  HInstruction* final_read = MakeIFieldGet(read_bottom, DataType::Type::kInt32, foo_offset);
+  HInstruction* return_exit = new (GetAllocator()) HReturn(final_read);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(final_read);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(read_early_return);
+  EXPECT_INS_EQ(return_early->InputAt(0), c42);
+  EXPECT_INS_RETAINED(final_read);
+  HNewInstance* moved_ni =
+      FindSingleInstruction<HNewInstance>(graph_, left_write_escape->GetSinglePredecessor());
+  EXPECT_TRUE(final_read->InputAt(0)->IsPhi());
+  EXPECT_INS_EQ(final_read->InputAt(0)->InputAt(0), moved_ni);
+  EXPECT_INS_EQ(final_read->InputAt(0)->InputAt(1), get_initial);
+}
+
+// // ENTRY
+// obj = new Obj();
+// obj.field = 3;
+// if (parameter_value) {
+//   // LEFT
+//   escape(obj);
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj.field = 2;
+// }
+// // MERGE
+// if (second_param) {
+//   // NON_ESCAPE
+//   obj.field = 1;
+//   noescape();
+// }
+// EXIT
+// predicated-ELIMINATE
+// return obj.field
+TEST_F(LoadStoreEliminationTest, PredicatedLoad2) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "merge"},
+                                                  {"right", "merge"},
+                                                  {"merge", "non_escape"},
+                                                  {"non_escape", "breturn"},
+                                                  {"merge", "crit_break"},
+                                                  {"crit_break", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+  GET_BLOCK(merge);
+  GET_BLOCK(non_escape);
+  GET_BLOCK(crit_break);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(merge, {left, right});
+  EnsurePredecessorOrder(breturn, {crit_break, non_escape});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* bool_value2 = MakeParam(DataType::Type::kBool);
+  HInstruction* null_const = graph_->GetNullConstant();
+  HInstruction* c1 = graph_->GetIntConstant(1);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_entry = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_entry);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right);
+  right->AddInstruction(goto_right);
+
+  HInstruction* merge_if = new (GetAllocator()) HIf(bool_value2);
+  merge->AddInstruction(merge_if);
+
+  crit_break->AddInstruction(new (GetAllocator()) HGoto());
+
+  HInstruction* write_non_escape = MakeIFieldSet(new_inst, c1, MemberOffset(32));
+  HInstruction* non_escape_call = MakeInvoke(DataType::Type::kVoid, {});
+  HInstruction* non_escape_goto = new (GetAllocator()) HGoto();
+  non_escape->AddInstruction(write_non_escape);
+  non_escape->AddInstruction(non_escape_call);
+  non_escape->AddInstruction(non_escape_goto);
+  non_escape_call->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_RETAINED(call_left);
+  std::vector<HPhi*> merges;
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  std::tie(merges) = FindAllInstructions<HPhi>(graph_);
+  ASSERT_EQ(merges.size(), 3u);
+  HPhi* merge_value_return = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->GetBlock() == breturn;
+  });
+  HPhi* merge_value_merge = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->GetBlock() != breturn;
+  });
+  HPhi* merge_alloc = FindOrNull(merges.begin(), merges.end(), [](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference;
+  });
+  ASSERT_NE(merge_alloc, nullptr);
+  EXPECT_TRUE(merge_alloc->InputAt(0)->IsNewInstance()) << *merge_alloc;
+  EXPECT_INS_EQ(merge_alloc->InputAt(0)->InputAt(0), cls)
+      << " phi is: " << merge_alloc->DumpWithArgs();
+  EXPECT_INS_EQ(merge_alloc->InputAt(1), null_const);
+  ASSERT_NE(pred_get, nullptr);
+  EXPECT_INS_EQ(pred_get->GetTarget(), merge_alloc);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue(), merge_value_return)
+      << "get is " << pred_get->DumpWithArgs();
+  EXPECT_INS_EQ(merge_value_return->InputAt(0), merge_value_merge)
+      << " phi is: " << *merge_value_return;
+  EXPECT_INS_EQ(merge_value_return->InputAt(1), c1)
+      << " phi is: " << merge_value_return->DumpWithArgs();
+  EXPECT_INS_EQ(merge_value_merge->InputAt(0), graph_->GetIntConstant(0))
+      << " phi is: " << *merge_value_merge;
+  EXPECT_INS_EQ(merge_value_merge->InputAt(1), c2)
+      << " phi is: " << merge_value_merge->DumpWithArgs();
+}
+
+// // ENTRY
+// obj = new Obj();
+// obj.field = 3;
+// if (parameter_value) {
+//   // LEFT
+//   escape(obj);
+// } else {
+//   // RIGHT
+//   // ELIMINATE
+//   obj.field = 2;
+// }
+// // MERGE
+// if (second_param) {
+//   // NON_ESCAPE
+//   obj.field = 1;
+// }
+// noescape();
+// EXIT
+// predicated-ELIMINATE
+// return obj.field
+TEST_F(LoadStoreEliminationTest, PredicatedLoad3) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "merge"},
+                                                  {"right", "merge"},
+                                                  {"merge", "non_escape"},
+                                                  {"non_escape", "breturn"},
+                                                  {"merge", "crit_break"},
+                                                  {"crit_break", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+  GET_BLOCK(merge);
+  GET_BLOCK(crit_break);
+  GET_BLOCK(non_escape);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(merge, {left, right});
+  EnsurePredecessorOrder(breturn, {crit_break, non_escape});
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* bool_value2 = MakeParam(DataType::Type::kBool);
+  HInstruction* null_const = graph_->GetNullConstant();
+  HInstruction* c1 = graph_->GetIntConstant(1);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_entry = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_entry);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_right = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right);
+  right->AddInstruction(goto_right);
+
+  HInstruction* merge_if = new (GetAllocator()) HIf(bool_value2);
+  merge->AddInstruction(merge_if);
+
+  HInstruction* write_non_escape = MakeIFieldSet(new_inst, c1, MemberOffset(32));
+  HInstruction* non_escape_goto = new (GetAllocator()) HGoto();
+  non_escape->AddInstruction(write_non_escape);
+  non_escape->AddInstruction(non_escape_goto);
+
+  crit_break->AddInstruction(new (GetAllocator()) HGoto());
+
+  HInstruction* bottom_call = MakeInvoke(DataType::Type::kVoid, {});
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(bottom_call);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+  bottom_call->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(read_bottom);
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_RETAINED(call_left);
+  std::vector<HPhi*> merges;
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  std::tie(merges) = FindAllInstructions<HPhi>(graph_);
+  ASSERT_EQ(merges.size(), 3u);
+  HPhi* merge_value_return = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->GetBlock() == breturn;
+  });
+  HPhi* merge_value_merge = FindOrNull(merges.begin(), merges.end(), [&](HPhi* p) {
+    return p->GetType() == DataType::Type::kInt32 && p->GetBlock() != breturn;
+  });
+  HPhi* merge_alloc = FindOrNull(merges.begin(), merges.end(), [](HPhi* p) {
+    return p->GetType() == DataType::Type::kReference;
+  });
+  ASSERT_NE(merge_alloc, nullptr);
+  EXPECT_TRUE(merge_alloc->InputAt(0)->IsNewInstance()) << merge_alloc->DumpWithArgs();
+  EXPECT_INS_EQ(merge_alloc->InputAt(0)->InputAt(0), cls)
+      << " phi is: " << merge_alloc->DumpWithArgs();
+  EXPECT_INS_EQ(merge_alloc->InputAt(1), null_const);
+  ASSERT_NE(pred_get, nullptr);
+  EXPECT_INS_EQ(pred_get->GetTarget(), merge_alloc);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue(), merge_value_return)
+      << "get is " << pred_get->DumpWithArgs();
+  EXPECT_INS_EQ(merge_value_return->InputAt(0), merge_value_merge)
+      << " phi is: " << *merge_value_return;
+  EXPECT_INS_EQ(merge_value_return->InputAt(1), c1) << " phi is: " << *merge_value_return;
+  EXPECT_INS_EQ(merge_value_merge->InputAt(0), graph_->GetIntConstant(0))
+      << " phi is: " << *merge_value_merge;
+  EXPECT_INS_EQ(merge_value_merge->InputAt(1), c2) << " phi is: " << *merge_value_merge;
+}
+
+// // ENTRY
+// obj = new Obj();
+// // ALL should be kept
+// switch (parameter_value) {
+//   case 1:
+//     // Case1
+//     obj.field = 1;
+//     call_func(obj);
+//     break;
+//   case 2:
+//     // Case2
+//     obj.field = 2;
+//     call_func(obj);
+//     break;
+//   default:
+//     // Case3
+//     obj.field = 3;
+//     do {
+//       if (test2()) { } else { obj.field = 5; }
+//     } while (test());
+//     break;
+// }
+// EXIT
+// // predicated-ELIMINATE
+// return obj.field
+TEST_F(LoadStoreEliminationTest, PartialLoopPhis1) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "bswitch"},
+                                                  {"bswitch", "case1"},
+                                                  {"bswitch", "case2"},
+                                                  {"bswitch", "case3"},
+                                                  {"case1", "breturn"},
+                                                  {"case2", "breturn"},
+                                                  {"case3", "loop_pre_header"},
+                                                  {"loop_pre_header", "loop_header"},
+                                                  {"loop_header", "loop_body"},
+                                                  {"loop_body", "loop_if_left"},
+                                                  {"loop_body", "loop_if_right"},
+                                                  {"loop_if_left", "loop_merge"},
+                                                  {"loop_if_right", "loop_merge"},
+                                                  {"loop_merge", "loop_end"},
+                                                  {"loop_end", "loop_header"},
+                                                  {"loop_end", "critical_break"},
+                                                  {"critical_break", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(bswitch);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(case1);
+  GET_BLOCK(case2);
+  GET_BLOCK(case3);
+
+  GET_BLOCK(loop_pre_header);
+  GET_BLOCK(loop_header);
+  GET_BLOCK(loop_body);
+  GET_BLOCK(loop_if_left);
+  GET_BLOCK(loop_if_right);
+  GET_BLOCK(loop_merge);
+  GET_BLOCK(loop_end);
+  GET_BLOCK(critical_break);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {case1, case2, critical_break});
+  EnsurePredecessorOrder(loop_header, {loop_pre_header, loop_end});
+  EnsurePredecessorOrder(loop_merge, {loop_if_left, loop_if_right});
+  CHECK_SUBROUTINE_FAILURE();
+  HInstruction* switch_val = MakeParam(DataType::Type::kInt32);
+  HInstruction* c1 = graph_->GetIntConstant(1);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c5 = graph_->GetIntConstant(5);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* entry_goto = new (GetAllocator()) HGoto();
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(entry_goto);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, switch_val);
+  bswitch->AddInstruction(switch_inst);
+
+  HInstruction* write_c1 = MakeIFieldSet(new_inst, c1, MemberOffset(32));
+  HInstruction* call_c1 = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_c1 = new (GetAllocator()) HGoto();
+  case1->AddInstruction(write_c1);
+  case1->AddInstruction(call_c1);
+  case1->AddInstruction(goto_c1);
+  call_c1->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_c2 = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* call_c2 = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_c2 = new (GetAllocator()) HGoto();
+  case2->AddInstruction(write_c2);
+  case2->AddInstruction(call_c2);
+  case2->AddInstruction(goto_c2);
+  call_c2->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_c3 = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* goto_c3 = new (GetAllocator()) HGoto();
+  case3->AddInstruction(write_c3);
+  case3->AddInstruction(goto_c3);
+
+  HInstruction* goto_preheader = new (GetAllocator()) HGoto();
+  loop_pre_header->AddInstruction(goto_preheader);
+
+  HInstruction* suspend_check_header = new (GetAllocator()) HSuspendCheck();
+  HInstruction* goto_header = new (GetAllocator()) HGoto();
+  loop_header->AddInstruction(suspend_check_header);
+  loop_header->AddInstruction(goto_header);
+  suspend_check_header->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_loop_body = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* if_loop_body = new (GetAllocator()) HIf(call_loop_body);
+  loop_body->AddInstruction(call_loop_body);
+  loop_body->AddInstruction(if_loop_body);
+  call_loop_body->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_loop_left = new (GetAllocator()) HGoto();
+  loop_if_left->AddInstruction(goto_loop_left);
+
+  HInstruction* write_loop_right = MakeIFieldSet(new_inst, c5, MemberOffset(32));
+  HInstruction* goto_loop_right = new (GetAllocator()) HGoto();
+  loop_if_right->AddInstruction(write_loop_right);
+  loop_if_right->AddInstruction(goto_loop_right);
+
+  HInstruction* goto_loop_merge = new (GetAllocator()) HGoto();
+  loop_merge->AddInstruction(goto_loop_merge);
+
+  HInstruction* call_end = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* if_end = new (GetAllocator()) HIf(call_end);
+  loop_end->AddInstruction(call_end);
+  loop_end->AddInstruction(if_end);
+  call_end->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_critical_break = new (GetAllocator()) HGoto();
+  critical_break->AddInstruction(goto_critical_break);
+
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  EXPECT_INS_REMOVED(read_bottom) << *read_bottom;
+  ASSERT_TRUE(pred_get != nullptr);
+  HPhi* inst_return_phi = pred_get->GetTarget()->AsPhi();
+  ASSERT_TRUE(inst_return_phi != nullptr) << pred_get->GetTarget()->DumpWithArgs();
+  EXPECT_INS_EQ(inst_return_phi->InputAt(0),
+                FindSingleInstruction<HNewInstance>(graph_, case1->GetSinglePredecessor()));
+  EXPECT_INS_EQ(inst_return_phi->InputAt(1),
+                FindSingleInstruction<HNewInstance>(graph_, case2->GetSinglePredecessor()));
+  EXPECT_INS_EQ(inst_return_phi->InputAt(2), graph_->GetNullConstant());
+  HPhi* inst_value_phi = pred_get->GetDefaultValue()->AsPhi();
+  ASSERT_TRUE(inst_value_phi != nullptr) << pred_get->GetDefaultValue()->DumpWithArgs();
+  EXPECT_INS_EQ(inst_value_phi->InputAt(0), graph_->GetIntConstant(0));
+  EXPECT_INS_EQ(inst_value_phi->InputAt(1), graph_->GetIntConstant(0));
+  HPhi* loop_merge_phi = FindSingleInstruction<HPhi>(graph_, loop_merge);
+  ASSERT_TRUE(loop_merge_phi != nullptr);
+  HPhi* loop_header_phi = FindSingleInstruction<HPhi>(graph_, loop_header);
+  ASSERT_TRUE(loop_header_phi != nullptr);
+  EXPECT_INS_EQ(loop_header_phi->InputAt(0), c3);
+  EXPECT_INS_EQ(loop_header_phi->InputAt(1), loop_merge_phi);
+  EXPECT_INS_EQ(loop_merge_phi->InputAt(0), loop_header_phi);
+  EXPECT_INS_EQ(loop_merge_phi->InputAt(1), c5);
+  EXPECT_INS_EQ(inst_value_phi->InputAt(2), loop_merge_phi);
+  EXPECT_INS_RETAINED(write_c1) << *write_c1;
+  EXPECT_INS_RETAINED(write_c2) << *write_c2;
+  EXPECT_INS_REMOVED(write_c3) << *write_c3;
+  EXPECT_INS_REMOVED(write_loop_right) << *write_loop_right;
+}
+
+// // ENTRY
+// obj = new Obj();
+// switch (parameter_value) {
+//   case 1:
+//     // Case1
+//     obj.field = 1;
+//     call_func(obj);
+//     break;
+//   case 2:
+//     // Case2
+//     obj.field = 2;
+//     call_func(obj);
+//     break;
+//   default:
+//     // Case3
+//     obj.field = 3;
+//     while (!test()) {
+//       if (test2()) { } else { obj.field = 5; }
+//     }
+//     break;
+// }
+// EXIT
+// // predicated-ELIMINATE
+// return obj.field
+TEST_F(LoadStoreEliminationTest, PartialLoopPhis2) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "bswitch"},
+                                                  {"bswitch", "case1"},
+                                                  {"bswitch", "case2"},
+                                                  {"bswitch", "case3"},
+                                                  {"case1", "breturn"},
+                                                  {"case2", "breturn"},
+                                                  {"case3", "loop_pre_header"},
+
+                                                  {"loop_pre_header", "loop_header"},
+                                                  {"loop_header", "critical_break"},
+                                                  {"loop_header", "loop_body"},
+                                                  {"loop_body", "loop_if_left"},
+                                                  {"loop_body", "loop_if_right"},
+                                                  {"loop_if_left", "loop_merge"},
+                                                  {"loop_if_right", "loop_merge"},
+                                                  {"loop_merge", "loop_header"},
+
+                                                  {"critical_break", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(bswitch);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(case1);
+  GET_BLOCK(case2);
+  GET_BLOCK(case3);
+
+  GET_BLOCK(loop_pre_header);
+  GET_BLOCK(loop_header);
+  GET_BLOCK(loop_body);
+  GET_BLOCK(loop_if_left);
+  GET_BLOCK(loop_if_right);
+  GET_BLOCK(loop_merge);
+  GET_BLOCK(critical_break);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {case1, case2, critical_break});
+  EnsurePredecessorOrder(loop_header, {loop_pre_header, loop_merge});
+  EnsurePredecessorOrder(loop_merge, {loop_if_left, loop_if_right});
+  CHECK_SUBROUTINE_FAILURE();
+  HInstruction* switch_val = MakeParam(DataType::Type::kInt32);
+  HInstruction* c1 = graph_->GetIntConstant(1);
+  HInstruction* c2 = graph_->GetIntConstant(2);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c5 = graph_->GetIntConstant(5);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* entry_goto = new (GetAllocator()) HGoto();
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(entry_goto);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, switch_val);
+  bswitch->AddInstruction(switch_inst);
+
+  HInstruction* write_c1 = MakeIFieldSet(new_inst, c1, MemberOffset(32));
+  HInstruction* call_c1 = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_c1 = new (GetAllocator()) HGoto();
+  case1->AddInstruction(write_c1);
+  case1->AddInstruction(call_c1);
+  case1->AddInstruction(goto_c1);
+  call_c1->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_c2 = MakeIFieldSet(new_inst, c2, MemberOffset(32));
+  HInstruction* call_c2 = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_c2 = new (GetAllocator()) HGoto();
+  case2->AddInstruction(write_c2);
+  case2->AddInstruction(call_c2);
+  case2->AddInstruction(goto_c2);
+  call_c2->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_c3 = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* goto_c3 = new (GetAllocator()) HGoto();
+  case3->AddInstruction(write_c3);
+  case3->AddInstruction(goto_c3);
+
+  HInstruction* goto_preheader = new (GetAllocator()) HGoto();
+  loop_pre_header->AddInstruction(goto_preheader);
+
+  HInstruction* suspend_check_header = new (GetAllocator()) HSuspendCheck();
+  HInstruction* call_header = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* if_header = new (GetAllocator()) HIf(call_header);
+  loop_header->AddInstruction(suspend_check_header);
+  loop_header->AddInstruction(call_header);
+  loop_header->AddInstruction(if_header);
+  call_header->CopyEnvironmentFrom(cls->GetEnvironment());
+  suspend_check_header->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_loop_body = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* if_loop_body = new (GetAllocator()) HIf(call_loop_body);
+  loop_body->AddInstruction(call_loop_body);
+  loop_body->AddInstruction(if_loop_body);
+  call_loop_body->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_loop_left = new (GetAllocator()) HGoto();
+  loop_if_left->AddInstruction(goto_loop_left);
+
+  HInstruction* write_loop_right = MakeIFieldSet(new_inst, c5, MemberOffset(32));
+  HInstruction* goto_loop_right = new (GetAllocator()) HGoto();
+  loop_if_right->AddInstruction(write_loop_right);
+  loop_if_right->AddInstruction(goto_loop_right);
+
+  HInstruction* goto_loop_merge = new (GetAllocator()) HGoto();
+  loop_merge->AddInstruction(goto_loop_merge);
+
+  HInstruction* goto_critical_break = new (GetAllocator()) HGoto();
+  critical_break->AddInstruction(goto_critical_break);
+
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  EXPECT_INS_REMOVED(read_bottom) << *read_bottom;
+  ASSERT_TRUE(pred_get != nullptr);
+  HPhi* inst_return_phi = pred_get->GetTarget()->AsPhi();
+  ASSERT_TRUE(inst_return_phi != nullptr) << pred_get->GetTarget()->DumpWithArgs();
+  EXPECT_INS_EQ(inst_return_phi->InputAt(0),
+                FindSingleInstruction<HNewInstance>(graph_, case1->GetSinglePredecessor()));
+  EXPECT_INS_EQ(inst_return_phi->InputAt(1),
+                FindSingleInstruction<HNewInstance>(graph_, case2->GetSinglePredecessor()));
+  EXPECT_INS_EQ(inst_return_phi->InputAt(2), graph_->GetNullConstant());
+  HPhi* inst_value_phi = pred_get->GetDefaultValue()->AsPhi();
+  ASSERT_TRUE(inst_value_phi != nullptr) << pred_get->GetDefaultValue()->DumpWithArgs();
+  EXPECT_INS_EQ(inst_value_phi->InputAt(0), graph_->GetIntConstant(0));
+  EXPECT_INS_EQ(inst_value_phi->InputAt(1), graph_->GetIntConstant(0));
+  HPhi* loop_merge_phi = FindSingleInstruction<HPhi>(graph_, loop_merge);
+  ASSERT_TRUE(loop_merge_phi != nullptr);
+  HPhi* loop_header_phi = FindSingleInstruction<HPhi>(graph_, loop_header);
+  ASSERT_TRUE(loop_header_phi != nullptr);
+  EXPECT_INS_EQ(loop_header_phi->InputAt(0), c3);
+  EXPECT_INS_EQ(loop_header_phi->InputAt(1), loop_merge_phi);
+  EXPECT_INS_EQ(loop_merge_phi->InputAt(0), loop_header_phi);
+  EXPECT_INS_EQ(loop_merge_phi->InputAt(1), c5);
+  EXPECT_INS_EQ(inst_value_phi->InputAt(2), loop_header_phi);
+  EXPECT_INS_RETAINED(write_c1) << *write_c1;
+  EXPECT_INS_RETAINED(write_c2) << *write_c2;
+  EXPECT_INS_REMOVED(write_c3) << *write_c3;
+  EXPECT_INS_REMOVED(write_loop_right) << *write_loop_right;
+}
+
+// // ENTRY
+// obj = new Obj();
+// obj.field = 3;
+// while (!test()) {
+//   if (test2()) { } else { obj.field = 5; }
+// }
+// if (parameter_value) {
+//   escape(obj);
+// }
+// EXIT
+// return obj.field
+TEST_F(LoadStoreEliminationTest, PartialLoopPhis3) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "loop_pre_header"},
+
+                                                  {"loop_pre_header", "loop_header"},
+                                                  {"loop_header", "escape_check"},
+                                                  {"loop_header", "loop_body"},
+                                                  {"loop_body", "loop_if_left"},
+                                                  {"loop_body", "loop_if_right"},
+                                                  {"loop_if_left", "loop_merge"},
+                                                  {"loop_if_right", "loop_merge"},
+                                                  {"loop_merge", "loop_header"},
+
+                                                  {"escape_check", "escape"},
+                                                  {"escape_check", "no_escape"},
+                                                  {"no_escape", "breturn"},
+                                                  {"escape", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(no_escape);
+  GET_BLOCK(escape);
+  GET_BLOCK(escape_check);
+
+  GET_BLOCK(loop_pre_header);
+  GET_BLOCK(loop_header);
+  GET_BLOCK(loop_body);
+  GET_BLOCK(loop_if_left);
+  GET_BLOCK(loop_if_right);
+  GET_BLOCK(loop_merge);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {no_escape, escape});
+  EnsurePredecessorOrder(loop_header, {loop_pre_header, loop_merge});
+  EnsurePredecessorOrder(loop_merge, {loop_if_left, loop_if_right});
+  CHECK_SUBROUTINE_FAILURE();
+  HInstruction* bool_val = MakeParam(DataType::Type::kBool);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c5 = graph_->GetIntConstant(5);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* entry_goto = new (GetAllocator()) HGoto();
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(entry_goto);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_pre_header = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* goto_preheader = new (GetAllocator()) HGoto();
+  loop_pre_header->AddInstruction(write_pre_header);
+  loop_pre_header->AddInstruction(goto_preheader);
+
+  HInstruction* suspend_check_header = new (GetAllocator()) HSuspendCheck();
+  HInstruction* call_header = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* if_header = new (GetAllocator()) HIf(call_header);
+  loop_header->AddInstruction(suspend_check_header);
+  loop_header->AddInstruction(call_header);
+  loop_header->AddInstruction(if_header);
+  call_header->CopyEnvironmentFrom(cls->GetEnvironment());
+  suspend_check_header->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_loop_body = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* if_loop_body = new (GetAllocator()) HIf(call_loop_body);
+  loop_body->AddInstruction(call_loop_body);
+  loop_body->AddInstruction(if_loop_body);
+  call_loop_body->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_loop_left = new (GetAllocator()) HGoto();
+  loop_if_left->AddInstruction(goto_loop_left);
+
+  HInstruction* write_loop_right = MakeIFieldSet(new_inst, c5, MemberOffset(32));
+  HInstruction* goto_loop_right = new (GetAllocator()) HGoto();
+  loop_if_right->AddInstruction(write_loop_right);
+  loop_if_right->AddInstruction(goto_loop_right);
+
+  HInstruction* goto_loop_merge = new (GetAllocator()) HGoto();
+  loop_merge->AddInstruction(goto_loop_merge);
+
+  HInstruction* if_esc_check = new (GetAllocator()) HIf(bool_val);
+  escape_check->AddInstruction(if_esc_check);
+
+  HInstruction* call_escape = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_escape = new (GetAllocator()) HGoto();
+  escape->AddInstruction(call_escape);
+  escape->AddInstruction(goto_escape);
+  call_escape->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_no_escape = new (GetAllocator()) HGoto();
+  no_escape->AddInstruction(goto_no_escape);
+
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  EXPECT_INS_REMOVED(read_bottom) << *read_bottom;
+  ASSERT_TRUE(pred_get != nullptr);
+  HPhi* inst_return_phi = pred_get->GetTarget()->AsPhi();
+  ASSERT_TRUE(inst_return_phi != nullptr) << pred_get->GetTarget()->DumpWithArgs();
+  EXPECT_INS_EQ(inst_return_phi->InputAt(0), graph_->GetNullConstant());
+  EXPECT_INS_EQ(inst_return_phi->InputAt(1),
+                FindSingleInstruction<HNewInstance>(graph_, escape->GetSinglePredecessor()));
+  HPhi* inst_value_phi = pred_get->GetDefaultValue()->AsPhi();
+  ASSERT_TRUE(inst_value_phi != nullptr) << pred_get->GetDefaultValue()->DumpWithArgs();
+  HPhi* loop_header_phi = FindSingleInstruction<HPhi>(graph_, loop_header);
+  HPhi* loop_merge_phi = FindSingleInstruction<HPhi>(graph_, loop_merge);
+  EXPECT_INS_EQ(inst_value_phi->InputAt(0), loop_header_phi);
+  EXPECT_INS_EQ(inst_value_phi->InputAt(1), graph_->GetIntConstant(0));
+  EXPECT_INS_EQ(loop_header_phi->InputAt(0), c3);
+  EXPECT_INS_EQ(loop_header_phi->InputAt(1), loop_merge_phi);
+  EXPECT_INS_EQ(loop_merge_phi->InputAt(0), loop_header_phi);
+  EXPECT_INS_EQ(loop_merge_phi->InputAt(1), c5);
+  HInstanceFieldSet* mat_set =
+      FindSingleInstruction<HInstanceFieldSet>(graph_, escape->GetSinglePredecessor());
+  ASSERT_NE(mat_set, nullptr);
+  EXPECT_INS_EQ(mat_set->InputAt(1), loop_header_phi);
+  EXPECT_INS_REMOVED(write_loop_right) << *write_loop_right;
+  EXPECT_INS_REMOVED(write_pre_header) << *write_pre_header;
+}
+
+// // ENTRY
+// obj = new Obj();
+// if (parameter_value) {
+//   escape(obj);
+// }
+// obj.field = 3;
+// while (!test()) {
+//   if (test2()) { } else { obj.field = 5; }
+// }
+// EXIT
+// return obj.field
+TEST_F(LoadStoreEliminationTest, PartialLoopPhis4) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "escape_check"},
+                                                  {"escape_check", "escape"},
+                                                  {"escape_check", "no_escape"},
+                                                  {"no_escape", "loop_pre_header"},
+                                                  {"escape", "loop_pre_header"},
+
+                                                  {"loop_pre_header", "loop_header"},
+                                                  {"loop_header", "breturn"},
+                                                  {"loop_header", "loop_body"},
+                                                  {"loop_body", "loop_if_left"},
+                                                  {"loop_body", "loop_if_right"},
+                                                  {"loop_if_left", "loop_merge"},
+                                                  {"loop_if_right", "loop_merge"},
+                                                  {"loop_merge", "loop_header"},
+
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(no_escape);
+  GET_BLOCK(escape);
+  GET_BLOCK(escape_check);
+
+  GET_BLOCK(loop_pre_header);
+  GET_BLOCK(loop_header);
+  GET_BLOCK(loop_body);
+  GET_BLOCK(loop_if_left);
+  GET_BLOCK(loop_if_right);
+  GET_BLOCK(loop_merge);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(loop_pre_header, {no_escape, escape});
+  EnsurePredecessorOrder(loop_header, {loop_pre_header, loop_merge});
+  EnsurePredecessorOrder(loop_merge, {loop_if_left, loop_if_right});
+  CHECK_SUBROUTINE_FAILURE();
+  HInstruction* bool_val = MakeParam(DataType::Type::kBool);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c5 = graph_->GetIntConstant(5);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* entry_goto = new (GetAllocator()) HGoto();
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(entry_goto);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* if_esc_check = new (GetAllocator()) HIf(bool_val);
+  escape_check->AddInstruction(if_esc_check);
+
+  HInstruction* call_escape = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_escape = new (GetAllocator()) HGoto();
+  escape->AddInstruction(call_escape);
+  escape->AddInstruction(goto_escape);
+  call_escape->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_no_escape = new (GetAllocator()) HGoto();
+  no_escape->AddInstruction(goto_no_escape);
+
+  HInstruction* write_pre_header = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* goto_preheader = new (GetAllocator()) HGoto();
+  loop_pre_header->AddInstruction(write_pre_header);
+  loop_pre_header->AddInstruction(goto_preheader);
+
+  HInstruction* suspend_check_header = new (GetAllocator()) HSuspendCheck();
+  HInstruction* call_header = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* if_header = new (GetAllocator()) HIf(call_header);
+  loop_header->AddInstruction(suspend_check_header);
+  loop_header->AddInstruction(call_header);
+  loop_header->AddInstruction(if_header);
+  call_header->CopyEnvironmentFrom(cls->GetEnvironment());
+  suspend_check_header->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_loop_body = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* if_loop_body = new (GetAllocator()) HIf(call_loop_body);
+  loop_body->AddInstruction(call_loop_body);
+  loop_body->AddInstruction(if_loop_body);
+  call_loop_body->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_loop_left = new (GetAllocator()) HGoto();
+  loop_if_left->AddInstruction(goto_loop_left);
+
+  HInstruction* write_loop_right = MakeIFieldSet(new_inst, c5, MemberOffset(32));
+  HInstruction* goto_loop_right = new (GetAllocator()) HGoto();
+  loop_if_right->AddInstruction(write_loop_right);
+  loop_if_right->AddInstruction(goto_loop_right);
+
+  HInstruction* goto_loop_merge = new (GetAllocator()) HGoto();
+  loop_merge->AddInstruction(goto_loop_merge);
+
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  EXPECT_INS_REMOVED(read_bottom) << *read_bottom;
+  ASSERT_TRUE(pred_get != nullptr);
+  HPhi* inst_return_phi = pred_get->GetTarget()->AsPhi();
+  ASSERT_TRUE(inst_return_phi != nullptr) << pred_get->GetTarget()->DumpWithArgs();
+  EXPECT_INS_EQ(inst_return_phi->InputAt(0), graph_->GetNullConstant());
+  EXPECT_INS_EQ(inst_return_phi->InputAt(1),
+                FindSingleInstruction<HNewInstance>(graph_, escape->GetSinglePredecessor()));
+  HPhi* inst_value_phi = pred_get->GetDefaultValue()->AsPhi();
+  ASSERT_TRUE(inst_value_phi != nullptr) << pred_get->GetDefaultValue()->DumpWithArgs();
+  HPhi* loop_header_phi = FindSingleInstruction<HPhi>(graph_, loop_header);
+  HPhi* loop_merge_phi = FindSingleInstruction<HPhi>(graph_, loop_merge);
+  EXPECT_INS_EQ(inst_value_phi, loop_header_phi);
+  EXPECT_INS_EQ(loop_header_phi->InputAt(0), c3);
+  EXPECT_INS_EQ(loop_header_phi->InputAt(1), loop_merge_phi);
+  EXPECT_INS_EQ(loop_merge_phi->InputAt(0), loop_header_phi);
+  EXPECT_INS_EQ(loop_merge_phi->InputAt(1), c5);
+  EXPECT_INS_RETAINED(write_loop_right) << *write_loop_right;
+  EXPECT_TRUE(write_loop_right->AsInstanceFieldSet()->GetIsPredicatedSet()) << *write_loop_right;
+  EXPECT_INS_RETAINED(write_pre_header) << *write_pre_header;
+  EXPECT_TRUE(write_pre_header->AsInstanceFieldSet()->GetIsPredicatedSet()) << *write_pre_header;
+}
+
+// // ENTRY
+// obj = new Obj();
+// obj.field = 3;
+// while (!test()) {
+//   if (test2()) { } else { obj.field += 5; }
+// }
+// if (parameter_value) {
+//   escape(obj);
+// }
+// EXIT
+// return obj.field
+TEST_F(LoadStoreEliminationTest, PartialLoopPhis5) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(/*handles=*/&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "loop_pre_header"},
+                                                  {"loop_pre_header", "loop_header"},
+                                                  {"loop_header", "escape_check"},
+                                                  {"loop_header", "loop_body"},
+                                                  {"loop_body", "loop_if_left"},
+                                                  {"loop_body", "loop_if_right"},
+                                                  {"loop_if_left", "loop_merge"},
+                                                  {"loop_if_right", "loop_merge"},
+                                                  {"loop_merge", "loop_header"},
+                                                  {"escape_check", "escape"},
+                                                  {"escape_check", "no_escape"},
+                                                  {"no_escape", "breturn"},
+                                                  {"escape", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(no_escape);
+  GET_BLOCK(escape);
+  GET_BLOCK(escape_check);
+
+  GET_BLOCK(loop_pre_header);
+  GET_BLOCK(loop_header);
+  GET_BLOCK(loop_body);
+  GET_BLOCK(loop_if_left);
+  GET_BLOCK(loop_if_right);
+  GET_BLOCK(loop_merge);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {no_escape, escape});
+  EnsurePredecessorOrder(loop_header, {loop_pre_header, loop_merge});
+  EnsurePredecessorOrder(loop_merge, {loop_if_left, loop_if_right});
+  CHECK_SUBROUTINE_FAILURE();
+  HInstruction* bool_val = MakeParam(DataType::Type::kBool);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c5 = graph_->GetIntConstant(5);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* entry_goto = new (GetAllocator()) HGoto();
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(entry_goto);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_pre_header = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* goto_preheader = new (GetAllocator()) HGoto();
+  loop_pre_header->AddInstruction(write_pre_header);
+  loop_pre_header->AddInstruction(goto_preheader);
+
+  HInstruction* suspend_check_header = new (GetAllocator()) HSuspendCheck();
+  HInstruction* call_header = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* if_header = new (GetAllocator()) HIf(call_header);
+  loop_header->AddInstruction(suspend_check_header);
+  loop_header->AddInstruction(call_header);
+  loop_header->AddInstruction(if_header);
+  call_header->CopyEnvironmentFrom(cls->GetEnvironment());
+  suspend_check_header->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_loop_body = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* if_loop_body = new (GetAllocator()) HIf(call_loop_body);
+  loop_body->AddInstruction(call_loop_body);
+  loop_body->AddInstruction(if_loop_body);
+  call_loop_body->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_loop_left = new (GetAllocator()) HGoto();
+  loop_if_left->AddInstruction(goto_loop_left);
+
+  HInstruction* read_loop_right = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* add_loop_right =
+      new (GetAllocator()) HAdd(DataType::Type::kInt32, read_loop_right, c5);
+  HInstruction* write_loop_right = MakeIFieldSet(new_inst, add_loop_right, MemberOffset(32));
+  HInstruction* goto_loop_right = new (GetAllocator()) HGoto();
+  loop_if_right->AddInstruction(read_loop_right);
+  loop_if_right->AddInstruction(add_loop_right);
+  loop_if_right->AddInstruction(write_loop_right);
+  loop_if_right->AddInstruction(goto_loop_right);
+
+  HInstruction* goto_loop_merge = new (GetAllocator()) HGoto();
+  loop_merge->AddInstruction(goto_loop_merge);
+
+  HInstruction* if_esc_check = new (GetAllocator()) HIf(bool_val);
+  escape_check->AddInstruction(if_esc_check);
+
+  HInstruction* call_escape = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_escape = new (GetAllocator()) HGoto();
+  escape->AddInstruction(call_escape);
+  escape->AddInstruction(goto_escape);
+  call_escape->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* goto_no_escape = new (GetAllocator()) HGoto();
+  no_escape->AddInstruction(goto_no_escape);
+
+  HInstruction* read_bottom = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_bottom);
+  breturn->AddInstruction(read_bottom);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSEWithPartial();
+  LOG(INFO) << "Post LSE " << blks;
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  EXPECT_INS_REMOVED(read_bottom) << *read_bottom;
+  ASSERT_TRUE(pred_get != nullptr);
+  HPhi* inst_return_phi = pred_get->GetTarget()->AsPhi();
+  ASSERT_TRUE(inst_return_phi != nullptr) << pred_get->GetTarget()->DumpWithArgs();
+  EXPECT_INS_EQ(inst_return_phi->InputAt(0), graph_->GetNullConstant());
+  EXPECT_INS_EQ(inst_return_phi->InputAt(1),
+                FindSingleInstruction<HNewInstance>(graph_, escape->GetSinglePredecessor()));
+  HPhi* inst_value_phi = pred_get->GetDefaultValue()->AsPhi();
+  ASSERT_TRUE(inst_value_phi != nullptr) << pred_get->GetDefaultValue()->DumpWithArgs();
+  HPhi* loop_header_phi = FindSingleInstruction<HPhi>(graph_, loop_header);
+  HPhi* loop_merge_phi = FindSingleInstruction<HPhi>(graph_, loop_merge);
+  EXPECT_INS_EQ(inst_value_phi->InputAt(0), loop_header_phi);
+  EXPECT_INS_EQ(inst_value_phi->InputAt(1), graph_->GetIntConstant(0));
+  EXPECT_INS_EQ(loop_header_phi->InputAt(0), c3);
+  EXPECT_INS_EQ(loop_header_phi->InputAt(1), loop_merge_phi);
+  EXPECT_INS_EQ(loop_merge_phi->InputAt(0), loop_header_phi);
+  EXPECT_INS_EQ(loop_merge_phi->InputAt(1), add_loop_right);
+  EXPECT_INS_EQ(add_loop_right->InputAt(0), loop_header_phi);
+  EXPECT_INS_EQ(add_loop_right->InputAt(1), c5);
+  HInstanceFieldSet* mat_set =
+      FindSingleInstruction<HInstanceFieldSet>(graph_, escape->GetSinglePredecessor());
+  ASSERT_NE(mat_set, nullptr);
+  EXPECT_INS_EQ(mat_set->InputAt(1), loop_header_phi);
+  EXPECT_INS_REMOVED(write_loop_right) << *write_loop_right;
+  EXPECT_INS_REMOVED(write_pre_header) << *write_pre_header;
+}
+
+// TODO This should really be in an Instruction simplifier Gtest but (1) that
+// doesn't exist and (2) we should move this simplification to directly in the
+// LSE pass since there is more information then.
+// // ENTRY
+// obj = new Obj();
+// obj.field = 3;
+// if (param) {
+//   escape(obj);
+// } else {
+//   obj.field = 10;
+// }
+// return obj.field;
+TEST_F(LoadStoreEliminationTest, SimplifyTest) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {left, right});
+
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c10 = graph_->GetIntConstant(10);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_start = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_start);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_right = MakeIFieldSet(new_inst, c10, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(write_right);
+  right->AddInstruction(goto_right);
+
+  HInstruction* read_end = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_end);
+  breturn->AddInstruction(read_end);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
   PerformLSE();
 
-  EXPECT_TRUE(IsRemoved(read_bottom));
-  EXPECT_TRUE(IsRemoved(write_right));
-  EXPECT_FALSE(IsRemoved(write_entry));
-  EXPECT_FALSE(IsRemoved(write_left));
-  EXPECT_FALSE(IsRemoved(call_left));
-  EXPECT_FALSE(IsRemoved(call_entry));
+  // Run the code-simplifier too
+  LOG(INFO) << "Pre simplification " << blks;
+  InstructionSimplifier simp(graph_, /*codegen=*/nullptr);
+  simp.Run();
+
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_REMOVED(write_start);
+  EXPECT_INS_REMOVED(read_end);
+  EXPECT_INS_RETAINED(call_left);
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  ASSERT_NE(pred_get, nullptr);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue(), c10);
+}
+
+
+// TODO This should really be in an Instruction simplifier Gtest but (1) that
+// doesn't exist and (2) we should move this simplification to directly in the
+// LSE pass since there is more information then.
+//
+// This checks that we don't replace phis when the replacement isn't valid at
+// that point (i.e. it doesn't dominate)
+// // ENTRY
+// obj = new Obj();
+// obj.field = 3;
+// if (param) {
+//   escape(obj);
+// } else {
+//   obj.field = noescape();
+// }
+// return obj.field;
+TEST_F(LoadStoreEliminationTest, SimplifyTest2) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+                                                  {"right", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {left, right});
+
+  HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_start = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_start);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, {new_inst});
+  HInstruction* goto_left = new (GetAllocator()) HGoto();
+  left->AddInstruction(call_left);
+  left->AddInstruction(goto_left);
+  call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_right = MakeInvoke(DataType::Type::kInt32, {});
+  HInstruction* write_right = MakeIFieldSet(new_inst, call_right, MemberOffset(32));
+  HInstruction* goto_right = new (GetAllocator()) HGoto();
+  right->AddInstruction(call_right);
+  right->AddInstruction(write_right);
+  right->AddInstruction(goto_right);
+  call_right->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* read_end = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_end);
+  breturn->AddInstruction(read_end);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSE();
+
+  // Run the code-simplifier too
+  LOG(INFO) << "Pre simplification " << blks;
+  InstructionSimplifier simp(graph_, /*codegen=*/nullptr);
+  simp.Run();
+
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(write_right);
+  EXPECT_INS_REMOVED(write_start);
+  EXPECT_INS_REMOVED(read_end);
+  EXPECT_INS_RETAINED(call_left);
+  EXPECT_INS_RETAINED(call_right);
+  EXPECT_EQ(call_right->GetBlock(), right);
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  ASSERT_NE(pred_get, nullptr);
+  EXPECT_TRUE(pred_get->GetDefaultValue()->IsPhi()) << pred_get->DumpWithArgs();
+  EXPECT_INS_EQ(pred_get->GetDefaultValue()->InputAt(0), graph_->GetIntConstant(0))
+      << pred_get->DumpWithArgs();
+  EXPECT_INS_EQ(pred_get->GetDefaultValue()->InputAt(1), call_right) << pred_get->DumpWithArgs();
+}
+
+// TODO This should really be in an Instruction simplifier Gtest but (1) that
+// doesn't exist and (2) we should move this simplification to directly in the
+// LSE pass since there is more information then.
+//
+// This checks that we replace phis even when there are multiple replacements as
+// long as they are equal
+// // ENTRY
+// obj = new Obj();
+// obj.field = 3;
+// switch (param) {
+//   case 1:
+//     escape(obj);
+//     break;
+//   case 2:
+//     obj.field = 10;
+//     break;
+//   case 3:
+//     obj.field = 10;
+//     break;
+// }
+// return obj.field;
+TEST_F(LoadStoreEliminationTest, SimplifyTest3) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "case1"},
+                                                  {"entry", "case2"},
+                                                  {"entry", "case3"},
+                                                  {"case1", "breturn"},
+                                                  {"case2", "breturn"},
+                                                  {"case3", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(case1);
+  GET_BLOCK(case2);
+  GET_BLOCK(case3);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {case1, case2, case3});
+
+  HInstruction* int_val = MakeParam(DataType::Type::kInt32);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c10 = graph_->GetIntConstant(10);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_start = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, int_val);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_start);
+  entry->AddInstruction(switch_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_case1 = MakeInvoke(DataType::Type::kVoid, {new_inst});
+  HInstruction* goto_case1 = new (GetAllocator()) HGoto();
+  case1->AddInstruction(call_case1);
+  case1->AddInstruction(goto_case1);
+  call_case1->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_case2 = MakeIFieldSet(new_inst, c10, MemberOffset(32));
+  HInstruction* goto_case2 = new (GetAllocator()) HGoto();
+  case2->AddInstruction(write_case2);
+  case2->AddInstruction(goto_case2);
+
+  HInstruction* write_case3 = MakeIFieldSet(new_inst, c10, MemberOffset(32));
+  HInstruction* goto_case3 = new (GetAllocator()) HGoto();
+  case3->AddInstruction(write_case3);
+  case3->AddInstruction(goto_case3);
+
+  HInstruction* read_end = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_end);
+  breturn->AddInstruction(read_end);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSE();
+
+  // Run the code-simplifier too
+  LOG(INFO) << "Pre simplification " << blks;
+  InstructionSimplifier simp(graph_, /*codegen=*/nullptr);
+  simp.Run();
+
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(write_case2);
+  EXPECT_INS_REMOVED(write_case3);
+  EXPECT_INS_REMOVED(write_start);
+  EXPECT_INS_REMOVED(read_end);
+  EXPECT_INS_RETAINED(call_case1);
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  ASSERT_NE(pred_get, nullptr);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue(), c10)
+      << pred_get->DumpWithArgs();
+}
+
+// TODO This should really be in an Instruction simplifier Gtest but (1) that
+// doesn't exist and (2) we should move this simplification to directly in the
+// LSE pass since there is more information then.
+//
+// This checks that we don't replace phis even when there are multiple
+// replacements if they are not equal
+// // ENTRY
+// obj = new Obj();
+// obj.field = 3;
+// switch (param) {
+//   case 1:
+//     escape(obj);
+//     break;
+//   case 2:
+//     obj.field = 10;
+//     break;
+//   case 3:
+//     obj.field = 20;
+//     break;
+// }
+// return obj.field;
+TEST_F(LoadStoreEliminationTest, SimplifyTest4) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+                                                 "exit",
+                                                 {{"entry", "case1"},
+                                                  {"entry", "case2"},
+                                                  {"entry", "case3"},
+                                                  {"case1", "breturn"},
+                                                  {"case2", "breturn"},
+                                                  {"case3", "breturn"},
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(case1);
+  GET_BLOCK(case2);
+  GET_BLOCK(case3);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {case1, case2, case3});
+
+  HInstruction* int_val = MakeParam(DataType::Type::kInt32);
+  HInstruction* c3 = graph_->GetIntConstant(3);
+  HInstruction* c10 = graph_->GetIntConstant(10);
+  HInstruction* c20 = graph_->GetIntConstant(20);
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_start = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+  HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, int_val);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_start);
+  entry->AddInstruction(switch_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* call_case1 = MakeInvoke(DataType::Type::kVoid, {new_inst});
+  HInstruction* goto_case1 = new (GetAllocator()) HGoto();
+  case1->AddInstruction(call_case1);
+  case1->AddInstruction(goto_case1);
+  call_case1->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* write_case2 = MakeIFieldSet(new_inst, c10, MemberOffset(32));
+  HInstruction* goto_case2 = new (GetAllocator()) HGoto();
+  case2->AddInstruction(write_case2);
+  case2->AddInstruction(goto_case2);
+
+  HInstruction* write_case3 = MakeIFieldSet(new_inst, c20, MemberOffset(32));
+  HInstruction* goto_case3 = new (GetAllocator()) HGoto();
+  case3->AddInstruction(write_case3);
+  case3->AddInstruction(goto_case3);
+
+  HInstruction* read_end = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_end);
+  breturn->AddInstruction(read_end);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSE();
+
+  // Run the code-simplifier too
+  LOG(INFO) << "Pre simplification " << blks;
+  InstructionSimplifier simp(graph_, /*codegen=*/nullptr);
+  simp.Run();
+
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_INS_REMOVED(write_case2);
+  EXPECT_INS_REMOVED(write_case3);
+  EXPECT_INS_REMOVED(write_start);
+  EXPECT_INS_REMOVED(read_end);
+  EXPECT_INS_RETAINED(call_case1);
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  ASSERT_NE(pred_get, nullptr);
+  EXPECT_TRUE(pred_get->GetDefaultValue()->IsPhi())
+      << pred_get->DumpWithArgs();
+  EXPECT_INS_EQ(pred_get->GetDefaultValue()->InputAt(0), graph_->GetIntConstant(0));
+  EXPECT_INS_EQ(pred_get->GetDefaultValue()->InputAt(1), c10);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue()->InputAt(2), c20);
+}
+
+// Make sure that irreducible loops don't screw up Partial LSE. We can't pull
+// phis through them so we need to treat them as escapes.
+// TODO We should be able to do better than this? Need to do some research.
+// // ENTRY
+// obj = new Obj();
+// obj.foo = 11;
+// if (param1) {
+// } else {
+//   // irreducible loop here. NB the objdoesn't actually escape
+//   obj.foo = 33;
+//   if (param2) {
+//     goto inner;
+//   } else {
+//     while (test()) {
+//       if (test()) {
+//         obj.foo = 66;
+//       } else {
+//       }
+//       inner:
+//     }
+//   }
+// }
+// return obj.foo;
+TEST_F(LoadStoreEliminationTest, PartialIrreducibleLoop) {
+  VariableSizedHandleScope vshs(Thread::Current());
+  CreateGraph(&vshs);
+  AdjacencyListGraph blks(SetupFromAdjacencyList("start",
+                                                 "exit",
+                                                 {{"start", "entry"},
+                                                  {"entry", "left"},
+                                                  {"entry", "right"},
+                                                  {"left", "breturn"},
+
+                                                  {"right", "right_crit_break_loop"},
+                                                  {"right_crit_break_loop", "loop_header"},
+                                                  {"right", "right_crit_break_end"},
+                                                  {"right_crit_break_end", "loop_end"},
+
+                                                  {"loop_header", "loop_body"},
+                                                  {"loop_body", "loop_left"},
+                                                  {"loop_body", "loop_right"},
+                                                  {"loop_left", "loop_end"},
+                                                  {"loop_right", "loop_end"},
+                                                  {"loop_end", "loop_header"},
+                                                  {"loop_header", "loop_header_crit_break"},
+                                                  {"loop_header_crit_break", "breturn"},
+
+                                                  {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+  GET_BLOCK(start);
+  GET_BLOCK(entry);
+  GET_BLOCK(exit);
+  GET_BLOCK(breturn);
+  GET_BLOCK(left);
+  GET_BLOCK(right);
+  GET_BLOCK(right_crit_break_end);
+  GET_BLOCK(right_crit_break_loop);
+  GET_BLOCK(loop_header);
+  GET_BLOCK(loop_header_crit_break);
+  GET_BLOCK(loop_body);
+  GET_BLOCK(loop_left);
+  GET_BLOCK(loop_right);
+  GET_BLOCK(loop_end);
+#undef GET_BLOCK
+  EnsurePredecessorOrder(breturn, {left, loop_header_crit_break});
+  HInstruction* c11 = graph_->GetIntConstant(11);
+  HInstruction* c33 = graph_->GetIntConstant(33);
+  HInstruction* c66 = graph_->GetIntConstant(66);
+  HInstruction* param1 = MakeParam(DataType::Type::kBool);
+  HInstruction* param2 = MakeParam(DataType::Type::kBool);
+
+  HInstruction* suspend = new (GetAllocator()) HSuspendCheck();
+  HInstruction* start_goto = new (GetAllocator()) HGoto();
+  start->AddInstruction(suspend);
+  start->AddInstruction(start_goto);
+  ManuallyBuildEnvFor(suspend, {});
+
+  HInstruction* cls = MakeClassLoad();
+  HInstruction* new_inst = MakeNewInstance(cls);
+  HInstruction* write_start = MakeIFieldSet(new_inst, c11, MemberOffset(32));
+  HInstruction* if_inst = new (GetAllocator()) HIf(param1);
+  entry->AddInstruction(cls);
+  entry->AddInstruction(new_inst);
+  entry->AddInstruction(write_start);
+  entry->AddInstruction(if_inst);
+  ManuallyBuildEnvFor(cls, {});
+  new_inst->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  left->AddInstruction(new (GetAllocator()) HGoto());
+
+  right->AddInstruction(MakeIFieldSet(new_inst, c33, MemberOffset(32)));
+  right->AddInstruction(new (GetAllocator()) HIf(param2));
+
+  right_crit_break_end->AddInstruction(new (GetAllocator()) HGoto());
+  right_crit_break_loop->AddInstruction(new (GetAllocator()) HGoto());
+
+  HInstruction* header_suspend = new (GetAllocator()) HSuspendCheck();
+  HInstruction* header_invoke = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* header_if = new (GetAllocator()) HIf(header_invoke);
+  loop_header->AddInstruction(header_suspend);
+  loop_header->AddInstruction(header_invoke);
+  loop_header->AddInstruction(header_if);
+  header_suspend->CopyEnvironmentFrom(cls->GetEnvironment());
+  header_invoke->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* body_invoke = MakeInvoke(DataType::Type::kBool, {});
+  HInstruction* body_if = new (GetAllocator()) HIf(body_invoke);
+  loop_body->AddInstruction(body_invoke);
+  loop_body->AddInstruction(body_if);
+  body_invoke->CopyEnvironmentFrom(cls->GetEnvironment());
+
+  HInstruction* left_set = MakeIFieldSet(new_inst, c66, MemberOffset(32));
+  HInstruction* left_goto = MakeIFieldSet(new_inst, c66, MemberOffset(32));
+  loop_left->AddInstruction(left_set);
+  loop_left->AddInstruction(left_goto);
+
+  loop_right->AddInstruction(new (GetAllocator()) HGoto());
+
+  loop_end->AddInstruction(new (GetAllocator()) HGoto());
+
+  HInstruction* read_end = MakeIFieldGet(new_inst, DataType::Type::kInt32, MemberOffset(32));
+  HInstruction* return_exit = new (GetAllocator()) HReturn(read_end);
+  breturn->AddInstruction(read_end);
+  breturn->AddInstruction(return_exit);
+
+  SetupExit(exit);
+
+  // PerformLSE expects this to be empty.
+  graph_->ClearDominanceInformation();
+  LOG(INFO) << "Pre LSE " << blks;
+  PerformLSE();
+  LOG(INFO) << "Post LSE " << blks;
+
+  EXPECT_TRUE(loop_header->IsLoopHeader());
+  EXPECT_TRUE(loop_header->GetLoopInformation()->IsIrreducible());
+
+  EXPECT_INS_RETAINED(left_set);
+  EXPECT_INS_REMOVED(write_start);
+  EXPECT_INS_REMOVED(read_end);
+
+  HPredicatedInstanceFieldGet* pred_get =
+      FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+  ASSERT_NE(pred_get, nullptr);
+  ASSERT_TRUE(pred_get->GetDefaultValue()->IsPhi()) << pred_get->DumpWithArgs();
+  EXPECT_INS_EQ(pred_get->GetDefaultValue()->InputAt(0), c11);
+  EXPECT_INS_EQ(pred_get->GetDefaultValue()->InputAt(1), graph_->GetIntConstant(0));
+  ASSERT_TRUE(pred_get->GetTarget()->IsPhi()) << pred_get->DumpWithArgs();
+  EXPECT_INS_EQ(pred_get->GetTarget()->InputAt(0), graph_->GetNullConstant());
+  HNewInstance* mat = FindSingleInstruction<HNewInstance>(graph_, right->GetSinglePredecessor());
+  ASSERT_NE(mat, nullptr);
+  EXPECT_INS_EQ(pred_get->GetTarget()->InputAt(1), mat);
 }
 
 }  // namespace art