Index: test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc |
diff --git a/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc |
index 6287a719b6c14980849af6c3a1753630d3f24789..dc74a7ba67b33885a03a2e2f588c5f3247b6b64d 100644 |
--- a/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc |
+++ b/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc |
@@ -84,11 +84,26 @@ static const uint32_t kLogicalImmediates[] = { |
// ARM64 arithmetic instructions. |
-static const MachInst2 kAddSubInstructions[] = { |
- {&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, kMachInt32}, |
- {&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add, kMachInt64}, |
- {&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, kMachInt32}, |
- {&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub, kMachInt64}}; |
+struct AddSub { |
+ MachInst2 mi; |
+ ArchOpcode negate_arch_opcode; |
+}; |
+ |
+ |
+std::ostream& operator<<(std::ostream& os, const AddSub& op) { |
+ return os << op.mi; |
+} |
+ |
+ |
+static const AddSub kAddSubInstructions[] = { |
+ {{&RawMachineAssembler::Int32Add, "Int32Add", kArm64Add32, kMachInt32}, |
+ kArm64Sub32}, |
+ {{&RawMachineAssembler::Int64Add, "Int64Add", kArm64Add, kMachInt64}, |
+ kArm64Sub}, |
+ {{&RawMachineAssembler::Int32Sub, "Int32Sub", kArm64Sub32, kMachInt32}, |
+ kArm64Add32}, |
+ {{&RawMachineAssembler::Int64Sub, "Int64Sub", kArm64Sub, kMachInt64}, |
+ kArm64Add}}; |
// ARM64 Add/Sub immediates: 12-bit immediate optionally shifted by 12. |
@@ -288,32 +303,32 @@ INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorLogicalTest, |
// ----------------------------------------------------------------------------- |
// Add and Sub instructions. |
-typedef InstructionSelectorTestWithParam<MachInst2> |
- InstructionSelectorAddSubTest; |
+typedef InstructionSelectorTestWithParam<AddSub> InstructionSelectorAddSubTest; |
TEST_P(InstructionSelectorAddSubTest, Parameter) { |
- const MachInst2 dpi = GetParam(); |
- const MachineType type = dpi.machine_type; |
+ const AddSub dpi = GetParam(); |
+ const MachineType type = dpi.mi.machine_type; |
StreamBuilder m(this, type, type, type); |
- m.Return((m.*dpi.constructor)(m.Parameter(0), m.Parameter(1))); |
+ m.Return((m.*dpi.mi.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(dpi.mi.arch_opcode, s[0]->arch_opcode()); |
EXPECT_EQ(2U, s[0]->InputCount()); |
EXPECT_EQ(1U, s[0]->OutputCount()); |
} |
TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) { |
- const MachInst2 dpi = GetParam(); |
- const MachineType type = dpi.machine_type; |
+ const AddSub dpi = GetParam(); |
+ const MachineType type = dpi.mi.machine_type; |
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { |
StreamBuilder m(this, type, type); |
- m.Return((m.*dpi.constructor)(m.Parameter(0), BuildConstant(m, type, imm))); |
+ m.Return( |
+ (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(m, type, imm))); |
Stream s = m.Build(); |
ASSERT_EQ(1U, s.size()); |
- EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); |
+ EXPECT_EQ(dpi.mi.arch_opcode, s[0]->arch_opcode()); |
ASSERT_EQ(2U, s[0]->InputCount()); |
EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); |
@@ -322,20 +337,52 @@ TEST_P(InstructionSelectorAddSubTest, ImmediateOnRight) { |
} |
-TEST_P(InstructionSelectorAddSubTest, ImmediateOnLeft) { |
- const MachInst2 dpi = GetParam(); |
- const MachineType type = dpi.machine_type; |
- |
+TEST_P(InstructionSelectorAddSubTest, NegImmediateOnRight) { |
+ const AddSub dpi = GetParam(); |
+ const MachineType type = dpi.mi.machine_type; |
TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { |
+ if (imm == 0) continue; |
StreamBuilder m(this, type, type); |
- m.Return((m.*dpi.constructor)(BuildConstant(m, type, imm), m.Parameter(0))); |
+ m.Return( |
+ (m.*dpi.mi.constructor)(m.Parameter(0), BuildConstant(m, type, -imm))); |
Stream s = m.Build(); |
+ ASSERT_EQ(1U, s.size()); |
+ EXPECT_EQ(dpi.negate_arch_opcode, s[0]->arch_opcode()); |
+ ASSERT_EQ(2U, s[0]->InputCount()); |
+ ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
+ EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); |
+ EXPECT_EQ(1U, s[0]->OutputCount()); |
+ } |
+} |
+ |
- // Add can support an immediate on the left by commuting, but Sub can't |
- // commute. We test zero-on-left Sub later. |
- if (strstr(dpi.constructor_name, "Add") != NULL) { |
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest, |
+ ::testing::ValuesIn(kAddSubInstructions)); |
+ |
+ |
+TEST_F(InstructionSelectorTest, AddImmediateOnLeft) { |
+ { |
+ // 32-bit add. |
+ TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { |
+ StreamBuilder m(this, kMachInt32, kMachInt32); |
+ m.Return(m.Int32Add(m.Int32Constant(imm), m.Parameter(0))); |
+ Stream s = m.Build(); |
ASSERT_EQ(1U, s.size()); |
- EXPECT_EQ(dpi.arch_opcode, s[0]->arch_opcode()); |
+ EXPECT_EQ(kArm64Add32, s[0]->arch_opcode()); |
+ ASSERT_EQ(2U, s[0]->InputCount()); |
+ EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
+ EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); |
+ EXPECT_EQ(1U, s[0]->OutputCount()); |
+ } |
+ } |
+ { |
+ // 64-bit add. |
+ TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { |
+ StreamBuilder m(this, kMachInt64, kMachInt64); |
+ m.Return(m.Int64Add(m.Int64Constant(imm), m.Parameter(0))); |
+ Stream s = m.Build(); |
+ ASSERT_EQ(1U, s.size()); |
+ EXPECT_EQ(kArm64Add, s[0]->arch_opcode()); |
ASSERT_EQ(2U, s[0]->InputCount()); |
EXPECT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); |
@@ -345,10 +392,6 @@ TEST_P(InstructionSelectorAddSubTest, ImmediateOnLeft) { |
} |
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest, InstructionSelectorAddSubTest, |
- ::testing::ValuesIn(kAddSubInstructions)); |
- |
- |
TEST_F(InstructionSelectorTest, SubZeroOnLeft) { |
// Subtraction with zero on the left maps to Neg. |
{ |
@@ -376,6 +419,42 @@ TEST_F(InstructionSelectorTest, SubZeroOnLeft) { |
} |
+TEST_F(InstructionSelectorTest, AddNegImmediateOnLeft) { |
+ { |
+ // 32-bit add. |
+ TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { |
+ if (imm == 0) continue; |
+ StreamBuilder m(this, kMachInt32, kMachInt32); |
+ m.Return(m.Int32Add(m.Int32Constant(-imm), m.Parameter(0))); |
+ Stream s = m.Build(); |
+ |
+ ASSERT_EQ(1U, s.size()); |
+ EXPECT_EQ(kArm64Sub32, s[0]->arch_opcode()); |
+ ASSERT_EQ(2U, s[0]->InputCount()); |
+ ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
+ EXPECT_EQ(imm, s.ToInt32(s[0]->InputAt(1))); |
+ EXPECT_EQ(1U, s[0]->OutputCount()); |
+ } |
+ } |
+ { |
+ // 64-bit add. |
+ TRACED_FOREACH(int32_t, imm, kAddSubImmediates) { |
+ if (imm == 0) continue; |
+ StreamBuilder m(this, kMachInt64, kMachInt64); |
+ m.Return(m.Int64Add(m.Int64Constant(-imm), m.Parameter(0))); |
+ Stream s = m.Build(); |
+ |
+ ASSERT_EQ(1U, s.size()); |
+ EXPECT_EQ(kArm64Sub, s[0]->arch_opcode()); |
+ ASSERT_EQ(2U, s[0]->InputCount()); |
+ ASSERT_TRUE(s[0]->InputAt(1)->IsImmediate()); |
+ EXPECT_EQ(imm, s.ToInt64(s[0]->InputAt(1))); |
+ EXPECT_EQ(1U, s[0]->OutputCount()); |
+ } |
+ } |
+} |
+ |
+ |
// ----------------------------------------------------------------------------- |
// Data processing controlled branches. |