summaryrefslogtreecommitdiff
path: root/compiler/optimizing/instruction_simplifier_test.cc
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/optimizing/instruction_simplifier_test.cc')
-rw-r--r--compiler/optimizing/instruction_simplifier_test.cc310
1 files changed, 310 insertions, 0 deletions
diff --git a/compiler/optimizing/instruction_simplifier_test.cc b/compiler/optimizing/instruction_simplifier_test.cc
new file mode 100644
index 0000000000..7d93809be6
--- /dev/null
+++ b/compiler/optimizing/instruction_simplifier_test.cc
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "instruction_simplifier.h"
+
+#include <initializer_list>
+#include <tuple>
+
+#include "gtest/gtest.h"
+#include "nodes.h"
+#include "optimizing/data_type.h"
+#include "optimizing_unit_test.h"
+
+namespace art {
+
+class InstructionSimplifierTest : public CommonCompilerTest, public OptimizingUnitTestHelper {
+ public:
+ void SetUp() override {
+ CommonCompilerTest::SetUp();
+ gLogVerbosity.compiler = true;
+ }
+
+ void TearDown() override {
+ CommonCompilerTest::TearDown();
+ gLogVerbosity.compiler = false;
+ }
+};
+
+// // ENTRY
+// switch (param) {
+// case 1:
+// obj1 = param2; break;
+// case 2:
+// obj1 = param3; break;
+// default:
+// obj2 = new Obj();
+// }
+// val_phi = PHI[3,4,10]
+// target_phi = PHI[param2, param3, obj2]
+// return PredFieldGet[val_phi, target_phi] => PredFieldGet[val_phi, target_phi]
+TEST_F(InstructionSimplifierTest, SimplifyPredicatedFieldGetNoMerge) {
+ VariableSizedHandleScope vshs(Thread::Current());
+ CreateGraph(&vshs);
+ AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+ "exit",
+ {{"entry", "case1"},
+ {"entry", "case2"},
+ {"entry", "case3"},
+ {"case1", "breturn"},
+ {"case2", "breturn"},
+ {"case3", "breturn"},
+ {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+ GET_BLOCK(entry);
+ GET_BLOCK(exit);
+ GET_BLOCK(case1);
+ GET_BLOCK(case2);
+ GET_BLOCK(case3);
+ GET_BLOCK(breturn);
+#undef GET_BLOCK
+
+ HInstruction* bool_value = MakeParam(DataType::Type::kInt32);
+ HInstruction* obj1_param = MakeParam(DataType::Type::kReference);
+ HInstruction* obj2_param = MakeParam(DataType::Type::kReference);
+ HInstruction* c3 = graph_->GetIntConstant(3);
+ HInstruction* c4 = graph_->GetIntConstant(4);
+ HInstruction* c10 = graph_->GetIntConstant(10);
+
+ HInstruction* cls = MakeClassLoad();
+ HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, bool_value);
+ entry->AddInstruction(cls);
+ entry->AddInstruction(switch_inst);
+ ManuallyBuildEnvFor(cls, {});
+
+ HInstruction* goto_c1 = new (GetAllocator()) HGoto();
+ case1->AddInstruction(goto_c1);
+
+ HInstruction* goto_c2 = new (GetAllocator()) HGoto();
+ case2->AddInstruction(goto_c2);
+
+ HInstruction* obj3 = MakeNewInstance(cls);
+ HInstruction* goto_c3 = new (GetAllocator()) HGoto();
+ case3->AddInstruction(obj3);
+ case3->AddInstruction(goto_c3);
+
+ HPhi* val_phi = MakePhi({c3, c4, c10});
+ HPhi* obj_phi = MakePhi({obj1_param, obj2_param, obj3});
+ HPredicatedInstanceFieldGet* read_end =
+ new (GetAllocator()) HPredicatedInstanceFieldGet(obj_phi,
+ nullptr,
+ val_phi,
+ val_phi->GetType(),
+ MemberOffset(10),
+ false,
+ 42,
+ 0,
+ graph_->GetDexFile(),
+ 0);
+ HInstruction* return_exit = new (GetAllocator()) HReturn(read_end);
+ breturn->AddPhi(val_phi);
+ breturn->AddPhi(obj_phi);
+ breturn->AddInstruction(read_end);
+ breturn->AddInstruction(return_exit);
+
+ SetupExit(exit);
+
+ LOG(INFO) << "Pre simplification " << blks;
+ graph_->ClearDominanceInformation();
+ graph_->BuildDominatorTree();
+ InstructionSimplifier simp(graph_, /*codegen=*/nullptr);
+ simp.Run();
+
+ LOG(INFO) << "Post simplify " << blks;
+
+ EXPECT_INS_RETAINED(read_end);
+
+ EXPECT_INS_EQ(read_end->GetTarget(), obj_phi);
+ EXPECT_INS_EQ(read_end->GetDefaultValue(), val_phi);
+}
+
+// // ENTRY
+// switch (param) {
+// case 1:
+// obj1 = param2; break;
+// case 2:
+// obj1 = param3; break;
+// default:
+// obj2 = new Obj();
+// }
+// val_phi = PHI[3,3,10]
+// target_phi = PHI[param2, param3, obj2]
+// return PredFieldGet[val_phi, target_phi] => PredFieldGet[3, target_phi]
+TEST_F(InstructionSimplifierTest, SimplifyPredicatedFieldGetMerge) {
+ VariableSizedHandleScope vshs(Thread::Current());
+ CreateGraph(&vshs);
+ AdjacencyListGraph blks(SetupFromAdjacencyList("entry",
+ "exit",
+ {{"entry", "case1"},
+ {"entry", "case2"},
+ {"entry", "case3"},
+ {"case1", "breturn"},
+ {"case2", "breturn"},
+ {"case3", "breturn"},
+ {"breturn", "exit"}}));
+#define GET_BLOCK(name) HBasicBlock* name = blks.Get(#name)
+ GET_BLOCK(entry);
+ GET_BLOCK(exit);
+ GET_BLOCK(case1);
+ GET_BLOCK(case2);
+ GET_BLOCK(case3);
+ GET_BLOCK(breturn);
+#undef GET_BLOCK
+
+ HInstruction* bool_value = MakeParam(DataType::Type::kInt32);
+ HInstruction* obj1_param = MakeParam(DataType::Type::kReference);
+ HInstruction* obj2_param = MakeParam(DataType::Type::kReference);
+ HInstruction* c3 = graph_->GetIntConstant(3);
+ HInstruction* c10 = graph_->GetIntConstant(10);
+
+ HInstruction* cls = MakeClassLoad();
+ HInstruction* switch_inst = new (GetAllocator()) HPackedSwitch(0, 2, bool_value);
+ entry->AddInstruction(cls);
+ entry->AddInstruction(switch_inst);
+ ManuallyBuildEnvFor(cls, {});
+
+ HInstruction* goto_c1 = new (GetAllocator()) HGoto();
+ case1->AddInstruction(goto_c1);
+
+ HInstruction* goto_c2 = new (GetAllocator()) HGoto();
+ case2->AddInstruction(goto_c2);
+
+ HInstruction* obj3 = MakeNewInstance(cls);
+ HInstruction* goto_c3 = new (GetAllocator()) HGoto();
+ case3->AddInstruction(obj3);
+ case3->AddInstruction(goto_c3);
+
+ HPhi* val_phi = MakePhi({c3, c3, c10});
+ HPhi* obj_phi = MakePhi({obj1_param, obj2_param, obj3});
+ HPredicatedInstanceFieldGet* read_end =
+ new (GetAllocator()) HPredicatedInstanceFieldGet(obj_phi,
+ nullptr,
+ val_phi,
+ val_phi->GetType(),
+ MemberOffset(10),
+ false,
+ 42,
+ 0,
+ graph_->GetDexFile(),
+ 0);
+ HInstruction* return_exit = new (GetAllocator()) HReturn(read_end);
+ breturn->AddPhi(val_phi);
+ breturn->AddPhi(obj_phi);
+ breturn->AddInstruction(read_end);
+ breturn->AddInstruction(return_exit);
+
+ SetupExit(exit);
+
+ LOG(INFO) << "Pre simplification " << blks;
+ graph_->ClearDominanceInformation();
+ graph_->BuildDominatorTree();
+ InstructionSimplifier simp(graph_, /*codegen=*/nullptr);
+ simp.Run();
+
+ LOG(INFO) << "Post simplify " << blks;
+
+ EXPECT_FALSE(obj3->CanBeNull());
+ EXPECT_INS_RETAINED(read_end);
+
+ EXPECT_INS_EQ(read_end->GetTarget(), obj_phi);
+ EXPECT_INS_EQ(read_end->GetDefaultValue(), c3);
+}
+
+// // ENTRY
+// if (param) {
+// obj1 = new Obj();
+// } else {
+// obj2 = new Obj();
+// }
+// val_phi = PHI[3,10]
+// target_phi = PHI[obj1, obj2]
+// return PredFieldGet[val_phi, target_phi] => FieldGet[target_phi]
+TEST_F(InstructionSimplifierTest, SimplifyPredicatedFieldGetNoNull) {
+ VariableSizedHandleScope vshs(Thread::Current());
+ CreateGraph(&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(left);
+ GET_BLOCK(right);
+ GET_BLOCK(breturn);
+#undef GET_BLOCK
+
+ HInstruction* bool_value = MakeParam(DataType::Type::kBool);
+ HInstruction* c3 = graph_->GetIntConstant(3);
+ HInstruction* c10 = graph_->GetIntConstant(10);
+
+ HInstruction* cls = MakeClassLoad();
+ HInstruction* if_inst = new (GetAllocator()) HIf(bool_value);
+ entry->AddInstruction(cls);
+ entry->AddInstruction(if_inst);
+ ManuallyBuildEnvFor(cls, {});
+
+ HInstruction* obj1 = MakeNewInstance(cls);
+ HInstruction* goto_left = new (GetAllocator()) HGoto();
+ left->AddInstruction(obj1);
+ left->AddInstruction(goto_left);
+
+ HInstruction* obj2 = MakeNewInstance(cls);
+ HInstruction* goto_right = new (GetAllocator()) HGoto();
+ right->AddInstruction(obj2);
+ right->AddInstruction(goto_right);
+
+ HPhi* val_phi = MakePhi({c3, c10});
+ HPhi* obj_phi = MakePhi({obj1, obj2});
+ HInstruction* read_end = new (GetAllocator()) HPredicatedInstanceFieldGet(obj_phi,
+ nullptr,
+ val_phi,
+ val_phi->GetType(),
+ MemberOffset(10),
+ false,
+ 42,
+ 0,
+ graph_->GetDexFile(),
+ 0);
+ HInstruction* return_exit = new (GetAllocator()) HReturn(read_end);
+ breturn->AddPhi(val_phi);
+ breturn->AddPhi(obj_phi);
+ breturn->AddInstruction(read_end);
+ breturn->AddInstruction(return_exit);
+
+ SetupExit(exit);
+
+ LOG(INFO) << "Pre simplification " << blks;
+ graph_->ClearDominanceInformation();
+ graph_->BuildDominatorTree();
+ InstructionSimplifier simp(graph_, /*codegen=*/nullptr);
+ simp.Run();
+
+ LOG(INFO) << "Post simplify " << blks;
+
+ EXPECT_FALSE(obj1->CanBeNull());
+ EXPECT_FALSE(obj2->CanBeNull());
+ EXPECT_INS_REMOVED(read_end);
+
+ HInstanceFieldGet* ifget = FindSingleInstruction<HInstanceFieldGet>(graph_, breturn);
+ ASSERT_NE(ifget, nullptr);
+ EXPECT_INS_EQ(ifget->InputAt(0), obj_phi);
+}
+
+} // namespace art