From: martyn.capewell Date: Tue, 7 Apr 2015 11:34:33 +0000 (-0700) Subject: ARM64: Support sign extend for add and subtract X-Git-Tag: upstream/4.7.83~3416 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=8e846a61660ae849a0e6cc8a43376a97f412927b;p=platform%2Fupstream%2Fv8.git ARM64: Support sign extend for add and subtract Support sxtb and sxth extend operators on add and subtract, as we've done for ubtx/h. This is similar to ARM support for sxtab/h. BUG= Review URL: https://codereview.chromium.org/1064813003 Cr-Commit-Position: refs/heads/master@{#27624} --- diff --git a/src/compiler/arm64/code-generator-arm64.cc b/src/compiler/arm64/code-generator-arm64.cc index f3dcdbd4c..2c0e8f5cd 100644 --- a/src/compiler/arm64/code-generator-arm64.cc +++ b/src/compiler/arm64/code-generator-arm64.cc @@ -75,6 +75,10 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter { return Operand(InputRegister32(index), UXTB); case kMode_Operand2_R_UXTH: return Operand(InputRegister32(index), UXTH); + case kMode_Operand2_R_SXTB: + return Operand(InputRegister32(index), SXTB); + case kMode_Operand2_R_SXTH: + return Operand(InputRegister32(index), SXTH); case kMode_MRI: case kMode_MRR: break; @@ -99,6 +103,10 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter { return Operand(InputRegister64(index), UXTB); case kMode_Operand2_R_UXTH: return Operand(InputRegister64(index), UXTH); + case kMode_Operand2_R_SXTB: + return Operand(InputRegister64(index), SXTB); + case kMode_Operand2_R_SXTH: + return Operand(InputRegister64(index), SXTH); case kMode_MRI: case kMode_MRR: break; @@ -117,6 +125,8 @@ class Arm64OperandConverter FINAL : public InstructionOperandConverter { case kMode_Operand2_R_ROR_I: case kMode_Operand2_R_UXTB: case kMode_Operand2_R_UXTH: + case kMode_Operand2_R_SXTB: + case kMode_Operand2_R_SXTH: break; case kMode_MRI: *first_index += 2; diff --git a/src/compiler/arm64/instruction-codes-arm64.h b/src/compiler/arm64/instruction-codes-arm64.h index be0981f65..2d473ad1f 100644 --- a/src/compiler/arm64/instruction-codes-arm64.h +++ b/src/compiler/arm64/instruction-codes-arm64.h @@ -141,15 +141,17 @@ namespace compiler { // I = immediate (handle, external, int32) // MRI = [register + immediate] // MRR = [register + register] -#define TARGET_ADDRESSING_MODE_LIST(V) \ - V(MRI) /* [%r0 + K] */ \ - V(MRR) /* [%r0 + %r1] */ \ - V(Operand2_R_LSL_I) /* %r0 LSL K */ \ - V(Operand2_R_LSR_I) /* %r0 LSR K */ \ - V(Operand2_R_ASR_I) /* %r0 ASR K */ \ - V(Operand2_R_ROR_I) /* %r0 ROR K */ \ - V(Operand2_R_UXTB) /* %r0 UXTB (unsigned extend byte) */ \ - V(Operand2_R_UXTH) /* %r0 UXTH (unsigned extend halfword) */ +#define TARGET_ADDRESSING_MODE_LIST(V) \ + V(MRI) /* [%r0 + K] */ \ + V(MRR) /* [%r0 + %r1] */ \ + V(Operand2_R_LSL_I) /* %r0 LSL K */ \ + V(Operand2_R_LSR_I) /* %r0 LSR K */ \ + V(Operand2_R_ASR_I) /* %r0 ASR K */ \ + V(Operand2_R_ROR_I) /* %r0 ROR K */ \ + V(Operand2_R_UXTB) /* %r0 UXTB (unsigned extend byte) */ \ + V(Operand2_R_UXTH) /* %r0 UXTH (unsigned extend halfword) */ \ + V(Operand2_R_SXTB) /* %r0 SXTB (signed extend byte) */ \ + V(Operand2_R_SXTH) /* %r0 SXTH (signed extend halfword) */ } // namespace internal } // namespace compiler diff --git a/src/compiler/arm64/instruction-selector-arm64.cc b/src/compiler/arm64/instruction-selector-arm64.cc index baebb1700..053ae8f53 100644 --- a/src/compiler/arm64/instruction-selector-arm64.cc +++ b/src/compiler/arm64/instruction-selector-arm64.cc @@ -157,17 +157,34 @@ bool TryMatchAnyShift(InstructionSelector* selector, Node* node, } -bool TryMatchAnyExtend(InstructionSelector* selector, Node* node, - InstructionCode* opcode) { - NodeMatcher nm(node); +bool TryMatchAnyExtend(Arm64OperandGenerator* g, InstructionSelector* selector, + Node* left_node, Node* right_node, + InstructionOperand* left_op, + InstructionOperand* right_op, InstructionCode* opcode) { + NodeMatcher nm(right_node); + if (nm.IsWord32And()) { - Int32BinopMatcher m(node); - if (m.right().HasValue()) { - if (m.right().Value() == 0xff) { - *opcode |= AddressingModeField::encode(kMode_Operand2_R_UXTB); - return true; - } else if (m.right().Value() == 0xffff) { - *opcode |= AddressingModeField::encode(kMode_Operand2_R_UXTH); + Int32BinopMatcher mright(right_node); + if (mright.right().Is(0xff) || mright.right().Is(0xffff)) { + int32_t mask = mright.right().Value(); + *left_op = g->UseRegister(left_node); + *right_op = g->UseRegister(mright.left().node()); + *opcode |= AddressingModeField::encode( + (mask == 0xff) ? kMode_Operand2_R_UXTB : kMode_Operand2_R_UXTH); + return true; + } + } else if (nm.IsWord32Sar()) { + Int32BinopMatcher mright(right_node); + if (selector->CanCover(mright.node(), mright.left().node()) && + mright.left().IsWord32Shl()) { + Int32BinopMatcher mleft_of_right(mright.left().node()); + if ((mright.right().Is(16) && mleft_of_right.right().Is(16)) || + (mright.right().Is(24) && mleft_of_right.right().Is(24))) { + int32_t shift = mright.right().Value(); + *left_op = g->UseRegister(left_node); + *right_op = g->UseRegister(mleft_of_right.left().node()); + *opcode |= AddressingModeField::encode( + (shift == 24) ? kMode_Operand2_R_SXTB : kMode_Operand2_R_SXTH); return true; } } @@ -193,35 +210,34 @@ void VisitBinop(InstructionSelector* selector, Node* node, is_add_sub = true; } - if (g.CanBeImmediate(m.right().node(), operand_mode)) { - inputs[input_count++] = g.UseRegister(m.left().node()); - inputs[input_count++] = g.UseImmediate(m.right().node()); - } else if (TryMatchAnyShift(selector, m.right().node(), &opcode, - !is_add_sub)) { - Matcher m_shift(m.right().node()); - inputs[input_count++] = g.UseRegister(m.left().node()); + Node* left_node = m.left().node(); + Node* right_node = m.right().node(); + + if (g.CanBeImmediate(right_node, operand_mode)) { + inputs[input_count++] = g.UseRegister(left_node); + inputs[input_count++] = g.UseImmediate(right_node); + } else if (is_add_sub && + TryMatchAnyExtend(&g, selector, left_node, right_node, &inputs[0], + &inputs[1], &opcode)) { + input_count += 2; + } else if (is_add_sub && m.HasProperty(Operator::kCommutative) && + TryMatchAnyExtend(&g, selector, right_node, left_node, &inputs[0], + &inputs[1], &opcode)) { + input_count += 2; + } else if (TryMatchAnyShift(selector, right_node, &opcode, !is_add_sub)) { + Matcher m_shift(right_node); + inputs[input_count++] = g.UseRegister(left_node); inputs[input_count++] = g.UseRegister(m_shift.left().node()); inputs[input_count++] = g.UseImmediate(m_shift.right().node()); } else if (m.HasProperty(Operator::kCommutative) && - TryMatchAnyShift(selector, m.left().node(), &opcode, - !is_add_sub)) { - Matcher m_shift(m.left().node()); - inputs[input_count++] = g.UseRegister(m.right().node()); + TryMatchAnyShift(selector, left_node, &opcode, !is_add_sub)) { + Matcher m_shift(left_node); + inputs[input_count++] = g.UseRegister(right_node); inputs[input_count++] = g.UseRegister(m_shift.left().node()); inputs[input_count++] = g.UseImmediate(m_shift.right().node()); - } else if (is_add_sub && - TryMatchAnyExtend(selector, m.right().node(), &opcode)) { - Matcher mright(m.right().node()); - inputs[input_count++] = g.UseRegister(m.left().node()); - inputs[input_count++] = g.UseRegister(mright.left().node()); - } else if (is_add_sub && m.HasProperty(Operator::kCommutative) && - TryMatchAnyExtend(selector, m.left().node(), &opcode)) { - Matcher mleft(m.left().node()); - inputs[input_count++] = g.UseRegister(m.right().node()); - inputs[input_count++] = g.UseRegister(mleft.left().node()); } else { - inputs[input_count++] = g.UseRegister(m.left().node()); - inputs[input_count++] = g.UseRegister(m.right().node()); + inputs[input_count++] = g.UseRegister(left_node); + inputs[input_count++] = g.UseRegister(right_node); } if (cont->IsBranch()) { diff --git a/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc index fd4766477..85b08e99a 100644 --- a/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc +++ b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc @@ -472,7 +472,7 @@ TEST_P(InstructionSelectorAddSubTest, ShiftByImmediateOnRight) { } -TEST_P(InstructionSelectorAddSubTest, ExtendByte) { +TEST_P(InstructionSelectorAddSubTest, UnsignedExtendByte) { const AddSub dpi = GetParam(); const MachineType type = dpi.mi.machine_type; StreamBuilder m(this, type, type, type); @@ -487,7 +487,7 @@ TEST_P(InstructionSelectorAddSubTest, ExtendByte) { } -TEST_P(InstructionSelectorAddSubTest, ExtendHalfword) { +TEST_P(InstructionSelectorAddSubTest, UnsignedExtendHalfword) { const AddSub dpi = GetParam(); const MachineType type = dpi.mi.machine_type; StreamBuilder m(this, type, type, type); @@ -502,6 +502,40 @@ TEST_P(InstructionSelectorAddSubTest, ExtendHalfword) { } +TEST_P(InstructionSelectorAddSubTest, SignedExtendByte) { + const AddSub dpi = GetParam(); + const MachineType type = dpi.mi.machine_type; + StreamBuilder m(this, type, type, type); + m.Return((m.*dpi.mi.constructor)( + m.Parameter(0), + m.Word32Sar(m.Word32Shl(m.Parameter(1), m.Int32Constant(24)), + m.Int32Constant(24)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); +} + + +TEST_P(InstructionSelectorAddSubTest, SignedExtendHalfword) { + const AddSub dpi = GetParam(); + const MachineType type = dpi.mi.machine_type; + StreamBuilder m(this, type, type, type); + m.Return((m.*dpi.mi.constructor)( + m.Parameter(0), + m.Word32Sar(m.Word32Shl(m.Parameter(1), m.Int32Constant(16)), + m.Int32Constant(16)))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); +} + + INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest, ::testing::ValuesIn(kAddSubInstructions)); @@ -646,7 +680,7 @@ TEST_F(InstructionSelectorTest, AddShiftByImmediateOnLeft) { } -TEST_F(InstructionSelectorTest, AddExtendByteOnLeft) { +TEST_F(InstructionSelectorTest, AddUnsignedExtendByteOnLeft) { { StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xff)), @@ -672,7 +706,7 @@ TEST_F(InstructionSelectorTest, AddExtendByteOnLeft) { } -TEST_F(InstructionSelectorTest, AddExtendHalfwordOnLeft) { +TEST_F(InstructionSelectorTest, AddUnsignedExtendHalfwordOnLeft) { { StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); m.Return(m.Int32Add(m.Word32And(m.Parameter(0), m.Int32Constant(0xffff)), @@ -698,6 +732,66 @@ TEST_F(InstructionSelectorTest, AddExtendHalfwordOnLeft) { } +TEST_F(InstructionSelectorTest, AddSignedExtendByteOnLeft) { + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + m.Return( + m.Int32Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)), + m.Int32Constant(24)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, kMachInt64, kMachInt32, kMachInt64); + m.Return( + m.Int64Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(24)), + m.Int32Constant(24)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_SXTB, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + } +} + + +TEST_F(InstructionSelectorTest, AddSignedExtendHalfwordOnLeft) { + { + StreamBuilder m(this, kMachInt32, kMachInt32, kMachInt32); + m.Return( + m.Int32Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(16)), + m.Int32Constant(16)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + } + { + StreamBuilder m(this, kMachInt64, kMachInt32, kMachInt64); + m.Return( + m.Int64Add(m.Word32Sar(m.Word32Shl(m.Parameter(0), m.Int32Constant(16)), + m.Int32Constant(16)), + m.Parameter(1))); + Stream s = m.Build(); + ASSERT_EQ(1U, s.size()); + EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); + EXPECT_EQ(kMode_Operand2_R_SXTH, s[0]->addressing_mode()); + ASSERT_EQ(2U, s[0]->InputCount()); + ASSERT_EQ(1U, s[0]->OutputCount()); + } +} + + // ----------------------------------------------------------------------------- // Data processing controlled branches.