For LSE, further optimize stores for singleton references.
Loop side effects shouldn't affect singletons whose fields are never stored into
inside a loop.
Change-Id: If3715d7b7e621bb077ef9481072a56f7fec87f2b
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index 2a2221a..727f2bb 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -119,10 +119,16 @@
: ref_info_(ref_info),
offset_(offset),
index_(index),
- declaring_class_def_index_(declaring_class_def_index) {
+ declaring_class_def_index_(declaring_class_def_index),
+ value_killed_by_loop_side_effects_(true) {
DCHECK(ref_info != nullptr);
DCHECK((offset == kInvalidFieldOffset && index != nullptr) ||
(offset != kInvalidFieldOffset && index == nullptr));
+ if (ref_info->IsSingleton() && !IsArrayElement()) {
+ // Assume this location's value cannot be killed by loop side effects
+ // until proven otherwise.
+ value_killed_by_loop_side_effects_ = false;
+ }
}
ReferenceInfo* GetReferenceInfo() const { return ref_info_; }
@@ -139,11 +145,22 @@
return index_ != nullptr;
}
+ bool IsValueKilledByLoopSideEffects() const {
+ return value_killed_by_loop_side_effects_;
+ }
+
+ void SetValueKilledByLoopSideEffects(bool val) {
+ value_killed_by_loop_side_effects_ = val;
+ }
+
private:
ReferenceInfo* const ref_info_; // reference for instance/static field or array access.
const size_t offset_; // offset of static/instance field.
HInstruction* const index_; // index of an array element.
const int16_t declaring_class_def_index_; // declaring class's def's dex index.
+ bool value_killed_by_loop_side_effects_; // value of this location may be killed by loop
+ // side effects because this location is stored
+ // into inside a loop.
DISALLOW_COPY_AND_ASSIGN(HeapLocation);
};
@@ -370,13 +387,13 @@
return heap_locations_[heap_location_idx];
}
- void VisitFieldAccess(HInstruction* ref, const FieldInfo& field_info) {
+ HeapLocation* VisitFieldAccess(HInstruction* ref, const FieldInfo& field_info) {
if (field_info.IsVolatile()) {
has_volatile_ = true;
}
const uint16_t declaring_class_def_index = field_info.GetDeclaringClassDefIndex();
const size_t offset = field_info.GetFieldOffset().SizeValue();
- GetOrCreateHeapLocation(ref, offset, nullptr, declaring_class_def_index);
+ return GetOrCreateHeapLocation(ref, offset, nullptr, declaring_class_def_index);
}
void VisitArrayAccess(HInstruction* array, HInstruction* index) {
@@ -390,8 +407,11 @@
}
void VisitInstanceFieldSet(HInstanceFieldSet* instruction) OVERRIDE {
- VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
+ HeapLocation* location = VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo());
has_heap_stores_ = true;
+ if (instruction->GetBlock()->GetLoopInformation() != nullptr) {
+ location->SetValueKilledByLoopSideEffects(true);
+ }
}
void VisitStaticFieldGet(HStaticFieldGet* instruction) OVERRIDE {
@@ -565,23 +585,26 @@
HBasicBlock* pre_header = block->GetLoopInformation()->GetPreHeader();
ArenaVector<HInstruction*>& pre_header_heap_values =
heap_values_for_[pre_header->GetBlockId()];
+ // Inherit the values from pre-header.
+ for (size_t i = 0; i < heap_values.size(); i++) {
+ heap_values[i] = pre_header_heap_values[i];
+ }
+
// We do a single pass in reverse post order. For loops, use the side effects as a hint
// to see if the heap values should be killed.
if (side_effects_.GetLoopEffects(block).DoesAnyWrite()) {
- for (size_t i = 0; i < pre_header_heap_values.size(); i++) {
- // heap value is killed by loop side effects, need to keep the last store.
- KeepIfIsStore(pre_header_heap_values[i]);
- }
- if (kIsDebugBuild) {
- // heap_values should all be kUnknownHeapValue that it is inited with.
- for (size_t i = 0; i < heap_values.size(); i++) {
- DCHECK_EQ(heap_values[i], kUnknownHeapValue);
- }
- }
- } else {
- // Inherit the values from pre-header.
for (size_t i = 0; i < heap_values.size(); i++) {
- heap_values[i] = pre_header_heap_values[i];
+ HeapLocation* location = heap_location_collector_.GetHeapLocation(i);
+ ReferenceInfo* ref_info = location->GetReferenceInfo();
+ if (!ref_info->IsSingleton() || location->IsValueKilledByLoopSideEffects()) {
+ // heap value is killed by loop side effects (stored into directly, or due to
+ // aliasing).
+ KeepIfIsStore(pre_header_heap_values[i]);
+ heap_values[i] = kUnknownHeapValue;
+ } else {
+ // A singleton's field that's not stored into inside a loop is invariant throughout
+ // the loop.
+ }
}
}
}
@@ -762,6 +785,9 @@
if (loop_info != nullptr) {
// instruction is a store in the loop so the loop must does write.
DCHECK(side_effects_.GetLoopEffects(loop_info->GetHeader()).DoesAnyWrite());
+ // If it's a singleton, IsValueKilledByLoopSideEffects() must be true.
+ DCHECK(!ref_info->IsSingleton() ||
+ heap_location_collector_.GetHeapLocation(idx)->IsValueKilledByLoopSideEffects());
if (loop_info->IsDefinedOutOfTheLoop(original_ref)) {
DCHECK(original_ref->GetBlock()->Dominates(loop_info->GetPreHeader()));
diff --git a/test/530-checker-lse/src/Main.java b/test/530-checker-lse/src/Main.java
index 7d89372..cadf706 100644
--- a/test/530-checker-lse/src/Main.java
+++ b/test/530-checker-lse/src/Main.java
@@ -489,27 +489,32 @@
return obj;
}
- /// CHECK-START: void Main.test21() load_store_elimination (before)
+ /// CHECK-START: void Main.test21(TestClass) load_store_elimination (before)
/// CHECK: NewInstance
/// CHECK: InstanceFieldSet
- /// CHECK: StaticFieldSet
- /// CHECK: StaticFieldGet
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldGet
+ /// CHECK: InstanceFieldGet
- /// CHECK-START: void Main.test21() load_store_elimination (after)
+ /// CHECK-START: void Main.test21(TestClass) load_store_elimination (after)
/// CHECK: NewInstance
/// CHECK: InstanceFieldSet
- /// CHECK: StaticFieldSet
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldSet
+ /// CHECK: InstanceFieldGet
/// CHECK: InstanceFieldGet
// Loop side effects can kill heap values, stores need to be kept in that case.
- static void test21() {
+ static void test21(TestClass obj0) {
TestClass obj = new TestClass();
+ obj0.str = "abc";
obj.str = "abc";
for (int i = 0; i < 2; i++) {
- // Generate some loop side effect that does write.
- obj.si = 1;
+ // Generate some loop side effect that writes into obj.
+ obj.str = "def";
}
- System.out.print(obj.str.substring(0, 0));
+ System.out.print(obj0.str.substring(0, 0) + obj.str.substring(0, 0));
}
/// CHECK-START: int Main.test22() load_store_elimination (before)
@@ -525,27 +530,29 @@
/// CHECK-START: int Main.test22() load_store_elimination (after)
/// CHECK: NewInstance
- /// CHECK: InstanceFieldSet
+ /// CHECK-NOT: InstanceFieldSet
/// CHECK: NewInstance
/// CHECK-NOT: InstanceFieldSet
/// CHECK-NOT: InstanceFieldGet
/// CHECK: NewInstance
/// CHECK-NOT: InstanceFieldSet
- /// CHECK: InstanceFieldGet
+ /// CHECK-NOT: InstanceFieldGet
/// CHECK-NOT: InstanceFieldGet
- // Loop side effects only affects stores into singletons that dominiates the loop header.
+ // For a singleton, loop side effects can kill its field values only if:
+ // (1) it dominiates the loop header, and
+ // (2) its fields are stored into inside a loop.
static int test22() {
int sum = 0;
TestClass obj1 = new TestClass();
- obj1.i = 2; // This store can't be eliminated since it can be killed by loop side effects.
+ obj1.i = 2; // This store can be eliminated since obj1 is never stored into inside a loop.
for (int i = 0; i < 2; i++) {
TestClass obj2 = new TestClass();
- obj2.i = 3; // This store can be eliminated since the singleton is inside the loop.
+ obj2.i = 3; // This store can be eliminated since the singleton is inside the loop.
sum += obj2.i;
}
TestClass obj3 = new TestClass();
- obj3.i = 5; // This store can be eliminated since the singleton is created after the loop.
+ obj3.i = 5; // This store can be eliminated since the singleton is created after the loop.
sum += obj1.i + obj3.i;
return sum;
}
@@ -715,7 +722,7 @@
float[] fa2 = { 1.8f };
assertFloatEquals(test19(fa1, fa2), 1.8f);
assertFloatEquals(test20().i, 0);
- test21();
+ test21(new TestClass());
assertIntEquals(test22(), 13);
assertIntEquals(test23(true), 4);
assertIntEquals(test23(false), 5);