Restore partial LSE.

This fixes a bug where we were using the wrong value for initializing an
allocation that we moved. See this test:
https://android-review.googlesource.com/c/platform/art/+/1825138/4/test/828-partial-lse/src/Main.java

Run LSE twice: one for the classical load store eliminiation, one for
moving allocations.

Test: test.py
Bug: 197981962
Change-Id: If317e10e239488876180047040dba66ae3fc8d4c
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 722cc83..ef902ce 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -335,7 +335,7 @@
              bool perform_partial_lse,
              OptimizingCompilerStats* stats);
 
-  void Run();
+  void Run(bool partial);
 
  private:
   class PhiPlaceholder {
@@ -2749,57 +2749,7 @@
             !success);
 }
 
-struct ScopedRestoreHeapValues {
- public:
-  ScopedRestoreHeapValues(ArenaStack* alloc,
-                          size_t num_heap_locs,
-                          ScopedArenaVector<ScopedArenaVector<LSEVisitor::ValueRecord>>& to_restore)
-      : alloc_(alloc),
-        updated_values_(alloc_.Adapter(kArenaAllocLSE)),
-        to_restore_(to_restore) {
-    updated_values_.reserve(num_heap_locs * to_restore_.size());
-  }
-
-  ~ScopedRestoreHeapValues() {
-    for (const auto& rec : updated_values_) {
-      to_restore_[rec.blk_id][rec.heap_loc].value = rec.val_;
-    }
-  }
-
-  template<typename Func>
-  void ForEachRecord(Func func) {
-    for (size_t blk_id : Range(to_restore_.size())) {
-      for (size_t heap_loc : Range(to_restore_[blk_id].size())) {
-        LSEVisitor::ValueRecord* vr = &to_restore_[blk_id][heap_loc];
-        LSEVisitor::Value initial = vr->value;
-        func(vr);
-        if (!vr->value.ExactEquals(initial)) {
-          updated_values_.push_back({blk_id, heap_loc, initial});
-        }
-      }
-    }
-  }
-
- private:
-  struct UpdateRecord {
-    size_t blk_id;
-    size_t heap_loc;
-    LSEVisitor::Value val_;
-  };
-  ScopedArenaAllocator alloc_;
-  ScopedArenaVector<UpdateRecord> updated_values_;
-  ScopedArenaVector<ScopedArenaVector<LSEVisitor::ValueRecord>>& to_restore_;
-
-  DISALLOW_COPY_AND_ASSIGN(ScopedRestoreHeapValues);
-};
-
 void LSEVisitor::FindStoresWritingOldValues() {
-  // Partial LSE relies on knowing the real heap-values not the
-  // store-replacement versions so we need to restore the map after removing
-  // stores.
-  ScopedRestoreHeapValues heap_vals(allocator_.GetArenaStack(),
-                                    heap_location_collector_.GetNumberOfHeapLocations(),
-                                    heap_values_for_);
   // The Phi placeholder replacements have so far been used for eliminating loads,
   // tracking values that would be stored if all stores were kept. As we want to
   // compare actual old values after removing unmarked stores, prune the Phi
@@ -2814,14 +2764,10 @@
   }
 
   // Update heap values at end of blocks.
-  heap_vals.ForEachRecord([&](ValueRecord* rec) {
-    UpdateValueRecordForStoreElimination(rec);
-  });
-
-  if (kIsDebugBuild) {
-    heap_vals.ForEachRecord([](ValueRecord* rec) {
-      DCHECK(!rec->value.NeedsNonLoopPhi()) << rec->value;
-    });
+  for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) {
+    for (ValueRecord& value_record : heap_values_for_[block->GetBlockId()]) {
+      UpdateValueRecordForStoreElimination(&value_record);
+    }
   }
 
   // Use local allocator to reduce peak memory usage.
@@ -2856,30 +2802,32 @@
   kept_stores_.Subtract(&eliminated_stores);
 }
 
