Commit 8e846a61 authored by martyn.capewell's avatar martyn.capewell Committed by Commit bot

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}
parent 59be4ba7
......@@ -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;
......
......@@ -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
......
......@@ -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()) {
......
......@@ -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.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment