From a5e69e87c630c08c0de1740427e60d531ce851b9 Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Fri, 24 Apr 2015 19:03:51 +0100 Subject: Quick: Rely on inferred types in GVN/LVN/DCE. Fix LVN::GetEndingVregValueNumberImpl() to check whether the requested wideness matches the SSA register type as recorded in MIRGraph::reg_location_. Add DCHECKs that the wideness matches when getting/setting sreg values, update Phi handling in LVN/DCE to use the type from MIRGraph::reg_location_ instead of determining it from the sreg value maps which would now trigger the DCHECKs. Update tests to initialize MIRGraph::reg_location_. Reenable DCE. Bug: 20572509 Change-Id: I1a4d4e32cd57807ca8b56d2f3ed5e1288660b82e --- compiler/dex/global_value_numbering_test.cc | 73 ++++++---- compiler/dex/gvn_dead_code_elimination.cc | 19 ++- compiler/dex/gvn_dead_code_elimination_test.cc | 21 ++- compiler/dex/local_value_numbering.cc | 25 ++-- compiler/dex/local_value_numbering.h | 10 +- compiler/dex/local_value_numbering_test.cc | 179 ++++++++++++++----------- compiler/dex/quick/quick_compiler.cc | 2 +- 7 files changed, 198 insertions(+), 131 deletions(-) (limited to 'compiler/dex') diff --git a/compiler/dex/global_value_numbering_test.cc b/compiler/dex/global_value_numbering_test.cc index c538d0b..c8aa990 100644 --- a/compiler/dex/global_value_numbering_test.cc +++ b/compiler/dex/global_value_numbering_test.cc @@ -290,6 +290,15 @@ class GlobalValueNumberingTest : public testing::Test { DoPrepareVregToSsaMapExit(bb_id, map, count); } + template + void MarkAsWideSRegs(const int32_t (&sregs)[count]) { + for (int32_t sreg : sregs) { + cu_.mir_graph->reg_location_[sreg].wide = true; + cu_.mir_graph->reg_location_[sreg + 1].wide = true; + cu_.mir_graph->reg_location_[sreg + 1].high_word = true; + } + } + void PerformGVN() { DoPerformGVN(); } @@ -360,9 +369,11 @@ class GlobalValueNumberingTest : public testing::Test { cu_.access_flags = kAccStatic; // Don't let "this" interfere with this test. allocator_.reset(ScopedArenaAllocator::Create(&cu_.arena_stack)); // By default, the zero-initialized reg_location_[.] with ref == false tells LVN that - // 0 constants are integral, not references. Nothing else is used by LVN/GVN. + // 0 constants are integral, not references, and the values are all narrow. + // Nothing else is used by LVN/GVN. Tests can override the default values as needed. cu_.mir_graph->reg_location_ = cu_.arena.AllocArray(kMaxSsaRegs, kArenaAllocRegAlloc); + cu_.mir_graph->num_ssa_regs_ = kMaxSsaRegs; // Bind all possible sregs to live vregs for test purposes. live_in_v_->SetInitialBits(kMaxSsaRegs); cu_.mir_graph->ssa_base_vregs_.reserve(kMaxSsaRegs); @@ -910,14 +921,14 @@ TEST_F(GlobalValueNumberingTestDiamond, AliasingArrays) { DEF_IGET(6, Instruction::AGET_OBJECT, 3u, 200u, 201u), // Same as at the left side. DEF_AGET(3, Instruction::AGET_WIDE, 4u, 300u, 301u), - DEF_CONST(5, Instruction::CONST_WIDE, 5u, 1000), - DEF_APUT(5, Instruction::APUT_WIDE, 5u, 300u, 301u), - DEF_AGET(6, Instruction::AGET_WIDE, 7u, 300u, 301u), // Differs from the top and the CONST. + DEF_CONST(5, Instruction::CONST_WIDE, 6u, 1000), + DEF_APUT(5, Instruction::APUT_WIDE, 6u, 300u, 301u), + DEF_AGET(6, Instruction::AGET_WIDE, 8u, 300u, 301u), // Differs from the top and the CONST. - DEF_AGET(3, Instruction::AGET_SHORT, 8u, 400u, 401u), - DEF_CONST(3, Instruction::CONST, 9u, 2000), - DEF_APUT(4, Instruction::APUT_SHORT, 9u, 400u, 401u), - DEF_APUT(5, Instruction::APUT_SHORT, 9u, 400u, 401u), + DEF_AGET(3, Instruction::AGET_SHORT, 10u, 400u, 401u), + DEF_CONST(3, Instruction::CONST, 11u, 2000), + DEF_APUT(4, Instruction::APUT_SHORT, 11u, 400u, 401u), + DEF_APUT(5, Instruction::APUT_SHORT, 11u, 400u, 401u), DEF_AGET(6, Instruction::AGET_SHORT, 12u, 400u, 401u), // Differs from the top, == CONST. DEF_AGET(3, Instruction::AGET_CHAR, 13u, 500u, 501u), @@ -939,6 +950,8 @@ TEST_F(GlobalValueNumberingTestDiamond, AliasingArrays) { }; PrepareMIRs(mirs); + static const int32_t wide_sregs[] = { 4, 6, 8 }; + MarkAsWideSRegs(wide_sregs); PerformGVN(); ASSERT_EQ(arraysize(mirs), value_names_.size()); EXPECT_EQ(value_names_[0], value_names_[1]); @@ -1057,6 +1070,12 @@ TEST_F(GlobalValueNumberingTestDiamond, PhiWide) { }; PrepareMIRs(mirs); + for (size_t i = 0u; i != arraysize(mirs); ++i) { + if ((mirs_[i].ssa_rep->defs[0] % 2) == 0) { + const int32_t wide_sregs[] = { mirs_[i].ssa_rep->defs[0] }; + MarkAsWideSRegs(wide_sregs); + } + } PerformGVN(); ASSERT_EQ(arraysize(mirs), value_names_.size()); EXPECT_EQ(value_names_[0], value_names_[7]); @@ -1493,27 +1512,27 @@ TEST_F(GlobalValueNumberingTestLoop, AliasingArrays) { static const MIRDef mirs[] = { // NOTE: MIRs here are ordered by unique tests. They will be put into appropriate blocks. DEF_AGET(3, Instruction::AGET_WIDE, 0u, 100u, 101u), - DEF_AGET(4, Instruction::AGET_WIDE, 1u, 100u, 101u), // Same as at the top. - DEF_AGET(5, Instruction::AGET_WIDE, 2u, 100u, 101u), // Same as at the top. + DEF_AGET(4, Instruction::AGET_WIDE, 2u, 100u, 101u), // Same as at the top. + DEF_AGET(5, Instruction::AGET_WIDE, 4u, 100u, 101u), // Same as at the top. - DEF_AGET(3, Instruction::AGET_BYTE, 3u, 200u, 201u), - DEF_AGET(4, Instruction::AGET_BYTE, 4u, 200u, 201u), // Differs from top... - DEF_APUT(4, Instruction::APUT_BYTE, 5u, 200u, 201u), // Because of this IPUT. - DEF_AGET(5, Instruction::AGET_BYTE, 6u, 200u, 201u), // Differs from top and the loop AGET. + DEF_AGET(3, Instruction::AGET_BYTE, 6u, 200u, 201u), + DEF_AGET(4, Instruction::AGET_BYTE, 7u, 200u, 201u), // Differs from top... + DEF_APUT(4, Instruction::APUT_BYTE, 8u, 200u, 201u), // Because of this IPUT. + DEF_AGET(5, Instruction::AGET_BYTE, 9u, 200u, 201u), // Differs from top and the loop AGET. - DEF_AGET(3, Instruction::AGET, 7u, 300u, 301u), - DEF_APUT(4, Instruction::APUT, 8u, 300u, 301u), // Because of this IPUT... - DEF_AGET(4, Instruction::AGET, 9u, 300u, 301u), // Differs from top. - DEF_AGET(5, Instruction::AGET, 10u, 300u, 301u), // Differs from top but == the loop AGET. + DEF_AGET(3, Instruction::AGET, 10u, 300u, 301u), + DEF_APUT(4, Instruction::APUT, 11u, 300u, 301u), // Because of this IPUT... + DEF_AGET(4, Instruction::AGET, 12u, 300u, 301u), // Differs from top. + DEF_AGET(5, Instruction::AGET, 13u, 300u, 301u), // Differs from top but == the loop AGET. - DEF_CONST(3, Instruction::CONST, 11u, 3000), - DEF_APUT(3, Instruction::APUT_CHAR, 11u, 400u, 401u), - DEF_APUT(3, Instruction::APUT_CHAR, 11u, 400u, 402u), - DEF_AGET(4, Instruction::AGET_CHAR, 14u, 400u, 401u), // Differs from 11u and 16u. - DEF_AGET(4, Instruction::AGET_CHAR, 15u, 400u, 402u), // Same as 14u. - DEF_CONST(4, Instruction::CONST, 16u, 4000), - DEF_APUT(4, Instruction::APUT_CHAR, 16u, 400u, 401u), - DEF_APUT(4, Instruction::APUT_CHAR, 16u, 400u, 402u), + DEF_CONST(3, Instruction::CONST, 14u, 3000), + DEF_APUT(3, Instruction::APUT_CHAR, 14u, 400u, 401u), + DEF_APUT(3, Instruction::APUT_CHAR, 14u, 400u, 402u), + DEF_AGET(4, Instruction::AGET_CHAR, 15u, 400u, 401u), // Differs from 11u and 16u. + DEF_AGET(4, Instruction::AGET_CHAR, 16u, 400u, 402u), // Same as 14u. + DEF_CONST(4, Instruction::CONST, 17u, 4000), + DEF_APUT(4, Instruction::APUT_CHAR, 17u, 400u, 401u), + DEF_APUT(4, Instruction::APUT_CHAR, 17u, 400u, 402u), DEF_AGET(5, Instruction::AGET_CHAR, 19u, 400u, 401u), // Differs from 11u and 14u... DEF_AGET(5, Instruction::AGET_CHAR, 20u, 400u, 402u), // and same as the CONST 16u. @@ -1531,6 +1550,8 @@ TEST_F(GlobalValueNumberingTestLoop, AliasingArrays) { }; PrepareMIRs(mirs); + static const int32_t wide_sregs[] = { 0, 2, 4 }; + MarkAsWideSRegs(wide_sregs); PerformGVN(); ASSERT_EQ(arraysize(mirs), value_names_.size()); EXPECT_EQ(value_names_[0], value_names_[1]); diff --git a/compiler/dex/gvn_dead_code_elimination.cc b/compiler/dex/gvn_dead_code_elimination.cc index bd7bd71..4f0e9d1 100644 --- a/compiler/dex/gvn_dead_code_elimination.cc +++ b/compiler/dex/gvn_dead_code_elimination.cc @@ -984,18 +984,17 @@ bool GvnDeadCodeElimination::RecordMIR(MIR* mir) { uint16_t opcode = mir->dalvikInsn.opcode; switch (opcode) { case kMirOpPhi: { - // We can't recognize wide variables in Phi from num_defs == 2 as we've got two Phis instead. + // Determine if this Phi is merging wide regs. + RegLocation raw_dest = gvn_->GetMirGraph()->GetRawDest(mir); + if (raw_dest.high_word) { + // This is the high part of a wide reg. Ignore the Phi. + return false; + } + bool wide = raw_dest.wide; + // Record the value. DCHECK_EQ(mir->ssa_rep->num_defs, 1); int s_reg = mir->ssa_rep->defs[0]; - bool wide = false; - uint16_t new_value = lvn_->GetSregValue(s_reg); - if (new_value == kNoValue) { - wide = true; - new_value = lvn_->GetSregValueWide(s_reg); - if (new_value == kNoValue) { - return false; // Ignore the high word Phi. - } - } + uint16_t new_value = wide ? lvn_->GetSregValueWide(s_reg) : lvn_->GetSregValue(s_reg); int v_reg = mir_graph_->SRegToVReg(s_reg); DCHECK_EQ(vreg_chains_.CurrentValue(v_reg), kNoValue); // No previous def for v_reg. diff --git a/compiler/dex/gvn_dead_code_elimination_test.cc b/compiler/dex/gvn_dead_code_elimination_test.cc index 3eb372c..f9f0882 100644 --- a/compiler/dex/gvn_dead_code_elimination_test.cc +++ b/compiler/dex/gvn_dead_code_elimination_test.cc @@ -406,6 +406,15 @@ class GvnDeadCodeEliminationTest : public testing::Test { } } + template + void MarkAsWideSRegs(const int32_t (&sregs)[count]) { + for (int32_t sreg : sregs) { + cu_.mir_graph->reg_location_[sreg].wide = true; + cu_.mir_graph->reg_location_[sreg + 1].wide = true; + cu_.mir_graph->reg_location_[sreg + 1].high_word = true; + } + } + void PerformDCE() { FillVregToSsaRegExitMaps(); cu_.mir_graph->GetNumOfCodeAndTempVRs(); @@ -467,9 +476,11 @@ class GvnDeadCodeEliminationTest : public testing::Test { cu_.access_flags = kAccStatic; // Don't let "this" interfere with this test. allocator_.reset(ScopedArenaAllocator::Create(&cu_.arena_stack)); // By default, the zero-initialized reg_location_[.] with ref == false tells LVN that - // 0 constants are integral, not references. Nothing else is used by LVN/GVN. + // 0 constants are integral, not references, and the values are all narrow. + // Nothing else is used by LVN/GVN. Tests can override the default values as needed. cu_.mir_graph->reg_location_ = static_cast(cu_.arena.Alloc( kMaxSsaRegs * sizeof(cu_.mir_graph->reg_location_[0]), kArenaAllocRegAlloc)); + cu_.mir_graph->num_ssa_regs_ = kMaxSsaRegs; // Bind all possible sregs to live vregs for test purposes. live_in_v_->SetInitialBits(kMaxSsaRegs); cu_.mir_graph->ssa_base_vregs_.reserve(kMaxSsaRegs); @@ -705,6 +716,8 @@ TEST_F(GvnDeadCodeEliminationTestSimple, Rename4) { PrepareSRegToVRegMap(sreg_to_vreg_map); PrepareMIRs(mirs); + static const int32_t wide_sregs[] = { 3 }; + MarkAsWideSRegs(wide_sregs); PerformGVN_DCE(); ASSERT_EQ(arraysize(mirs), value_names_.size()); @@ -745,6 +758,8 @@ TEST_F(GvnDeadCodeEliminationTestSimple, Rename5) { PrepareIFields(ifields); PrepareMIRs(mirs); + static const int32_t wide_sregs[] = { 5 }; + MarkAsWideSRegs(wide_sregs); PerformGVN_DCE(); ASSERT_EQ(arraysize(mirs), value_names_.size()); @@ -777,6 +792,8 @@ TEST_F(GvnDeadCodeEliminationTestSimple, Rename6) { PrepareSRegToVRegMap(sreg_to_vreg_map); PrepareMIRs(mirs); + static const int32_t wide_sregs[] = { 0, 2 }; + MarkAsWideSRegs(wide_sregs); PerformGVN_DCE(); ASSERT_EQ(arraysize(mirs), value_names_.size()); @@ -1255,6 +1272,8 @@ TEST_F(GvnDeadCodeEliminationTestSimple, Simple4) { PrepareIFields(ifields); PrepareMIRs(mirs); + static const int32_t wide_sregs[] = { 1, 6 }; + MarkAsWideSRegs(wide_sregs); PerformGVN_DCE(); ASSERT_EQ(arraysize(mirs), value_names_.size()); diff --git a/compiler/dex/local_value_numbering.cc b/compiler/dex/local_value_numbering.cc index cdf5e38..cc9dbe4 100644 --- a/compiler/dex/local_value_numbering.cc +++ b/compiler/dex/local_value_numbering.cc @@ -1152,28 +1152,20 @@ uint16_t LocalValueNumbering::HandlePhi(MIR* mir) { // Running LVN without a full GVN? return kNoValue; } - int32_t* uses = mir->ssa_rep->uses; - // Try to find out if this is merging wide regs. - if (mir->ssa_rep->defs[0] != 0 && - sreg_wide_value_map_.count(mir->ssa_rep->defs[0] - 1) != 0u) { + // Determine if this Phi is merging wide regs. + RegLocation raw_dest = gvn_->GetMirGraph()->GetRawDest(mir); + if (raw_dest.high_word) { // This is the high part of a wide reg. Ignore the Phi. return kNoValue; } - BasicBlockId* incoming = mir->meta.phi_incoming; - int16_t pos = 0; - // Check if we're merging a wide value based on the first merged LVN. - const LocalValueNumbering* first_lvn = gvn_->merge_lvns_[0]; - DCHECK_LT(pos, mir->ssa_rep->num_uses); - while (incoming[pos] != first_lvn->Id()) { - ++pos; - DCHECK_LT(pos, mir->ssa_rep->num_uses); - } - int first_s_reg = uses[pos]; - bool wide = (first_lvn->sreg_wide_value_map_.count(first_s_reg) != 0u); + bool wide = raw_dest.wide; // Iterate over *merge_lvns_ and skip incoming sregs for BBs without associated LVN. merge_names_.clear(); uint16_t value_name = kNoValue; bool same_values = true; + BasicBlockId* incoming = mir->meta.phi_incoming; + int32_t* uses = mir->ssa_rep->uses; + int16_t pos = 0; for (const LocalValueNumbering* lvn : gvn_->merge_lvns_) { DCHECK_LT(pos, mir->ssa_rep->num_uses); while (incoming[pos] != lvn->Id()) { @@ -1994,6 +1986,9 @@ uint16_t LocalValueNumbering::GetEndingVregValueNumberImpl(int v_reg, bool wide) if (s_reg == INVALID_SREG) { return kNoValue; } + if (gvn_->GetMirGraph()->GetRegLocation(s_reg).wide != wide) { + return kNoValue; + } if (wide) { int high_s_reg = bb->data_flow_info->vreg_to_ssa_map_exit[v_reg + 1]; if (high_s_reg != s_reg + 1) { diff --git a/compiler/dex/local_value_numbering.h b/compiler/dex/local_value_numbering.h index 379c952..67fb647 100644 --- a/compiler/dex/local_value_numbering.h +++ b/compiler/dex/local_value_numbering.h @@ -53,10 +53,12 @@ class LocalValueNumbering : public DeletableArenaObject { } uint16_t GetSregValue(uint16_t s_reg) const { + DCHECK(!gvn_->GetMirGraph()->GetRegLocation(s_reg).wide); return GetSregValueImpl(s_reg, &sreg_value_map_); } uint16_t GetSregValueWide(uint16_t s_reg) const { + DCHECK(gvn_->GetMirGraph()->GetRegLocation(s_reg).wide); return GetSregValueImpl(s_reg, &sreg_wide_value_map_); } @@ -123,21 +125,27 @@ class LocalValueNumbering : public DeletableArenaObject { void SetOperandValue(uint16_t s_reg, uint16_t value) { DCHECK_EQ(sreg_wide_value_map_.count(s_reg), 0u); + DCHECK(!gvn_->GetMirGraph()->GetRegLocation(s_reg).wide); SetOperandValueImpl(s_reg, value, &sreg_value_map_); } uint16_t GetOperandValue(int s_reg) const { DCHECK_EQ(sreg_wide_value_map_.count(s_reg), 0u); + DCHECK(!gvn_->GetMirGraph()->GetRegLocation(s_reg).wide); return GetOperandValueImpl(s_reg, &sreg_value_map_); } void SetOperandValueWide(uint16_t s_reg, uint16_t value) { DCHECK_EQ(sreg_value_map_.count(s_reg), 0u); + DCHECK(gvn_->GetMirGraph()->GetRegLocation(s_reg).wide); + DCHECK(!gvn_->GetMirGraph()->GetRegLocation(s_reg).high_word); SetOperandValueImpl(s_reg, value, &sreg_wide_value_map_); } uint16_t GetOperandValueWide(int s_reg) const { DCHECK_EQ(sreg_value_map_.count(s_reg), 0u); + DCHECK(gvn_->GetMirGraph()->GetRegLocation(s_reg).wide); + DCHECK(!gvn_->GetMirGraph()->GetRegLocation(s_reg).high_word); return GetOperandValueImpl(s_reg, &sreg_wide_value_map_); } @@ -331,7 +339,7 @@ class LocalValueNumbering : public DeletableArenaObject { void CopyLiveSregValues(SregValueMap* dest, const SregValueMap& src); - // Intersect maps as sets. The value type must be equality-comparable. + // Intersect SSA reg value maps as sets, ignore dead regs. template void IntersectSregValueMaps(); diff --git a/compiler/dex/local_value_numbering_test.cc b/compiler/dex/local_value_numbering_test.cc index 0393410..bd00690 100644 --- a/compiler/dex/local_value_numbering_test.cc +++ b/compiler/dex/local_value_numbering_test.cc @@ -182,6 +182,15 @@ class LocalValueNumberingTest : public testing::Test { ~MirSFieldLoweringInfo::kFlagClassIsInitialized; } + template + void MarkAsWideSRegs(const int32_t (&sregs)[count]) { + for (int32_t sreg : sregs) { + cu_.mir_graph->reg_location_[sreg].wide = true; + cu_.mir_graph->reg_location_[sreg + 1].wide = true; + cu_.mir_graph->reg_location_[sreg + 1].high_word = true; + } + } + void PerformLVN() { cu_.mir_graph->temp_.gvn.ifield_ids = GlobalValueNumbering::PrepareGvnFieldIds( allocator_.get(), cu_.mir_graph->ifield_lowering_infos_); @@ -210,9 +219,11 @@ class LocalValueNumberingTest : public testing::Test { cu_.mir_graph.reset(new MIRGraph(&cu_, &cu_.arena)); allocator_.reset(ScopedArenaAllocator::Create(&cu_.arena_stack)); // By default, the zero-initialized reg_location_[.] with ref == false tells LVN that - // 0 constants are integral, not references. Nothing else is used by LVN/GVN. + // 0 constants are integral, not references, and the values are all narrow. + // Nothing else is used by LVN/GVN. Tests can override the default values as needed. cu_.mir_graph->reg_location_ = static_cast(cu_.arena.Alloc( kMaxSsaRegs * sizeof(cu_.mir_graph->reg_location_[0]), kArenaAllocRegAlloc)); + cu_.mir_graph->num_ssa_regs_ = kMaxSsaRegs; } static constexpr size_t kMaxSsaRegs = 16384u; @@ -379,26 +390,28 @@ TEST_F(LocalValueNumberingTest, UnresolvedIField) { { 3u, 0u, 0u, false, kDexMemAccessWord }, // Unresolved field. }; static const MIRDef mirs[] = { - DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 20u), - DEF_IGET(Instruction::IGET, 1u, 20u, 0u), // Resolved field #1, unique object. - DEF_IGET(Instruction::IGET, 2u, 21u, 0u), // Resolved field #1. - DEF_IGET_WIDE(Instruction::IGET_WIDE, 3u, 21u, 1u), // Resolved field #2. - DEF_IGET(Instruction::IGET, 4u, 22u, 2u), // Unresolved IGET can be "acquire". - DEF_IGET(Instruction::IGET, 5u, 20u, 0u), // Resolved field #1, unique object. - DEF_IGET(Instruction::IGET, 6u, 21u, 0u), // Resolved field #1. - DEF_IGET_WIDE(Instruction::IGET_WIDE, 7u, 21u, 1u), // Resolved field #2. - DEF_IPUT(Instruction::IPUT, 8u, 22u, 2u), // IPUT clobbers field #1 (#2 is wide). - DEF_IGET(Instruction::IGET, 9u, 20u, 0u), // Resolved field #1, unique object. - DEF_IGET(Instruction::IGET, 10u, 21u, 0u), // Resolved field #1, new value name. - DEF_IGET_WIDE(Instruction::IGET_WIDE, 11u, 21u, 1u), // Resolved field #2. - DEF_IGET_WIDE(Instruction::IGET_WIDE, 12u, 20u, 1u), // Resolved field #2, unique object. - DEF_IPUT(Instruction::IPUT, 13u, 20u, 2u), // IPUT clobbers field #1 (#2 is wide). - DEF_IGET(Instruction::IGET, 14u, 20u, 0u), // Resolved field #1, unique object. - DEF_IGET_WIDE(Instruction::IGET_WIDE, 15u, 20u, 1u), // Resolved field #2, unique object. + DEF_UNIQUE_REF(Instruction::NEW_INSTANCE, 30u), + DEF_IGET(Instruction::IGET, 1u, 30u, 0u), // Resolved field #1, unique object. + DEF_IGET(Instruction::IGET, 2u, 31u, 0u), // Resolved field #1. + DEF_IGET_WIDE(Instruction::IGET_WIDE, 3u, 31u, 1u), // Resolved field #2. + DEF_IGET(Instruction::IGET, 5u, 32u, 2u), // Unresolved IGET can be "acquire". + DEF_IGET(Instruction::IGET, 6u, 30u, 0u), // Resolved field #1, unique object. + DEF_IGET(Instruction::IGET, 7u, 31u, 0u), // Resolved field #1. + DEF_IGET_WIDE(Instruction::IGET_WIDE, 8u, 31u, 1u), // Resolved field #2. + DEF_IPUT(Instruction::IPUT, 10u, 32u, 2u), // IPUT clobbers field #1 (#2 is wide). + DEF_IGET(Instruction::IGET, 11u, 30u, 0u), // Resolved field #1, unique object. + DEF_IGET(Instruction::IGET, 12u, 31u, 0u), // Resolved field #1, new value name. + DEF_IGET_WIDE(Instruction::IGET_WIDE, 13u, 31u, 1u), // Resolved field #2. + DEF_IGET_WIDE(Instruction::IGET_WIDE, 15u, 30u, 1u), // Resolved field #2, unique object. + DEF_IPUT(Instruction::IPUT, 17u, 30u, 2u), // IPUT clobbers field #1 (#2 is wide). + DEF_IGET(Instruction::IGET, 18u, 30u, 0u), // Resolved field #1, unique object. + DEF_IGET_WIDE(Instruction::IGET_WIDE, 19u, 30u, 1u), // Resolved field #2, unique object. }; PrepareIFields(ifields); PrepareMIRs(mirs); + static const int32_t wide_sregs[] = { 3, 8, 13, 15, 19 }; + MarkAsWideSRegs(wide_sregs); PerformLVN(); ASSERT_EQ(value_names_.size(), 16u); // Unresolved field is potentially volatile, so we need to adhere to the volatile semantics. @@ -430,16 +443,18 @@ TEST_F(LocalValueNumberingTest, UnresolvedSField) { static const MIRDef mirs[] = { DEF_SGET(Instruction::SGET, 0u, 0u), // Resolved field #1. DEF_SGET_WIDE(Instruction::SGET_WIDE, 1u, 1u), // Resolved field #2. - DEF_SGET(Instruction::SGET, 2u, 2u), // Unresolved SGET can be "acquire". - DEF_SGET(Instruction::SGET, 3u, 0u), // Resolved field #1. - DEF_SGET_WIDE(Instruction::SGET_WIDE, 4u, 1u), // Resolved field #2. - DEF_SPUT(Instruction::SPUT, 5u, 2u), // SPUT clobbers field #1 (#2 is wide). - DEF_SGET(Instruction::SGET, 6u, 0u), // Resolved field #1. - DEF_SGET_WIDE(Instruction::SGET_WIDE, 7u, 1u), // Resolved field #2. + DEF_SGET(Instruction::SGET, 3u, 2u), // Unresolved SGET can be "acquire". + DEF_SGET(Instruction::SGET, 4u, 0u), // Resolved field #1. + DEF_SGET_WIDE(Instruction::SGET_WIDE, 5u, 1u), // Resolved field #2. + DEF_SPUT(Instruction::SPUT, 7u, 2u), // SPUT clobbers field #1 (#2 is wide). + DEF_SGET(Instruction::SGET, 8u, 0u), // Resolved field #1. + DEF_SGET_WIDE(Instruction::SGET_WIDE, 9u, 1u), // Resolved field #2. }; PrepareSFields(sfields); PrepareMIRs(mirs); + static const int32_t wide_sregs[] = { 1, 5, 9 }; + MarkAsWideSRegs(wide_sregs); PerformLVN(); ASSERT_EQ(value_names_.size(), 8u); // Unresolved field is potentially volatile, so we need to adhere to the volatile semantics. @@ -585,18 +600,20 @@ TEST_F(LocalValueNumberingTest, EscapingRefs) { DEF_IGET(Instruction::IGET, 7u, 20u, 0u), // New value. DEF_IGET(Instruction::IGET, 8u, 20u, 1u), // Still the same. DEF_IPUT_WIDE(Instruction::IPUT_WIDE, 9u, 31u, 3u), // No aliasing, different type. - DEF_IGET(Instruction::IGET, 10u, 20u, 0u), - DEF_IGET(Instruction::IGET, 11u, 20u, 1u), - DEF_IPUT_WIDE(Instruction::IPUT_WIDE, 12u, 31u, 5u), // No aliasing, different type. - DEF_IGET(Instruction::IGET, 13u, 20u, 0u), - DEF_IGET(Instruction::IGET, 14u, 20u, 1u), - DEF_IPUT(Instruction::IPUT, 15u, 31u, 4u), // Aliasing, same type. - DEF_IGET(Instruction::IGET, 16u, 20u, 0u), - DEF_IGET(Instruction::IGET, 17u, 20u, 1u), + DEF_IGET(Instruction::IGET, 11u, 20u, 0u), + DEF_IGET(Instruction::IGET, 12u, 20u, 1u), + DEF_IPUT_WIDE(Instruction::IPUT_WIDE, 13u, 31u, 5u), // No aliasing, different type. + DEF_IGET(Instruction::IGET, 15u, 20u, 0u), + DEF_IGET(Instruction::IGET, 16u, 20u, 1u), + DEF_IPUT(Instruction::IPUT, 17u, 31u, 4u), // Aliasing, same type. + DEF_IGET(Instruction::IGET, 18u, 20u, 0u), + DEF_IGET(Instruction::IGET, 19u, 20u, 1u), }; PrepareIFields(ifields); PrepareMIRs(mirs); + static const int32_t wide_sregs[] = { 9, 13 }; + MarkAsWideSRegs(wide_sregs); PerformLVN(); ASSERT_EQ(value_names_.size(), 18u); EXPECT_EQ(value_names_[1], value_names_[4]); @@ -626,14 +643,16 @@ TEST_F(LocalValueNumberingTest, EscapingArrayRefs) { DEF_AGET(Instruction::AGET, 4u, 20u, 40u), DEF_AGET(Instruction::AGET, 5u, 20u, 41u), DEF_APUT_WIDE(Instruction::APUT_WIDE, 6u, 31u, 43u), // No aliasing, different type. - DEF_AGET(Instruction::AGET, 7u, 20u, 40u), - DEF_AGET(Instruction::AGET, 8u, 20u, 41u), - DEF_APUT(Instruction::APUT, 9u, 32u, 40u), // May alias with all elements. - DEF_AGET(Instruction::AGET, 10u, 20u, 40u), // New value (same index name). - DEF_AGET(Instruction::AGET, 11u, 20u, 41u), // New value (different index name). + DEF_AGET(Instruction::AGET, 8u, 20u, 40u), + DEF_AGET(Instruction::AGET, 9u, 20u, 41u), + DEF_APUT(Instruction::APUT, 10u, 32u, 40u), // May alias with all elements. + DEF_AGET(Instruction::AGET, 11u, 20u, 40u), // New value (same index name). + DEF_AGET(Instruction::AGET, 12u, 20u, 41u), // New value (different index name). }; PrepareMIRs(mirs); + static const int32_t wide_sregs[] = { 6 }; + MarkAsWideSRegs(wide_sregs); PerformLVN(); ASSERT_EQ(value_names_.size(), 12u); EXPECT_EQ(value_names_[1], value_names_[4]); @@ -769,6 +788,8 @@ TEST_F(LocalValueNumberingTest, DivZeroCheck) { }; PrepareMIRs(mirs); + static const int32_t wide_sregs[] = { 5, 7, 12, 14, 16 }; + MarkAsWideSRegs(wide_sregs); PerformLVN(); for (size_t i = 0u; i != mir_count_; ++i) { int expected = expected_ignore_div_zero_check[i] ? MIR_IGNORE_DIV_ZERO_CHECK : 0u; @@ -780,51 +801,55 @@ TEST_F(LocalValueNumberingTest, ConstWide) { static const MIRDef mirs[] = { // Core reg constants. DEF_CONST(Instruction::CONST_WIDE_16, 0u, 0), - DEF_CONST(Instruction::CONST_WIDE_16, 1u, 1), - DEF_CONST(Instruction::CONST_WIDE_16, 2u, -1), - DEF_CONST(Instruction::CONST_WIDE_32, 3u, 1 << 16), - DEF_CONST(Instruction::CONST_WIDE_32, 4u, -1 << 16), - DEF_CONST(Instruction::CONST_WIDE_32, 5u, (1 << 16) + 1), - DEF_CONST(Instruction::CONST_WIDE_32, 6u, (1 << 16) - 1), - DEF_CONST(Instruction::CONST_WIDE_32, 7u, -(1 << 16) + 1), - DEF_CONST(Instruction::CONST_WIDE_32, 8u, -(1 << 16) - 1), - DEF_CONST(Instruction::CONST_WIDE, 9u, INT64_C(1) << 32), - DEF_CONST(Instruction::CONST_WIDE, 10u, INT64_C(-1) << 32), - DEF_CONST(Instruction::CONST_WIDE, 11u, (INT64_C(1) << 32) + 1), - DEF_CONST(Instruction::CONST_WIDE, 12u, (INT64_C(1) << 32) - 1), - DEF_CONST(Instruction::CONST_WIDE, 13u, (INT64_C(-1) << 32) + 1), - DEF_CONST(Instruction::CONST_WIDE, 14u, (INT64_C(-1) << 32) - 1), - DEF_CONST(Instruction::CONST_WIDE_HIGH16, 15u, 1), // Effectively 1 << 48. - DEF_CONST(Instruction::CONST_WIDE_HIGH16, 16u, 0xffff), // Effectively -1 << 48. - DEF_CONST(Instruction::CONST_WIDE, 17u, (INT64_C(1) << 48) + 1), - DEF_CONST(Instruction::CONST_WIDE, 18u, (INT64_C(1) << 48) - 1), - DEF_CONST(Instruction::CONST_WIDE, 19u, (INT64_C(-1) << 48) + 1), - DEF_CONST(Instruction::CONST_WIDE, 20u, (INT64_C(-1) << 48) - 1), + DEF_CONST(Instruction::CONST_WIDE_16, 2u, 1), + DEF_CONST(Instruction::CONST_WIDE_16, 4u, -1), + DEF_CONST(Instruction::CONST_WIDE_32, 6u, 1 << 16), + DEF_CONST(Instruction::CONST_WIDE_32, 8u, -1 << 16), + DEF_CONST(Instruction::CONST_WIDE_32, 10u, (1 << 16) + 1), + DEF_CONST(Instruction::CONST_WIDE_32, 12u, (1 << 16) - 1), + DEF_CONST(Instruction::CONST_WIDE_32, 14u, -(1 << 16) + 1), + DEF_CONST(Instruction::CONST_WIDE_32, 16u, -(1 << 16) - 1), + DEF_CONST(Instruction::CONST_WIDE, 18u, INT64_C(1) << 32), + DEF_CONST(Instruction::CONST_WIDE, 20u, INT64_C(-1) << 32), + DEF_CONST(Instruction::CONST_WIDE, 22u, (INT64_C(1) << 32) + 1), + DEF_CONST(Instruction::CONST_WIDE, 24u, (INT64_C(1) << 32) - 1), + DEF_CONST(Instruction::CONST_WIDE, 26u, (INT64_C(-1) << 32) + 1), + DEF_CONST(Instruction::CONST_WIDE, 28u, (INT64_C(-1) << 32) - 1), + DEF_CONST(Instruction::CONST_WIDE_HIGH16, 30u, 1), // Effectively 1 << 48. + DEF_CONST(Instruction::CONST_WIDE_HIGH16, 32u, 0xffff), // Effectively -1 << 48. + DEF_CONST(Instruction::CONST_WIDE, 34u, (INT64_C(1) << 48) + 1), + DEF_CONST(Instruction::CONST_WIDE, 36u, (INT64_C(1) << 48) - 1), + DEF_CONST(Instruction::CONST_WIDE, 38u, (INT64_C(-1) << 48) + 1), + DEF_CONST(Instruction::CONST_WIDE, 40u, (INT64_C(-1) << 48) - 1), // FP reg constants. - DEF_CONST(Instruction::CONST_WIDE_16, 21u, 0), - DEF_CONST(Instruction::CONST_WIDE_16, 22u, 1), - DEF_CONST(Instruction::CONST_WIDE_16, 23u, -1), - DEF_CONST(Instruction::CONST_WIDE_32, 24u, 1 << 16), - DEF_CONST(Instruction::CONST_WIDE_32, 25u, -1 << 16), - DEF_CONST(Instruction::CONST_WIDE_32, 26u, (1 << 16) + 1), - DEF_CONST(Instruction::CONST_WIDE_32, 27u, (1 << 16) - 1), - DEF_CONST(Instruction::CONST_WIDE_32, 28u, -(1 << 16) + 1), - DEF_CONST(Instruction::CONST_WIDE_32, 29u, -(1 << 16) - 1), - DEF_CONST(Instruction::CONST_WIDE, 30u, INT64_C(1) << 32), - DEF_CONST(Instruction::CONST_WIDE, 31u, INT64_C(-1) << 32), - DEF_CONST(Instruction::CONST_WIDE, 32u, (INT64_C(1) << 32) + 1), - DEF_CONST(Instruction::CONST_WIDE, 33u, (INT64_C(1) << 32) - 1), - DEF_CONST(Instruction::CONST_WIDE, 34u, (INT64_C(-1) << 32) + 1), - DEF_CONST(Instruction::CONST_WIDE, 35u, (INT64_C(-1) << 32) - 1), - DEF_CONST(Instruction::CONST_WIDE_HIGH16, 36u, 1), // Effectively 1 << 48. - DEF_CONST(Instruction::CONST_WIDE_HIGH16, 37u, 0xffff), // Effectively -1 << 48. - DEF_CONST(Instruction::CONST_WIDE, 38u, (INT64_C(1) << 48) + 1), - DEF_CONST(Instruction::CONST_WIDE, 39u, (INT64_C(1) << 48) - 1), - DEF_CONST(Instruction::CONST_WIDE, 40u, (INT64_C(-1) << 48) + 1), - DEF_CONST(Instruction::CONST_WIDE, 41u, (INT64_C(-1) << 48) - 1), + DEF_CONST(Instruction::CONST_WIDE_16, 42u, 0), + DEF_CONST(Instruction::CONST_WIDE_16, 44u, 1), + DEF_CONST(Instruction::CONST_WIDE_16, 46u, -1), + DEF_CONST(Instruction::CONST_WIDE_32, 48u, 1 << 16), + DEF_CONST(Instruction::CONST_WIDE_32, 50u, -1 << 16), + DEF_CONST(Instruction::CONST_WIDE_32, 52u, (1 << 16) + 1), + DEF_CONST(Instruction::CONST_WIDE_32, 54u, (1 << 16) - 1), + DEF_CONST(Instruction::CONST_WIDE_32, 56u, -(1 << 16) + 1), + DEF_CONST(Instruction::CONST_WIDE_32, 58u, -(1 << 16) - 1), + DEF_CONST(Instruction::CONST_WIDE, 60u, INT64_C(1) << 32), + DEF_CONST(Instruction::CONST_WIDE, 62u, INT64_C(-1) << 32), + DEF_CONST(Instruction::CONST_WIDE, 64u, (INT64_C(1) << 32) + 1), + DEF_CONST(Instruction::CONST_WIDE, 66u, (INT64_C(1) << 32) - 1), + DEF_CONST(Instruction::CONST_WIDE, 68u, (INT64_C(-1) << 32) + 1), + DEF_CONST(Instruction::CONST_WIDE, 70u, (INT64_C(-1) << 32) - 1), + DEF_CONST(Instruction::CONST_WIDE_HIGH16, 72u, 1), // Effectively 1 << 48. + DEF_CONST(Instruction::CONST_WIDE_HIGH16, 74u, 0xffff), // Effectively -1 << 48. + DEF_CONST(Instruction::CONST_WIDE, 76u, (INT64_C(1) << 48) + 1), + DEF_CONST(Instruction::CONST_WIDE, 78u, (INT64_C(1) << 48) - 1), + DEF_CONST(Instruction::CONST_WIDE, 80u, (INT64_C(-1) << 48) + 1), + DEF_CONST(Instruction::CONST_WIDE, 82u, (INT64_C(-1) << 48) - 1), }; PrepareMIRs(mirs); + for (size_t i = 0; i != arraysize(mirs); ++i) { + const int32_t wide_sregs[] = { mirs_[i].ssa_rep->defs[0] }; + MarkAsWideSRegs(wide_sregs); + } for (size_t i = arraysize(mirs) / 2u; i != arraysize(mirs); ++i) { cu_.mir_graph->reg_location_[mirs_[i].ssa_rep->defs[0]].fp = true; } diff --git a/compiler/dex/quick/quick_compiler.cc b/compiler/dex/quick/quick_compiler.cc index 39eb117..73cfe92 100644 --- a/compiler/dex/quick/quick_compiler.cc +++ b/compiler/dex/quick/quick_compiler.cc @@ -575,7 +575,7 @@ static uint32_t kCompilerOptimizerDisableFlags = 0 | // Disable specific optimi // (1 << kNullCheckElimination) | // (1 << kClassInitCheckElimination) | // (1 << kGlobalValueNumbering) | - (1 << kGvnDeadCodeElimination) | + // (1 << kGvnDeadCodeElimination) | // (1 << kLocalValueNumbering) | // (1 << kPromoteRegs) | // (1 << kTrackLiveTemps) | -- cgit v1.1