[turbofan] ARM64 branch selector additions

Add support for selecting Cmp and Cmn instructions, and tests for branching on
the result of arithmetic or logical operations.

BUG=
R=bmeurer@chromium.org

Review URL: https://codereview.chromium.org/556823002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23808 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 48a91826
...@@ -339,6 +339,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) { ...@@ -339,6 +339,12 @@ void CodeGenerator::AssembleArchInstruction(Instruction* instr) {
case kArm64Cmp32: case kArm64Cmp32:
__ Cmp(i.InputRegister32(0), i.InputOperand32(1)); __ Cmp(i.InputRegister32(0), i.InputOperand32(1));
break; break;
case kArm64Cmn:
__ Cmn(i.InputRegister(0), i.InputOperand(1));
break;
case kArm64Cmn32:
__ Cmn(i.InputRegister32(0), i.InputOperand32(1));
break;
case kArm64Tst: case kArm64Tst:
__ Tst(i.InputRegister(0), i.InputOperand(1)); __ Tst(i.InputRegister(0), i.InputOperand(1));
break; break;
......
...@@ -18,6 +18,8 @@ namespace compiler { ...@@ -18,6 +18,8 @@ namespace compiler {
V(Arm64And32) \ V(Arm64And32) \
V(Arm64Cmp) \ V(Arm64Cmp) \
V(Arm64Cmp32) \ V(Arm64Cmp32) \
V(Arm64Cmn) \
V(Arm64Cmn32) \
V(Arm64Tst) \ V(Arm64Tst) \
V(Arm64Tst32) \ V(Arm64Tst32) \
V(Arm64Or) \ V(Arm64Or) \
......
...@@ -12,6 +12,8 @@ namespace compiler { ...@@ -12,6 +12,8 @@ namespace compiler {
namespace { namespace {
typedef RawMachineAssembler::Label MLabel;
template <typename T> template <typename T>
struct MachInst { struct MachInst {
T constructor; T constructor;
...@@ -88,6 +90,13 @@ static const int32_t kAddSubImmediates[] = { ...@@ -88,6 +90,13 @@ static const int32_t kAddSubImmediates[] = {
15597568, 15892480, 16773120}; 15597568, 15892480, 16773120};
// ARM64 flag setting data processing instructions.
static const MachInst2 kDPFlagSetInstructions[] = {
{&RawMachineAssembler::Word32And, "Word32And", kArm64Tst32, kMachInt32},
{&RawMachineAssembler::Int32Add, "Int32Add", kArm64Cmn32, kMachInt32},
{&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Cmp32, kMachInt32}};
// ARM64 arithmetic with overflow instructions. // ARM64 arithmetic with overflow instructions.
static const MachInst2 kOvfAddSubInstructions[] = { static const MachInst2 kOvfAddSubInstructions[] = {
{&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow", {&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
...@@ -343,6 +352,129 @@ TEST_F(InstructionSelectorTest, SubZeroOnLeft) { ...@@ -343,6 +352,129 @@ TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
} }
// -----------------------------------------------------------------------------
// Data processing controlled branches.
typedef InstructionSelectorTestWithParam<MachInst2>
InstructionSelectorDPFlagSetTest;
TEST_P(InstructionSelectorDPFlagSetTest, BranchWithParameters) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
StreamBuilder m(this, type, type, type);
MLabel a, b;
m.Branch((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1)), &a, &b);
m.Bind(&a);
m.Return(m.Int32Constant(1));
m.Bind(&b);
m.Return(m.Int32Constant(0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
EXPECT_EQ(kNotEqual, s[0]->flags_condition());
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorDPFlagSetTest,
::testing::ValuesIn(kDPFlagSetInstructions));
TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnRight) {
TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
StreamBuilder m(this, kMachInt32, kMachInt32);
MLabel a, b;
m.Branch(m.Word32And(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
m.Bind(&a);
m.Return(m.Int32Constant(1));
m.Bind(&b);
m.Return(m.Int32Constant(0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
EXPECT_EQ(kNotEqual, s[0]->flags_condition());
}
}
TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnRight) {
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
StreamBuilder m(this, kMachInt32, kMachInt32);
MLabel a, b;
m.Branch(m.Int32Add(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
m.Bind(&a);
m.Return(m.Int32Constant(1));
m.Bind(&b);
m.Return(m.Int32Constant(0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
EXPECT_EQ(kNotEqual, s[0]->flags_condition());
}
}
TEST_F(InstructionSelectorTest, SubBranchWithImmediateOnRight) {
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
StreamBuilder m(this, kMachInt32, kMachInt32);
MLabel a, b;
m.Branch(m.Int32Sub(m.Parameter(0), m.Int32Constant(imm)), &a, &b);
m.Bind(&a);
m.Return(m.Int32Constant(1));
m.Bind(&b);
m.Return(m.Int32Constant(0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Cmp32, s[0]->arch_opcode());
EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
EXPECT_EQ(kNotEqual, s[0]->flags_condition());
}
}
TEST_F(InstructionSelectorTest, AndBranchWithImmediateOnLeft) {
TRACED_FOREACH(int32_t, imm, kLogicalImmediates) {
StreamBuilder m(this, kMachInt32, kMachInt32);
MLabel a, b;
m.Branch(m.Word32And(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
m.Bind(&a);
m.Return(m.Int32Constant(1));
m.Bind(&b);
m.Return(m.Int32Constant(0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Tst32, s[0]->arch_opcode());
ASSERT_LE(1U, s[0]->InputCount());
EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
EXPECT_EQ(kNotEqual, s[0]->flags_condition());
}
}
TEST_F(InstructionSelectorTest, AddBranchWithImmediateOnLeft) {
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
StreamBuilder m(this, kMachInt32, kMachInt32);
MLabel a, b;
m.Branch(m.Int32Add(m.Int32Constant(imm), m.Parameter(0)), &a, &b);
m.Bind(&a);
m.Return(m.Int32Constant(1));
m.Bind(&b);
m.Return(m.Int32Constant(0));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Cmn32, s[0]->arch_opcode());
ASSERT_LE(1U, s[0]->InputCount());
EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
EXPECT_EQ(kNotEqual, s[0]->flags_condition());
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Add and subtract instructions with overflow. // Add and subtract instructions with overflow.
...@@ -454,6 +586,50 @@ TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) { ...@@ -454,6 +586,50 @@ TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) {
} }
TEST_P(InstructionSelectorOvfAddSubTest, BranchWithParameters) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
StreamBuilder m(this, type, type, type);
MLabel a, b;
Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
m.Branch(m.Projection(1, n), &a, &b);
m.Bind(&a);
m.Return(m.Int32Constant(0));
m.Bind(&b);
m.Return(m.Projection(0, n));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(4U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
EXPECT_EQ(kOverflow, s[0]->flags_condition());
}
TEST_P(InstructionSelectorOvfAddSubTest, BranchWithImmediateOnRight) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
StreamBuilder m(this, type, type);
MLabel a, b;
Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
m.Branch(m.Projection(1, n), &a, &b);
m.Bind(&a);
m.Return(m.Int32Constant(0));
m.Bind(&b);
m.Return(m.Projection(0, n));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
ASSERT_EQ(4U, s[0]->InputCount());
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
EXPECT_EQ(kOverflow, s[0]->flags_condition());
}
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorOvfAddSubTest, InstructionSelectorOvfAddSubTest,
::testing::ValuesIn(kOvfAddSubInstructions)); ::testing::ValuesIn(kOvfAddSubInstructions));
...@@ -512,6 +688,29 @@ TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) { ...@@ -512,6 +688,29 @@ TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) {
} }
TEST_F(InstructionSelectorTest, OvfBranchWithImmediateOnLeft) {
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
StreamBuilder m(this, kMachInt32, kMachInt32);
MLabel a, b;
Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
m.Branch(m.Projection(1, n), &a, &b);
m.Bind(&a);
m.Return(m.Int32Constant(0));
m.Bind(&b);
m.Return(m.Projection(0, n));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
ASSERT_EQ(4U, s[0]->InputCount());
EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
EXPECT_EQ(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_branch, s[0]->flags_mode());
EXPECT_EQ(kOverflow, s[0]->flags_condition());
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Shift instructions. // Shift instructions.
......
...@@ -525,6 +525,10 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node, ...@@ -525,6 +525,10 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node,
void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) { void InstructionSelector::VisitWord32Test(Node* node, FlagsContinuation* cont) {
switch (node->opcode()) { switch (node->opcode()) {
case IrOpcode::kInt32Add:
return VisitWordCompare(this, node, kArm64Cmn32, cont, true);
case IrOpcode::kInt32Sub:
return VisitWordCompare(this, node, kArm64Cmp32, cont, false);
case IrOpcode::kWord32And: case IrOpcode::kWord32And:
return VisitWordCompare(this, node, kArm64Tst32, cont, true); return VisitWordCompare(this, node, kArm64Tst32, cont, true);
default: default:
......
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