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