[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
This commit is contained in:
m.m.capewell@googlemail.com 2014-09-08 14:08:16 +00:00
parent b9614b9599
commit 79c8293b99
2 changed files with 189 additions and 12 deletions

View File

@ -88,6 +88,14 @@ static const int32_t kAddSubImmediates[] = {
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.
static const MachInst2 kShiftInstructions[] = {
{&RawMachineAssembler::Word32Shl, "Word32Shl", kArm64Shl32, kMachInt32},
@ -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.

View File

@ -10,9 +10,9 @@ namespace internal {
namespace compiler {
enum ImmediateMode {
kArithimeticImm, // 12 bit unsigned immediate shifted left 0 or 12 bits
kShift32Imm, // 0 - 31
kShift64Imm, // 0 -63
kArithmeticImm, // 12 bit unsigned immediate shifted left 0 or 12 bits
kShift32Imm, // 0 - 31
kShift64Imm, // 0 - 63
kLogical32Imm,
kLogical64Imm,
kLoadStoreImm, // unsigned 9 bit or signed 7 bit
@ -47,7 +47,7 @@ class Arm64OperandGenerator FINAL : public OperandGenerator {
case kLogical64Imm:
return Assembler::IsImmLogical(static_cast<uint64_t>(value), 64,
&ignored, &ignored, &ignored);
case kArithimeticImm:
case kArithmeticImm:
// TODO(dcarney): -values can be handled by instruction swapping
return Assembler::IsImmAddSub(value);
case kShift32Imm:
@ -316,12 +316,12 @@ void InstructionSelector::VisitWord64Ror(Node* node) {
void InstructionSelector::VisitInt32Add(Node* node) {
VisitBinop(this, node, kArm64Add32, kArithimeticImm);
VisitBinop(this, node, kArm64Add32, kArithmeticImm);
}
void InstructionSelector::VisitInt64Add(Node* node) {
VisitBinop(this, node, kArm64Add, kArithimeticImm);
VisitBinop(this, node, kArm64Add, kArithmeticImm);
}
@ -332,7 +332,7 @@ void InstructionSelector::VisitInt32Sub(Node* node) {
Emit(kArm64Neg32, g.DefineAsRegister(node),
g.UseRegister(m.right().node()));
} else {
VisitBinop(this, node, kArm64Sub32, kArithimeticImm);
VisitBinop(this, node, kArm64Sub32, kArithmeticImm);
}
}
@ -343,7 +343,7 @@ void InstructionSelector::VisitInt64Sub(Node* node) {
if (m.left().Is(0)) {
Emit(kArm64Neg, g.DefineAsRegister(node), g.UseRegister(m.right().node()));
} else {
VisitBinop(this, node, kArm64Sub, kArithimeticImm);
VisitBinop(this, node, kArm64Sub, kArithmeticImm);
}
}
@ -474,13 +474,13 @@ void InstructionSelector::VisitFloat64Mod(Node* node) {
void InstructionSelector::VisitInt32AddWithOverflow(Node* node,
FlagsContinuation* cont) {
VisitBinop(this, node, kArm64Add32, kArithimeticImm, cont);
VisitBinop(this, node, kArm64Add32, kArithmeticImm, cont);
}
void InstructionSelector::VisitInt32SubWithOverflow(Node* node,
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,
Node* right = node->InputAt(1);
// 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),
cont);
} else if (g.CanBeImmediate(left, kArithimeticImm)) {
} else if (g.CanBeImmediate(left, kArithmeticImm)) {
if (!commutative) cont->Commute();
VisitCompare(selector, opcode, g.UseRegister(right), g.UseImmediate(left),
cont);