Index: src/compiler/arm64/instruction-selector-arm64-unittest.cc |
diff --git a/src/compiler/arm64/instruction-selector-arm64-unittest.cc b/src/compiler/arm64/instruction-selector-arm64-unittest.cc |
index 581e89c6e0392d52f16c90b8cf26546b60e3a366..58a6b99fe4d617494d99809a599eb8080f27274e 100644 |
--- a/src/compiler/arm64/instruction-selector-arm64-unittest.cc |
+++ b/src/compiler/arm64/instruction-selector-arm64-unittest.cc |
@@ -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}, |
@@ -336,6 +344,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. |