From 47e0d126af2eae63a791f1f380b9c95c54d3dc4b Mon Sep 17 00:00:00 2001 From: HyukWoo Park Date: Thu, 13 Jul 2023 19:04:32 +0900 Subject: [PATCH] Refactor definition of SIMD binary and unary instructions Signed-off-by: HyukWoo Park --- src/interpreter/ByteCode.h | 79 +-- src/interpreter/Interpreter.cpp | 718 +++++++----------------- test/wasm-spec/core/simd/simd_load.wast | 188 +++++++ 3 files changed, 416 insertions(+), 569 deletions(-) create mode 100644 test/wasm-spec/core/simd/simd_load.wast diff --git a/src/interpreter/ByteCode.h b/src/interpreter/ByteCode.h index 82b9f648d..95ab51d37 100644 --- a/src/interpreter/ByteCode.h +++ b/src/interpreter/ByteCode.h @@ -357,24 +357,25 @@ class FunctionType; F(I64X2ShrS, intShr, int64_t) \ F(I64X2ShrU, intShr, uint64_t) -#define FOR_EACH_BYTECODE_SIMD_BINARY_OTHER(F) \ - F(I16X8ExtmulLowI8X16S) \ - F(I16X8ExtmulHighI8X16S) \ - F(I16X8ExtmulLowI8X16U) \ - F(I16X8ExtmulHighI8X16U) \ - F(I32X4ExtmulLowI16X8S) \ - F(I32X4ExtmulHighI16X8S) \ - F(I32X4ExtmulLowI16X8U) \ - F(I32X4ExtmulHighI16X8U) \ - F(I64X2ExtmulLowI32X4S) \ - F(I64X2ExtmulHighI32X4S) \ - F(I64X2ExtmulLowI32X4U) \ - F(I64X2ExtmulHighI32X4U) \ - F(I32X4DotI16X8S) \ - F(I8X16NarrowI16X8S) \ - F(I8X16NarrowI16X8U) \ - F(I16X8NarrowI32X4S) \ - F(I16X8NarrowI32X4U) +#define FOR_EACH_BYTECODE_SIMD_BINARY_OTHER(F) \ + F(I8X16Swizzle, (simdSwizzleOperation)) \ + F(I16X8ExtmulLowI8X16S, (simdExtmulOperation)) \ + F(I16X8ExtmulHighI8X16S, (simdExtmulOperation)) \ + F(I16X8ExtmulLowI8X16U, (simdExtmulOperation)) \ + F(I16X8ExtmulHighI8X16U, (simdExtmulOperation)) \ + F(I32X4ExtmulLowI16X8S, (simdExtmulOperation)) \ + F(I32X4ExtmulHighI16X8S, (simdExtmulOperation)) \ + F(I32X4ExtmulLowI16X8U, (simdExtmulOperation)) \ + F(I32X4ExtmulHighI16X8U, (simdExtmulOperation)) \ + F(I64X2ExtmulLowI32X4S, (simdExtmulOperation)) \ + F(I64X2ExtmulHighI32X4S, (simdExtmulOperation)) \ + F(I64X2ExtmulLowI32X4U, (simdExtmulOperation)) \ + F(I64X2ExtmulHighI32X4U, (simdExtmulOperation)) \ + F(I32X4DotI16X8S, (simdDotOperation)) \ + F(I8X16NarrowI16X8S, (simdNarrowOperation)) \ + F(I8X16NarrowI16X8U, (simdNarrowOperation)) \ + F(I16X8NarrowI32X4S, (simdNarrowOperation)) \ + F(I16X8NarrowI32X4U, (simdNarrowOperation)) #define FOR_EACH_BYTECODE_SIMD_UNARY_OP(F) \ F(I8X16Neg, intNeg, uint8_t) \ @@ -418,27 +419,27 @@ class FunctionType; F(F64X2ConvertLowI32X4S, int32_t, double, true) \ F(F64X2ConvertLowI32X4U, uint32_t, double, true) -#define FOR_EACH_BYTECODE_SIMD_UNARY_OTHER(F) \ - F(V128AnyTrue) \ - F(I8X16Bitmask) \ - F(I8X16AllTrue) \ - F(I16X8Bitmask) \ - F(I16X8AllTrue) \ - F(I32X4Bitmask) \ - F(I32X4AllTrue) \ - F(I64X2Bitmask) \ - F(I64X2AllTrue) \ - F(I16X8ExtaddPairwiseI8X16S) \ - F(I16X8ExtaddPairwiseI8X16U) \ - F(I32X4ExtaddPairwiseI16X8S) \ - F(I32X4ExtaddPairwiseI16X8U) \ - F(I32X4TruncSatF32X4S) \ - F(I32X4TruncSatF32X4U) \ - F(I32X4TruncSatF64X2SZero) \ - F(I32X4TruncSatF64X2UZero) \ - F(F32X4ConvertI32X4S) \ - F(F32X4ConvertI32X4U) \ - F(F32X4DemoteF64X2Zero) +#define FOR_EACH_BYTECODE_SIMD_UNARY_OTHER(F) \ + F(V128AnyTrue, (simdAnyTrueOperation)) \ + F(I8X16Bitmask, (simdBitmaskOperation)) \ + F(I8X16AllTrue, (simdAllTrueOperation)) \ + F(I16X8Bitmask, (simdBitmaskOperation)) \ + F(I16X8AllTrue, (simdAllTrueOperation)) \ + F(I32X4Bitmask, (simdBitmaskOperation)) \ + F(I32X4AllTrue, (simdAllTrueOperation)) \ + F(I64X2Bitmask, (simdBitmaskOperation)) \ + F(I64X2AllTrue, (simdAllTrueOperation)) \ + F(I16X8ExtaddPairwiseI8X16S, (simdExtaddPairwiseOperation)) \ + F(I16X8ExtaddPairwiseI8X16U, (simdExtaddPairwiseOperation)) \ + F(I32X4ExtaddPairwiseI16X8S, (simdExtaddPairwiseOperation)) \ + F(I32X4ExtaddPairwiseI16X8U, (simdExtaddPairwiseOperation)) \ + F(I32X4TruncSatF32X4S, (simdTruncSatOperation)) \ + F(I32X4TruncSatF32X4U, (simdTruncSatOperation)) \ + F(I32X4TruncSatF64X2SZero, (simdTruncSatZeroOperation)) \ + F(I32X4TruncSatF64X2UZero, (simdTruncSatZeroOperation)) \ + F(F32X4ConvertI32X4S, (simdConvertOperation)) \ + F(F32X4ConvertI32X4U, (simdConvertOperation)) \ + F(F32X4DemoteF64X2Zero, (simdDemoteZeroOperation)) #define FOR_EACH_BYTECODE_SIMD_LOAD_SPLAT_OP(F) \ F(V128Load8Splat, uint8_t) \ diff --git a/src/interpreter/Interpreter.cpp b/src/interpreter/Interpreter.cpp index f33577836..9e86ea2e9 100644 --- a/src/interpreter/Interpreter.cpp +++ b/src/interpreter/Interpreter.cpp @@ -194,6 +194,8 @@ ALWAYS_INLINE T readValue(uint8_t* bp, ByteCodeStackOffset offset) return *reinterpret_cast(bp + offset); } +// SIMD helper function + template bool intEqz(T val) { return val == 0; } template @@ -283,6 +285,172 @@ R doConvert(ExecutionState& state, T val) return convert(val); } +template +inline static void simdSwizzleOperation(ExecutionState& state, BinaryOperation* code, uint8_t* bp) +{ + using Type = typename SIMDType::Type; + auto lhs = readValue(bp, code->srcOffset()[0]); + auto rhs = readValue(bp, code->srcOffset()[1]); + Type result; + for (uint8_t i = 0; i < Type::Lanes; i++) { + result[i] = rhs[i] < Type::Lanes ? lhs[rhs[i]] : 0; + } + writeValue(bp, code->dstOffset(), result); +} + +// FIXME optimize this function +template +inline static void simdExtmulOperation(ExecutionState& state, BinaryOperation* code, uint8_t* bp) +{ + using ParamType = typename SIMDType

