[wasm-simd] Prototype i32x4.widen_i8x16_{s,u}
This prototypes i32x4.widen_i8x16_s and i32x4.widen_i8x16_u for the interpreter. This is the first instruction of its kind, a post-mvp, unary operation that takes one immediate. Which is why there are more changes to the decoder than usual. Bug: v8:11297 Change-Id: Ib5c58965e0cba8d7a395b0dc57673110bc60e87c Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2617385 Reviewed-by: Deepti Gandluri <gdeepti@chromium.org> Commit-Queue: Zhi An Ng <zhin@chromium.org> Cr-Commit-Position: refs/heads/master@{#72170}
This commit is contained in:
parent
f6450b97ec
commit
a1d39bbaed
@ -1453,6 +1453,8 @@ class WasmDecoder : public Decoder {
|
|||||||
case kExprI32x4ReplaceLane:
|
case kExprI32x4ReplaceLane:
|
||||||
case kExprS128Load32Lane:
|
case kExprS128Load32Lane:
|
||||||
case kExprS128Store32Lane:
|
case kExprS128Store32Lane:
|
||||||
|
case kExprI32x4WidenI8x16S:
|
||||||
|
case kExprI32x4WidenI8x16U:
|
||||||
num_lanes = 4;
|
num_lanes = 4;
|
||||||
break;
|
break;
|
||||||
case kExprI16x8ExtractLaneS:
|
case kExprI16x8ExtractLaneS:
|
||||||
@ -2029,6 +2031,7 @@ class WasmDecoder : public Decoder {
|
|||||||
opcode = this->read_prefixed_opcode<validate>(pc);
|
opcode = this->read_prefixed_opcode<validate>(pc);
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(DECLARE_OPCODE_CASE)
|
FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(DECLARE_OPCODE_CASE)
|
||||||
|
FOREACH_SIMD_POST_MVP_ONE_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
|
||||||
return {1, 1};
|
return {1, 1};
|
||||||
FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(DECLARE_OPCODE_CASE)
|
FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(DECLARE_OPCODE_CASE)
|
||||||
FOREACH_SIMD_MASK_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
|
FOREACH_SIMD_MASK_OPERAND_OPCODE(DECLARE_OPCODE_CASE)
|
||||||
@ -3746,6 +3749,10 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
|||||||
case kExprPrefetchNT: {
|
case kExprPrefetchNT: {
|
||||||
return SimdPrefetch(opcode_length, /*temporal=*/false);
|
return SimdPrefetch(opcode_length, /*temporal=*/false);
|
||||||
}
|
}
|
||||||
|
case kExprI32x4WidenI8x16S:
|
||||||
|
case kExprI32x4WidenI8x16U: {
|
||||||
|
return SimdExtractLane(opcode, kWasmS128, opcode_length);
|
||||||
|
}
|
||||||
default: {
|
default: {
|
||||||
const FunctionSig* sig = WasmOpcodes::Signature(opcode);
|
const FunctionSig* sig = WasmOpcodes::Signature(opcode);
|
||||||
if (!VALIDATE(sig != nullptr)) {
|
if (!VALIDATE(sig != nullptr)) {
|
||||||
|
@ -365,6 +365,9 @@ constexpr const char* WasmOpcodes::OpcodeName(WasmOpcode opcode) {
|
|||||||
CASE_OP(PrefetchT, "prefetch_t")
|
CASE_OP(PrefetchT, "prefetch_t")
|
||||||
CASE_OP(PrefetchNT, "prefetch_nt")
|
CASE_OP(PrefetchNT, "prefetch_nt")
|
||||||
|
|
||||||
|
CASE_I32x4_OP(WidenI8x16S, "widen_i8x16_s")
|
||||||
|
CASE_I32x4_OP(WidenI8x16U, "widen_i8x16_u")
|
||||||
|
|
||||||
// Atomic operations.
|
// Atomic operations.
|
||||||
CASE_OP(AtomicNotify, "atomic.notify")
|
CASE_OP(AtomicNotify, "atomic.notify")
|
||||||
CASE_INT_OP(AtomicWait, "atomic.wait")
|
CASE_INT_OP(AtomicWait, "atomic.wait")
|
||||||
@ -534,6 +537,7 @@ constexpr bool WasmOpcodes::IsSimdPostMvpOpcode(WasmOpcode opcode) {
|
|||||||
#define CHECK_OPCODE(name, opcode, _) case kExpr##name:
|
#define CHECK_OPCODE(name, opcode, _) case kExpr##name:
|
||||||
FOREACH_SIMD_POST_MVP_OPCODE(CHECK_OPCODE)
|
FOREACH_SIMD_POST_MVP_OPCODE(CHECK_OPCODE)
|
||||||
FOREACH_SIMD_POST_MVP_MEM_OPCODE(CHECK_OPCODE)
|
FOREACH_SIMD_POST_MVP_MEM_OPCODE(CHECK_OPCODE)
|
||||||
|
FOREACH_SIMD_POST_MVP_ONE_OPERAND_OPCODE(CHECK_OPCODE)
|
||||||
#undef CHECK_OPCODE
|
#undef CHECK_OPCODE
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
|
@ -516,6 +516,10 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
|
|||||||
V(F32x4RecipApprox, 0xfdb3, s_s) \
|
V(F32x4RecipApprox, 0xfdb3, s_s) \
|
||||||
V(F32x4RecipSqrtApprox, 0xfdbc, s_s)
|
V(F32x4RecipSqrtApprox, 0xfdbc, s_s)
|
||||||
|
|
||||||
|
#define FOREACH_SIMD_POST_MVP_ONE_OPERAND_OPCODE(V) \
|
||||||
|
V(I32x4WidenI8x16S, 0xfd67, s_s) \
|
||||||
|
V(I32x4WidenI8x16U, 0xfd68, s_s)
|
||||||
|
|
||||||
#define FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(V) \
|
#define FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(V) \
|
||||||
V(I8x16ExtractLaneS, 0xfd15, _) \
|
V(I8x16ExtractLaneS, 0xfd15, _) \
|
||||||
V(I8x16ExtractLaneU, 0xfd16, _) \
|
V(I8x16ExtractLaneU, 0xfd16, _) \
|
||||||
@ -540,7 +544,8 @@ bool V8_EXPORT_PRIVATE IsJSCompatibleSignature(const FunctionSig* sig,
|
|||||||
|
|
||||||
#define FOREACH_SIMD_1_OPERAND_OPCODE(V) \
|
#define FOREACH_SIMD_1_OPERAND_OPCODE(V) \
|
||||||
FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(V) \
|
FOREACH_SIMD_1_OPERAND_1_PARAM_OPCODE(V) \
|
||||||
FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(V)
|
FOREACH_SIMD_1_OPERAND_2_PARAM_OPCODE(V) \
|
||||||
|
FOREACH_SIMD_POST_MVP_ONE_OPERAND_OPCODE(V)
|
||||||
|
|
||||||
#define FOREACH_SIMD_OPCODE(V) \
|
#define FOREACH_SIMD_OPCODE(V) \
|
||||||
FOREACH_SIMD_0_OPERAND_OPCODE(V) \
|
FOREACH_SIMD_0_OPERAND_OPCODE(V) \
|
||||||
|
@ -2103,6 +2103,86 @@ WASM_SIMD_TEST(I32x4ShrU) {
|
|||||||
LogicalShiftRight);
|
LogicalShiftRight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if V8_TARGET_ARCH_X64
|
||||||
|
// TODO(v8:11297) Prototype i32x4.widen_i8x16_{u,s}
|
||||||
|
WASM_SIMD_TEST_NO_LOWERING(I32x4WidenI8x16U) {
|
||||||
|
// TODO(zhin): Add TurboFan support.
|
||||||
|
if (execution_tier != TestExecutionTier::kInterpreter) return;
|
||||||
|
FLAG_SCOPE(wasm_simd_post_mvp);
|
||||||
|
|
||||||
|
WasmRunner<uint32_t, uint32_t> r(execution_tier, lower_simd);
|
||||||
|
uint32_t* g0 = r.builder().AddGlobal<uint32_t>(kWasmS128);
|
||||||
|
uint32_t* g1 = r.builder().AddGlobal<uint32_t>(kWasmS128);
|
||||||
|
uint32_t* g2 = r.builder().AddGlobal<uint32_t>(kWasmS128);
|
||||||
|
uint32_t* g3 = r.builder().AddGlobal<uint32_t>(kWasmS128);
|
||||||
|
byte arg = 0;
|
||||||
|
|
||||||
|
#define COPY_PARAM_TO_I32X4_LANE(idx) \
|
||||||
|
WASM_SIMD_I32x4_REPLACE_LANE(idx, WASM_GLOBAL_GET(idx), WASM_LOCAL_GET(arg))
|
||||||
|
#define WIDEN(idx) WASM_SIMD_OP(kExprI32x4WidenI8x16U), idx, kExprGlobalSet, idx
|
||||||
|
BUILD(r,
|
||||||
|
// g0 = widen_u([arg, 0, 0, 0], 0)
|
||||||
|
COPY_PARAM_TO_I32X4_LANE(0), WIDEN(0),
|
||||||
|
// g1 = widen_u([0, arg, 0, 0], 1)
|
||||||
|
COPY_PARAM_TO_I32X4_LANE(1), WIDEN(1),
|
||||||
|
// g2 = widen_u([0, 0, arg, 0], 2)
|
||||||
|
COPY_PARAM_TO_I32X4_LANE(2), WIDEN(2),
|
||||||
|
// g3 = widen_u([0, 0, 0, arg], 3)
|
||||||
|
COPY_PARAM_TO_I32X4_LANE(3), WIDEN(3), WASM_ONE);
|
||||||
|
#undef WIDEN
|
||||||
|
#undef COPY_PARAM_TO_I32X4_LANE
|
||||||
|
|
||||||
|
FOR_UINT8_INPUTS(x) {
|
||||||
|
r.Call(x << 24 | x << 16 | x << 8 | x);
|
||||||
|
uint32_t expected = static_cast<uint32_t>(x);
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
CHECK_EQ(expected, ReadLittleEndianValue<uint32_t>(&g0[i]));
|
||||||
|
CHECK_EQ(expected, ReadLittleEndianValue<uint32_t>(&g1[i]));
|
||||||
|
CHECK_EQ(expected, ReadLittleEndianValue<uint32_t>(&g2[i]));
|
||||||
|
CHECK_EQ(expected, ReadLittleEndianValue<uint32_t>(&g3[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
WASM_SIMD_TEST_NO_LOWERING(I32x4WidenI8x16S) {
|
||||||
|
// TODO(zhin): Add TurboFan support.
|
||||||
|
if (execution_tier != TestExecutionTier::kInterpreter) return;
|
||||||
|
FLAG_SCOPE(wasm_simd_post_mvp);
|
||||||
|
|
||||||
|
WasmRunner<int32_t, int32_t> r(execution_tier, lower_simd);
|
||||||
|
int32_t* g0 = r.builder().AddGlobal<int32_t>(kWasmS128);
|
||||||
|
int32_t* g1 = r.builder().AddGlobal<int32_t>(kWasmS128);
|
||||||
|
int32_t* g2 = r.builder().AddGlobal<int32_t>(kWasmS128);
|
||||||
|
int32_t* g3 = r.builder().AddGlobal<int32_t>(kWasmS128);
|
||||||
|
byte arg = 0;
|
||||||
|
#define COPY_PARAM_TO_I32X4_LANE(idx) \
|
||||||
|
WASM_SIMD_I32x4_REPLACE_LANE(idx, WASM_GLOBAL_GET(idx), WASM_LOCAL_GET(arg))
|
||||||
|
#define WIDEN(idx) WASM_SIMD_OP(kExprI32x4WidenI8x16S), idx, kExprGlobalSet, idx
|
||||||
|
BUILD(r,
|
||||||
|
// g0 = widen_s([arg, 0, 0, 0], 0)
|
||||||
|
COPY_PARAM_TO_I32X4_LANE(0), WIDEN(0),
|
||||||
|
// g1 = widen_s([0, arg, 0, 0], 1)
|
||||||
|
COPY_PARAM_TO_I32X4_LANE(1), WIDEN(1),
|
||||||
|
// g2 = widen_s([0, 0, arg, 0], 2)
|
||||||
|
COPY_PARAM_TO_I32X4_LANE(2), WIDEN(2),
|
||||||
|
// g3 = widen_s([0, 0, 0, arg], 3)
|
||||||
|
COPY_PARAM_TO_I32X4_LANE(3), WIDEN(3), WASM_ONE);
|
||||||
|
#undef WIDEN
|
||||||
|
#undef COPY_PARAM_TO_I32X4_LANE
|
||||||
|
|
||||||
|
FOR_UINT8_INPUTS(x) {
|
||||||
|
r.Call(x << 24 | x << 16 | x << 8 | x);
|
||||||
|
int32_t expected_signed = static_cast<int32_t>(bit_cast<int8_t>((x)));
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
CHECK_EQ(expected_signed, ReadLittleEndianValue<int32_t>(&g0[i]));
|
||||||
|
CHECK_EQ(expected_signed, ReadLittleEndianValue<int32_t>(&g1[i]));
|
||||||
|
CHECK_EQ(expected_signed, ReadLittleEndianValue<int32_t>(&g2[i]));
|
||||||
|
CHECK_EQ(expected_signed, ReadLittleEndianValue<int32_t>(&g3[i]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // V8_TARGET_ARCH_X64
|
||||||
|
|
||||||
// Tests both signed and unsigned conversion from I8x16 (unpacking).
|
// Tests both signed and unsigned conversion from I8x16 (unpacking).
|
||||||
WASM_SIMD_TEST(I16x8ConvertI8x16) {
|
WASM_SIMD_TEST(I16x8ConvertI8x16) {
|
||||||
WasmRunner<int32_t, int32_t> r(execution_tier, lower_simd);
|
WasmRunner<int32_t, int32_t> r(execution_tier, lower_simd);
|
||||||
|
@ -28,6 +28,7 @@
|
|||||||
#include "src/wasm/wasm-module.h"
|
#include "src/wasm/wasm-module.h"
|
||||||
#include "src/wasm/wasm-objects-inl.h"
|
#include "src/wasm/wasm-objects-inl.h"
|
||||||
#include "src/wasm/wasm-opcodes-inl.h"
|
#include "src/wasm/wasm-opcodes-inl.h"
|
||||||
|
#include "src/wasm/wasm-opcodes.h"
|
||||||
#include "src/zone/accounting-allocator.h"
|
#include "src/zone/accounting-allocator.h"
|
||||||
#include "src/zone/zone-containers.h"
|
#include "src/zone/zone-containers.h"
|
||||||
|
|
||||||
@ -2098,6 +2099,25 @@ class WasmInterpreterInternals {
|
|||||||
bool ExecuteSimdOp(WasmOpcode opcode, Decoder* decoder, InterpreterCode* code,
|
bool ExecuteSimdOp(WasmOpcode opcode, Decoder* decoder, InterpreterCode* code,
|
||||||
pc_t pc, int* const len) {
|
pc_t pc, int* const len) {
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
|
#define WIDEN_CASE(op, expr) \
|
||||||
|
case op: { \
|
||||||
|
uint8_t lane = \
|
||||||
|
decoder->read_u8<Decoder::kNoValidation>(code->at(pc + *len), "lane"); \
|
||||||
|
*len += 1; \
|
||||||
|
int16 s = Pop().to_s128().to_i8x16(); \
|
||||||
|
int4 r; \
|
||||||
|
for (int i = 0; i < 4; i++) { \
|
||||||
|
auto x = s.val[LANE(lane * 4 + i, s)]; \
|
||||||
|
r.val[LANE(i, r)] = expr; \
|
||||||
|
} \
|
||||||
|
Push(WasmValue(Simd128(r))); \
|
||||||
|
return true; \
|
||||||
|
}
|
||||||
|
WIDEN_CASE(kExprI32x4WidenI8x16S, static_cast<int32_t>(x))
|
||||||
|
WIDEN_CASE(kExprI32x4WidenI8x16U,
|
||||||
|
static_cast<int32_t>(bit_cast<uint8_t>(x)))
|
||||||
|
#undef WIDEN_CASE
|
||||||
|
|
||||||
#define SPLAT_CASE(format, sType, valType, num) \
|
#define SPLAT_CASE(format, sType, valType, num) \
|
||||||
case kExpr##format##Splat: { \
|
case kExpr##format##Splat: { \
|
||||||
WasmValue val = Pop(); \
|
WasmValue val = Pop(); \
|
||||||
|
Loading…
Reference in New Issue
Block a user