-void LSEVisitor::Run() {
-  // 1. Process blocks and instructions in reverse post order.
+void LSEVisitor::Run(bool partial) {
+  // Process blocks and instructions in reverse post order.
   for (HBasicBlock* block : GetGraph()->GetReversePostOrder()) {
     VisitBasicBlock(block);
   }
 
-  // 2. Process loads that require loop Phis, trying to find/create replacements.
-  current_phase_ = Phase::kLoadElimination;
-  ProcessLoadsRequiringLoopPhis();
+  if (partial) {
+    // Move partial escapes down and fixup with PHIs.
+    current_phase_ = Phase::kPartialElimination;
+    MovePartialEscapes();
+  } else {
+    // Process loads that require loop Phis, trying to find/create replacements.
+    current_phase_ = Phase::kLoadElimination;
+    ProcessLoadsRequiringLoopPhis();
 
-  // 3. Determine which stores to keep and which to eliminate.
-  current_phase_ = Phase::kStoreElimination;
-  // Finish marking stores for keeping.
-  SearchPhiPlaceholdersForKeptStores();
+    // Determine which stores to keep and which to eliminate.
+    current_phase_ = Phase::kStoreElimination;
+    // Finish marking stores for keeping.
+    SearchPhiPlaceholdersForKeptStores();
 
-  // Find stores that write the same value as is already present in the location.
-  FindStoresWritingOldValues();
+    // Find stores that write the same value as is already present in the location.
+    FindStoresWritingOldValues();
 
-  // 4. Replace loads and remove unnecessary stores and singleton allocations.
-  FinishFullLSE();
-
-  // 5. Move partial escapes down and fixup with PHIs.
-  current_phase_ = Phase::kPartialElimination;
-  MovePartialEscapes();
+    // Replace loads and remove unnecessary stores and singleton allocations.
+    FinishFullLSE();
+  }
 }
 
 // Clear unknown loop-phi results. Here we'll be able to use partial-unknowns so we need to
@@ -3863,8 +3811,8 @@
                     OptimizingCompilerStats* stats)
       : lse_visitor_(graph, heap_location_collector, perform_partial_lse, stats) {}
 
-  void Run() {
-    lse_visitor_.Run();
+  void Run(bool partial) {
+    lse_visitor_.Run(partial);
   }
 
  private:
@@ -3884,22 +3832,37 @@
   // This is O(blocks^3) time complexity. It means we can query reachability in
   // O(1) though.
   graph_->ComputeReachabilityInformation();
-  ScopedArenaAllocator allocator(graph_->GetArenaStack());
-  LoadStoreAnalysis lsa(graph_,
-                        stats_,
-                        &allocator,
-                        enable_partial_lse ? LoadStoreAnalysisType::kFull
-                                           : LoadStoreAnalysisType::kNoPredicatedInstructions);
-  lsa.Run();
-  const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector();
-  if (heap_location_collector.GetNumberOfHeapLocations() == 0) {
-    // No HeapLocation information from LSA, skip this optimization.
-    return false;
-  }
 
-  std::unique_ptr<LSEVisitorWrapper> lse_visitor(new (&allocator) LSEVisitorWrapper(
-      graph_, heap_location_collector, enable_partial_lse, stats_));
-  lse_visitor->Run();
+  {
+    ScopedArenaAllocator allocator(graph_->GetArenaStack());
+    LoadStoreAnalysis lsa(graph_,
+                          stats_,
+                          &allocator,
+                          LoadStoreAnalysisType::kNoPredicatedInstructions);
+    lsa.Run();
+    const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector();
+    if (heap_location_collector.GetNumberOfHeapLocations() == 0) {
+      // No HeapLocation information from LSA, skip this optimization.
+      return false;
+    }
+    std::unique_ptr<LSEVisitorWrapper> lse_visitor(new (&allocator) LSEVisitorWrapper(
+        graph_, heap_location_collector, enable_partial_lse, stats_));
+    lse_visitor->Run(/* partial= */ false);
+  }
+  if (enable_partial_lse) {
+    ScopedArenaAllocator allocator(graph_->GetArenaStack());
+    LoadStoreAnalysis lsa(graph_,
+                          stats_,
+                          &allocator,
+                          LoadStoreAnalysisType::kFull);
+    lsa.Run();
+    const HeapLocationCollector& heap_location_collector = lsa.GetHeapLocationCollector();
+    if (heap_location_collector.GetNumberOfHeapLocations() != 0) {
+      std::unique_ptr<LSEVisitorWrapper> lse_visitor(new (&allocator) LSEVisitorWrapper(
+          graph_, heap_location_collector, enable_partial_lse, stats_));
+      lse_visitor->Run(/* partial= */ true);
+    }
+  }
   return true;
 }
 
