Commit 650ca8b5 authored by Ng Zhi An's avatar Ng Zhi An Committed by Commit Bot

[wasm-simd] Implement v128.andnot for x64 and interpreter

Note the tricky part in instruction-selector-x64, where we flip the
inputs given to the code generator. This is because the semantics we
want is: v128.andnot a b = a & !b, but the x64 instruction performs
andnps a b = !a & b. Therefore we flip the inputs, and combined with
g.DefineSameAsFirst, the output register will be the same as b, and we
can use andnps without any modifications in both SSE and AVX cases.

Bug: v8:10082
Change-Id: Iff98dc1dd944fbc642875f6306c6633d5d646615
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1980894Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Reviewed-by: 's avatarDeepti Gandluri <gdeepti@chromium.org>
Commit-Queue: Zhi An Ng <zhin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#65738}
parent e869518f
......@@ -2163,6 +2163,8 @@ void InstructionSelector::VisitNode(Node* node) {
return MarkAsSimd128(node), VisitS128Not(node);
case IrOpcode::kS128Select:
return MarkAsSimd128(node), VisitS128Select(node);
case IrOpcode::kS128AndNot:
return MarkAsSimd128(node), VisitS128AndNot(node);
case IrOpcode::kS8x16Swizzle:
return MarkAsSimd128(node), VisitS8x16Swizzle(node);
case IrOpcode::kS8x16Shuffle:
......@@ -2622,6 +2624,7 @@ void InstructionSelector::VisitI64x2ReplaceLaneI32Pair(Node* node) {
#endif // !V8_TARGET_ARCH_IA32
#if !V8_TARGET_ARCH_X64
void InstructionSelector::VisitS128AndNot(Node* node) { UNIMPLEMENTED(); }
#if !V8_TARGET_ARCH_ARM64
void InstructionSelector::VisitF64x2SConvertI64x2(Node* node) {
UNIMPLEMENTED();
......
......@@ -3615,6 +3615,14 @@ CodeGenerator::CodeGenResult CodeGenerator::AssembleArchInstruction(
__ Xorps(dst, i.InputSimd128Register(2));
break;
}
case kX64S128AndNot: {
XMMRegister dst = i.OutputSimd128Register();
DCHECK_EQ(dst, i.InputSimd128Register(0));
// The inputs have been inverted by instruction selector, so we can call
// andnps here without any modifications.
__ Andnps(dst, i.InputSimd128Register(1));
break;
}
case kX64S8x16Swizzle: {
CpuFeatureScope sse_scope(tasm(), SSSE3);
DCHECK_EQ(i.OutputSimd128Register(), i.InputSimd128Register(0));
......
......@@ -309,6 +309,7 @@ namespace compiler {
V(X64S128Or) \
V(X64S128Xor) \
V(X64S128Select) \
V(X64S128AndNot) \
V(X64S8x16Swizzle) \
V(X64S8x16Shuffle) \
V(X64S8x16LoadSplat) \
......
......@@ -281,6 +281,7 @@ int InstructionScheduler::GetTargetInstructionFlags(
case kX64S128Not:
case kX64S128Select:
case kX64S128Zero:
case kX64S128AndNot:
case kX64S1x2AnyTrue:
case kX64S1x2AllTrue:
case kX64S1x4AnyTrue:
......
......@@ -2879,6 +2879,13 @@ void InstructionSelector::VisitS128Select(Node* node) {
g.UseRegister(node->InputAt(2)));
}
void InstructionSelector::VisitS128AndNot(Node* node) {
X64OperandGenerator g(this);
// andnps a b does ~a & b, but we want a & !b, so flip the input.
Emit(kX64S128AndNot, g.DefineSameAsFirst(node),
g.UseRegister(node->InputAt(1)), g.UseRegister(node->InputAt(0)));
}
void InstructionSelector::VisitF64x2Abs(Node* node) {
X64OperandGenerator g(this);
InstructionOperand temps[] = {g.TempDoubleRegister()};
......
......@@ -454,6 +454,7 @@ MachineType AtomicOpType(Operator const* op) {
V(S128Xor, Operator::kAssociative | Operator::kCommutative, 2, 0, 1) \
V(S128Not, Operator::kNoProperties, 1, 0, 1) \
V(S128Select, Operator::kNoProperties, 3, 0, 1) \
V(S128AndNot, Operator::kNoProperties, 2, 0, 1) \
V(S1x2AnyTrue, Operator::kNoProperties, 1, 0, 1) \
V(S1x2AllTrue, Operator::kNoProperties, 1, 0, 1) \
V(S1x4AnyTrue, Operator::kNoProperties, 1, 0, 1) \
......
......@@ -706,6 +706,7 @@ class V8_EXPORT_PRIVATE MachineOperatorBuilder final
const Operator* S128Xor();
const Operator* S128Not();
const Operator* S128Select();
const Operator* S128AndNot();
const Operator* S8x16Swizzle();
const Operator* S8x16Shuffle(const uint8_t shuffle[16]);
......
......@@ -916,6 +916,7 @@
V(S128Or) \
V(S128Xor) \
V(S128Select) \
V(S128AndNot) \
V(S8x16Swizzle) \
V(S8x16Shuffle) \
V(S1x2AnyTrue) \
......
......@@ -4509,6 +4509,9 @@ Node* WasmGraphBuilder::SimdOp(wasm::WasmOpcode opcode, Node* const* inputs) {
case wasm::kExprS128Select:
return graph()->NewNode(mcgraph()->machine()->S128Select(), inputs[2],
inputs[0], inputs[1]);
case wasm::kExprS128AndNot:
return graph()->NewNode(mcgraph()->machine()->S128AndNot(), inputs[0],
inputs[1]);
case wasm::kExprS1x2AnyTrue:
return graph()->NewNode(mcgraph()->machine()->S1x2AnyTrue(), inputs[0]);
case wasm::kExprS1x2AllTrue:
......
......@@ -2312,6 +2312,7 @@ class ThreadImpl {
BINOP_CASE(S128And, i32x4, int4, 4, a & b)
BINOP_CASE(S128Or, i32x4, int4, 4, a | b)
BINOP_CASE(S128Xor, i32x4, int4, 4, a ^ b)
BINOP_CASE(S128AndNot, i32x4, int4, 4, a & ~b)
BINOP_CASE(I16x8Add, i16x8, int8, 8, base::AddWithWraparound(a, b))
BINOP_CASE(I16x8Sub, i16x8, int8, 8, base::SubWithWraparound(a, b))
BINOP_CASE(I16x8Mul, i16x8, int8, 8, base::MulWithWraparound(a, b))
......
......@@ -308,6 +308,7 @@ const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
CASE_S128_OP(Xor, "xor")
CASE_S128_OP(Not, "not")
CASE_S128_OP(Select, "select")
CASE_S128_OP(AndNot, "andnot")
CASE_S8x16_OP(Swizzle, "swizzle")
CASE_S8x16_OP(Shuffle, "shuffle")
CASE_S1x2_OP(AnyTrue, "any_true")
......
......@@ -444,6 +444,7 @@ bool IsJSCompatibleSignature(const FunctionSig* sig, const WasmFeatures&);
V(I32x4Load16x4U, 0xfdd5, s_s) \
V(I64x2Load32x2S, 0xfdd6, s_s) \
V(I64x2Load32x2U, 0xfdd7, s_s) \
V(S128AndNot, 0xfdd8, s_ss) \
V(I8x16RoundingAverageU, 0xfdd9, s_ss) \
V(I16x8RoundingAverageU, 0xfdda, s_ss) \
V(I16x8AddHoriz, 0xfdbd, s_ss) \
......
......@@ -279,6 +279,11 @@ T Sqrt(T a) {
return std::sqrt(a);
}
template <typename T>
T AndNot(T a, T b) {
return a & ~b;
}
// only used for F64x2 tests below
int64_t Equal(double a, double b) { return a == b ? -1 : 0; }
......@@ -1907,6 +1912,13 @@ WASM_SIMD_TEST(S128Xor) {
RunI32x4BinOpTest(execution_tier, lower_simd, kExprS128Xor, Xor);
}
#if V8_TARGET_ARCH_X64
// Bitwise operation, doesn't really matter what simd type we test it with.
WASM_SIMD_TEST_NO_LOWERING(S128AndNot) {
RunI32x4BinOpTest(execution_tier, lower_simd, kExprS128AndNot, AndNot);
}
#endif // V8_TARGET_ARCH_X64
WASM_SIMD_TEST(I32x4Eq) {
RunI32x4BinOpTest(execution_tier, lower_simd, kExprI32x4Eq, Equal);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment