Commit 618bc445 authored by Aseem Garg's avatar Aseem Garg Committed by Commit Bot

[wasm] add simd convert and pack to interpreter

R=gdeepti@chromium.org
BUG=v8:6020

Change-Id: Ibdeb926ef3e2884b9a3f0831e9482ebe2da227ac
Reviewed-on: https://chromium-review.googlesource.com/1105464Reviewed-by: 's avatarDeepti Gandluri <gdeepti@chromium.org>
Commit-Queue: Aseem Garg <aseemgarg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53898}
parent 9dcc665c
......@@ -1765,7 +1765,6 @@ VISIT_ATOMIC_BINOP(Xor)
V(I16x8Ne) \
V(I16x8GtS) \
V(I16x8GeS) \
V(I16x8UConvertI32x4) \
V(I16x8AddSaturateU) \
V(I16x8SubSaturateU) \
V(I16x8MinU) \
......@@ -1783,7 +1782,6 @@ VISIT_ATOMIC_BINOP(Xor)
V(I8x16Ne) \
V(I8x16GtS) \
V(I8x16GeS) \
V(I8x16UConvertI16x8) \
V(I8x16AddSaturateU) \
V(I8x16SubSaturateU) \
V(I8x16MinU) \
......@@ -2006,6 +2004,26 @@ SIMD_BINOP_LIST(VISIT_SIMD_BINOP)
#undef VISIT_SIMD_BINOP
#undef SIMD_BINOP_LIST
void VisitPack(InstructionSelector* selector, Node* node, ArchOpcode avx_opcode,
ArchOpcode sse_opcode) {
IA32OperandGenerator g(selector);
InstructionOperand operand0 = g.UseUniqueRegister(node->InputAt(0));
InstructionOperand operand1 = g.UseUnique(node->InputAt(1));
if (selector->IsSupported(AVX)) {
selector->Emit(avx_opcode, g.UseUniqueRegister(node), operand0, operand1);
} else {
selector->Emit(sse_opcode, g.UseUniqueRegister(node), operand0, operand1);
}
}
void InstructionSelector::VisitI16x8UConvertI32x4(Node* node) {
VisitPack(this, node, kAVXI16x8UConvertI32x4, kSSEI16x8UConvertI32x4);
}
void InstructionSelector::VisitI8x16UConvertI16x8(Node* node) {
VisitPack(this, node, kAVXI8x16UConvertI16x8, kSSEI8x16UConvertI16x8);
}
void InstructionSelector::VisitInt32AbsWithOverflow(Node* node) {
UNREACHABLE();
}
......
......@@ -1848,6 +1848,75 @@ class ThreadImpl {
SHIFT_CASE(I8x16ShrU, i8x16, int16, 16,
static_cast<uint8_t>(a) >> imm.shift)
#undef SHIFT_CASE
#define CONVERT_CASE(op, src_type, name, dst_type, count, start_index, ctype, \
expr) \
case kExpr##op: { \
WasmValue v = Pop(); \
src_type s = v.to_s128().to_##name(); \
dst_type res; \
for (size_t i = 0; i < count; ++i) { \
ctype a = s.val[start_index + i]; \
res.val[i] = expr; \
} \
Push(WasmValue(Simd128(res))); \
return true; \
}
CONVERT_CASE(F32x4SConvertI32x4, int4, i32x4, float4, 4, 0, int32_t,
static_cast<float>(a))
CONVERT_CASE(F32x4UConvertI32x4, int4, i32x4, float4, 4, 0, uint32_t,
static_cast<float>(a))
CONVERT_CASE(I32x4SConvertF32x4, float4, f32x4, int4, 4, 0, double,
std::isnan(a) ? 0
: a<kMinInt ? kMinInt : a> kMaxInt
? kMaxInt
: static_cast<int32_t>(a))
CONVERT_CASE(I32x4UConvertF32x4, float4, f32x4, int4, 4, 0, double,
std::isnan(a)
? 0
: a<0 ? 0 : a> kMaxUInt32 ? kMaxUInt32
: static_cast<uint32_t>(a))
CONVERT_CASE(I32x4SConvertI16x8High, int8, i16x8, int4, 4, 4, int16_t,
a)
CONVERT_CASE(I32x4UConvertI16x8High, int8, i16x8, int4, 4, 4, uint16_t,
a)
CONVERT_CASE(I32x4SConvertI16x8Low, int8, i16x8, int4, 4, 0, int16_t, a)
CONVERT_CASE(I32x4UConvertI16x8Low, int8, i16x8, int4, 4, 0, uint16_t,
a)
CONVERT_CASE(I16x8SConvertI8x16High, int16, i8x16, int8, 8, 8, int8_t,
a)
CONVERT_CASE(I16x8UConvertI8x16High, int16, i8x16, int8, 8, 8, uint8_t,
a)
CONVERT_CASE(I16x8SConvertI8x16Low, int16, i8x16, int8, 8, 0, int8_t, a)
CONVERT_CASE(I16x8UConvertI8x16Low, int16, i8x16, int8, 8, 0, uint8_t,
a)
#undef CONVERT_CASE
#define PACK_CASE(op, src_type, name, dst_type, count, ctype, dst_ctype, \
is_unsigned) \
case kExpr##op: { \
WasmValue v2 = Pop(); \
WasmValue v1 = Pop(); \
src_type s1 = v1.to_s128().to_##name(); \
src_type s2 = v2.to_s128().to_##name(); \
dst_type res; \
int64_t min = std::numeric_limits<ctype>::min(); \
int64_t max = std::numeric_limits<ctype>::max(); \
for (size_t i = 0; i < count; ++i) { \
int32_t v = i < count / 2 ? s1.val[i] : s2.val[i - count / 2]; \
int64_t a = is_unsigned ? static_cast<int64_t>(v & 0xFFFFFFFFu) : v; \
res.val[i] = static_cast<dst_ctype>(std::max(min, std::min(max, a))); \
} \
Push(WasmValue(Simd128(res))); \
return true; \
}
PACK_CASE(I16x8SConvertI32x4, int4, i32x4, int8, 8, int16_t, int16_t,
false)
PACK_CASE(I16x8UConvertI32x4, int4, i32x4, int8, 8, uint16_t, int16_t,
true)
PACK_CASE(I8x16SConvertI16x8, int8, i16x8, int16, 16, int8_t, int8_t,
false)
PACK_CASE(I8x16UConvertI16x8, int8, i16x8, int16, 16, uint8_t, int8_t,
true)
#undef PACK_CASE
default:
return false;
}
......
......@@ -465,7 +465,7 @@ WASM_SIMD_TEST(F32x4ReplaceLane) {
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS || \
V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_IA32
// Tests both signed and unsigned conversion.
WASM_SIMD_COMPILED_AND_LOWERED_TEST(F32x4ConvertI32x4) {
WASM_SIMD_TEST(F32x4ConvertI32x4) {
WasmRunner<int32_t, int32_t, float, float> r(execution_mode, lower_simd);
byte a = 0;
byte expected_signed = 1;
......@@ -861,7 +861,7 @@ int32_t ConvertToInt(double val, bool unsigned_integer) {
}
// Tests both signed and unsigned conversion.
WASM_SIMD_COMPILED_AND_LOWERED_TEST(I32x4ConvertF32x4) {
WASM_SIMD_TEST(I32x4ConvertF32x4) {
WasmRunner<int32_t, float, int32_t, int32_t> r(execution_mode, lower_simd);
byte a = 0;
byte expected_signed = 1;
......@@ -886,7 +886,7 @@ WASM_SIMD_COMPILED_AND_LOWERED_TEST(I32x4ConvertF32x4) {
}
// Tests both signed and unsigned conversion from I16x8 (unpacking).
WASM_SIMD_COMPILED_AND_LOWERED_TEST(I32x4ConvertI16x8) {
WASM_SIMD_TEST(I32x4ConvertI16x8) {
WasmRunner<int32_t, int32_t, int32_t, int32_t, int32_t> r(execution_mode,
lower_simd);
byte a = 0;
......@@ -1108,7 +1108,7 @@ WASM_SIMD_TEST(I32x4ShrU) {
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS || \
V8_TARGET_ARCH_MIPS64
// Tests both signed and unsigned conversion from I8x16 (unpacking).
WASM_SIMD_COMPILED_AND_LOWERED_TEST(I16x8ConvertI8x16) {
WASM_SIMD_TEST(I16x8ConvertI8x16) {
WasmRunner<int32_t, int32_t, int32_t, int32_t, int32_t> r(execution_mode,
lower_simd);
byte a = 0;
......@@ -1172,30 +1172,47 @@ WASM_SIMD_TEST(I16x8Neg) {
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS || \
V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_IA32
// Tests both signed and unsigned conversion from I32x4 (packing).
WASM_SIMD_COMPILED_AND_LOWERED_TEST(I16x8ConvertI32x4) {
WasmRunner<int32_t, int32_t, int32_t, int32_t> r(execution_mode, lower_simd);
WASM_SIMD_TEST(I16x8ConvertI32x4) {
WasmRunner<int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t> r(
execution_mode, lower_simd);
byte a = 0;
byte packed_signed = 1;
byte packed_unsigned = 2;
byte b = 1;
// indices for packed signed params
byte ps_a = 2;
byte ps_b = 3;
// indices for packed unsigned params
byte pu_a = 4;
byte pu_b = 5;
byte simd0 = r.AllocateLocal(kWasmS128);
byte simd1 = r.AllocateLocal(kWasmS128);
byte simd2 = r.AllocateLocal(kWasmS128);
BUILD(r, WASM_SET_LOCAL(simd0, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(a))),
WASM_SET_LOCAL(simd1, WASM_SIMD_BINOP(kExprI16x8SConvertI32x4,
WASM_SET_LOCAL(simd1, WASM_SIMD_I32x4_SPLAT(WASM_GET_LOCAL(b))),
WASM_SET_LOCAL(simd2, WASM_SIMD_BINOP(kExprI16x8SConvertI32x4,
WASM_GET_LOCAL(simd0),
WASM_GET_LOCAL(simd0))),
WASM_SIMD_CHECK_SPLAT8(I16x8, simd1, I32, packed_signed),
WASM_GET_LOCAL(simd1))),
WASM_SIMD_CHECK8(I16x8, simd2, I32, ps_a, ps_a, ps_a, ps_a, ps_b, ps_b,
ps_b, ps_b),
WASM_SET_LOCAL(simd2, WASM_SIMD_BINOP(kExprI16x8UConvertI32x4,
WASM_GET_LOCAL(simd0),
WASM_GET_LOCAL(simd0))),
WASM_SIMD_CHECK_SPLAT8(I16x8, simd2, I32, packed_unsigned), WASM_ONE);
WASM_GET_LOCAL(simd1))),
WASM_SIMD_CHECK8(I16x8, simd2, I32, pu_a, pu_a, pu_a, pu_a, pu_b, pu_b,
pu_b, pu_b),
WASM_ONE);
FOR_INT32_INPUTS(i) {
int32_t packed_signed = Narrow<int16_t>(*i);
int32_t packed_unsigned = UnsignedNarrow<int16_t>(*i);
FOR_INT32_INPUTS(j) {
// packed signed values
int32_t ps_a = Narrow<int16_t>(*i);
int32_t ps_b = Narrow<int16_t>(*j);
// packed unsigned values
int32_t pu_a = UnsignedNarrow<int16_t>(*i);
int32_t pu_b = UnsignedNarrow<int16_t>(*j);
// Sign-extend here, since ExtractLane sign extends.
if (packed_unsigned & 0x8000) packed_unsigned |= 0xFFFF0000;
CHECK_EQ(1, r.Call(*i, packed_signed, packed_unsigned));
if (pu_a & 0x8000) pu_a |= 0xFFFF0000;
if (pu_b & 0x8000) pu_b |= 0xFFFF0000;
CHECK_EQ(1, r.Call(*i, *j, ps_a, ps_b, pu_a, pu_b));
}
}
}
#endif // V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS ||
......@@ -1385,30 +1402,49 @@ WASM_SIMD_TEST(I8x16Neg) {
#if V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS || \
V8_TARGET_ARCH_MIPS64 || V8_TARGET_ARCH_IA32
// Tests both signed and unsigned conversion from I16x8 (packing).
WASM_SIMD_COMPILED_AND_LOWERED_TEST(I8x16ConvertI16x8) {
WasmRunner<int32_t, int32_t, int32_t, int32_t> r(execution_mode, lower_simd);
WASM_SIMD_TEST(I8x16ConvertI16x8) {
WasmRunner<int32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t> r(
execution_mode, lower_simd);
byte a = 0;
byte packed_signed = 1;
byte packed_unsigned = 2;
byte b = 1;
// indices for packed signed params
byte ps_a = 2;
byte ps_b = 3;
// indices for packed unsigned params
byte pu_a = 4;
byte pu_b = 5;
byte simd0 = r.AllocateLocal(kWasmS128);
byte simd1 = r.AllocateLocal(kWasmS128);
byte simd2 = r.AllocateLocal(kWasmS128);
BUILD(r, WASM_SET_LOCAL(simd0, WASM_SIMD_I16x8_SPLAT(WASM_GET_LOCAL(a))),
WASM_SET_LOCAL(simd1, WASM_SIMD_BINOP(kExprI8x16SConvertI16x8,
WASM_SET_LOCAL(simd1, WASM_SIMD_I16x8_SPLAT(WASM_GET_LOCAL(b))),
WASM_SET_LOCAL(simd2, WASM_SIMD_BINOP(kExprI8x16SConvertI16x8,
WASM_GET_LOCAL(simd0),
WASM_GET_LOCAL(simd0))),
WASM_SIMD_CHECK_SPLAT16(I8x16, simd1, I32, packed_signed),
WASM_GET_LOCAL(simd1))),
WASM_SIMD_CHECK16(I8x16, simd2, I32, ps_a, ps_a, ps_a, ps_a, ps_a, ps_a,
ps_a, ps_a, ps_b, ps_b, ps_b, ps_b, ps_b, ps_b, ps_b,
ps_b),
WASM_SET_LOCAL(simd2, WASM_SIMD_BINOP(kExprI8x16UConvertI16x8,
WASM_GET_LOCAL(simd0),
WASM_GET_LOCAL(simd0))),
WASM_SIMD_CHECK_SPLAT16(I8x16, simd2, I32, packed_unsigned), WASM_ONE);
WASM_GET_LOCAL(simd1))),
WASM_SIMD_CHECK16(I8x16, simd2, I32, pu_a, pu_a, pu_a, pu_a, pu_a, pu_a,
pu_a, pu_a, pu_b, pu_b, pu_b, pu_b, pu_b, pu_b, pu_b,
pu_b),
WASM_ONE);
FOR_INT16_INPUTS(i) {
int32_t packed_signed = Narrow<int8_t>(*i);
int32_t packed_unsigned = UnsignedNarrow<int8_t>(*i);
FOR_INT16_INPUTS(j) {
// packed signed values
int32_t ps_a = Narrow<int8_t>(*i);
int32_t ps_b = Narrow<int8_t>(*j);
// packed unsigned values
int32_t pu_a = UnsignedNarrow<int8_t>(*i);
int32_t pu_b = UnsignedNarrow<int8_t>(*j);
// Sign-extend here, since ExtractLane sign extends.
if (packed_unsigned & 0x80) packed_unsigned |= 0xFFFFFF00;
CHECK_EQ(1, r.Call(*i, packed_signed, packed_unsigned));
if (pu_a & 0x80) pu_a |= 0xFFFFFF00;
if (pu_b & 0x80) pu_b |= 0xFFFFFF00;
CHECK_EQ(1, r.Call(*i, *j, ps_a, ps_b, pu_a, pu_b));
}
}
}
#endif // V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_ARM64 || V8_TARGET_ARCH_MIPS ||
......
......@@ -304,7 +304,10 @@ void WasmFunctionWrapper::Init(CallDescriptor* call_descriptor,
// Function, context_address, effect, and control.
Node** parameters = zone()->NewArray<Node*>(param_types.length() + 4);
graph()->SetStart(graph()->NewNode(common()->Start(7)));
int start_value_output_count =
static_cast<int>(signature_->parameter_count()) + 1;
graph()->SetStart(
graph()->NewNode(common()->Start(start_value_output_count)));
Node* effect = graph()->start();
int parameter_count = 0;
......
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