diff --git a/compiler/optimizing/load_store_elimination.h b/compiler/optimizing/load_store_elimination.h
index 6ad2eb2..e73ef5e 100644
--- a/compiler/optimizing/load_store_elimination.h
+++ b/compiler/optimizing/load_store_elimination.h
@@ -27,7 +27,7 @@
  public:
   // Whether or not we should attempt partial Load-store-elimination which
   // requires additional blocks and predicated instructions.
-  static constexpr bool kEnablePartialLSE = false;
+  static constexpr bool kEnablePartialLSE = true;
 
   // Controls whether to enable VLOG(compiler) logs explaining the transforms taking place.
   static constexpr bool kVerboseLoggingMode = false;
diff --git a/compiler/optimizing/load_store_elimination_test.cc b/compiler/optimizing/load_store_elimination_test.cc
index 812a32a..0943489 100644
--- a/compiler/optimizing/load_store_elimination_test.cc
+++ b/compiler/optimizing/load_store_elimination_test.cc
@@ -7503,20 +7503,10 @@
                 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;
 }
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index a707a8a..f3f3ed7 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -3964,6 +3964,249 @@
     return res;
   }
 
+    /// CHECK-START: int Main.$noinline$testPartialEscape2(TestClass, boolean) load_store_elimination (before)
+  /// CHECK-DAG:     ParameterValue
+  /// CHECK-DAG:     NewInstance
+  /// CHECK-DAG:     InvokeStaticOrDirect
+  /// CHECK-DAG:     InvokeStaticOrDirect
+  /// CHECK-DAG:     InvokeStaticOrDirect
+  /// CHECK-DAG:     InstanceFieldSet
+  /// CHECK-DAG:     InstanceFieldSet
+  /// CHECK-DAG:     InstanceFieldSet
+  /// CHECK-DAG:     InstanceFieldGet
+  /// CHECK-DAG:     InstanceFieldGet
+  //
+  /// CHECK-START: int Main.$noinline$testPartialEscape2(TestClass, boolean) load_store_elimination (after)
+  /// CHECK-DAG:     ParameterValue
+  /// CHECK-DAG:     NewInstance
+  /// CHECK-DAG:     Phi
+  //
+  /// CHECK-START: int Main.$noinline$testPartialEscape2(TestClass, boolean) load_store_elimination (after)
+  /// CHECK:         InvokeStaticOrDirect
+  /// CHECK:         InvokeStaticOrDirect
+  /// CHECK:         InvokeStaticOrDirect
+  //
+  /// CHECK-NOT:     InvokeStaticOrDirect
+
+  /// CHECK-START: int Main.$noinline$testPartialEscape2(TestClass, boolean) load_store_elimination (after)
+  /// CHECK:         InstanceFieldSet predicated:false
+  /// CHECK-NOT:     InstanceFieldSet predicated:false
+  //
+  /// CHECK-START: int Main.$noinline$testPartialEscape2(TestClass, boolean) load_store_elimination (after)
+  /// CHECK:         InstanceFieldSet predicated:true
+  /// CHECK-NOT:     InstanceFieldSet predicated:true
+  //
+  /// CHECK-START: int Main.$noinline$testPartialEscape2(TestClass, boolean) load_store_elimination (after)
+  /// CHECK:         InstanceFieldGet
+  //
+  /// CHECK-NOT:     InstanceFieldGet
+  //
+  /// CHECK-START: int Main.$noinline$testPartialEscape2(TestClass, boolean) load_store_elimination (after)
+  /// CHECK:         PredicatedInstanceFieldGet
+  //
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  private static int $noinline$testPartialEscape2(TestClass obj, boolean escape) {
+    TestClass i = new SubTestClass();
+    if ($noinline$getBoolean(escape)) {
+      i.next = obj;
+      $noinline$Escape(i);
+    } else {
+      i.next = obj;
+    }
+    $noinline$clobberObservables();
+    // Predicated-get
+    TestClass res = i.next;
+    // Predicated-set
+    i.next = null;
+    return res.i;
+  }
+
+  /// CHECK-START: float Main.$noinline$testPartialEscape3_float(boolean) load_store_elimination (before)
+  /// CHECK-NOT:     Phi
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  //
+  /// CHECK-START: float Main.$noinline$testPartialEscape3_float(boolean) load_store_elimination (after)
+  /// CHECK:         Phi
+  /// CHECK:         Phi
+  /// CHECK-NOT:     Phi
+  //
+  /// CHECK-START: float Main.$noinline$testPartialEscape3_float(boolean) load_store_elimination (after)
+  /// CHECK:         InstanceFieldSet predicated:true
+  /// CHECK-NOT:     InstanceFieldSet predicated:true
+  //
+  /// CHECK-START: float Main.$noinline$testPartialEscape3_float(boolean) load_store_elimination (after)
+  /// CHECK:         PredicatedInstanceFieldGet
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  private static float $noinline$testPartialEscape3_float(boolean escape) {
+    TestClass4 tc = new TestClass4();
+    if ($noinline$getBoolean(escape)) {
+      $noinline$Escape4(tc);
+    } else {
+      tc.floatField -= 1f;
+    }
+    // Partial escape
+    $noinline$clobberObservables();
+    // Predicated set
+    tc.floatField *= 10;
+    // Predicated get
+    return tc.floatField;
+  }
+
+  /// CHECK-START: double Main.$noinline$testPartialEscape3_double(boolean) load_store_elimination (before)
+  /// CHECK-NOT:     Phi
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  //
+  /// CHECK-START: double Main.$noinline$testPartialEscape3_double(boolean) load_store_elimination (after)
+  /// CHECK:         Phi
+  /// CHECK:         Phi
+  /// CHECK-NOT:     Phi
+  //
+  /// CHECK-START: double Main.$noinline$testPartialEscape3_double(boolean) load_store_elimination (after)
+  /// CHECK:         InstanceFieldSet predicated:true
+  /// CHECK-NOT:     InstanceFieldSet predicated:true
+  //
+  /// CHECK-START: double Main.$noinline$testPartialEscape3_double(boolean) load_store_elimination (after)
+  /// CHECK:         PredicatedInstanceFieldGet
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  private static double $noinline$testPartialEscape3_double(boolean escape) {
+    TestClass4 tc = new TestClass4();
+    if ($noinline$getBoolean(escape)) {
+      $noinline$Escape4(tc);
+    } else {
+      tc.doubleField -= 1d;
+    }
+    // Partial escape
+    $noinline$clobberObservables();
+    // Predicated set
+    tc.doubleField *= 10;
+    // Predicated get
+    return tc.doubleField;
+  }
+
+  /// CHECK-START: short Main.$noinline$testPartialEscape3_short(boolean) load_store_elimination (before)
+  /// CHECK-NOT:     Phi
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  //
+  /// CHECK-START: short Main.$noinline$testPartialEscape3_short(boolean) load_store_elimination (after)
+  /// CHECK:         Phi
+  /// CHECK:         Phi
+  /// CHECK-NOT:     Phi
+  //
+  /// CHECK-START: short Main.$noinline$testPartialEscape3_short(boolean) load_store_elimination (after)
+  /// CHECK:         InstanceFieldSet predicated:true
+  /// CHECK-NOT:     InstanceFieldSet predicated:true
+  //
+  /// CHECK-START: short Main.$noinline$testPartialEscape3_short(boolean) load_store_elimination (after)
+  /// CHECK:         PredicatedInstanceFieldGet
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  private static short $noinline$testPartialEscape3_short(boolean escape) {
+    TestClass4 tc = new TestClass4();
+    if ($noinline$getBoolean(escape)) {
+      $noinline$Escape4(tc);
+    } else {
+      tc.shortField -= 1;
+    }
+    // Partial escape
+    $noinline$clobberObservables();
+    // Predicated set
+    tc.shortField *= 10;
+    // Predicated get
+    return tc.shortField;
+  }
+
+  /// CHECK-START: byte Main.$noinline$testPartialEscape3_byte(boolean) load_store_elimination (before)
+  /// CHECK-NOT:     Phi
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  //
+  /// CHECK-START: byte Main.$noinline$testPartialEscape3_byte(boolean) load_store_elimination (after)
+  /// CHECK:         Phi
+  /// CHECK:         Phi
+  /// CHECK-NOT:     Phi
+  //
+  /// CHECK-START: byte Main.$noinline$testPartialEscape3_byte(boolean) load_store_elimination (after)
+  /// CHECK:         InstanceFieldSet predicated:true
+  /// CHECK-NOT:     InstanceFieldSet predicated:true
+  //
+  /// CHECK-START: byte Main.$noinline$testPartialEscape3_byte(boolean) load_store_elimination (after)
+  /// CHECK:         PredicatedInstanceFieldGet
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  private static byte $noinline$testPartialEscape3_byte(boolean escape) {
+    TestClass4 tc = new TestClass4();
+    if ($noinline$getBoolean(escape)) {
+      $noinline$Escape4(tc);
+    } else {
+      tc.byteField -= 1;
+    }
+    // Partial escape
+    $noinline$clobberObservables();
+    // Predicated set
+    tc.byteField *= 10;
+    // Predicated get
+    return tc.byteField;
+  }
+
+  /// CHECK-START: int Main.$noinline$testPartialEscape3_int(boolean) load_store_elimination (before)
+  /// CHECK-NOT:     Phi
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  //
+  /// CHECK-START: int Main.$noinline$testPartialEscape3_int(boolean) load_store_elimination (after)
+  /// CHECK:         Phi
+  /// CHECK:         Phi
+  /// CHECK-NOT:     Phi
+  //
+  /// CHECK-START: int Main.$noinline$testPartialEscape3_int(boolean) load_store_elimination (after)
+  /// CHECK:         InstanceFieldSet predicated:true
+  /// CHECK-NOT:     InstanceFieldSet predicated:true
+  //
+  /// CHECK-START: int Main.$noinline$testPartialEscape3_int(boolean) load_store_elimination (after)
+  /// CHECK:         PredicatedInstanceFieldGet
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  private static int $noinline$testPartialEscape3_int(boolean escape) {
+    TestClass4 tc = new TestClass4();
+    if ($noinline$getBoolean(escape)) {
+      $noinline$Escape4(tc);
+    } else {
+      tc.intField -= 1;
+    }
+    // Partial escape
+    $noinline$clobberObservables();
+    // Predicated set
+    tc.intField *= 10;
+    // Predicated get
+    return tc.intField;
+  }
+
+  /// CHECK-START: long Main.$noinline$testPartialEscape3_long(boolean) load_store_elimination (before)
+  /// CHECK-NOT:     Phi
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  //
+  /// CHECK-START: long Main.$noinline$testPartialEscape3_long(boolean) load_store_elimination (after)
+  /// CHECK:         Phi
+  /// CHECK:         Phi
+  /// CHECK-NOT:     Phi
+  //
+  /// CHECK-START: long Main.$noinline$testPartialEscape3_long(boolean) load_store_elimination (after)
+  /// CHECK:         InstanceFieldSet predicated:true
+  /// CHECK-NOT:     InstanceFieldSet predicated:true
+  //
+  /// CHECK-START: long Main.$noinline$testPartialEscape3_long(boolean) load_store_elimination (after)
+  /// CHECK:         PredicatedInstanceFieldGet
+  /// CHECK-NOT:     PredicatedInstanceFieldGet
+  private static long $noinline$testPartialEscape3_long(boolean escape) {
+    TestClass4 tc = new TestClass4();
+    if ($noinline$getBoolean(escape)) {
+      $noinline$Escape4(tc);
+    } else {
+      tc.longField -= 1;
+    }
+    // Partial escape
+    $noinline$clobberObservables();
+    // Predicated set
+    tc.longField *= 10;
+    // Predicated get
+    return tc.longField;
+  }
+
   private static void $noinline$clobberObservables() {}
 
   static void assertLongEquals(long result, long expected) {
@@ -4370,5 +4613,19 @@
     assertLongEquals(testOverlapLoop(50), 7778742049l);
     assertIntEquals($noinline$testPartialEscape1(new TestClass(), true), 1);
     assertIntEquals($noinline$testPartialEscape1(new TestClass(), false), 0);
+    assertIntEquals($noinline$testPartialEscape2(new TestClass(), true), 1);
+    assertIntEquals($noinline$testPartialEscape2(new TestClass(), false), 0);
+    assertDoubleEquals($noinline$testPartialEscape3_double(true), -20d);
+    assertDoubleEquals($noinline$testPartialEscape3_double(false), -40d);
+    assertFloatEquals($noinline$testPartialEscape3_float(true), -20f);
+    assertFloatEquals($noinline$testPartialEscape3_float(false), -40f);
+    assertIntEquals($noinline$testPartialEscape3_int(true), -20);
+    assertIntEquals($noinline$testPartialEscape3_int(false), -40);
+    assertIntEquals($noinline$testPartialEscape3_byte(true), -20);
+    assertIntEquals($noinline$testPartialEscape3_byte(false), -40);
+    assertIntEquals($noinline$testPartialEscape3_short(true), -20);
+    assertIntEquals($noinline$testPartialEscape3_short(false), -40);
+    assertLongEquals($noinline$testPartialEscape3_long(true), -20);
+    assertLongEquals($noinline$testPartialEscape3_long(false), -40);
   }
 }
