Revision: 24407
Author: [email protected]
Date: Mon Oct 6 10:39:23 2014 UTC
Log: [turbofan] Negated immediates for ARM64 add/sub
Add ARM64 instruction selector support for negating the sense of an
arithmetic
instruction when its immediate is negative.
BUG=
[email protected]
Review URL: https://codereview.chromium.org/610323004
https://code.google.com/p/v8/source/detail?r=24407
Modified:
/branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64.cc
/branches/bleeding_edge/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
=======================================
---
/branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64.cc
Wed Oct 1 10:39:11 2014 UTC
+++
/branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64.cc
Mon Oct 6 10:39:23 2014 UTC
@@ -44,6 +44,10 @@
value = OpParameter<int64_t>(node);
else
return false;
+ return CanBeImmediate(value, mode);
+ }
+
+ bool CanBeImmediate(int64_t value, ImmediateMode mode) {
unsigned ignored;
switch (mode) {
case kLogical32Imm:
@@ -55,7 +59,6 @@
return Assembler::IsImmLogical(static_cast<uint64_t>(value), 64,
&ignored, &ignored, &ignored);
case kArithmeticImm:
- // TODO(dcarney): -values can be handled by instruction swapping
return Assembler::IsImmAddSub(value);
case kShift32Imm:
return 0 <= value && value < 32;
@@ -153,6 +156,22 @@
FlagsContinuation cont;
VisitBinop<Matcher>(selector, node, opcode, operand_mode, &cont);
}
+
+
+template <typename Matcher>
+static void VisitAddSub(InstructionSelector* selector, Node* node,
+ ArchOpcode opcode, ArchOpcode negate_opcode) {
+ Arm64OperandGenerator g(selector);
+ Matcher m(node);
+ if (m.right().HasValue() && (m.right().Value() < 0) &&
+ g.CanBeImmediate(-m.right().Value(), kArithmeticImm)) {
+ selector->Emit(negate_opcode, g.DefineAsRegister(node),
+ g.UseRegister(m.left().node()),
+ g.TempImmediate(-m.right().Value()));
+ } else {
+ VisitBinop<Matcher>(selector, node, opcode, kArithmeticImm);
+ }
+}
void InstructionSelector::VisitLoad(Node* node) {
@@ -442,7 +461,7 @@
g.UseRegister(mright.right().node()),
g.UseRegister(m.left().node()));
return;
}
- VisitBinop<Int32BinopMatcher>(this, node, kArm64Add32, kArithmeticImm);
+ VisitAddSub<Int32BinopMatcher>(this, node, kArm64Add32, kArm64Sub32);
}
@@ -465,7 +484,7 @@
g.UseRegister(mright.right().node()),
g.UseRegister(m.left().node()));
return;
}
- VisitBinop<Int64BinopMatcher>(this, node, kArm64Add, kArithmeticImm);
+ VisitAddSub<Int64BinopMatcher>(this, node, kArm64Add, kArm64Sub);
}
@@ -486,7 +505,7 @@
Emit(kArm64Neg32, g.DefineAsRegister(node),
g.UseRegister(m.right().node()));
} else {
- VisitBinop<Int32BinopMatcher>(this, node, kArm64Sub32, kArithmeticImm);
+ VisitAddSub<Int32BinopMatcher>(this, node, kArm64Sub32, kArm64Add32);
}
}
@@ -507,7 +526,7 @@
if (m.left().Is(0)) {
Emit(kArm64Neg, g.DefineAsRegister(node),
g.UseRegister(m.right().node()));
} else {
- VisitBinop<Int64BinopMatcher>(this, node, kArm64Sub, kArithmeticImm);
+ VisitAddSub<Int64BinopMatcher>(this, node, kArm64Sub, kArm64Add);
}
}
=======================================
---
/branches/bleeding_edge/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
Wed Oct 1 10:39:11 2014 UTC
+++
/branches/bleeding_edge/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
Mon Oct 6 10:39:23 2014 UTC
@@ -84,11 +84,26 @@
// 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 @@
//
-----------------------------------------------------------------------------
// 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, 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(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(dpi.arch_opcode, s[0]->arch_opcode());
+ 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)));
@@ -343,10 +390,6 @@
}
}
}
-
-
-INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
InstructionSelectorAddSubTest,
- ::testing::ValuesIn(kAddSubInstructions));
TEST_F(InstructionSelectorTest, SubZeroOnLeft) {
@@ -374,6 +417,42 @@
EXPECT_EQ(1U, s[0]->OutputCount());
}
}
+
+
+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());
+ }
+ }
+}
//
-----------------------------------------------------------------------------
--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
---
You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
For more options, visit https://groups.google.com/d/optout.