diff options
Diffstat (limited to 'src/wasm')
-rw-r--r-- | src/wasm/literal.cpp | 82 | ||||
-rw-r--r-- | src/wasm/wasm-binary.cpp | 48 | ||||
-rw-r--r-- | src/wasm/wasm-stack.cpp | 50 | ||||
-rw-r--r-- | src/wasm/wasm-validator.cpp | 14 | ||||
-rw-r--r-- | src/wasm/wasm.cpp | 9 |
5 files changed, 202 insertions, 1 deletions
diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index 43adec6f6..b382d1a3d 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -1785,4 +1785,86 @@ Literal Literal::bitselectV128(const Literal& left, return andV128(left).orV128(notV128().andV128(right)); } +template<typename T> struct TwiceWidth {}; +template<> struct TwiceWidth<int8_t> { using type = int16_t; }; +template<> struct TwiceWidth<int16_t> { using type = int32_t; }; + +template<typename T> +Literal saturating_narrow( + typename TwiceWidth<typename std::make_signed<T>::type>::type val) { + using WideT = typename TwiceWidth<typename std::make_signed<T>::type>::type; + if (val > WideT(std::numeric_limits<T>::max())) { + val = std::numeric_limits<T>::max(); + } else if (val < WideT(std::numeric_limits<T>::min())) { + val = std::numeric_limits<T>::min(); + } + return Literal(int32_t(val)); +} + +template<size_t Lanes, + typename T, + LaneArray<Lanes / 2> (Literal::*IntoLanes)() const> +Literal narrow(const Literal& low, const Literal& high) { + LaneArray<Lanes / 2> lowLanes = (low.*IntoLanes)(); + LaneArray<Lanes / 2> highLanes = (high.*IntoLanes)(); + LaneArray<Lanes> result; + for (size_t i = 0; i < Lanes / 2; ++i) { + result[i] = saturating_narrow<T>(lowLanes[i].geti32()); + result[Lanes / 2 + i] = saturating_narrow<T>(highLanes[i].geti32()); + } + return Literal(result); +} + +Literal Literal::narrowSToVecI8x16(const Literal& other) const { + return narrow<16, int8_t, &Literal::getLanesSI16x8>(*this, other); +} +Literal Literal::narrowUToVecI8x16(const Literal& other) const { + return narrow<16, uint8_t, &Literal::getLanesSI16x8>(*this, other); +} +Literal Literal::narrowSToVecI16x8(const Literal& other) const { + return narrow<8, int16_t, &Literal::getLanesI32x4>(*this, other); +} +Literal Literal::narrowUToVecI16x8(const Literal& other) const { + return narrow<8, uint16_t, &Literal::getLanesI32x4>(*this, other); +} + +enum class LaneOrder { Low, High }; + +template<size_t Lanes, + LaneArray<Lanes * 2> (Literal::*IntoLanes)() const, + LaneOrder Side> +Literal widen(const Literal& vec) { + LaneArray<Lanes* 2> lanes = (vec.*IntoLanes)(); + LaneArray<Lanes> result; + for (size_t i = 0; i < Lanes; ++i) { + result[i] = lanes[(Side == LaneOrder::Low) ? i : i + Lanes]; + } + return Literal(result); +} + +Literal Literal::widenLowSToVecI16x8() const { + return widen<8, &Literal::getLanesSI8x16, LaneOrder::Low>(*this); +} +Literal Literal::widenHighSToVecI16x8() const { + return widen<8, &Literal::getLanesSI8x16, LaneOrder::High>(*this); +} +Literal Literal::widenLowUToVecI16x8() const { + return widen<8, &Literal::getLanesUI8x16, LaneOrder::Low>(*this); +} +Literal Literal::widenHighUToVecI16x8() const { + return widen<8, &Literal::getLanesUI8x16, LaneOrder::High>(*this); +} +Literal Literal::widenLowSToVecI32x4() const { + return widen<4, &Literal::getLanesSI16x8, LaneOrder::Low>(*this); +} +Literal Literal::widenHighSToVecI32x4() const { + return widen<4, &Literal::getLanesSI16x8, LaneOrder::High>(*this); +} +Literal Literal::widenLowUToVecI32x4() const { + return widen<4, &Literal::getLanesUI16x8, LaneOrder::Low>(*this); +} +Literal Literal::widenHighUToVecI32x4() const { + return widen<4, &Literal::getLanesUI16x8, LaneOrder::High>(*this); +} + } // namespace wasm diff --git a/src/wasm/wasm-binary.cpp b/src/wasm/wasm-binary.cpp index 529a3ff52..7b9d9c624 100644 --- a/src/wasm/wasm-binary.cpp +++ b/src/wasm/wasm-binary.cpp @@ -3943,6 +3943,22 @@ bool WasmBinaryBuilder::maybeVisitSIMDBinary(Expression*& out, uint32_t code) { curr = allocator.alloc<Binary>(); curr->op = MaxVecF64x2; break; + case BinaryConsts::I8x16NarrowSI16x8: + curr = allocator.alloc<Binary>(); + curr->op = NarrowSVecI16x8ToVecI8x16; + break; + case BinaryConsts::I8x16NarrowUI16x8: + curr = allocator.alloc<Binary>(); + curr->op = NarrowUVecI16x8ToVecI8x16; + break; + case BinaryConsts::I16x8NarrowSI32x4: + curr = allocator.alloc<Binary>(); + curr->op = NarrowSVecI32x4ToVecI16x8; + break; + case BinaryConsts::I16x8NarrowUI32x4: + curr = allocator.alloc<Binary>(); + curr->op = NarrowUVecI32x4ToVecI16x8; + break; default: return false; } @@ -4090,6 +4106,38 @@ bool WasmBinaryBuilder::maybeVisitSIMDUnary(Expression*& out, uint32_t code) { curr = allocator.alloc<Unary>(); curr->op = ConvertUVecI64x2ToVecF64x2; break; + case BinaryConsts::I16x8WidenLowSI8x16: + curr = allocator.alloc<Unary>(); + curr->op = WidenLowSVecI8x16ToVecI16x8; + break; + case BinaryConsts::I16x8WidenHighSI8x16: + curr = allocator.alloc<Unary>(); + curr->op = WidenHighSVecI8x16ToVecI16x8; + break; + case BinaryConsts::I16x8WidenLowUI8x16: + curr = allocator.alloc<Unary>(); + curr->op = WidenLowUVecI8x16ToVecI16x8; + break; + case BinaryConsts::I16x8WidenHighUI8x16: + curr = allocator.alloc<Unary>(); + curr->op = WidenHighUVecI8x16ToVecI16x8; + break; + case BinaryConsts::I32x4WidenLowSI16x8: + curr = allocator.alloc<Unary>(); + curr->op = WidenLowSVecI16x8ToVecI32x4; + break; + case BinaryConsts::I32x4WidenHighSI16x8: + curr = allocator.alloc<Unary>(); + curr->op = WidenHighSVecI16x8ToVecI32x4; + break; + case BinaryConsts::I32x4WidenLowUI16x8: + curr = allocator.alloc<Unary>(); + curr->op = WidenLowUVecI16x8ToVecI32x4; + break; + case BinaryConsts::I32x4WidenHighUI16x8: + curr = allocator.alloc<Unary>(); + curr->op = WidenHighUVecI16x8ToVecI32x4; + break; default: return false; } diff --git a/src/wasm/wasm-stack.cpp b/src/wasm/wasm-stack.cpp index 498a53cb2..1da6e9015 100644 --- a/src/wasm/wasm-stack.cpp +++ b/src/wasm/wasm-stack.cpp @@ -917,6 +917,38 @@ void BinaryInstWriter::visitUnary(Unary* curr) { o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2ConvertUI64x2); break; + case WidenLowSVecI8x16ToVecI16x8: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I16x8WidenLowSI8x16); + break; + case WidenHighSVecI8x16ToVecI16x8: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I16x8WidenHighSI8x16); + break; + case WidenLowUVecI8x16ToVecI16x8: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I16x8WidenLowUI8x16); + break; + case WidenHighUVecI8x16ToVecI16x8: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I16x8WidenHighUI8x16); + break; + case WidenLowSVecI16x8ToVecI32x4: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I32x4WidenLowSI16x8); + break; + case WidenHighSVecI16x8ToVecI32x4: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I32x4WidenHighSI16x8); + break; + case WidenLowUVecI16x8ToVecI32x4: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I32x4WidenLowUI16x8); + break; + case WidenHighUVecI16x8ToVecI32x4: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I32x4WidenHighUI16x8); + break; case InvalidUnary: WASM_UNREACHABLE(); } @@ -1394,6 +1426,24 @@ void BinaryInstWriter::visitBinary(Binary* curr) { case MaxVecF64x2: o << int8_t(BinaryConsts::SIMDPrefix) << U32LEB(BinaryConsts::F64x2Max); break; + + case NarrowSVecI16x8ToVecI8x16: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I8x16NarrowSI16x8); + break; + case NarrowUVecI16x8ToVecI8x16: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I8x16NarrowUI16x8); + break; + case NarrowSVecI32x4ToVecI16x8: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I16x8NarrowSI32x4); + break; + case NarrowUVecI32x4ToVecI16x8: + o << int8_t(BinaryConsts::SIMDPrefix) + << U32LEB(BinaryConsts::I16x8NarrowUI32x4); + break; + case InvalidBinary: WASM_UNREACHABLE(); } diff --git a/src/wasm/wasm-validator.cpp b/src/wasm/wasm-validator.cpp index f2d6c259b..e64e2ef73 100644 --- a/src/wasm/wasm-validator.cpp +++ b/src/wasm/wasm-validator.cpp @@ -1330,7 +1330,11 @@ void FunctionValidator::visitBinary(Binary* curr) { case MulVecF64x2: case DivVecF64x2: case MinVecF64x2: - case MaxVecF64x2: { + case MaxVecF64x2: + case NarrowSVecI16x8ToVecI8x16: + case NarrowUVecI16x8ToVecI8x16: + case NarrowSVecI32x4ToVecI16x8: + case NarrowUVecI32x4ToVecI16x8: { shouldBeEqualOrFirstIsUnreachable( curr->left->type, v128, curr, "v128 op"); shouldBeEqualOrFirstIsUnreachable( @@ -1528,6 +1532,14 @@ void FunctionValidator::visitUnary(Unary* curr) { case ConvertUVecI32x4ToVecF32x4: case ConvertSVecI64x2ToVecF64x2: case ConvertUVecI64x2ToVecF64x2: + case WidenLowSVecI8x16ToVecI16x8: + case WidenHighSVecI8x16ToVecI16x8: + case WidenLowUVecI8x16ToVecI16x8: + case WidenHighUVecI8x16ToVecI16x8: + case WidenLowSVecI16x8ToVecI32x4: + case WidenHighSVecI16x8ToVecI32x4: + case WidenLowUVecI16x8ToVecI32x4: + case WidenHighUVecI16x8ToVecI32x4: shouldBeEqual(curr->type, v128, curr, "expected v128 type"); shouldBeEqual(curr->value->type, v128, curr, "expected v128 operand"); break; diff --git a/src/wasm/wasm.cpp b/src/wasm/wasm.cpp index ec23b5c94..f8439ea96 100644 --- a/src/wasm/wasm.cpp +++ b/src/wasm/wasm.cpp @@ -749,6 +749,14 @@ void Unary::finalize() { case ConvertUVecI32x4ToVecF32x4: case ConvertSVecI64x2ToVecF64x2: case ConvertUVecI64x2ToVecF64x2: + case WidenLowSVecI8x16ToVecI16x8: + case WidenHighSVecI8x16ToVecI16x8: + case WidenLowUVecI8x16ToVecI16x8: + case WidenHighUVecI8x16ToVecI16x8: + case WidenLowSVecI16x8ToVecI32x4: + case WidenHighSVecI16x8ToVecI32x4: + case WidenLowUVecI16x8ToVecI32x4: + case WidenHighUVecI16x8ToVecI32x4: type = v128; break; case AnyTrueVecI8x16: @@ -761,6 +769,7 @@ void Unary::finalize() { case AllTrueVecI64x2: type = i32; break; + case InvalidUnary: WASM_UNREACHABLE(); } |