summaryrefslogtreecommitdiff
path: root/src/wasm
diff options
context:
space:
mode:
Diffstat (limited to 'src/wasm')
-rw-r--r--src/wasm/literal.cpp82
-rw-r--r--src/wasm/wasm-binary.cpp48
-rw-r--r--src/wasm/wasm-stack.cpp50
-rw-r--r--src/wasm/wasm-validator.cpp14
-rw-r--r--src/wasm/wasm.cpp9
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();
}