Handle predicated-gets with default values
Due to an oversight the default-value of a PredicatedGet did not
support being a Default value. This fixes that oversight.
Test: ./art/tools/compile-jar.py --profile-line 'HSLe/k/a/g/i;->i(Le/k/a/g/d;Ljava/io/OutputStream;)V' --arch arm64 ~/no.nrk.mobil.radio_10922_base_split.apk --compiler-filter=speed-profile --dump-stats -j1 --force-allow-oj-inlines
Test: LoadStoreEliminationTest.PredicatedLoadDefaultValue
Bug: 183898383
Change-Id: I11bccddb0b5a5c2e958690864ff2d4449a9f2fad
diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc
index b1ec62a..1ea2ece 100644
--- a/compiler/optimizing/load_store_elimination.cc
+++ b/compiler/optimizing/load_store_elimination.cc
@@ -3613,9 +3613,13 @@
HInstruction* res = Replacement(pred).GetInstruction();
LSE_VLOG << pred << " materialized to " << res->DumpWithArgs();
return res;
+ } else if (pred.IsDefault()) {
+ HInstruction* res = GetDefaultValue(read->GetType());
+ LSE_VLOG << pred << " materialized to " << res->DumpWithArgs();
+ return res;
}
LOG(FATAL) << "Unable to find unescaped value at " << read->DumpWithArgs()
- << "! This should be impossible!";
+ << "! This should be impossible! Value is " << pred;
UNREACHABLE();
}
diff --git a/compiler/optimizing/load_store_elimination_test.cc b/compiler/optimizing/load_store_elimination_test.cc
index 9ba364e..eb5079f 100644
--- a/compiler/optimizing/load_store_elimination_test.cc
+++ b/compiler/optimizing/load_store_elimination_test.cc
@@ -6242,6 +6242,89 @@
// // ENTRY
// obj = new Obj();
+// if (parameter_value) {
+// // LEFT
+// obj.field = 3;
+// escape(obj);
+// } else {
+// // RIGHT - Leave it as default value
+// }
+// EXIT
+// predicated-ELIMINATE
+// return obj.field
+TEST_F(LoadStoreEliminationTest, PredicatedLoadDefaultValue) {
+ 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* c0 = graph_->GetIntConstant(0);
+ 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* write_left = MakeIFieldSet(new_inst, c3, MemberOffset(32));
+ HInstruction* call_left = MakeInvoke(DataType::Type::kVoid, { new_inst });
+ HInstruction* goto_left = new (GetAllocator()) HGoto();
+ left->AddInstruction(write_left);
+ left->AddInstruction(call_left);
+ left->AddInstruction(goto_left);
+ call_left->CopyEnvironmentFrom(cls->GetEnvironment());
+
+ HInstruction* goto_right = new (GetAllocator()) HGoto();
+ 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_RETAINED(write_left);
+ EXPECT_INS_RETAINED(call_left);
+ HPredicatedInstanceFieldGet* pred_get =
+ FindSingleInstruction<HPredicatedInstanceFieldGet>(graph_, breturn);
+ 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);
+ ASSERT_NE(pred_get, nullptr);
+ EXPECT_INS_EQ(pred_get->GetTarget(), merge_alloc);
+ EXPECT_INS_EQ(pred_get->GetDefaultValue(), c0) << " pred-get is: " << *pred_get;
+}
+
+// // ENTRY
+// obj = new Obj();
// // ALL should be kept
// switch (parameter_value) {
// case 1: