{&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
// 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());
}
}
+
+// -----------------------------------------------------------------------------
+// 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
} // namespace v8
}
+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);
}