diff options
author | Vladimir Marko <vmarko@google.com> | 2015-03-18 11:33:58 +0000 |
---|---|---|
committer | Vladimir Marko <vmarko@google.com> | 2015-03-18 14:50:07 +0000 |
commit | 22fe45de11ed7afdf21400d2de3abd23f3a62800 (patch) | |
tree | 47eb3fa0dba432667774eb1d0eb9f66b897a66d3 /compiler/dex/global_value_numbering_test.cc | |
parent | d6f00810e2419489f526e4f0c94cb13318a365fd (diff) | |
download | android_art-22fe45de11ed7afdf21400d2de3abd23f3a62800.tar.gz android_art-22fe45de11ed7afdf21400d2de3abd23f3a62800.tar.bz2 android_art-22fe45de11ed7afdf21400d2de3abd23f3a62800.zip |
Quick: Eliminate check-cast guaranteed by instance-of.
Eliminate check-cast if the result of an instance-of with
the very same type on the same value is used to branch to
the check-cast's block or a dominator of it.
Note that there already exists a verifier-based elimination
of check-cast but it excludes check-cast on interfaces. This
new optimization works for interface types and, since it's
GVN-based, it can better recognize when the same reference
is used for instance-of and check-cast.
Change-Id: Ib315199805099d1cb0534bb4a90dc51baa409685
Diffstat (limited to 'compiler/dex/global_value_numbering_test.cc')
-rw-r--r-- | compiler/dex/global_value_numbering_test.cc | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/compiler/dex/global_value_numbering_test.cc b/compiler/dex/global_value_numbering_test.cc index b91c3cac8f..b4559ef375 100644 --- a/compiler/dex/global_value_numbering_test.cc +++ b/compiler/dex/global_value_numbering_test.cc @@ -136,6 +136,7 @@ class GlobalValueNumberingTest : public testing::Test { { bb, static_cast<Instruction::Code>(kMirOpPhi), 0, 0u, 2u, { src1, src2 }, 1, { reg } } #define DEF_BINOP(bb, opcode, result, src1, src2) \ { bb, opcode, 0u, 0u, 2, { src1, src2 }, 1, { result } } +#define DEF_UNOP(bb, opcode, result, src) DEF_MOVE(bb, opcode, result, src) void DoPrepareIFields(const IFieldDef* defs, size_t count) { cu_.mir_graph->ifield_lowering_infos_.clear(); @@ -2315,4 +2316,95 @@ TEST_F(GlobalValueNumberingTestDiamond, DivZeroCheckDiamond) { } } +TEST_F(GlobalValueNumberingTestDiamond, CheckCastDiamond) { + static const MIRDef mirs[] = { + DEF_UNOP(3u, Instruction::INSTANCE_OF, 0u, 100u), + DEF_UNOP(3u, Instruction::INSTANCE_OF, 1u, 200u), + DEF_IFZ(3u, Instruction::IF_NEZ, 0u), + DEF_INVOKE1(4u, Instruction::CHECK_CAST, 100u), + DEF_INVOKE1(5u, Instruction::CHECK_CAST, 100u), + DEF_INVOKE1(5u, Instruction::CHECK_CAST, 200u), + DEF_INVOKE1(5u, Instruction::CHECK_CAST, 100u), + DEF_INVOKE1(6u, Instruction::CHECK_CAST, 100u), + }; + + static const bool expected_ignore_check_cast[] = { + false, // instance-of + false, // instance-of + false, // if-nez + false, // Not eliminated, fall-through branch. + true, // Eliminated. + false, // Not eliminated, different value. + false, // Not eliminated, different type. + false, // Not eliminated, bottom block. + }; + + PrepareMIRs(mirs); + mirs_[0].dalvikInsn.vC = 1234; // type for instance-of + mirs_[1].dalvikInsn.vC = 1234; // type for instance-of + mirs_[3].dalvikInsn.vB = 1234; // type for check-cast + mirs_[4].dalvikInsn.vB = 1234; // type for check-cast + mirs_[5].dalvikInsn.vB = 1234; // type for check-cast + mirs_[6].dalvikInsn.vB = 4321; // type for check-cast + mirs_[7].dalvikInsn.vB = 1234; // type for check-cast + PerformGVN(); + PerformGVNCodeModifications(); + ASSERT_EQ(arraysize(expected_ignore_check_cast), mir_count_); + for (size_t i = 0u; i != mir_count_; ++i) { + int expected = expected_ignore_check_cast[i] ? MIR_IGNORE_CHECK_CAST : 0u; + EXPECT_EQ(expected, mirs_[i].optimization_flags) << i; + } +} + +TEST_F(GlobalValueNumberingTest, CheckCastDominators) { + const BBDef bbs[] = { + DEF_BB(kNullBlock, DEF_SUCC0(), DEF_PRED0()), + DEF_BB(kEntryBlock, DEF_SUCC1(3), DEF_PRED0()), + DEF_BB(kExitBlock, DEF_SUCC0(), DEF_PRED1(7)), + DEF_BB(kDalvikByteCode, DEF_SUCC2(4, 5), DEF_PRED1(1)), // Block #3, top of the diamond. + DEF_BB(kDalvikByteCode, DEF_SUCC1(7), DEF_PRED1(3)), // Block #4, left side. + DEF_BB(kDalvikByteCode, DEF_SUCC1(6), DEF_PRED1(3)), // Block #5, right side. + DEF_BB(kDalvikByteCode, DEF_SUCC1(7), DEF_PRED1(5)), // Block #6, right side. + DEF_BB(kDalvikByteCode, DEF_SUCC1(2), DEF_PRED2(4, 6)), // Block #7, bottom. + }; + static const MIRDef mirs[] = { + DEF_UNOP(3u, Instruction::INSTANCE_OF, 0u, 100u), + DEF_UNOP(3u, Instruction::INSTANCE_OF, 1u, 200u), + DEF_IFZ(3u, Instruction::IF_NEZ, 0u), + DEF_INVOKE1(4u, Instruction::CHECK_CAST, 100u), + DEF_INVOKE1(6u, Instruction::CHECK_CAST, 100u), + DEF_INVOKE1(6u, Instruction::CHECK_CAST, 200u), + DEF_INVOKE1(6u, Instruction::CHECK_CAST, 100u), + DEF_INVOKE1(7u, Instruction::CHECK_CAST, 100u), + }; + + static const bool expected_ignore_check_cast[] = { + false, // instance-of + false, // instance-of + false, // if-nez + false, // Not eliminated, fall-through branch. + true, // Eliminated. + false, // Not eliminated, different value. + false, // Not eliminated, different type. + false, // Not eliminated, bottom block. + }; + + PrepareBasicBlocks(bbs); + PrepareMIRs(mirs); + mirs_[0].dalvikInsn.vC = 1234; // type for instance-of + mirs_[1].dalvikInsn.vC = 1234; // type for instance-of + mirs_[3].dalvikInsn.vB = 1234; // type for check-cast + mirs_[4].dalvikInsn.vB = 1234; // type for check-cast + mirs_[5].dalvikInsn.vB = 1234; // type for check-cast + mirs_[6].dalvikInsn.vB = 4321; // type for check-cast + mirs_[7].dalvikInsn.vB = 1234; // type for check-cast + PerformGVN(); + PerformGVNCodeModifications(); + ASSERT_EQ(arraysize(expected_ignore_check_cast), mir_count_); + for (size_t i = 0u; i != mir_count_; ++i) { + int expected = expected_ignore_check_cast[i] ? MIR_IGNORE_CHECK_CAST : 0u; + EXPECT_EQ(expected, mirs_[i].optimization_flags) << i; + } +} + } // namespace art |