diff --git a/test/639-checker-code-sinking/src/Main.java b/test/639-checker-code-sinking/src/Main.java
index 91c3ec4..28fa57c 100644
--- a/test/639-checker-code-sinking/src/Main.java
+++ b/test/639-checker-code-sinking/src/Main.java
@@ -110,6 +110,8 @@
   /// CHECK: <<Int42:i\d+>>       IntConstant 42
   /// CHECK:                      begin_block
   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:Main
+  /// CHECK:                      If
+  /// CHECK:                      begin_block
   /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
   /// CHECK:                      InstanceFieldSet [<<NewInstance>>,<<Int42>>]
   /// CHECK:                      Throw
@@ -119,14 +121,14 @@
   /// CHECK-NOT:                  NewInstance
   /// CHECK:                      If
   /// CHECK:                      begin_block
-  /// CHECK: <<Error:l\d+>>       LoadClass class_name:java.lang.Error
-  /// CHECK-NOT:                  begin_block
   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:Main
   /// CHECK-NOT:                  begin_block
   /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
   /// CHECK-NOT:                  begin_block
   /// CHECK:                      InstanceFieldSet [<<NewInstance>>,<<Int42>>]
   /// CHECK-NOT:                  begin_block
+  /// CHECK: <<Error:l\d+>>       LoadClass class_name:java.lang.Error
+  /// CHECK-NOT:                  begin_block
   /// CHECK: <<Throw:l\d+>>       NewInstance [<<Error>>]
   /// CHECK-NOT:                  begin_block
   /// CHECK:                      Throw [<<Throw>>]
