diff options
-rw-r--r-- | src/literal.h | 6 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 8 | ||||
-rw-r--r-- | src/wasm/literal.cpp | 48 | ||||
-rw-r--r-- | test/spec/simd.wast | 23 |
4 files changed, 83 insertions, 2 deletions
diff --git a/src/literal.h b/src/literal.h index 746fa5d3e..f7ce78f7a 100644 --- a/src/literal.h +++ b/src/literal.h @@ -636,6 +636,12 @@ public: Literal extendHighSToI64x2() const; Literal extendLowUToI64x2() const; Literal extendHighUToI64x2() const; + Literal convertLowSToF64x2() const; + Literal convertLowUToF64x2() const; + Literal truncSatZeroSToI32x4() const; + Literal truncSatZeroUToI32x4() const; + Literal demoteZeroToF32x4() const; + Literal promoteLowToF64x2() const; Literal swizzleI8x16(const Literal& other) const; // Checks if an RTT value is a sub-rtt of another, that is, whether GC data diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index a846edf97..77e432436 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -399,7 +399,6 @@ public: return value.extendS16(); case ExtendS32Int64: return value.extendS32(); - case NegFloat32: case NegFloat64: return value.neg(); @@ -570,12 +569,17 @@ public: case ExtendHighUVecI32x4ToVecI64x2: return value.extendHighUToI64x2(); case ConvertLowSVecI32x4ToVecF64x2: + return value.convertLowSToF64x2(); case ConvertLowUVecI32x4ToVecF64x2: + return value.convertLowUToF64x2(); case TruncSatZeroSVecF64x2ToVecI32x4: + return value.truncSatZeroSToI32x4(); case TruncSatZeroUVecF64x2ToVecI32x4: + return value.truncSatZeroUToI32x4(); case DemoteZeroVecF64x2ToVecF32x4: + return value.demoteZeroToF32x4(); case PromoteLowVecF32x4ToVecF64x2: - WASM_UNREACHABLE("unimp"); + return value.promoteLowToF64x2(); case InvalidUnary: WASM_UNREACHABLE("invalid unary op"); } diff --git a/src/wasm/literal.cpp b/src/wasm/literal.cpp index b6618219d..c7a9ca844 100644 --- a/src/wasm/literal.cpp +++ b/src/wasm/literal.cpp @@ -2388,6 +2388,16 @@ Literal extend(const Literal& vec) { return Literal(result); } +template<LaneOrder Side> Literal extendF32(const Literal& vec) { + LaneArray<4> lanes = vec.getLanesF32x4(); + LaneArray<2> result; + for (size_t i = 0; i < 2; ++i) { + size_t idx = (Side == LaneOrder::Low) ? i : i + 2; + result[i] = Literal((double)lanes[idx].getf32()); + } + return Literal(result); +} + Literal Literal::extendLowSToI16x8() const { return extend<8, int8_t, int16_t, LaneOrder::Low>(*this); } @@ -2475,6 +2485,44 @@ Literal Literal::extMulHighUI64x2(const Literal& other) const { return extMul<2, uint32_t, uint64_t, LaneOrder::High>(*this, other); } +Literal Literal::convertLowSToF64x2() const { + return extend<2, int32_t, double, LaneOrder::Low>(*this); +} +Literal Literal::convertLowUToF64x2() const { + return extend<2, uint32_t, double, LaneOrder::Low>(*this); +} + +template<int Lanes, + LaneArray<Lanes / 2> (Literal::*IntoLanes)() const, + Literal (Literal::*UnaryOp)(void) const> +static Literal unary_zero(const Literal& val) { + LaneArray<Lanes / 2> lanes = (val.*IntoLanes)(); + LaneArray<Lanes> result; + for (size_t i = 0; i < Lanes / 2; ++i) { + result[i] = (lanes[i].*UnaryOp)(); + } + for (size_t i = Lanes / 2; i < Lanes; ++i) { + result[i] = Literal::makeZero(lanes[0].type); + } + return Literal(result); +} + +Literal Literal::truncSatZeroSToI32x4() const { + return unary_zero<4, &Literal::getLanesF64x2, &Literal::truncSatToSI32>( + *this); +} +Literal Literal::truncSatZeroUToI32x4() const { + return unary_zero<4, &Literal::getLanesF64x2, &Literal::truncSatToUI32>( + *this); +} + +Literal Literal::demoteZeroToF32x4() const { + return unary_zero<4, &Literal::getLanesF64x2, &Literal::demote>(*this); +} +Literal Literal::promoteLowToF64x2() const { + return extendF32<LaneOrder::Low>(*this); +} + Literal Literal::swizzleI8x16(const Literal& other) const { auto lanes = getLanesUI8x16(); auto indices = other.getLanesUI8x16(); diff --git a/test/spec/simd.wast b/test/spec/simd.wast index d246cfdd0..cec571387 100644 --- a/test/spec/simd.wast +++ b/test/spec/simd.wast @@ -254,6 +254,12 @@ (func (export "v128.load32_zero") (param $0 i32) (result v128) (v128.load32_zero (local.get $0))) (func (export "v128.load64_zero") (param $0 i32) (result v128) (v128.load64_zero (local.get $0))) (func (export "i8x16.swizzle") (param $0 v128) (param $1 v128) (result v128) (i8x16.swizzle (local.get $0) (local.get $1))) + (func (export "f64x2.convert_low_i32x4_s") (param $0 v128) (result v128) (f64x2.convert_low_i32x4_s (local.get $0))) + (func (export "f64x2.convert_low_i32x4_u") (param $0 v128) (result v128) (f64x2.convert_low_i32x4_u (local.get $0))) + (func (export "i32x4.trunc_sat_f64x2_s_zero") (param $0 v128) (result v128) (i32x4.trunc_sat_f64x2_s_zero (local.get $0))) + (func (export "i32x4.trunc_sat_f64x2_u_zero") (param $0 v128) (result v128) (i32x4.trunc_sat_f64x2_u_zero (local.get $0))) + (func (export "f32x4.demote_f64x2_zero") (param $0 v128) (result v128) (f32x4.demote_f64x2_zero (local.get $0))) + (func (export "f64x2.promote_low_f32x4") (param $0 v128) (result v128) (f64x2.promote_low_f32x4 (local.get $0))) ) ;; TODO: Additional f64x2 conversions if specified @@ -1123,3 +1129,20 @@ ) (v128.const i8x16 0xf0 0xf4 0xf8 0xfc 0x00 0x00 0x00 0x00 0x00 0x00 0xff 0xfd 0xfc 0xf8 0xf4 0xf0) ) + +(assert_return (invoke "f64x2.convert_low_i32x4_s" (v128.const i32x4 1 -2147483648 0 0)) (v128.const f64x2 1.0 -2147483648)) +(assert_return (invoke "f64x2.convert_low_i32x4_u" (v128.const i32x4 -2147483648 0xffffffff 0 0)) (v128.const f64x2 2147483648 4294967295.0)) +(assert_return (invoke "i32x4.trunc_sat_f64x2_s_zero" (v128.const f64x2 -inf 4294967296.0)) (v128.const i32x4 -2147483648 2147483647 0 0)) +(assert_return (invoke "i32x4.trunc_sat_f64x2_u_zero" (v128.const f64x2 -inf 4294967296.0)) (v128.const i32x4 0 4294967295 0 0)) +(assert_return + (invoke "f32x4.demote_f64x2_zero" + (v128.const f64x2 0x1.fffffe0000000p-127 -0x1.6972b30cfb562p+1) + ) + (v128.const f32x4 0x1p-126 -0x1.6972b4p+1 0 0) +) +(assert_return + (invoke "f64x2.promote_low_f32x4" + (v128.const f32x4 -0x1p-149 0x1.8f867ep+125 0 0) + ) + (v128.const f64x2 -0x1p-149 6.6382536710104395e+37) +) |