[turbofan] Add ARM64 overflow selector tests

Add more selector tests and correct a typo in the instruction selector code.

BUG=
R=bmeurer@chromium.org

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

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@23775 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent b9614b95
...@@ -88,6 +88,14 @@ static const int32_t kAddSubImmediates[] = { ...@@ -88,6 +88,14 @@ static const int32_t kAddSubImmediates[] = {
15597568, 15892480, 16773120}; 15597568, 15892480, 16773120};
// ARM64 arithmetic with overflow instructions.
static const MachInst2 kOvfAddSubInstructions[] = {
{&RawMachineAssembler::Int32AddWithOverflow, "Int32AddWithOverflow",
kArm64Add32, kMachInt32},
{&RawMachineAssembler::Int32SubWithOverflow, "Int32SubWithOverflow",
kArm64Sub32, kMachInt32}};
// ARM64 shift instructions. // ARM64 shift instructions.
static const MachInst2 kShiftInstructions[] = { static const MachInst2 kShiftInstructions[] = {
{&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Shl32, kMachInt32}, {&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Shl32, kMachInt32},
...@@ -335,6 +343,175 @@ TEST_F(InstructionSelectorTest, SubZeroOnLeft) { ...@@ -335,6 +343,175 @@ TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
} }
// -----------------------------------------------------------------------------
// Add and subtract instructions with overflow.
typedef InstructionSelectorTestWithParam<MachInst2>
InstructionSelectorOvfAddSubTest;
TEST_P(InstructionSelectorOvfAddSubTest, OvfParameter) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
StreamBuilder m(this, type, type, type);
m.Return(
m.Projection(1, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_LE(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kOverflow, s[0]->flags_condition());
}
TEST_P(InstructionSelectorOvfAddSubTest, OvfImmediateOnRight) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
StreamBuilder m(this, type, type);
m.Return(m.Projection(
1, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
EXPECT_LE(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kOverflow, s[0]->flags_condition());
}
}
TEST_P(InstructionSelectorOvfAddSubTest, ValParameter) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
StreamBuilder m(this, type, type, type);
m.Return(
m.Projection(0, (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_LE(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_none, s[0]->flags_mode());
}
TEST_P(InstructionSelectorOvfAddSubTest, ValImmediateOnRight) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
StreamBuilder m(this, type, type);
m.Return(m.Projection(
0, (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm))));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
EXPECT_LE(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_none, s[0]->flags_mode());
}
}
TEST_P(InstructionSelectorOvfAddSubTest, BothParameter) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
StreamBuilder m(this, type, type, type);
Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Parameter(1));
m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
Stream s = m.Build();
ASSERT_LE(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(2U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kOverflow, s[0]->flags_condition());
}
TEST_P(InstructionSelectorOvfAddSubTest, BothImmediateOnRight) {
const MachInst2 dpi = GetParam();
const MachineType type = dpi.machine_type;
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
StreamBuilder m(this, type, type);
Node* n = (m.*dpi.constructor)(m.Parameter(0), m.Int32Constant(imm));
m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
Stream s = m.Build();
ASSERT_LE(1U, s.size());
EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
EXPECT_EQ(2U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kOverflow, s[0]->flags_condition());
}
}
INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorOvfAddSubTest,
::testing::ValuesIn(kOvfAddSubInstructions));
TEST_F(InstructionSelectorTest, OvfFlagAddImmediateOnLeft) {
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
StreamBuilder m(this, kMachInt32, kMachInt32);
m.Return(m.Projection(
1, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
EXPECT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
EXPECT_LE(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kOverflow, s[0]->flags_condition());
}
}
TEST_F(InstructionSelectorTest, OvfValAddImmediateOnLeft) {
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
StreamBuilder m(this, kMachInt32, kMachInt32);
m.Return(m.Projection(
0, m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0))));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
EXPECT_LE(1U, s[0]->OutputCount());
EXPECT_EQ(kFlags_none, s[0]->flags_mode());
}
}
TEST_F(InstructionSelectorTest, OvfBothAddImmediateOnLeft) {
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) {
StreamBuilder m(this, kMachInt32, kMachInt32);
Node* n = m.Int32AddWithOverflow(m.Int32Constant(imm), m.Parameter(0));
m.Return(m.Word32Equal(m.Projection(0, n), m.Projection(1, n)));
Stream s = m.Build();
ASSERT_LE(1U, s.size());
EXPECT_EQ(kArm64Add32, s[0]->arch_opcode());
ASSERT_EQ(2U, s[0]->InputCount());
EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1)));
EXPECT_EQ(2U, s[0]->OutputCount());
EXPECT_EQ(kFlags_set, s[0]->flags_mode());
EXPECT_EQ(kOverflow, s[0]->flags_condition());
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Shift instructions. // Shift instructions.
......
...@@ -10,9 +10,9 @@ namespace internal { ...@@ -10,9 +10,9 @@ namespace internal {
namespace compiler { namespace compiler {
enum ImmediateMode { enum ImmediateMode {
kArithimeticImm, // 12 bit unsigned immediate shifted left 0 or 12 bits kArithmeticImm, // 12 bit unsigned immediate shifted left 0 or 12 bits
kShift32Imm, // 0 - 31 kShift32Imm, // 0 - 31
kShift64Imm, // 0 -63 kShift64Imm, // 0 - 63
kLogical32Imm, kLogical32Imm,
kLogical64Imm, kLogical64Imm,
kLoadStoreImm, // unsigned 9 bit or signed 7 bit kLoadStoreImm, // unsigned 9 bit or signed 7 bit
...@@ -47,7 +47,7 @@ class Arm64OperandGenerator FINAL : public OperandGenerator { ...@@ -47,7 +47,7 @@ class Arm64OperandGenerator FINAL : public OperandGenerator {
case kLogical64Imm: case kLogical64Imm:
return Assembler::IsImmLogical(static_cast<uint64_t>(value), 64, return Assembler::IsImmLogical(static_cast<uint64_t>(value), 64,
&ignored, &ignored, &ignored); &ignored, &ignored, &ignored);
case kArithimeticImm: case kArithmeticImm:
// TODO(dcarney): -values can be handled by instruction swapping // TODO(dcarney): -values can be handled by instruction swapping
return Assembler::IsImmAddSub(value); return Assembler::IsImmAddSub(value);
case kShift32Imm: case kShift32Imm:
...@@ -316,12 +316,12 @@ void InstructionSelector::VisitWord64Ror(Node* node) { ...@@ -316,12 +316,12 @@ void InstructionSelector::VisitWord64Ror(Node* node) {
void InstructionSelector::VisitInt32Add(Node* node) { void InstructionSelector::VisitInt32Add(Node* node) {
VisitBinop(this, node, kArm64Add32, kArithimeticImm); VisitBinop(this, node, kArm64Add32, kArithmeticImm);
} }
void InstructionSelector::VisitInt64Add(Node* node) { void InstructionSelector::VisitInt64Add(Node* node) {
VisitBinop(this, node, kArm64Add, kArithimeticImm); VisitBinop(this, node, kArm64Add, kArithmeticImm);
} }
...@@ -332,7 +332,7 @@ void InstructionSelector::VisitInt32Sub(Node* node) { ...@@ -332,7 +332,7 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
Emit(kArm64Neg32, g.DefineAsRegister(node), Emit(kArm64Neg32, g.DefineAsRegister(node),
g.UseRegister(m.right().node())); g.UseRegister(m.right().node()));
} else { } else {
VisitBinop(this, node, kArm64Sub32, kArithimeticImm); VisitBinop(this, node, kArm64Sub32, kArithmeticImm);
} }
} }
...@@ -343,7 +343,7 @@ void InstructionSelector::VisitInt64Sub(Node* node) { ...@@ -343,7 +343,7 @@ void InstructionSelector::VisitInt64Sub(Node* node) {
if (m.left().Is(0)) { if (m.left().Is(0)) {
Emit(kArm64Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node())); Emit(kArm64Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node()));
} else { } else {
VisitBinop(this, node, kArm64Sub, kArithimeticImm); VisitBinop(this, node, kArm64Sub, kArithmeticImm);
} }
} }
...@@ -474,13 +474,13 @@ void InstructionSelector::VisitFloat64Mod(Node* node) { ...@@ -474,13 +474,13 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
void InstructionSelector::VisitInt32AddWithOverflow(Node* node, void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
FlagsContinuation* cont) { FlagsContinuation* cont) {
VisitBinop(this, node, kArm64Add32, kArithimeticImm, cont); VisitBinop(this, node, kArm64Add32, kArithmeticImm, cont);
} }
void InstructionSelector::VisitInt32SubWithOverflow(Node* node, void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
FlagsContinuation* cont) { FlagsContinuation* cont) {
VisitBinop(this, node, kArm64Sub32, kArithimeticImm, cont); VisitBinop(this, node, kArm64Sub32, kArithmeticImm, cont);
} }
...@@ -509,10 +509,10 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node, ...@@ -509,10 +509,10 @@ static void VisitWordCompare(InstructionSelector* selector, Node* node,
Node* right = node->InputAt(1); Node* right = node->InputAt(1);
// Match immediates on left or right side of comparison. // Match immediates on left or right side of comparison.
if (g.CanBeImmediate(right, kArithimeticImm)) { if (g.CanBeImmediate(right, kArithmeticImm)) {
VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right), VisitCompare(selector, opcode, g.UseRegister(left), g.UseImmediate(right),
cont); cont);
} else if (g.CanBeImmediate(left, kArithimeticImm)) { } else if (g.CanBeImmediate(left, kArithmeticImm)) {
if (!commutative) cont->Commute(); if (!commutative) cont->Commute();
VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left), VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
cont); cont);
......
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