@@ -323,7 +325,12 @@
   /// CHECK: <<Int42:i\d+>>       IntConstant 42
   /// CHECK: <<Int43:i\d+>>       IntConstant 43
   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:Main
+  /// CHECK:                      If
+  /// CHECK:                      begin_block
+  // Moved to throw block by partial-LSE and DCE.
   /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
+  // These were moved by partial LSE and order of sets is not observable and are
+  // in an arbitrary order.
   /// CHECK-DAG:                  InstanceFieldSet [<<NewInstance>>,<<Int42>>]
   /// CHECK-DAG:                  InstanceFieldSet [<<NewInstance>>,<<Int43>>]
   /// CHECK:                      Throw
@@ -335,14 +342,14 @@
   /// CHECK-NOT:                  NewInstance
   /// CHECK:                      If
   /// CHECK:                      begin_block
-  /// CHECK: <<Error:l\d+>>       LoadClass class_name:java.lang.Error
-  /// CHECK-NOT:                  begin_block
   /// CHECK: <<LoadClass:l\d+>>   LoadClass class_name:Main
   /// CHECK: <<NewInstance:l\d+>> NewInstance [<<LoadClass>>]
   /// CHECK-NOT:                  begin_block
   /// CHECK-DAG:                  InstanceFieldSet [<<NewInstance>>,<<Int42>>]
   /// CHECK-DAG:                  InstanceFieldSet [<<NewInstance>>,<<Int43>>]
   /// CHECK-NOT:                  begin_block
+  /// CHECK: <<Error:l\d+>>       LoadClass class_name:java.lang.Error
+  /// CHECK-NOT:                  begin_block
   /// CHECK:                      NewInstance [<<Error>>]
   /// CHECK:                      Throw
   /// CHECK-NOT:                  InstanceFieldSet