Revision: 24188
Author: [email protected]
Date: Wed Sep 24 14:55:50 2014 UTC
Log: [turbofan] ARM64 support for inverted logical ops
Select ARM64 inverted rhs instructions (bic, orn, eon) for cases where the
rhs
input is inverted (using e/xor), and add some tests for this. Also, rename
xor
to eor in the ARM64 backend.
BUG=
[email protected]
Review URL: https://codereview.chromium.org/591383003
https://code.google.com/p/v8/source/detail?r=24188
Modified:
/branches/bleeding_edge/src/compiler/arm64/code-generator-arm64.cc
/branches/bleeding_edge/src/compiler/arm64/instruction-codes-arm64.h
/branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64-unittest.cc
/branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64.cc
=======================================
--- /branches/bleeding_edge/src/compiler/arm64/code-generator-arm64.cc Wed
Sep 24 11:08:35 2014 UTC
+++ /branches/bleeding_edge/src/compiler/arm64/code-generator-arm64.cc Wed
Sep 24 14:55:50 2014 UTC
@@ -189,6 +189,12 @@
case kArm64And32:
__ And(i.OutputRegister32(), i.InputRegister32(0),
i.InputOperand32(1));
break;
+ case kArm64Bic:
+ __ Bic(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+ break;
+ case kArm64Bic32:
+ __ Bic(i.OutputRegister32(), i.InputRegister32(0),
i.InputOperand32(1));
+ break;
case kArm64Mul:
__ Mul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
break;
@@ -256,12 +262,24 @@
case kArm64Or32:
__ Orr(i.OutputRegister32(), i.InputRegister32(0),
i.InputOperand32(1));
break;
- case kArm64Xor:
+ case kArm64Orn:
+ __ Orn(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+ break;
+ case kArm64Orn32:
+ __ Orn(i.OutputRegister32(), i.InputRegister32(0),
i.InputOperand32(1));
+ break;
+ case kArm64Eor:
__ Eor(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
break;
- case kArm64Xor32:
+ case kArm64Eor32:
__ Eor(i.OutputRegister32(), i.InputRegister32(0),
i.InputOperand32(1));
break;
+ case kArm64Eon:
+ __ Eon(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+ break;
+ case kArm64Eon32:
+ __ Eon(i.OutputRegister32(), i.InputRegister32(0),
i.InputOperand32(1));
+ break;
case kArm64Sub:
__ Sub(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
break;
=======================================
--- /branches/bleeding_edge/src/compiler/arm64/instruction-codes-arm64.h
Wed Sep 24 11:08:35 2014 UTC
+++ /branches/bleeding_edge/src/compiler/arm64/instruction-codes-arm64.h
Wed Sep 24 14:55:50 2014 UTC
@@ -16,6 +16,8 @@
V(Arm64Add32) \
V(Arm64And) \
V(Arm64And32) \
+ V(Arm64Bic) \
+ V(Arm64Bic32) \
V(Arm64Cmp) \
V(Arm64Cmp32) \
V(Arm64Cmn) \
@@ -24,8 +26,12 @@
V(Arm64Tst32) \
V(Arm64Or) \
V(Arm64Or32) \
- V(Arm64Xor) \
- V(Arm64Xor32) \
+ V(Arm64Orn) \
+ V(Arm64Orn32) \
+ V(Arm64Eor) \
+ V(Arm64Eor32) \
+ V(Arm64Eon) \
+ V(Arm64Eon32) \
V(Arm64Sub) \
V(Arm64Sub32) \
V(Arm64Mul) \
=======================================
---
/branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64-unittest.cc
Wed Sep 24 11:08:35 2014 UTC
+++
/branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64-unittest.cc
Wed Sep 24 14:55:50 2014 UTC
@@ -58,8 +58,8 @@
{&RawMachineAssembler::Word64And, "Word64And", kArm64And, kMachInt64},
{&RawMachineAssembler::Word32Or, "Word32Or", kArm64Or32, kMachInt32},
{&RawMachineAssembler::Word64Or, "Word64Or", kArm64Or, kMachInt64},
- {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Xor32,
kMachInt32},
- {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Xor, kMachInt64}};
+ {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eor32,
kMachInt32},
+ {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eor, kMachInt64}};
// ARM64 logical immediates: contiguous set bits, rotated about a power of
two
@@ -1049,7 +1049,7 @@
// Compare with 0 are turned into tst instruction.
if (imm == 0) continue;
StreamBuilder m(this, type, type);
- m.Return((m.*cmp.constructor)(m.Parameter(0), BuildConstant(m, type,
imm)));
+ m.Return((m.*cmp.constructor)(BuildConstant(m, type, imm),
m.Parameter(0)));
Stream s = m.Build();
ASSERT_EQ(1U, s.size());
EXPECT_EQ(cmp.arch_opcode, s[0]->arch_opcode());
@@ -1121,6 +1121,166 @@
EXPECT_EQ(kEqual, s[0]->flags_condition());
}
}
+
+
+//
-----------------------------------------------------------------------------
+// Miscellaneous
+
+
+static const MachInst2 kLogicalWithNotRHSs[] = {
+ {&RawMachineAssembler::Word32And, "Word32And", kArm64Bic32,
kMachInt32},
+ {&RawMachineAssembler::Word64And, "Word64And", kArm64Bic, kMachInt64},
+ {&RawMachineAssembler::Word32Or, "Word32Or", kArm64Orn32, kMachInt32},
+ {&RawMachineAssembler::Word64Or, "Word64Or", kArm64Orn, kMachInt64},
+ {&RawMachineAssembler::Word32Xor, "Word32Xor", kArm64Eon32,
kMachInt32},
+ {&RawMachineAssembler::Word64Xor, "Word64Xor", kArm64Eon, kMachInt64}};
+
+
+typedef InstructionSelectorTestWithParam<MachInst2>
+ InstructionSelectorLogicalWithNotRHSTest;
+
+
+TEST_P(InstructionSelectorLogicalWithNotRHSTest, Parameter) {
+ const MachInst2 inst = GetParam();
+ const MachineType type = inst.machine_type;
+ // Test cases where RHS is Xor(x, -1).
+ {
+ StreamBuilder m(this, type, type, type);
+ if (type == kMachInt32) {
+ m.Return((m.*inst.constructor)(
+ m.Parameter(0), m.Word32Xor(m.Parameter(1),
m.Int32Constant(-1))));
+ } else {
+ ASSERT_EQ(kMachInt64, type);
+ m.Return((m.*inst.constructor)(
+ m.Parameter(0), m.Word64Xor(m.Parameter(1),
m.Int64Constant(-1))));
+ }
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+ EXPECT_EQ(2U, s[0]->InputCount());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ }
+ {
+ StreamBuilder m(this, type, type, type);
+ if (type == kMachInt32) {
+ m.Return((m.*inst.constructor)(
+ m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)),
m.Parameter(1)));
+ } else {
+ ASSERT_EQ(kMachInt64, type);
+ m.Return((m.*inst.constructor)(
+ m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)),
m.Parameter(1)));
+ }
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+ EXPECT_EQ(2U, s[0]->InputCount());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ }
+ // Test cases where RHS is Not(x).
+ {
+ StreamBuilder m(this, type, type, type);
+ if (type == kMachInt32) {
+ m.Return(
+ (m.*inst.constructor)(m.Parameter(0),
m.Word32Not(m.Parameter(1))));
+ } else {
+ ASSERT_EQ(kMachInt64, type);
+ m.Return(
+ (m.*inst.constructor)(m.Parameter(0),
m.Word64Not(m.Parameter(1))));
+ }
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+ EXPECT_EQ(2U, s[0]->InputCount());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ }
+ {
+ StreamBuilder m(this, type, type, type);
+ if (type == kMachInt32) {
+ m.Return(
+ (m.*inst.constructor)(m.Word32Not(m.Parameter(0)),
m.Parameter(1)));
+ } else {
+ ASSERT_EQ(kMachInt64, type);
+ m.Return(
+ (m.*inst.constructor)(m.Word64Not(m.Parameter(0)),
m.Parameter(1)));
+ }
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(inst.arch_opcode, s[0]->arch_opcode());
+ EXPECT_EQ(2U, s[0]->InputCount());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ }
+}
+
+
+INSTANTIATE_TEST_CASE_P(InstructionSelectorTest,
+ InstructionSelectorLogicalWithNotRHSTest,
+ ::testing::ValuesIn(kLogicalWithNotRHSs));
+
+
+TEST_F(InstructionSelectorTest, Word32NotWithParameter) {
+ StreamBuilder m(this, kMachInt32, kMachInt32);
+ m.Return(m.Word32Not(m.Parameter(0)));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
+ EXPECT_EQ(1U, s[0]->InputCount());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Word64NotWithParameter) {
+ StreamBuilder m(this, kMachInt64, kMachInt64);
+ m.Return(m.Word64Not(m.Parameter(0)));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
+ EXPECT_EQ(1U, s[0]->InputCount());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+}
+
+
+TEST_F(InstructionSelectorTest, Word32XorMinusOneWithParameter) {
+ {
+ StreamBuilder m(this, kMachInt32, kMachInt32);
+ m.Return(m.Word32Xor(m.Parameter(0), m.Int32Constant(-1)));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
+ EXPECT_EQ(1U, s[0]->InputCount());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ }
+ {
+ StreamBuilder m(this, kMachInt32, kMachInt32);
+ m.Return(m.Word32Xor(m.Int32Constant(-1), m.Parameter(0)));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArm64Not32, s[0]->arch_opcode());
+ EXPECT_EQ(1U, s[0]->InputCount());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ }
+}
+
+
+TEST_F(InstructionSelectorTest, Word64XorMinusOneWithParameter) {
+ {
+ StreamBuilder m(this, kMachInt64, kMachInt64);
+ m.Return(m.Word64Xor(m.Parameter(0), m.Int64Constant(-1)));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
+ EXPECT_EQ(1U, s[0]->InputCount());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ }
+ {
+ StreamBuilder m(this, kMachInt64, kMachInt64);
+ m.Return(m.Word64Xor(m.Int64Constant(-1), m.Parameter(0)));
+ Stream s = m.Build();
+ ASSERT_EQ(1U, s.size());
+ EXPECT_EQ(kArm64Not, s[0]->arch_opcode());
+ EXPECT_EQ(1U, s[0]->InputCount());
+ EXPECT_EQ(1U, s[0]->OutputCount());
+ }
+}
} // namespace compiler
} // namespace internal
=======================================
---
/branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64.cc
Wed Sep 24 11:08:35 2014 UTC
+++
/branches/bleeding_edge/src/compiler/arm64/instruction-selector-arm64.cc
Wed Sep 24 14:55:50 2014 UTC
@@ -265,47 +265,121 @@
g.UseRegister(base), g.UseRegister(index), g.UseRegister(value));
}
}
+
+
+template <typename Matcher>
+static void VisitLogical(InstructionSelector* selector, Node* node,
Matcher* m,
+ ArchOpcode opcode, bool left_can_cover,
+ bool right_can_cover, ImmediateMode imm_mode) {
+ Arm64OperandGenerator g(selector);
+
+ // Map instruction to equivalent operation with inverted right input.
+ ArchOpcode inv_opcode = opcode;
+ switch (opcode) {
+ case kArm64And32:
+ inv_opcode = kArm64Bic32;
+ break;
+ case kArm64And:
+ inv_opcode = kArm64Bic;
+ break;
+ case kArm64Or32:
+ inv_opcode = kArm64Orn32;
+ break;
+ case kArm64Or:
+ inv_opcode = kArm64Orn;
+ break;
+ case kArm64Eor32:
+ inv_opcode = kArm64Eon32;
+ break;
+ case kArm64Eor:
+ inv_opcode = kArm64Eon;
+ break;
+ default:
+ UNREACHABLE();
+ }
+
+ // Select Logical(y, ~x) for Logical(Xor(x, -1), y).
+ if ((m->left().IsWord32Xor() || m->left().IsWord64Xor()) &&
left_can_cover) {
+ Matcher mleft(m->left().node());
+ if (mleft.right().Is(-1)) {
+ // TODO(all): support shifted operand on right.
+ selector->Emit(inv_opcode, g.DefineAsRegister(node),
+ g.UseRegister(m->right().node()),
+ g.UseRegister(mleft.left().node()));
+ return;
+ }
+ }
+
+ // Select Logical(x, ~y) for Logical(x, Xor(y, -1)).
+ if ((m->right().IsWord32Xor() || m->right().IsWord64Xor()) &&
+ right_can_cover) {
+ Matcher mright(m->right().node());
+ if (mright.right().Is(-1)) {
+ // TODO(all): support shifted operand on right.
+ selector->Emit(inv_opcode, g.DefineAsRegister(node),
+ g.UseRegister(m->left().node()),
+ g.UseRegister(mright.left().node()));
+ return;
+ }
+ }
+
+ if (m->IsWord32Xor() && m->right().Is(-1)) {
+ selector->Emit(kArm64Not32, g.DefineAsRegister(node),
+ g.UseRegister(m->left().node()));
+ } else if (m->IsWord64Xor() && m->right().Is(-1)) {
+ selector->Emit(kArm64Not, g.DefineAsRegister(node),
+ g.UseRegister(m->left().node()));
+ } else {
+ VisitBinop<Matcher>(selector, node, opcode, imm_mode);
+ }
+}
void InstructionSelector::VisitWord32And(Node* node) {
- VisitBinop<Int32BinopMatcher>(this, node, kArm64And32, kLogical32Imm);
+ Int32BinopMatcher m(node);
+ VisitLogical<Int32BinopMatcher>(
+ this, node, &m, kArm64And32, CanCover(node, m.left().node()),
+ CanCover(node, m.right().node()), kLogical32Imm);
}
void InstructionSelector::VisitWord64And(Node* node) {
- VisitBinop<Int64BinopMatcher>(this, node, kArm64And, kLogical64Imm);
+ Int64BinopMatcher m(node);
+ VisitLogical<Int64BinopMatcher>(
+ this, node, &m, kArm64And, CanCover(node, m.left().node()),
+ CanCover(node, m.right().node()), kLogical64Imm);
}
void InstructionSelector::VisitWord32Or(Node* node) {
- VisitBinop<Int32BinopMatcher>(this, node, kArm64Or32, kLogical32Imm);
+ Int32BinopMatcher m(node);
+ VisitLogical<Int32BinopMatcher>(
+ this, node, &m, kArm64Or32, CanCover(node, m.left().node()),
+ CanCover(node, m.right().node()), kLogical32Imm);
}
void InstructionSelector::VisitWord64Or(Node* node) {
- VisitBinop<Int64BinopMatcher>(this, node, kArm64Or, kLogical64Imm);
+ Int64BinopMatcher m(node);
+ VisitLogical<Int64BinopMatcher>(
+ this, node, &m, kArm64Or, CanCover(node, m.left().node()),
+ CanCover(node, m.right().node()), kLogical64Imm);
}
void InstructionSelector::VisitWord32Xor(Node* node) {
- Arm64OperandGenerator g(this);
Int32BinopMatcher m(node);
- if (m.right().Is(-1)) {
- Emit(kArm64Not32, g.DefineAsRegister(node),
g.UseRegister(m.left().node()));
- } else {
- VisitBinop<Int32BinopMatcher>(this, node, kArm64Xor32, kLogical32Imm);
- }
+ VisitLogical<Int32BinopMatcher>(
+ this, node, &m, kArm64Eor32, CanCover(node, m.left().node()),
+ CanCover(node, m.right().node()), kLogical32Imm);
}
void InstructionSelector::VisitWord64Xor(Node* node) {
- Arm64OperandGenerator g(this);
Int64BinopMatcher m(node);
- if (m.right().Is(-1)) {
- Emit(kArm64Not, g.DefineAsRegister(node),
g.UseRegister(m.left().node()));
- } else {
- VisitBinop<Int64BinopMatcher>(this, node, kArm64Xor, kLogical32Imm);
- }
+ VisitLogical<Int64BinopMatcher>(
+ this, node, &m, kArm64Eor, CanCover(node, m.left().node()),
+ CanCover(node, m.right().node()), kLogical64Imm);
}
--
--
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.