LSE: Fix tracking stores for merged default values.
Test: Additional test in 530-checker-lse.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 166246377
Bug: 77906240
Change-Id: Ia31099fdfcdf416cb35c9baac6e7c13572e81eb7
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 57839dc..e08c585 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -1167,25 +1167,16 @@
}
ArrayRef<HBasicBlock* const> predecessors(block->GetPredecessors());
Value merged_stored_by = heap_values_for_[predecessors[0]->GetBlockId()][idx].stored_by;
- if (merged_value.IsDefault()) {
- DCHECK(std::all_of(predecessors.begin(),
- predecessors.end(),
- [this, idx](HBasicBlock* predecessor) {
- uint32_t predecessor_block_id = predecessor->GetBlockId();
- return heap_values_for_[predecessor_block_id][idx].stored_by.IsUnknown();
- }));
- DCHECK(merged_stored_by.IsUnknown());
- } else if (predecessors.size() >= 2u &&
- !std::all_of(predecessors.begin() + 1,
- predecessors.end(),
- [this, idx, merged_stored_by](HBasicBlock* predecessor) {
- uint32_t predecessor_block_id = predecessor->GetBlockId();
- return heap_values_for_[predecessor_block_id][idx].stored_by.Equals(
- merged_stored_by);
- })) {
- // Use the Phi placeholder to track that we need to keep stores from all predecessors.
- const PhiPlaceholder* phi_placeholder = GetPhiPlaceholder(block->GetBlockId(), idx);
- merged_stored_by = Value::ForNonLoopPhiPlaceholder(phi_placeholder);
+ for (size_t predecessor_idx = 1u; predecessor_idx != predecessors.size(); ++predecessor_idx) {
+ uint32_t predecessor_block_id = predecessors[predecessor_idx]->GetBlockId();
+ Value stored_by = heap_values_for_[predecessor_block_id][idx].stored_by;
+ if ((!stored_by.IsUnknown() || !merged_stored_by.IsUnknown()) &&
+ !merged_stored_by.Equals(stored_by)) {
+ // Use the Phi placeholder to track that we need to keep stores from all predecessors.
+ const PhiPlaceholder* phi_placeholder = GetPhiPlaceholder(block->GetBlockId(), idx);
+ merged_stored_by = Value::ForNonLoopPhiPlaceholder(phi_placeholder);
+ break;
+ }
}
heap_values.push_back({ merged_value, merged_stored_by });
}
@@ -1292,7 +1283,7 @@
record.value = Value::Unknown();
}
if (record.value.IsDefault()) {
- DCHECK(record.stored_by.IsUnknown());
+ KeepStores(record.stored_by);
HInstruction* constant = GetDefaultValue(instruction->GetType());
AddRemovedLoad(instruction, constant);
record.value = Value::ForInstruction(constant);
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index 34a445f..7bc6e4b 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -2116,6 +2116,37 @@
return a[1];
}
+ /// CHECK-START: int Main.testLocalArrayMerge8(boolean) load_store_elimination (before)
+ /// CHECK-DAG: NewArray
+ /// CHECK-DAG: ArraySet
+ /// CHECK-DAG: ArraySet
+ /// CHECK-DAG: ArraySet
+ /// CHECK-DAG: ArraySet
+ /// CHECK-DAG: ArrayGet
+ /// CHECK-DAG: ArrayGet
+
+ /// CHECK-START: int Main.testLocalArrayMerge8(boolean) load_store_elimination (after)
+ /// CHECK-NOT: NewArray
+ /// CHECK-NOT: ArraySet
+ /// CHECK-NOT: ArrayGet
+
+ // Test Merging default value and an identical value.
+ private static int testLocalArrayMerge8(boolean x) {
+ int[] a = new int[2];
+ if (x) {
+ a[0] = 1; // Make sure the store below is not eliminated immediately as
+ // storing the same value already present in the heap location.
+ a[0] = 0; // Store the same value as default value to test merging with
+ // the default value from else-block.
+ } else {
+ // Do the same as then-block for a different heap location to avoid
+ // relying on block ordering. (Test both `default+0` and `0+default`.)
+ a[1] = 1;
+ a[1] = 0;
+ }
+ return a[0] + a[1];
+ }
+
/// CHECK-START: void Main.$noinline$testThrowingArraySet(java.lang.Object[], java.lang.Object) load_store_elimination (before)
/// CHECK-DAG: ArrayGet
/// CHECK-DAG: ArraySet
@@ -3801,6 +3832,8 @@
assertIntEquals(testLocalArrayMerge7(new int[2], true, false), 2);
assertIntEquals(testLocalArrayMerge7(new int[2], false, true), 0);
assertIntEquals(testLocalArrayMerge7(new int[2], false, false), 0);
+ assertIntEquals(testLocalArrayMerge8(true), 0);
+ assertIntEquals(testLocalArrayMerge8(false), 0);
TestClass[] tca = new TestClass[] { new TestClass(), null };
try {