diff options
-rw-r--r-- | src/literal.h | 1 | ||||
-rw-r--r-- | src/wasm/literal.cpp | 11 | ||||
-rw-r--r-- | test/spec/simd.wast | 9 |
3 files changed, 19 insertions, 2 deletions
diff --git a/src/literal.h b/src/literal.h index 965ec157c..0b1b6fa90 100644 --- a/src/literal.h +++ b/src/literal.h @@ -644,6 +644,7 @@ private: Literal subSatUI8(const Literal& other) const; Literal subSatSI16(const Literal& other) const; Literal subSatUI16(const Literal& other) const; + Literal q15MulrSatSI16(const Literal& other) const; Literal minInt(const Literal& other) const; Literal maxInt(const Literal& other) const; Literal minUInt(const Literal& other) const; diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index c3a2ddf7a..afaafe5e4 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -1070,6 +1070,14 @@ Literal Literal::subSatUI16(const Literal& other) const { return Literal(sub_sat_u<uint16_t>(geti32(), other.geti32())); } +Literal Literal::q15MulrSatSI16(const Literal& other) const { + int64_t value = + (int64_t(geti32()) * int64_t(other.geti32()) + 0x4000LL) >> 15LL; + int64_t lower = std::numeric_limits<int16_t>::min(); + int64_t upper = std::numeric_limits<int16_t>::max(); + return Literal(int16_t(std::min(std::max(value, lower), upper))); +} + Literal Literal::mul(const Literal& other) const { switch (type.getBasic()) { case Type::i32: @@ -2201,7 +2209,8 @@ Literal Literal::avgrUI16x8(const Literal& other) const { return binary<8, &Literal::getLanesUI16x8, &Literal::avgrUInt>(*this, other); } Literal Literal::q15MulrSatSI16x8(const Literal& other) const { - WASM_UNREACHABLE("TODO: implement Q15 rounding, saturating multiplication"); + return binary<8, &Literal::getLanesSI16x8, &Literal::q15MulrSatSI16>(*this, + other); } Literal Literal::addI32x4(const Literal& other) const { return binary<4, &Literal::getLanesI32x4, &Literal::add>(*this, other); diff --git a/test/spec/simd.wast b/test/spec/simd.wast index 0eda03fc5..9a76fec3b 100644 --- a/test/spec/simd.wast +++ b/test/spec/simd.wast @@ -151,7 +151,7 @@ (func (export "i16x8.max_s") (param $0 v128) (param $1 v128) (result v128) (i16x8.max_s (local.get $0) (local.get $1))) (func (export "i16x8.max_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.max_u (local.get $0) (local.get $1))) (func (export "i16x8.avgr_u") (param $0 v128) (param $1 v128) (result v128) (i16x8.avgr_u (local.get $0) (local.get $1))) - ;; TODO: Q15 rounding, saturating multiplication + (func (export "i16x8.q15mulr_sat_s") (param $0 v128) (param $1 v128) (result v128) (i16x8.q15mulr_sat_s (local.get $0) (local.get $1))) ;; TODO: extending multiplications (func (export "i32x4.abs") (param $0 v128) (result v128) (i32x4.abs (local.get $0))) (func (export "i32x4.neg") (param $0 v128) (result v128) (i32x4.neg (local.get $0))) @@ -783,6 +783,13 @@ ) (v128.const i16x8 384 32641 32768 32768 17280 38912 64640 16384) ) +(assert_return + (invoke "i16x8.q15mulr_sat_s" + (v128.const i16x8 -1 -16383 32765 65535 -32768 65535 -16385 -32768) + (v128.const i16x8 -1 -16384 1 -32768 -32768 1 -16384 -1) + ) + (v128.const i16x8 0 8192 1 1 32767 0 8193 1) +) ;; i32x4 arithmetic (assert_return (invoke "i32x4.abs" (v128.const i32x4 0 1 0x80000000 0x80000001)) (v128.const i32x4 0 1 0x80000000 0x7fffffff)) |