::Type; + using ResultType = typename SIMDType::Type; + auto lhs = readValue(bp, code->srcOffset()[0]); + auto rhs = readValue(bp, code->srcOffset()[1]); + ResultType result; + for (uint8_t i = 0; i < ResultType::Lanes; i++) { + uint8_t laneIdx = (Low ? 0 : ResultType::Lanes) + i; + result[i] = static_cast(lhs[laneIdx]) * static_cast(rhs[laneIdx]); + } + writeValue(bp, code->dstOffset(), result); +} + +inline static void simdDotOperation(ExecutionState& state, BinaryOperation* code, uint8_t* bp) +{ + using ParamType = typename SIMDType::Type; + using ResultType = typename SIMDType::Type; + auto lhs = readValue(bp, code->srcOffset()[0]); + auto rhs = readValue(bp, code->srcOffset()[1]); + ResultType result; + for (uint8_t i = 0; i < ResultType::Lanes; i++) { + uint8_t laneIdx = i * 2; + uint32_t lo = static_cast(lhs[laneIdx]) * static_cast(rhs[laneIdx]); + uint32_t hi = static_cast(lhs[laneIdx + 1]) * static_cast(rhs[laneIdx + 1]); + result[i] = add(state, lo, hi); + } + writeValue(bp, code->dstOffset(), result); +} + +template +inline static void simdNarrowOperation(ExecutionState& state, BinaryOperation* code, uint8_t* bp) +{ + using ParamType = typename SIMDType

::Type; + using ResultType = typename SIMDType::Type; + auto lhs = readValue(bp, code->srcOffset()[0]); + auto rhs = readValue(bp, code->srcOffset()[1]); + ResultType result; + for (uint8_t i = 0; i < ParamType::Lanes; i++) { + result[i] = saturate(lhs[i]); + } + for (uint8_t i = 0; i < ParamType::Lanes; i++) { + result[ParamType::Lanes + i] = saturate(rhs[i]); + } + writeValue(bp, code->dstOffset(), result); +} + +inline static void simdAnyTrueOperation(ExecutionState& state, UnaryOperation* code, uint8_t* bp) +{ + using Type = typename SIMDType::Type; + auto val = readValue(bp, code->srcOffset()); + uint32_t result = (std::count_if(std::begin(val.v), std::end(val.v), [](uint8_t x) { return x != 0; }) >= 1); + writeValue(bp, code->dstOffset(), result); +} + +template +inline static void simdBitmaskOperation(ExecutionState& state, UnaryOperation* code, uint8_t* bp) +{ + using Type = typename SIMDType::Type; + auto val = readValue(bp, code->srcOffset()); + uint32_t result = 0; + for (uint8_t i = 0; i < Type::Lanes; i++) { + if (val[i] < 0) { + result |= 1 << i; + } + } + writeValue(bp, code->dstOffset(), result); +} + +template +inline static void simdAllTrueOperation(ExecutionState& state, UnaryOperation* code, uint8_t* bp) +{ + using Type = typename SIMDType::Type; + auto val = readValue(bp, code->srcOffset()); + uint32_t result = (std::count_if(std::begin(val.v), std::end(val.v), [](uint8_t x) { return x != 0; }) >= Count); + writeValue(bp, code->dstOffset(), result); +} + +template +inline static void simdExtaddPairwiseOperation(ExecutionState& state, UnaryOperation* code, uint8_t* bp) +{ + using ParamType = typename SIMDType

::Type; + using ResultType = typename SIMDType::Type; + auto val = readValue(bp, code->srcOffset()); + ResultType result; + for (uint8_t i = 0; i < ResultType::Lanes; i++) { + uint8_t laneIdx = i * 2; + result[i] = static_cast(val[laneIdx]) + static_cast(val[laneIdx + 1]); + } + writeValue(bp, code->dstOffset(), result); +} + +template +inline static void simdTruncSatOperation(ExecutionState& state, UnaryOperation* code, uint8_t* bp) +{ + using ParamType = typename SIMDType

::Type; + using ResultType = typename SIMDType::Type; + auto val = readValue(bp, code->srcOffset()); + ResultType result; + for (uint8_t i = 0; i < ParamType::Lanes; i++) { + result[i] = intTruncSat(state, val[i]); + } + writeValue(bp, code->dstOffset(), result); +} + +template +inline static void simdTruncSatZeroOperation(ExecutionState& state, UnaryOperation* code, uint8_t* bp) +{ + // FIXME init result vector with zeros + using ParamType = typename SIMDType

::Type; + using ResultType = typename SIMDType::Type; + auto val = readValue(bp, code->srcOffset()); + ResultType result; + for (uint8_t i = 0; i < ParamType::Lanes; i++) { + result[i] = intTruncSat(state, val[i]); + } + for (uint8_t i = ParamType::Lanes; i < ResultType::Lanes; i++) { + result[i] = 0; + } + writeValue(bp, code->dstOffset(), result); +} + +template +inline static void simdConvertOperation(ExecutionState& state, UnaryOperation* code, uint8_t* bp) +{ + using ParamType = typename SIMDType

::Type; + using ResultType = typename SIMDType::Type; + auto val = readValue(bp, code->srcOffset()); + ResultType result; + for (uint8_t i = 0; i < ResultType::Lanes; i++) { + result[i] = convert(val[i]); + } + writeValue(bp, code->dstOffset(), result); +} + +inline static void simdDemoteZeroOperation(ExecutionState& state, UnaryOperation* code, uint8_t* bp) +{ + using ParamType = typename SIMDType::Type; + using ResultType = typename SIMDType::Type; + auto val = readValue(bp, code->srcOffset()); + ResultType result; + for (uint8_t i = 0; i < ParamType::Lanes; i++) { + result[i] = convert(val[i]); + } + for (uint8_t i = ParamType::Lanes; i < ResultType::Lanes; i++) { + result[i] = 0; + } + writeValue(bp, code->dstOffset(), result); +} + + #if defined(WALRUS_ENABLE_COMPUTED_GOTO) static void initAddressToOpcodeTable() { @@ -373,6 +541,15 @@ ByteCodeStackOffset* Interpreter::interpret(ExecutionState& state, NEXT_INSTRUCTION(); \ } +#define SIMD_BINARY_OTHER_OPERATION(name, op) \ + DEFINE_OPCODE(name) \ + : \ + { \ + op(state, (BinaryOperation*)programCounter, bp); \ + ADD_PROGRAM_COUNTER(BinaryOperation); \ + NEXT_INSTRUCTION(); \ + } + #define SIMD_UNARY_OPERATION(name, op, type) \ DEFINE_OPCODE(name) \ : \ @@ -406,6 +583,15 @@ ByteCodeStackOffset* Interpreter::interpret(ExecutionState& state, NEXT_INSTRUCTION(); \ } +#define SIMD_UNARY_OTHER_OPERATION(name, op) \ + DEFINE_OPCODE(name) \ + : \ + { \ + op(state, (UnaryOperation*)programCounter, bp); \ + ADD_PROGRAM_COUNTER(UnaryOperation); \ + NEXT_INSTRUCTION(); \ + } + #define MEMORY_LOAD_OPERATION(opcodeName, readType, writeType) \ DEFINE_OPCODE(opcodeName) \ : \ @@ -638,538 +824,10 @@ ByteCodeStackOffset* Interpreter::interpret(ExecutionState& state, FOR_EACH_BYTECODE_UNARY_OP_2(UNARY_OPERATION_2) FOR_EACH_BYTECODE_SIMD_BINARY_OP(SIMD_BINARY_OPERATION) FOR_EACH_BYTECODE_SIMD_BINARY_SHIFT_OP(SIMD_BINARY_SHIFT_OPERATION) + FOR_EACH_BYTECODE_SIMD_BINARY_OTHER(SIMD_BINARY_OTHER_OPERATION) FOR_EACH_BYTECODE_SIMD_UNARY_OP(SIMD_UNARY_OPERATION) FOR_EACH_BYTECODE_SIMD_UNARY_CONVERT_OP(SIMD_UNARY_CONVERT_OPERATION) - - // FIXME optimize this macro -#define SIMD_EXTMUL_OPERATION(PT, RT, LOW) \ - using ParamType = typename SIMDType::Type; \ - using ResultType = typename SIMDType::Type; \ - BinaryOperation* code = (BinaryOperation*)programCounter; \ - auto lhs = readValue(bp, code->srcOffset()[0]); \ - auto rhs = readValue(bp, code->srcOffset()[1]); \ - ResultType result; \ - for (uint8_t i = 0; i < ResultType::Lanes; i++) { \ - uint8_t laneIdx = (LOW ? 0 : ResultType::Lanes) + i; \ - result[i] = static_cast(lhs[laneIdx]) * static_cast(rhs[laneIdx]); \ - } \ - writeValue(bp, code->dstOffset(), result); - - - DEFINE_OPCODE(I16X8ExtmulLowI8X16S) - : - { - SIMD_EXTMUL_OPERATION(int8_t, int16_t, true) - ADD_PROGRAM_COUNTER(I16X8ExtmulLowI8X16S); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I16X8ExtmulHighI8X16S) - : - { - SIMD_EXTMUL_OPERATION(int8_t, int16_t, false) - ADD_PROGRAM_COUNTER(I16X8ExtmulHighI8X16S); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I16X8ExtmulLowI8X16U) - : - { - SIMD_EXTMUL_OPERATION(uint8_t, uint16_t, true) - ADD_PROGRAM_COUNTER(I16X8ExtmulLowI8X16U); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I16X8ExtmulHighI8X16U) - : - { - SIMD_EXTMUL_OPERATION(uint8_t, uint16_t, false) - ADD_PROGRAM_COUNTER(I16X8ExtmulHighI8X16U); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4ExtmulLowI16X8S) - : - { - SIMD_EXTMUL_OPERATION(int16_t, int32_t, true) - ADD_PROGRAM_COUNTER(I32X4ExtmulLowI16X8S); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4ExtmulHighI16X8S) - : - { - SIMD_EXTMUL_OPERATION(int16_t, int32_t, false) - ADD_PROGRAM_COUNTER(I32X4ExtmulHighI16X8S); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4ExtmulLowI16X8U) - : - { - SIMD_EXTMUL_OPERATION(uint16_t, uint32_t, true) - ADD_PROGRAM_COUNTER(I32X4ExtmulLowI16X8U); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4ExtmulHighI16X8U) - : - { - SIMD_EXTMUL_OPERATION(uint16_t, uint32_t, false) - ADD_PROGRAM_COUNTER(I32X4ExtmulHighI16X8U); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I64X2ExtmulLowI32X4S) - : - { - SIMD_EXTMUL_OPERATION(int32_t, int64_t, true) - ADD_PROGRAM_COUNTER(I64X2ExtmulLowI32X4S); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I64X2ExtmulHighI32X4S) - : - { - SIMD_EXTMUL_OPERATION(int32_t, int64_t, false) - ADD_PROGRAM_COUNTER(I64X2ExtmulHighI32X4S); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I64X2ExtmulLowI32X4U) - : - { - SIMD_EXTMUL_OPERATION(uint32_t, uint64_t, true) - ADD_PROGRAM_COUNTER(I64X2ExtmulLowI32X4U); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I64X2ExtmulHighI32X4U) - : - { - SIMD_EXTMUL_OPERATION(uint32_t, uint64_t, false) - ADD_PROGRAM_COUNTER(I64X2ExtmulHighI32X4U); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4DotI16X8S) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - I32X4DotI16X8S* code = (I32X4DotI16X8S*)programCounter; - auto lhs = readValue(bp, code->srcOffset()[0]); - auto rhs = readValue(bp, code->srcOffset()[1]); - ResultType result; - for (uint8_t i = 0; i < ResultType::Lanes; i++) { - uint8_t laneIdx = i * 2; - uint32_t lo = static_cast(lhs[laneIdx]) * static_cast(rhs[laneIdx]); - uint32_t hi = static_cast(lhs[laneIdx + 1]) * static_cast(rhs[laneIdx + 1]); - result[i] = add(state, lo, hi); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(I32X4DotI16X8S); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I8X16NarrowI16X8S) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - BinaryOperation* code = (BinaryOperation*)programCounter; - auto lhs = readValue(bp, code->srcOffset()[0]); - auto rhs = readValue(bp, code->srcOffset()[1]); - ResultType result; - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[i] = saturate(lhs[i]); - } - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[ParamType::Lanes + i] = saturate(rhs[i]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(BinaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I8X16NarrowI16X8U) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - BinaryOperation* code = (BinaryOperation*)programCounter; - auto lhs = readValue(bp, code->srcOffset()[0]); - auto rhs = readValue(bp, code->srcOffset()[1]); - ResultType result; - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[i] = saturate(lhs[i]); - } - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[ParamType::Lanes + i] = saturate(rhs[i]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(BinaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I16X8NarrowI32X4S) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - BinaryOperation* code = (BinaryOperation*)programCounter; - auto lhs = readValue(bp, code->srcOffset()[0]); - auto rhs = readValue(bp, code->srcOffset()[1]); - ResultType result; - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[i] = saturate(lhs[i]); - } - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[ParamType::Lanes + i] = saturate(rhs[i]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(BinaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I16X8NarrowI32X4U) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - BinaryOperation* code = (BinaryOperation*)programCounter; - auto lhs = readValue(bp, code->srcOffset()[0]); - auto rhs = readValue(bp, code->srcOffset()[1]); - ResultType result; - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[i] = saturate(lhs[i]); - } - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[ParamType::Lanes + i] = saturate(rhs[i]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(BinaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(V128AnyTrue) - : - { - using Type = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - uint32_t result = (std::count_if(std::begin(val.v), std::end(val.v), [](uint8_t x) { return x != 0; }) >= 1); - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I8X16Bitmask) - : - { - using Type = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - uint32_t result = 0; - for (uint8_t i = 0; i < Type::Lanes; i++) { - if (val[i] < 0) { - result |= 1 << i; - } - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I8X16AllTrue) - : - { - using Type = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - uint32_t result = (std::count_if(std::begin(val.v), std::end(val.v), [](uint8_t x) { return x != 0; }) >= 16); - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I16X8Bitmask) - : - { - using Type = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - uint32_t result = 0; - for (uint8_t i = 0; i < Type::Lanes; i++) { - if (val[i] < 0) { - result |= 1 << i; - } - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I16X8AllTrue) - : - { - using Type = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - uint32_t result = (std::count_if(std::begin(val.v), std::end(val.v), [](uint8_t x) { return x != 0; }) >= 8); - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4Bitmask) - : - { - using Type = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - uint32_t result = 0; - for (uint8_t i = 0; i < Type::Lanes; i++) { - if (val[i] < 0) { - result |= 1 << i; - } - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4AllTrue) - : - { - using Type = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - uint32_t result = (std::count_if(std::begin(val.v), std::end(val.v), [](uint8_t x) { return x != 0; }) >= 4); - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I64X2Bitmask) - : - { - using Type = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - uint32_t result = 0; - for (uint8_t i = 0; i < Type::Lanes; i++) { - if (val[i] < 0) { - result |= 1 << i; - } - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I64X2AllTrue) - : - { - using Type = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - uint32_t result = (std::count_if(std::begin(val.v), std::end(val.v), [](uint8_t x) { return x != 0; }) >= 2); - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I16X8ExtaddPairwiseI8X16S) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - I16X8ExtaddPairwiseI8X16S* code = (I16X8ExtaddPairwiseI8X16S*)programCounter; - auto val = readValue(bp, code->srcOffset()); - ResultType result; - for (uint8_t i = 0; i < ResultType::Lanes; i++) { - uint8_t laneIdx = i * 2; - result[i] = static_cast(val[laneIdx]) + static_cast(val[laneIdx + 1]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(I16X8ExtaddPairwiseI8X16S); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I16X8ExtaddPairwiseI8X16U) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - I16X8ExtaddPairwiseI8X16U* code = (I16X8ExtaddPairwiseI8X16U*)programCounter; - auto val = readValue(bp, code->srcOffset()); - ResultType result; - for (uint8_t i = 0; i < ResultType::Lanes; i++) { - uint8_t laneIdx = i * 2; - result[i] = static_cast(val[laneIdx]) + static_cast(val[laneIdx + 1]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(I16X8ExtaddPairwiseI8X16U); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4ExtaddPairwiseI16X8S) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - I32X4ExtaddPairwiseI16X8S* code = (I32X4ExtaddPairwiseI16X8S*)programCounter; - auto val = readValue(bp, code->srcOffset()); - ResultType result; - for (uint8_t i = 0; i < ResultType::Lanes; i++) { - uint8_t laneIdx = i * 2; - result[i] = static_cast(val[laneIdx]) + static_cast(val[laneIdx + 1]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(I32X4ExtaddPairwiseI16X8S); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4ExtaddPairwiseI16X8U) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - I32X4ExtaddPairwiseI16X8U* code = (I32X4ExtaddPairwiseI16X8U*)programCounter; - auto val = readValue(bp, code->srcOffset()); - ResultType result; - for (uint8_t i = 0; i < ResultType::Lanes; i++) { - uint8_t laneIdx = i * 2; - result[i] = static_cast(val[laneIdx]) + static_cast(val[laneIdx + 1]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(I32X4ExtaddPairwiseI16X8U); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4TruncSatF32X4S) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - I32X4TruncSatF32X4S* code = (I32X4TruncSatF32X4S*)programCounter; - auto val = readValue(bp, code->srcOffset()); - ResultType result; - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[i] = intTruncSat(state, val[i]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(I32X4TruncSatF32X4S); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4TruncSatF32X4U) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - I32X4TruncSatF32X4U* code = (I32X4TruncSatF32X4U*)programCounter; - auto val = readValue(bp, code->srcOffset()); - ResultType result; - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[i] = intTruncSat(state, val[i]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(I32X4TruncSatF32X4U); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4TruncSatF64X2SZero) - : - { - // FIXME init result vector with zeros - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - I32X4TruncSatF64X2SZero* code = (I32X4TruncSatF64X2SZero*)programCounter; - auto val = readValue(bp, code->srcOffset()); - ResultType result; - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[i] = intTruncSat(state, val[i]); - } - for (uint8_t i = ParamType::Lanes; i < ResultType::Lanes; i++) { - result[i] = 0; - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(I32X4TruncSatF64X2SZero); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(I32X4TruncSatF64X2UZero) - : - { - // FIXME init result vector with zeros - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - I32X4TruncSatF64X2UZero* code = (I32X4TruncSatF64X2UZero*)programCounter; - auto val = readValue(bp, code->srcOffset()); - ResultType result; - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[i] = intTruncSat(state, val[i]); - } - for (uint8_t i = ParamType::Lanes; i < ResultType::Lanes; i++) { - result[i] = 0; - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(I32X4TruncSatF64X2UZero); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(F32X4ConvertI32X4S) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - ResultType result; - for (uint8_t i = 0; i < ResultType::Lanes; i++) { - result[i] = convert(val[i]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(F32X4ConvertI32X4U) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - ResultType result; - for (uint8_t i = 0; i < ResultType::Lanes; i++) { - result[i] = convert(val[i]); - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } - - DEFINE_OPCODE(F32X4DemoteF64X2Zero) - : - { - using ParamType = typename SIMDType::Type; - using ResultType = typename SIMDType::Type; - UnaryOperation* code = (UnaryOperation*)programCounter; - auto val = readValue(bp, code->srcOffset()); - ResultType result; - for (uint8_t i = 0; i < ParamType::Lanes; i++) { - result[i] = convert(val[i]); - } - for (uint8_t i = ParamType::Lanes; i < ResultType::Lanes; i++) { - result[i] = 0; - } - writeValue(bp, code->dstOffset(), result); - ADD_PROGRAM_COUNTER(UnaryOperation); - NEXT_INSTRUCTION(); - } + FOR_EACH_BYTECODE_SIMD_UNARY_OTHER(SIMD_UNARY_OTHER_OPERATION) DEFINE_OPCODE(Jump) : diff --git a/test/wasm-spec/core/simd/simd_load.wast b/test/wasm-spec/core/simd/simd_load.wast new file mode 100644 index 000000000..4b2edc160 --- /dev/null +++ b/test/wasm-spec/core/simd/simd_load.wast @@ -0,0 +1,188 @@ +;; v128.load operater with normal argument (e.g. (i8x16, i16x8 i32x4)) + +(module + (memory 1) + (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\00\01\02\03") + (func (export "v128.load") (result v128) + (v128.load (i32.const 0)) + ) +) + +(assert_return (invoke "v128.load") (v128.const i8x16 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08 0x09 0x0a 0x0b 0x0c 0x0d 0x0e 0x0f)) +(assert_return (invoke "v128.load") (v128.const i16x8 0x0100 0x0302 0x0504 0x0706 0x0908 0x0b0a 0x0d0c 0x0f0e)) +(assert_return (invoke "v128.load") (v128.const i32x4 0x03020100 0x07060504 0x0b0a0908 0x0f0e0d0c)) + + +;; v128.load operater as the argument of other SIMD instructions + +(module (memory 1) + (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\00\01\02\03") + (func (export "as-i8x16_extract_lane_s-value/0") (result i32) + (i8x16.extract_lane_s 0 (v128.load (i32.const 0))) + ) +) +(assert_return (invoke "as-i8x16_extract_lane_s-value/0") (i32.const 0x00)) + +(module (memory 1) + (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\00\01\02\03") + (func (export "as-i8x16.eq-operand") (result v128) + (i8x16.eq (v128.load offset=0 (i32.const 0)) (v128.load offset=16 (i32.const 0))) + ) +) +(assert_return (invoke "as-i8x16.eq-operand") (v128.const i32x4 0xffffffff 0x00000000 0x00000000 0x00000000)) + +(module (memory 1) + (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\00\01\02\03") + (func (export "as-v128.not-operand") (result v128) + (v128.not (v128.load (i32.const 0))) + ) + (func (export "as-i8x16.all_true-operand") (result i32) + (i8x16.all_true (v128.load (i32.const 0))) + ) +) +(assert_return (invoke "as-v128.not-operand") (v128.const i32x4 0xfcfdfeff 0xf8f9fafb 0xf4f5f6f7 0xf0f1f2f3)) +(assert_return (invoke "as-i8x16.all_true-operand") (i32.const 0)) + +(module (memory 1) + (data (offset (i32.const 0)) "\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA") + (data (offset (i32.const 16)) "\BB\BB\BB\BB\BB\BB\BB\BB\BB\BB\BB\BB\BB\BB\BB\BB") + (data (offset (i32.const 32)) "\F0\F0\F0\F0\FF\FF\FF\FF\00\00\00\00\FF\00\FF\00") + (func (export "as-v128.bitselect-operand") (result v128) + (v128.bitselect (v128.load (i32.const 0)) (v128.load (i32.const 16)) (v128.load (i32.const 32))) + ) +) +(assert_return (invoke "as-v128.bitselect-operand") (v128.const i32x4 0xabababab 0xaaaaaaaa 0xbbbbbbbb 0xbbaabbaa)) + +(module (memory 1) + (data (offset (i32.const 0)) "\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA") + (func (export "as-i8x16.shl-operand") (result v128) + (i8x16.shl (v128.load (i32.const 0)) (i32.const 1)) + ) +) +(assert_return (invoke "as-i8x16.shl-operand") (v128.const i32x4 0x54545454 0x54545454 0x54545454 0x54545454)) ;; 1010 1000 << 1010 1010 + +(module (memory 1) + (data (offset (i32.const 0)) "\02\00\00\00\02\00\00\00\02\00\00\00\02\00\00\00") + (data (offset (i32.const 16)) "\03\00\00\00\03\00\00\00\03\00\00\00\03\00\00\00") + (func (export "as-add/sub-operand") (result v128) + ;; 2 2 2 2 + 3 3 3 3 = 5 5 5 5 + ;; 5 5 5 5 - 3 3 3 3 = 2 2 2 2 + (i8x16.sub + (i8x16.add (v128.load (i32.const 0)) (v128.load (i32.const 16))) + (v128.load (i32.const 16)) + ) + ) +) +(assert_return (invoke "as-add/sub-operand") (v128.const i32x4 2 2 2 2)) + +(module (memory 1) + (data (offset (i32.const 0)) "\00\00\00\43\00\00\80\3f\66\66\e6\3f\00\00\80\bf") ;; 128 1.0 1.8 -1 + (data (offset (i32.const 16)) "\00\00\00\40\00\00\00\40\00\00\00\40\00\00\00\40") ;; 2.0 2.0 2.0 2.0 + (func (export "as-f32x4.mul-operand") (result v128) + (f32x4.mul (v128.load (i32.const 0)) (v128.load (i32.const 16))) + ) +) +(assert_return (invoke "as-f32x4.mul-operand") (v128.const f32x4 256 2 3.6 -2)) + +(module (memory 1) + (data (offset (i32.const 0)) "\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff\ff") ;; 1111 ... + (func (export "as-f32x4.abs-operand") (result v128) + (f32x4.abs (v128.load (i32.const 0))) + ) +) +(assert_return (invoke "as-f32x4.abs-operand") (v128.const i32x4 0x7fffffff 0x7fffffff 0x7fffffff 0x7fffffff)) ;; 1111 -> 0111 + +(module (memory 1) + (data (offset (i32.const 0)) "\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA\AA") + (data (offset (i32.const 16)) "\02\00\00\00\02\00\00\00\02\00\00\00\02\00\00\00") + (func (export "as-f32x4.min-operand") (result v128) + (f32x4.min (v128.load (i32.const 0)) (v128.load offset=16 (i32.const 1))) + ) +) +(assert_return (invoke "as-f32x4.min-operand") (v128.const i32x4 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa 0xaaaaaaaa)) ;; signed 1010 < 0010 + +(module (memory 1) + (data (offset (i32.const 0)) "\00\00\00\43\00\00\80\3f\66\66\e6\3f\00\00\80\bf") ;; 128 1.0 1.8 -1 + (func (export "as-i32x4.trunc_sat_f32x4_s-operand") (result v128) + (i32x4.trunc_sat_f32x4_s (v128.load (i32.const 0))) + ) +) +(assert_return (invoke "as-i32x4.trunc_sat_f32x4_s-operand") (v128.const i32x4 128 1 1 -1)) ;; 128 1.0 1.8 -1 -> 128 1 1 -1 + +(module (memory 1) + (data (offset (i32.const 0)) "\02\00\00\00\02\00\00\00\02\00\00\00\02\00\00\00") + (func (export "as-f32x4.convert_i32x4_u-operand") (result v128) + (f32x4.convert_i32x4_u (v128.load (i32.const 0))) + ) +) +(assert_return (invoke "as-f32x4.convert_i32x4_u-operand") (v128.const f32x4 2 2 2 2)) + +(module (memory 1) + (data (offset (i32.const 0)) "\64\65\66\67\68\69\6a\6b\6c\6d\6e\6f\70\71\72\73") ;; 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 + (data (offset (i32.const 16)) "\0f\0e\0d\0c\0b\0a\09\08\07\06\05\04\03\02\01\00") ;; 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00 + (func (export "as-i8x16.swizzle-operand") (result v128) + (i8x16.swizzle (v128.load (i32.const 0)) (v128.load offset=15 (i32.const 1))) + ) +) +(assert_return(invoke "as-i8x16.swizzle-operand") (v128.const i8x16 115 114 113 112 111 110 109 108 107 106 105 104 103 102 101 100)) + +(module (memory 1) + (data (i32.const 0) "\00\01\02\03\04\05\06\07\08\09\0a\0b\0c\0d\0e\0f\00\01\02\03") + (func (export "as-br-value") (result v128) + (block (result v128) (br 0 (v128.load (i32.const 0)))) + ) +) +(assert_return (invoke "as-br-value") (v128.const i32x4 0x03020100 0x07060504 0x0b0a0908 0x0f0e0d0c)) + + +;; Unknown operator(e.g. v128.load8, v128.load16, v128.load32) + +(assert_malformed + (module quote + "(memory 1)" + "(func (local v128) (drop (v128.load8 (i32.const 0))))" + ) + "unknown operator" +) +(assert_malformed + (module quote + "(memory 1)" + "(func (local v128) (drop (v128.load16 (i32.const 0))))" + ) + "unknown operator" +) +(assert_malformed + (module quote + "(memory 1)" + "(func (local v128) (drop (v128.load32 (i32.const 0))))" + ) + "unknown operator" +) + + +;; Type mismatched (e.g. v128.load(f32.const 0), type address empty) + +(assert_invalid + (module (memory 1) (func (local v128) (drop (v128.load (f32.const 0))))) + "type mismatch" +) +(assert_invalid + (module (memory 1) (func (local v128) (block (br_if 0 (v128.load (i32.const 0)))))) + "type mismatch" +) +(assert_invalid + (module (memory 1) (func (local v128) (v128.load (i32.const 0)))) + "type mismatch" +) + + +;; Type address empty + +(assert_invalid + (module (memory 1) (func (drop (v128.load (local.get 2))))) + "unknown local 2" +) +(assert_invalid + (module (memory 1) (func (drop (v128.load)))) + "type mismatch" +) \ No newline at end of file