[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:
parent
b9614b9599
commit
79c8293b99
@ -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.
|
||||
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user