summaryrefslogtreecommitdiff
path: root/compiler
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2024-08-23 16:05:19 +0200
committer Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2024-08-28 12:20:39 +0000
commitc9ea8725f4e71d3014850c066736d991d0f2d4bd (patch)
tree38b9cb61712cfa2cfc551ef06bc54537c74ab414 /compiler
parent074876edf2d0329ab7772f851e321ce8264a5c2a (diff)
Add LSE gtests for inserting type conversions.
Add tests for the cases where the LSE correctly inserts the required type conversion instructions as needed, as well as tests for currently broken cases. The latter are guarded by `GTEST_SKIP()` until we fix them in a separate change. Test: m test-art-host-gtest Bug: 341476044 Change-Id: Id6002bc31cef542564b84258defcab45b06e6445
Diffstat (limited to 'compiler')
-rw-r--r--compiler/optimizing/load_store_elimination_test.cc444
-rw-r--r--compiler/optimizing/nodes.h4
-rw-r--r--compiler/optimizing/optimizing_unit_test.h12
3 files changed, 429 insertions, 31 deletions
diff --git a/compiler/optimizing/load_store_elimination_test.cc b/compiler/optimizing/load_store_elimination_test.cc
index 569760e99e..1e5c7082a4 100644
--- a/compiler/optimizing/load_store_elimination_test.cc
+++ b/compiler/optimizing/load_store_elimination_test.cc
@@ -98,6 +98,48 @@ class LoadStoreEliminationTestBase : public SuperTest, public OptimizingUnitTest
MakeGoto(entry_block_);
}
+ // Create suspend check, linear loop variable and loop condition.
+ // The `HPhi` for the loop variable can be easily retrieved as the only `HPhi` in the loop block.
+ // The `HSuspendCheck` can be retrieved as the first non-Phi instruction from the loop block.
+ void MakeSimpleLoopInstructions(HBasicBlock* loop,
+ HBasicBlock* body,
+ std::initializer_list<HInstruction*> suspend_check_env = {}) {
+ CHECK(loop->GetInstructions().IsEmpty());
+ CHECK_IMPLIES(loop != body, body->IsSingleGoto());
+ HInstruction* c128 = graph_->GetIntConstant(128);
+ MakeSuspendCheck(loop, suspend_check_env);
+ auto [phi, increment] = MakeLinearLoopVar(loop, body, /*initial=*/ 0, /*increment=*/ 1);
+ HInstruction* cmp = MakeCondition(loop, kCondGE, phi, c128);
+ MakeIf(loop, cmp);
+ }
+
+ // Create a do-while loop with instructions:
+ // i = 0;
+ // do {
+ // HSuspendCheck;
+ // cmp = i < 128;
+ // ++i;
+ // } while (cmp);
+ // Return the pre-header and loop block.
+ std::tuple<HBasicBlock*, HBasicBlock*> CreateDoWhileLoopWithInstructions(
+ HBasicBlock* loop_exit, std::initializer_list<HInstruction*> suspend_check_env = {}) {
+ auto [pre_header, loop] = CreateDoWhileLoop(loop_exit);
+ MakeSimpleLoopInstructions(loop, loop, suspend_check_env);
+ return {pre_header, loop};
+ }
+
+ // Create a for loop with instructions:
+ // for (int i = 0; i < 128; ++i) {
+ // HSuspendCheck;
+ // }
+ // Return the pre-header, header and body blocks.
+ std::tuple<HBasicBlock*, HBasicBlock*, HBasicBlock*> CreateForLoopWithInstructions(
+ HBasicBlock* loop_exit, std::initializer_list<HInstruction*> suspend_check_env = {}) {
+ auto [pre_header, loop_header, loop_body] = CreateWhileLoop(loop_exit);
+ MakeSimpleLoopInstructions(loop_header, loop_body, suspend_check_env);
+ return {pre_header, loop_header, loop_body};
+ }
+
// Create the major CFG used by tests:
// entry
// |
@@ -110,20 +152,11 @@ class LoadStoreEliminationTestBase : public SuperTest, public OptimizingUnitTest
// exit
void CreateTestControlFlowGraph() {
InitGraphAndParameters();
- std::tie(pre_header_, loop_) = CreateDoWhileLoop(return_block_);
-
- HInstruction* c128 = graph_->GetIntConstant(128);
-
CreateEntryBlockInstructions();
-
- // loop block:
- // suspend_check
- // phi++;
- // if (phi >= 128)
- suspend_check_ = MakeSuspendCheck(loop_, /*env=*/ {array_, i_, j_});
- std::tie(phi_, std::ignore) = MakeLinearLoopVar(loop_, loop_, /*initial=*/ 0, /*increment=*/ 1);
- HInstruction* cmp = MakeCondition(loop_, kCondGE, phi_, c128);
- MakeIf(loop_, cmp);
+ std::tie(pre_header_, loop_) =
+ CreateDoWhileLoopWithInstructions(return_block_, /*suspend_check_env=*/ {array_, i_, j_});
+ phi_ = loop_->GetFirstPhi()->AsPhi();
+ suspend_check_ = loop_->GetFirstInstruction()->AsSuspendCheck();
}
// Create the diamond-shaped CFG:
@@ -219,16 +252,6 @@ class LoadStoreEliminationTestBase : public SuperTest, public OptimizingUnitTest
class LoadStoreEliminationTest : public LoadStoreEliminationTestBase<CommonCompilerTest> {};
-enum class TestOrder { kSameAsAlloc, kReverseOfAlloc };
-std::ostream& operator<<(std::ostream& os, const TestOrder& ord) {
- switch (ord) {
- case TestOrder::kSameAsAlloc:
- return os << "SameAsAlloc";
- case TestOrder::kReverseOfAlloc:
- return os << "ReverseOfAlloc";
- }
-}
-
TEST_F(LoadStoreEliminationTest, ArrayGetSetElimination) {
CreateTestControlFlowGraph();
@@ -1293,6 +1316,381 @@ TEST_F(LoadStoreEliminationTest, ArrayLoopAliasing2) {
EXPECT_INS_RETAINED(ret_get2);
}
+class TwoTypesConversionsTestGroup : public LoadStoreEliminationTestBase<
+ CommonCompilerTestWithParam<std::tuple<DataType::Type, DataType::Type>>> {
+ protected:
+ DataType::Type FieldTypeForLoadType(DataType::Type load_type) {
+ // `Uint8` is not a valid field type but it's a valid load type we can set for
+ // a `HInstanceFieldGet` after constructing it.
+ return (load_type == DataType::Type::kUint8) ? DataType::Type::kInt8 : load_type;
+ }
+};
+
+TEST_P(TwoTypesConversionsTestGroup, StoreLoad) {
+ auto [param_type, load_type] = GetParam();
+ DataType::Type field_type = FieldTypeForLoadType(load_type);
+
+ HBasicBlock* main = InitEntryMainExitGraph();
+ HInstruction* param = MakeParam(param_type);
+ HInstruction* object = MakeParam(DataType::Type::kReference);
+
+ HInstruction* write = MakeIFieldSet(main, object, param, field_type, MemberOffset(32));
+ HInstanceFieldGet* read = MakeIFieldGet(main, object, field_type, MemberOffset(32));
+ read->SetType(load_type);
+ HInstruction* ret = MakeReturn(main, read);
+
+ PerformLSE();
+
+ EXPECT_INS_RETAINED(write);
+ EXPECT_INS_REMOVED(read);
+
+ HInstruction* ret_input = ret->InputAt(0);
+ if (DataType::IsTypeConversionImplicit(param_type, load_type)) {
+ ASSERT_EQ(param, ret_input) << ret_input->DebugName();
+ } else {
+ ASSERT_TRUE(ret_input->IsTypeConversion()) << ret_input->DebugName();
+ ASSERT_EQ(load_type, ret_input->GetType());
+ ASSERT_EQ(param, ret_input->InputAt(0)) << ret_input->InputAt(0)->DebugName();
+ }
+}
+
+TEST_P(TwoTypesConversionsTestGroup, StoreLoadStoreLoad) {
+ auto [load_type1, load_type2] = GetParam();
+ DataType::Type field_type1 = FieldTypeForLoadType(load_type1);
+ DataType::Type field_type2 = FieldTypeForLoadType(load_type2);
+
+ HBasicBlock* main = InitEntryMainExitGraph();
+ HInstruction* param = MakeParam(DataType::Type::kInt32);
+ HInstruction* object = MakeParam(DataType::Type::kReference);
+
+ HInstruction* write1 = MakeIFieldSet(main, object, param, field_type1, MemberOffset(32));
+ HInstanceFieldGet* read1 = MakeIFieldGet(main, object, field_type1, MemberOffset(32));
+ read1->SetType(load_type1);
+ HInstruction* write2 = MakeIFieldSet(main, object, read1, field_type2, MemberOffset(40));
+ HInstanceFieldGet* read2 = MakeIFieldGet(main, object, field_type2, MemberOffset(40));
+ read2->SetType(load_type2);
+ HInstruction* ret = MakeReturn(main, read2);
+
+ PerformLSE();
+
+ EXPECT_INS_RETAINED(write1);
+ EXPECT_INS_RETAINED(write2);
+ EXPECT_INS_REMOVED(read1);
+ EXPECT_INS_REMOVED(read2);
+
+ // Note: Sometimes we create two type conversions when one is enough (Int32->Int16->Int8).
+ // We currently rely on the instruction simplifier to remove the intermediate conversion.
+ HInstruction* current = ret->InputAt(0);
+ if (!DataType::IsTypeConversionImplicit(load_type1, load_type2)) {
+ ASSERT_TRUE(current->IsTypeConversion()) << current->DebugName();
+ ASSERT_EQ(load_type2, current->GetType());
+ current = current->InputAt(0);
+ }
+ if (!DataType::IsTypeConversionImplicit(DataType::Type::kInt32, load_type1)) {
+ ASSERT_TRUE(current->IsTypeConversion()) << current->DebugName();
+ ASSERT_EQ(load_type1, current->GetType());
+ current = current->InputAt(0);
+ }
+ ASSERT_EQ(param, current) << current->DebugName();
+}
+
+TEST_P(TwoTypesConversionsTestGroup, DefaultValueStores_LoadAfterLoop) {
+ auto [default_load_type, load_type] = GetParam();
+ DataType::Type default_field_type = FieldTypeForLoadType(default_load_type);
+ DataType::Type field_type = FieldTypeForLoadType(load_type);
+
+ HBasicBlock* return_block = InitEntryMainExitGraph();
+ auto [pre_header, loop] = CreateDoWhileLoopWithInstructions(return_block);
+
+ HInstruction* object = MakeParam(DataType::Type::kReference);
+ HInstruction* cls = MakeLoadClass(pre_header);
+ HInstruction* default_object = MakeNewInstance(pre_header, cls);
+ HInstanceFieldGet* default_value =
+ MakeIFieldGet(pre_header, default_object, default_field_type, MemberOffset(40));
+ default_value->SetType(default_load_type);
+ // Make the `default_object` escape to avoid write elimination (test only load elimination).
+ HInstruction* invoke = MakeInvokeStatic(return_block, DataType::Type::kVoid, {default_object});
+
+ HInstruction* write =
+ MakeIFieldSet(return_block, object, default_value, field_type, MemberOffset(32));
+ HInstanceFieldGet* read = MakeIFieldGet(return_block, object, field_type, MemberOffset(32));
+ read->SetType(load_type);
+ HInstruction* ret = MakeReturn(return_block, read);
+
+ PerformLSE();
+
+ EXPECT_INS_RETAINED(default_object);
+ EXPECT_INS_REMOVED(default_value);
+ EXPECT_INS_RETAINED(write);
+ EXPECT_INS_REMOVED(read);
+
+ HInstruction* ret_input = ret->InputAt(0);
+ ASSERT_TRUE(ret_input->IsIntConstant()) << ret_input->DebugName();
+ ASSERT_EQ(ret_input->AsIntConstant()->GetValue(), 0);
+}
+
+TEST_P(TwoTypesConversionsTestGroup, SingleValueStores_LoadAfterLoop) {
+ auto [param_type, load_type] = GetParam();
+ DataType::Type field_type = FieldTypeForLoadType(load_type);
+
+ HBasicBlock* return_block = InitEntryMainExitGraph();
+ auto [pre_header, loop_header, loop_body] = CreateForLoopWithInstructions(return_block);
+
+ HInstruction* param = MakeParam(param_type);
+ HInstruction* object = MakeParam(DataType::Type::kReference);
+
+ // Write the value in pre-header.
+ HInstruction* write1 =
+ MakeIFieldSet(pre_header, object, param, field_type, MemberOffset(32));
+
+ // In the body, make a call to clobber all fields, then write the same value as in pre-header.
+ MakeInvokeStatic(loop_body, DataType::Type::kVoid, {object});
+ HInstruction* write2 =
+ MakeIFieldSet(loop_body, object, param, field_type, MemberOffset(32));
+
+ HInstanceFieldGet* read = MakeIFieldGet(return_block, object, field_type, MemberOffset(32));
+ read->SetType(load_type);
+ HInstruction* ret = MakeReturn(return_block, read);
+
+ PerformLSE();
+
+ EXPECT_INS_RETAINED(write1);
+ EXPECT_INS_RETAINED(write2);
+ EXPECT_INS_REMOVED(read);
+
+ HInstruction* ret_input = ret->InputAt(0);
+ if (DataType::IsTypeConversionImplicit(param_type, load_type)) {
+ ASSERT_EQ(param, ret_input) << ret_input->DebugName();
+ } else {
+ ASSERT_TRUE(ret_input->IsTypeConversion()) << ret_input->DebugName();
+ ASSERT_EQ(load_type, ret_input->GetType());
+ ASSERT_EQ(param, ret_input->InputAt(0)) << ret_input->InputAt(0)->DebugName();
+ }
+}
+
+TEST_P(TwoTypesConversionsTestGroup, StoreLoopLoad) {
+ auto [param_type, load_type] = GetParam();
+ DataType::Type field_type = FieldTypeForLoadType(load_type);
+
+ HBasicBlock* return_block = InitEntryMainExitGraph();
+ auto [pre_header, loop] = CreateDoWhileLoopWithInstructions(return_block);
+
+ HInstruction* param = MakeParam(param_type);
+ HInstruction* object = MakeParam(DataType::Type::kReference);
+
+ HInstruction* write = MakeIFieldSet(pre_header, object, param, field_type, MemberOffset(32));
+
+ HInstanceFieldGet* read = MakeIFieldGet(return_block, object, field_type, MemberOffset(32));
+ read->SetType(load_type);
+ HInstruction* ret = MakeReturn(return_block, read);
+
+ PerformLSE();
+
+ EXPECT_INS_RETAINED(write);
+ EXPECT_INS_REMOVED(read);
+
+ HInstruction* ret_input = ret->InputAt(0);
+ if (DataType::IsTypeConversionImplicit(param_type, load_type)) {
+ ASSERT_EQ(param, ret_input) << ret_input->DebugName();
+ } else {
+ ASSERT_TRUE(ret_input->IsTypeConversion()) << ret_input->DebugName();
+ ASSERT_EQ(load_type, ret_input->GetType());
+ ASSERT_EQ(param, ret_input->InputAt(0)) << ret_input->InputAt(0)->DebugName();
+ }
+}
+
+TEST_P(TwoTypesConversionsTestGroup, StoreLoopLoadStoreLoad) {
+ auto [load_type1, load_type2] = GetParam();
+ DataType::Type field_type1 = FieldTypeForLoadType(load_type1);
+ DataType::Type field_type2 = FieldTypeForLoadType(load_type2);
+
+ HBasicBlock* return_block = InitEntryMainExitGraph();
+ auto [pre_header, loop] = CreateDoWhileLoopWithInstructions(return_block);
+ HInstruction* param = MakeParam(DataType::Type::kInt32);
+ HInstruction* object = MakeParam(DataType::Type::kReference);
+
+ HInstruction* write1 = MakeIFieldSet(pre_header, object, param, field_type1, MemberOffset(32));
+
+ HInstanceFieldGet* read1 = MakeIFieldGet(return_block, object, field_type1, MemberOffset(32));
+ read1->SetType(load_type1);
+ HInstruction* write2 = MakeIFieldSet(return_block, object, read1, field_type2, MemberOffset(40));
+ HInstanceFieldGet* read2 = MakeIFieldGet(return_block, object, field_type2, MemberOffset(40));
+ read2->SetType(load_type2);
+ HInstruction* ret = MakeReturn(return_block, read2);
+
+ PerformLSE();
+
+ EXPECT_INS_RETAINED(write1);
+ EXPECT_INS_RETAINED(write2);
+ EXPECT_INS_REMOVED(read1);
+ EXPECT_INS_REMOVED(read2);
+
+ if (load_type1 != DataType::Type::kInt32 && load_type2 != load_type1) {
+ GTEST_SKIP() << "FIXME: Missing type conversions. Bug: 341476044";
+ }
+ // Note: Sometimes we create two type conversions when one is enough (Int32->Int16->Int8).
+ // We currently rely on the instruction simplifier to remove the intermediate conversion.
+ HInstruction* current = ret->InputAt(0);
+ if (!DataType::IsTypeConversionImplicit(load_type1, load_type2)) {
+ ASSERT_TRUE(current->IsTypeConversion()) << current->DebugName();
+ ASSERT_EQ(load_type2, current->GetType());
+ current = current->InputAt(0);
+ }
+ if (!DataType::IsTypeConversionImplicit(DataType::Type::kInt32, load_type1)) {
+ ASSERT_TRUE(current->IsTypeConversion()) << current->DebugName();
+ ASSERT_EQ(load_type1, current->GetType()) << load_type2;
+ current = current->InputAt(0);
+ }
+ ASSERT_EQ(param, current) << current->DebugName();
+}
+
+TEST_P(TwoTypesConversionsTestGroup, MergingConvertedValueStore) {
+ auto [param_type, load_type] = GetParam();
+ DataType::Type field_type = FieldTypeForLoadType(load_type);
+ DataType::Type phi_field_type = DataType::Type::kInt32; // "phi field" can hold the full value.
+ CHECK(DataType::IsTypeConversionImplicit(param_type, phi_field_type));
+ CHECK(DataType::IsTypeConversionImplicit(load_type, phi_field_type));
+
+ HBasicBlock* return_block = InitEntryMainExitGraph();
+ auto [pre_header, loop_header, loop_body] = CreateForLoopWithInstructions(return_block);
+
+ HInstruction* param = MakeParam(param_type);
+ HInstruction* object = MakeParam(DataType::Type::kReference);
+
+ // Initialize the "phi field".
+ HInstruction* pre_header_write =
+ MakeIFieldSet(pre_header, object, param, phi_field_type, MemberOffset(40));
+
+ // In the body, we read the "phi field", store and load the value to a different field
+ // to force type conversion, and store back to the "phi field".
+ HInstanceFieldGet* phi_read = MakeIFieldGet(loop_body, object, phi_field_type, MemberOffset(40));
+ HInstruction* conversion_write =
+ MakeIFieldSet(loop_body, object, phi_read, field_type, MemberOffset(32));
+ HInstanceFieldGet* conversion_read =
+ MakeIFieldGet(loop_body, object, field_type, MemberOffset(32));
+ conversion_read->SetType(load_type);
+ HInstruction* phi_write =
+ MakeIFieldSet(loop_body, object, conversion_read, phi_field_type, MemberOffset(40));
+
+ HInstanceFieldGet* final_read =
+ MakeIFieldGet(return_block, object, phi_field_type, MemberOffset(40));
+ HInstruction* ret = MakeReturn(return_block, final_read);
+
+ PerformLSE();
+
+ EXPECT_INS_RETAINED(pre_header_write);
+ EXPECT_INS_RETAINED(conversion_write);
+ EXPECT_INS_REMOVED(phi_read);
+ EXPECT_INS_REMOVED(conversion_read);
+ EXPECT_INS_REMOVED(final_read);
+
+ HInstruction* ret_input = ret->InputAt(0);
+ if (DataType::IsTypeConversionImplicit(param_type, load_type)) {
+ EXPECT_INS_REMOVED(phi_write) << "\n" << param_type << "/" << load_type;
+ ASSERT_EQ(param, ret_input) << ret_input->DebugName();
+ } else {
+ GTEST_SKIP() << "FIXME: Missing type conversions. Bug: 341476044";
+ EXPECT_INS_RETAINED(phi_write) << "\n" << param_type << "/" << load_type;
+ ASSERT_TRUE(ret_input->IsPhi()) << ret_input->DebugName();
+ HInstruction* pre_header_input = ret_input->InputAt(0);
+ HInstruction* loop_body_input = ret_input->InputAt(1);
+ ASSERT_EQ(param, pre_header_input) << pre_header_input->DebugName();
+ ASSERT_TRUE(loop_body_input->IsTypeConversion());
+ ASSERT_EQ(load_type, loop_body_input->GetType());
+ ASSERT_EQ(ret_input, loop_body_input->InputAt(0));
+ }
+}
+
+TEST_P(TwoTypesConversionsTestGroup, MergingTwiceConvertedValueStore) {
+ auto [load_type1, load_type2] = GetParam();
+ DataType::Type field_type1 = FieldTypeForLoadType(load_type1);
+ DataType::Type field_type2 = FieldTypeForLoadType(load_type2);
+ DataType::Type phi_field_type = DataType::Type::kInt32; // "phi field" can hold the full value.
+ CHECK(DataType::IsTypeConversionImplicit(load_type1, phi_field_type));
+ CHECK(DataType::IsTypeConversionImplicit(load_type2, phi_field_type));
+
+ HBasicBlock* return_block = InitEntryMainExitGraph();
+ auto [pre_header, loop_header, loop_body] = CreateForLoopWithInstructions(return_block);
+
+ HInstruction* param = MakeParam(DataType::Type::kInt32);
+ HInstruction* object = MakeParam(DataType::Type::kReference);
+
+ // Initialize the "phi field".
+ HInstruction* pre_header_write =
+ MakeIFieldSet(pre_header, object, param, phi_field_type, MemberOffset(40));
+
+ // In the body, we read the "phi field", store and load the value to a different field
+ // to force type conversion - twice, and store back to the "phi field".
+ HInstanceFieldGet* phi_read = MakeIFieldGet(loop_body, object, phi_field_type, MemberOffset(40));
+ HInstruction* conversion_write1 =
+ MakeIFieldSet(loop_body, object, phi_read, field_type1, MemberOffset(32));
+ HInstanceFieldGet* conversion_read1 =
+ MakeIFieldGet(loop_body, object, field_type1, MemberOffset(32));
+ conversion_read1->SetType(load_type1);
+ HInstruction* conversion_write2 =
+ MakeIFieldSet(loop_body, object, conversion_read1, field_type2, MemberOffset(36));
+ HInstanceFieldGet* conversion_read2 =
+ MakeIFieldGet(loop_body, object, field_type2, MemberOffset(36));
+ conversion_read2->SetType(load_type2);
+ HInstruction* phi_write =
+ MakeIFieldSet(loop_body, object, conversion_read2, phi_field_type, MemberOffset(40));
+
+ HInstanceFieldGet* final_read =
+ MakeIFieldGet(return_block, object, phi_field_type, MemberOffset(40));
+ HInstruction* ret = MakeReturn(return_block, final_read);
+
+ PerformLSE();
+
+ EXPECT_INS_RETAINED(pre_header_write);
+ EXPECT_INS_RETAINED(conversion_write1);
+ EXPECT_INS_RETAINED(conversion_write2);
+ EXPECT_INS_REMOVED(phi_read);
+ EXPECT_INS_REMOVED(conversion_read1);
+ EXPECT_INS_REMOVED(conversion_read2);
+ EXPECT_INS_REMOVED(final_read);
+
+ HInstruction* ret_input = ret->InputAt(0);
+ if (load_type1 == DataType::Type::kInt32 && load_type2 == DataType::Type::kInt32) {
+ EXPECT_INS_REMOVED(phi_write) << "\n" << load_type1 << "/" << load_type2;
+ ASSERT_EQ(param, ret_input) << ret_input->DebugName();
+ } else {
+ GTEST_SKIP() << "FIXME: Missing type conversions. Bug: 341476044";
+ EXPECT_INS_RETAINED(phi_write) << "\n" << load_type1 << "/" << load_type2;
+ ASSERT_TRUE(ret_input->IsPhi()) << ret_input->DebugName();
+ HInstruction* pre_header_input = ret_input->InputAt(0);
+ HInstruction* loop_body_input = ret_input->InputAt(1);
+ ASSERT_EQ(param, pre_header_input) << pre_header_input->DebugName();
+ ASSERT_TRUE(loop_body_input->IsTypeConversion());
+ // Note: Sometimes we create two type conversions when one is enough (Int32->Int16->Int8).
+ // We currently rely on the instruction simplifier to remove the intermediate conversion.
+ HInstruction* current = loop_body_input;
+ if (!DataType::IsTypeConversionImplicit(load_type1, load_type2)) {
+ ASSERT_TRUE(current->IsTypeConversion()) << current->DebugName();
+ ASSERT_EQ(load_type2, current->GetType());
+ current = current->InputAt(0);
+ }
+ if (!DataType::IsTypeConversionImplicit(DataType::Type::kInt32, load_type1)) {
+ ASSERT_TRUE(current->IsTypeConversion()) << current->DebugName();
+ ASSERT_EQ(load_type1, current->GetType()) << load_type2;
+ current = current->InputAt(0);
+ }
+ ASSERT_EQ(current, ret_input);
+ }
+}
+
+auto Int32AndSmallerTypesGenerator() {
+ return testing::Values(DataType::Type::kInt32,
+ DataType::Type::kInt16,
+ DataType::Type::kInt8,
+ DataType::Type::kUint16,
+ DataType::Type::kUint8);
+}
+
+INSTANTIATE_TEST_SUITE_P(
+ LoadStoreEliminationTest,
+ TwoTypesConversionsTestGroup,
+ testing::Combine(Int32AndSmallerTypesGenerator(), Int32AndSmallerTypesGenerator()));
+
// // ENTRY
// obj = new Obj();
// // ALL should be kept
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index cc4bc11bdd..23cc3704e9 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -6218,7 +6218,7 @@ inline std::ostream& operator<<(std::ostream& os, const FieldInfo& a) {
class HInstanceFieldGet final : public HExpression<1> {
public:
- HInstanceFieldGet(HInstruction* value,
+ HInstanceFieldGet(HInstruction* object,
ArtField* field,
DataType::Type field_type,
MemberOffset field_offset,
@@ -6238,7 +6238,7 @@ class HInstanceFieldGet final : public HExpression<1> {
field_idx,
declaring_class_def_index,
dex_file) {
- SetRawInputAt(0, value);
+ SetRawInputAt(0, object);
}
bool IsClonable() const override { return true; }
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index f4f62e67ed..2fe11299fc 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -507,22 +507,22 @@ class OptimizingUnitTestHelper {
}
HInstanceFieldSet* MakeIFieldSet(HBasicBlock* block,
- HInstruction* inst,
+ HInstruction* object,
HInstruction* data,
MemberOffset off,
uint32_t dex_pc = kNoDexPc) {
CHECK(data != nullptr);
- return MakeIFieldSet(block, inst, data, data->GetType(), off, dex_pc);
+ return MakeIFieldSet(block, object, data, data->GetType(), off, dex_pc);
}
HInstanceFieldSet* MakeIFieldSet(HBasicBlock* block,
- HInstruction* inst,
+ HInstruction* object,
HInstruction* data,
DataType::Type field_type,
MemberOffset off,
uint32_t dex_pc = kNoDexPc) {
HInstanceFieldSet* ifield_set = new (GetAllocator()) HInstanceFieldSet(
- inst,
+ object,
data,
/* field= */ nullptr,
field_type,
@@ -537,12 +537,12 @@ class OptimizingUnitTestHelper {
}
HInstanceFieldGet* MakeIFieldGet(HBasicBlock* block,
- HInstruction* inst,
+ HInstruction* object,
DataType::Type type,
MemberOffset off,
uint32_t dex_pc = kNoDexPc) {
HInstanceFieldGet* ifield_get = new (GetAllocator()) HInstanceFieldGet(
- inst,
+ object,
/* field= */ nullptr,
/* field_type= */ type,
/* field_offset= */ off,