diff options
| author | Henry Gressmann <mail@henrygressmann.de> | 2026-01-05 21:22:31 +0100 |
|---|---|---|
| committer | Henry Gressmann <mail@henrygressmann.de> | 2026-01-05 21:22:31 +0100 |
| commit | dd8f0cad73c690be7d4c441e0d8f4aba6ceec227 (patch) | |
| tree | 07e54522ff0a0d02ec86195911be461c741264cc /crates | |
| parent | 2911204b3b2508c729c2584016cccd3ef57ffc91 (diff) | |
chore: more simd stuff
Signed-off-by: Henry Gressmann <mail@henrygressmann.de>
Diffstat (limited to 'crates')
| -rw-r--r-- | crates/tinywasm/src/interpreter/executor.rs | 160 | ||||
| -rw-r--r-- | crates/tinywasm/src/interpreter/value128.rs | 180 | ||||
| -rw-r--r-- | crates/tinywasm/tests/generated/wasm-simd.csv | 2 |
3 files changed, 260 insertions, 82 deletions
diff --git a/crates/tinywasm/src/interpreter/executor.rs b/crates/tinywasm/src/interpreter/executor.rs index f026244..c186c01 100644 --- a/crates/tinywasm/src/interpreter/executor.rs +++ b/crates/tinywasm/src/interpreter/executor.rs @@ -338,30 +338,24 @@ impl<'store, 'stack> Executor<'store, 'stack> { V128Store64Lane(arg, lane) => self.exec_mem_store_lane::<i64, 8>(arg.mem_addr(), arg.offset(), *lane)?, // Load a single 32-bit or 64-bit element into the lowest bits of a v128 vector, and initialize all other bits of the v128 vector to zero. - V128Load32Zero(arg) => self.exec_mem_load::<i32, 4, Value128>(arg.mem_addr(), arg.offset(), |v| { - let bytes = v.to_le_bytes(); - Value128::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]) - })?, - V128Load64Zero(arg) => self.exec_mem_load::<i64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| { - let bytes = v.to_le_bytes(); - Value128::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5], bytes[6], bytes[7], 0, 0, 0, 0, 0, 0, 0, 0]) - })?, + V128Load32Zero(arg) => self.exec_mem_load::<i32, 4, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i32x4([v, 0, 0, 0]))?, + V128Load64Zero(arg) => self.exec_mem_load::<i64, 8, Value128>(arg.mem_addr(), arg.offset(), |v| Value128::from_i64x2([v, 0]))?, V128Const(arg) => self.exec_const::<Value128>( self.cf.data().v128_constants[*arg as usize].into()), - // I8x16ExtractLaneS(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v[*lane as usize] as i32)).to_cf()?, - // I8x16ExtractLaneU(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v[*lane as usize] as i32)).to_cf()?, - // I16x8ExtractLaneS(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v[*lane as usize] as i32)).to_cf()?, - // I16x8ExtractLaneU(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v[*lane as usize] as i32)).to_cf()?, - // I32x4ExtractLane(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v[*lane as usize])).to_cf()?, - // I64x2ExtractLane(lane) => self.stack.values.replace_top::<Value128, i64>(|v| Ok(v[*lane as usize])).to_cf()?, - // F32x4ExtractLane(lane) => self.stack.values.replace_top::<Value128, f32>(|v| Ok(v[*lane as usize])).to_cf()?, - // F64x2ExtractLane(lane) => self.stack.values.replace_top::<Value128, f64>(|v| Ok(v[*lane as usize])).to_cf()?, + I8x16ExtractLaneS(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_i8(*lane) as i32)).to_cf()?, + I8x16ExtractLaneU(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_u8(*lane) as i32)).to_cf()?, + I16x8ExtractLaneS(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_i16(*lane) as i32)).to_cf()?, + I16x8ExtractLaneU(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_u16(*lane) as i32)).to_cf()?, + I32x4ExtractLane(lane) => self.stack.values.replace_top::<Value128, i32>(|v| Ok(v.extract_lane_i32(*lane))).to_cf()?, + I64x2ExtractLane(lane) => self.stack.values.replace_top::<Value128, i64>(|v| Ok(v.extract_lane_i64(*lane))).to_cf()?, + F32x4ExtractLane(lane) => self.stack.values.replace_top::<Value128, f32>(|v| Ok(v.extract_lane_f32(*lane))).to_cf()?, + F64x2ExtractLane(lane) => self.stack.values.replace_top::<Value128, f64>(|v| Ok(v.extract_lane_f64(*lane))).to_cf()?, - // V128Load8Lane(arg, lane) => self.exec_mem_load_lane::<i8, i8x16, 1>(arg.mem_addr(), arg.offset(), *lane)?, - // V128Load16Lane(arg, lane) => self.exec_mem_load_lane::<i16, i16x8, 2>(arg.mem_addr(), arg.offset(), *lane)?, - // V128Load32Lane(arg, lane) => self.exec_mem_load_lane::<i32, i32x4, 4>(arg.mem_addr(), arg.offset(), *lane)?, - // V128Load64Lane(arg, lane) => self.exec_mem_load_lane::<i64, i64x2, 8>(arg.mem_addr(), arg.offset(), *lane)?, + V128Load8Lane(arg, lane) => self.exec_mem_load_lane::<i8, 1>(arg.mem_addr(), arg.offset(), *lane)?, + V128Load16Lane(arg, lane) => self.exec_mem_load_lane::<i16, 2>(arg.mem_addr(), arg.offset(), *lane)?, + V128Load32Lane(arg, lane) => self.exec_mem_load_lane::<i32, 4>(arg.mem_addr(), arg.offset(), *lane)?, + V128Load64Lane(arg, lane) => self.exec_mem_load_lane::<i64, 8>(arg.mem_addr(), arg.offset(), *lane)?, // I8x16ReplaceLane(_lane) => unimplemented!(), // I16x8ReplaceLane(_lane) => unimplemented!(), @@ -370,12 +364,12 @@ impl<'store, 'stack> Executor<'store, 'stack> { // F32x4ReplaceLane(_lane) => unimplemented!(), // F64x2ReplaceLane(_lane) => unimplemented!(), - // I8x16Splat => self.stack.values.replace_top::<i32, i8x16>(|v| Ok(Simd::<i8, 16>::splat(v as i8))).to_cf()?, - // I16x8Splat => self.stack.values.replace_top::<i32, i16x8>(|v| Ok(Simd::<i16, 8>::splat(v as i16))).to_cf()?, - // I32x4Splat => self.stack.values.replace_top::<i32, i32x4>(|v| Ok(Simd::<i32, 4>::splat(v))).to_cf()?, - // I64x2Splat => self.stack.values.replace_top::<i64, i64x2>(|v| Ok(Simd::<i64, 2>::splat(v))).to_cf()?, - // F32x4Splat => self.stack.values.replace_top::<f32, f32x4>(|v| Ok(Simd::<f32, 4>::splat(v))).to_cf()?, - // F64x2Splat => self.stack.values.replace_top::<f64, f64x2>(|v| Ok(Simd::<f64, 2>::splat(v))).to_cf()?, + I8x16Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Value128::splat_i8(v as i8))).to_cf()?, + I16x8Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Value128::splat_i16(v as i16))).to_cf()?, + I32x4Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Value128::splat_i32(v))).to_cf()?, + I64x2Splat => self.stack.values.replace_top::<i64, Value128>(|v| Ok(Value128::splat_i64(v))).to_cf()?, + F32x4Splat => self.stack.values.replace_top::<f32, Value128>(|v| Ok(Value128::splat_f32(v))).to_cf()?, + F64x2Splat => self.stack.values.replace_top::<f64, Value128>(|v| Ok(Value128::splat_f64(v))).to_cf()?, // I8x16Eq => self.stack.values.calculate_same::<i8x16>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, // I16x8Eq => self.stack.values.calculate_same::<i16x8>(|a, b| Ok(a.simd_eq(b).to_int())).to_cf()?, @@ -551,41 +545,44 @@ impl<'store, 'stack> Executor<'store, 'stack> { // I8x16Popcnt => self.stack.values.replace_top::<i8x16, _>(|v| Ok(v.count_ones())).to_cf()?, // I8x16Shuffle(_idx) => unimplemented!(), - - // I16x8Q15MulrSatS => self.stack.values.calculate_same::<i16x8>(|a, b| { - // let subq15mulr = |a,b| { - // let a = a as i32; - // let b = b as i32; - // let r = (a * b + 0x4000) >> 15; - // if r > i16::MAX as i32 { - // i16::MAX - // } else if r < i16::MIN as i32 { - // i16::MIN - // } else { - // r as i16 - // } - // }; - // Ok(Simd::<i16, 8>::from_array([ - // subq15mulr(a[0], b[0]), - // subq15mulr(a[1], b[1]), - // subq15mulr(a[2], b[2]), - // subq15mulr(a[3], b[3]), - // subq15mulr(a[4], b[4]), - // subq15mulr(a[5], b[5]), - // subq15mulr(a[6], b[6]), - // subq15mulr(a[7], b[7]), - // ])) - // }).to_cf()?, + I16x8Q15MulrSatS => self.stack.values.calculate_same::<Value128>(|a, b| { + let subq15mulr = |a,b| { + let a = a as i32; + let b = b as i32; + let r = (a * b + 0x4000) >> 15; + if r > i16::MAX as i32 { + i16::MAX + } else if r < i16::MIN as i32 { + i16::MIN + } else { + r as i16 + } + }; + let a = a.as_i16x8(); + let b = b.as_i16x8(); + Ok(Value128::from_i16x8([ + subq15mulr(a[0], b[0]), + subq15mulr(a[1], b[1]), + subq15mulr(a[2], b[2]), + subq15mulr(a[3], b[3]), + subq15mulr(a[4], b[4]), + subq15mulr(a[5], b[5]), + subq15mulr(a[6], b[6]), + subq15mulr(a[7], b[7]), + ])) + }).to_cf()?, - // I32x4DotI16x8S => self.stack.values.calculate::<i16x8, i32x4>(|a, b| { - // Ok(Simd::<i32, 4>::from_array([ - // i32::from(a[0] * b[0] + a[1] * b[1]), - // i32::from(a[2] * b[2] + a[3] * b[3]), - // i32::from(a[4] * b[4] + a[5] * b[5]), - // i32::from(a[6] * b[6] + a[7] * b[7]), - // ])) - // }).to_cf()?, + I32x4DotI16x8S => self.stack.values.calculate::<Value128, Value128>(|a, b| { + let a = a.as_i16x8(); + let b = b.as_i16x8(); + Ok(Value128::from_i32x4([ + i32::from(a[0] * b[0] + a[1] * b[1]), + i32::from(a[2] * b[2] + a[3] * b[3]), + i32::from(a[4] * b[4] + a[5] * b[5]), + i32::from(a[6] * b[6] + a[7] * b[7]), + ])) + }).to_cf()?, // F32x4Ceil => self.stack.values.replace_top_same::<f32x4>(|v| Ok(v.ceil())).to_cf()?, // F64x2Ceil => self.stack.values.replace_top_same::<f64x2>(|v| Ok(v.ceil())).to_cf()?, @@ -1038,30 +1035,31 @@ impl<'store, 'stack> Executor<'store, 'stack> { } } - // fn exec_mem_load_lane<LOAD: MemValue<LOAD_SIZE>, const LOAD_SIZE: usize>( - // &mut self, - // mem_addr: tinywasm_types::MemAddr, - // offset: u64, - // lane: u8, - // ) -> ControlFlow<Option<Error>> { - // let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)); - // let mut imm = self.stack.values.pop::<Value128>().to_mem_bytes(); - // let val = self.stack.values.pop::<i32>() as u64; - // let Some(Ok(addr)) = offset.checked_add(val).map(TryInto::try_into) else { - // cold(); - // return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds { - // offset: val as usize, - // len: LOAD_SIZE, - // max: 0, - // }))); - // }; - // let val = mem.load_as::<LOAD_SIZE, LOAD>(addr).to_cf()?.to_mem_bytes(); + fn exec_mem_load_lane<LOAD: MemValue<LOAD_SIZE>, const LOAD_SIZE: usize>( + &mut self, + mem_addr: tinywasm_types::MemAddr, + offset: u64, + lane: u8, + ) -> ControlFlow<Option<Error>> { + let mem = self.store.get_mem(self.module.resolve_mem_addr(mem_addr)); + let mut imm = self.stack.values.pop::<Value128>().to_mem_bytes(); + let val = self.stack.values.pop::<i32>() as u64; + let Some(Ok(addr)) = offset.checked_add(val).map(TryInto::try_into) else { + cold(); + return ControlFlow::Break(Some(Error::Trap(Trap::MemoryOutOfBounds { + offset: val as usize, + len: LOAD_SIZE, + max: 0, + }))); + }; + let val = mem.load_as::<LOAD_SIZE, LOAD>(addr).to_cf()?.to_mem_bytes(); - // // imm[lane as usize] = val; + let offset = lane as usize * LOAD_SIZE; + imm[offset..offset + LOAD_SIZE].copy_from_slice(&val); - // self.stack.values.push(Value128::from_mem_bytes(imm)); - // ControlFlow::Continue(()) - // } + self.stack.values.push(Value128::from_mem_bytes(imm)); + ControlFlow::Continue(()) + } fn exec_mem_load<LOAD: MemValue<LOAD_SIZE>, const LOAD_SIZE: usize, TARGET: InternalValue>( &mut self, diff --git a/crates/tinywasm/src/interpreter/value128.rs b/crates/tinywasm/src/interpreter/value128.rs index b9c96a9..fcd208f 100644 --- a/crates/tinywasm/src/interpreter/value128.rs +++ b/crates/tinywasm/src/interpreter/value128.rs @@ -10,6 +10,115 @@ impl Value128 { self.0.to_le_bytes() } + #[rustfmt::skip] + pub const fn as_i8x16(self) -> [i8; 16] { + let b = self.to_le_bytes(); + [b[0] as i8, b[1] as i8, b[2] as i8, b[3] as i8, b[4] as i8, b[5] as i8, b[6] as i8, b[7] as i8, b[8] as i8, b[9] as i8, b[10] as i8, b[11] as i8, b[12] as i8, b[13] as i8, b[14] as i8, b[15] as i8] + } + + #[rustfmt::skip] + pub const fn as_u8x16(self) -> [u8; 16] { + self.to_le_bytes() + } + + #[rustfmt::skip] + pub const fn from_i8x16(x: [i8; 16]) -> Self { + Self::from_le_bytes([x[0] as u8, x[1] as u8, x[2] as u8, x[3] as u8, x[4] as u8, x[5] as u8, x[6] as u8, x[7] as u8, x[8] as u8, x[9] as u8, x[10] as u8, x[11] as u8, x[12] as u8, x[13] as u8, x[14] as u8, x[15] as u8]) + } + + #[rustfmt::skip] + pub const fn from_u8x16(x: [u8; 16]) -> Self { + Self::from_le_bytes(x) + } + + #[rustfmt::skip] + pub const fn as_i16x8(self) -> [i16; 8] { + let b = self.to_le_bytes(); + [i16::from_le_bytes([b[0], b[1]]), i16::from_le_bytes([b[2], b[3]]), i16::from_le_bytes([b[4], b[5]]), i16::from_le_bytes([b[6], b[7]]), i16::from_le_bytes([b[8], b[9]]), i16::from_le_bytes([b[10], b[11]]), i16::from_le_bytes([b[12], b[13]]), i16::from_le_bytes([b[14], b[15]])] + } + + #[rustfmt::skip] + pub const fn as_u16x8(self) -> [u16; 8] { + let b = self.to_le_bytes(); + [u16::from_le_bytes([b[0], b[1]]), u16::from_le_bytes([b[2], b[3]]), u16::from_le_bytes([b[4], b[5]]), u16::from_le_bytes([b[6], b[7]]), u16::from_le_bytes([b[8], b[9]]), u16::from_le_bytes([b[10], b[11]]), u16::from_le_bytes([b[12], b[13]]), u16::from_le_bytes([b[14], b[15]])] + } + + #[rustfmt::skip] + pub const fn from_i16x8(x: [i16; 8]) -> Self { + Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[4].to_le_bytes()[0], x[4].to_le_bytes()[1], x[5].to_le_bytes()[0], x[5].to_le_bytes()[1], x[6].to_le_bytes()[0], x[6].to_le_bytes()[1], x[7].to_le_bytes()[0], x[7].to_le_bytes()[1]]) + } + + #[rustfmt::skip] + pub const fn from_u16x8(x: [u16; 8]) -> Self { + Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[4].to_le_bytes()[0], x[4].to_le_bytes()[1], x[5].to_le_bytes()[0], x[5].to_le_bytes()[1], x[6].to_le_bytes()[0], x[6].to_le_bytes()[1], x[7].to_le_bytes()[0], x[7].to_le_bytes()[1]]) + } + + #[rustfmt::skip] + pub const fn as_i32x4(self) -> [i32; 4] { + let b = self.to_le_bytes(); + [i32::from_le_bytes([b[0], b[1], b[2], b[3]]), i32::from_le_bytes([b[4], b[5], b[6], b[7]]), i32::from_le_bytes([b[8], b[9], b[10], b[11]]), i32::from_le_bytes([b[12], b[13], b[14], b[15]])] + } + + #[rustfmt::skip] + pub const fn as_u32x4(self) -> [u32; 4] { + let b = self.to_le_bytes(); + [u32::from_le_bytes([b[0], b[1], b[2], b[3]]), u32::from_le_bytes([b[4], b[5], b[6], b[7]]), u32::from_le_bytes([b[8], b[9], b[10], b[11]]), u32::from_le_bytes([b[12], b[13], b[14], b[15]])] + } + + #[rustfmt::skip] + pub const fn as_f32x4(self) -> [f32; 4] { + let b = self.to_le_bytes(); + [f32::from_bits(u32::from_le_bytes([b[0], b[1], b[2], b[3]])), f32::from_bits(u32::from_le_bytes([b[4], b[5], b[6], b[7]])), f32::from_bits(u32::from_le_bytes([b[8], b[9], b[10], b[11]])), f32::from_bits(u32::from_le_bytes([b[12], b[13], b[14], b[15]]))] + } + + #[rustfmt::skip] + pub const fn from_i32x4(x: [i32; 4]) -> Self { + Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[2].to_le_bytes()[2], x[2].to_le_bytes()[3], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[3].to_le_bytes()[2], x[3].to_le_bytes()[3]]) + } + + #[rustfmt::skip] + pub const fn from_u32x4(x: [u32; 4]) -> Self { + Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[2].to_le_bytes()[0], x[2].to_le_bytes()[1], x[2].to_le_bytes()[2], x[2].to_le_bytes()[3], x[3].to_le_bytes()[0], x[3].to_le_bytes()[1], x[3].to_le_bytes()[2], x[3].to_le_bytes()[3]]) + } + + #[rustfmt::skip] + pub const fn from_f32x4(x: [f32; 4]) -> Self { + Self::from_le_bytes([x[0].to_bits().to_le_bytes()[0], x[0].to_bits().to_le_bytes()[1], x[0].to_bits().to_le_bytes()[2], x[0].to_bits().to_le_bytes()[3], x[1].to_bits().to_le_bytes()[0], x[1].to_bits().to_le_bytes()[1], x[1].to_bits().to_le_bytes()[2], x[1].to_bits().to_le_bytes()[3], x[2].to_bits().to_le_bytes()[0], x[2].to_bits().to_le_bytes()[1], x[2].to_bits().to_le_bytes()[2], x[2].to_bits().to_le_bytes()[3], x[3].to_bits().to_le_bytes()[0], x[3].to_bits().to_le_bytes()[1], x[3].to_bits().to_le_bytes()[2], x[3].to_bits().to_le_bytes()[3]]) + } + + #[rustfmt::skip] + pub const fn as_i64x2(self) -> [i64; 2] { + let b = self.to_le_bytes(); + [i64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]), i64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]])] + } + + #[rustfmt::skip] + pub const fn as_u64x2(self) -> [u64; 2] { + let b = self.to_le_bytes(); + [u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]]), u64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]])] + } + + #[rustfmt::skip] + pub const fn as_f64x2(self) -> [f64; 2] { + let b = self.to_le_bytes(); + [f64::from_bits(u64::from_le_bytes([b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]])), f64::from_bits(u64::from_le_bytes([b[8], b[9], b[10], b[11], b[12], b[13], b[14], b[15]]))] + } + + #[rustfmt::skip] + pub const fn from_i64x2(x: [i64; 2]) -> Self { + Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[0].to_le_bytes()[4], x[0].to_le_bytes()[5], x[0].to_le_bytes()[6], x[0].to_le_bytes()[7], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[1].to_le_bytes()[4], x[1].to_le_bytes()[5], x[1].to_le_bytes()[6], x[1].to_le_bytes()[7]]) + } + + #[rustfmt::skip] + pub const fn from_u64x2(x: [u64; 2]) -> Self { + Self::from_le_bytes([x[0].to_le_bytes()[0], x[0].to_le_bytes()[1], x[0].to_le_bytes()[2], x[0].to_le_bytes()[3], x[0].to_le_bytes()[4], x[0].to_le_bytes()[5], x[0].to_le_bytes()[6], x[0].to_le_bytes()[7], x[1].to_le_bytes()[0], x[1].to_le_bytes()[1], x[1].to_le_bytes()[2], x[1].to_le_bytes()[3], x[1].to_le_bytes()[4], x[1].to_le_bytes()[5], x[1].to_le_bytes()[6], x[1].to_le_bytes()[7]]) + } + + #[rustfmt::skip] + pub const fn from_f64x2(x: [f64; 2]) -> Self { + Self::from_le_bytes([x[0].to_bits().to_le_bytes()[0], x[0].to_bits().to_le_bytes()[1], x[0].to_bits().to_le_bytes()[2], x[0].to_bits().to_le_bytes()[3], x[0].to_bits().to_le_bytes()[4], x[0].to_bits().to_le_bytes()[5], x[0].to_bits().to_le_bytes()[6], x[0].to_bits().to_le_bytes()[7], x[1].to_bits().to_le_bytes()[0], x[1].to_bits().to_le_bytes()[1], x[1].to_bits().to_le_bytes()[2], x[1].to_bits().to_le_bytes()[3], x[1].to_bits().to_le_bytes()[4], x[1].to_bits().to_le_bytes()[5], x[1].to_bits().to_le_bytes()[6], x[1].to_bits().to_le_bytes()[7]]) + } + pub const fn reduce_or(self) -> u8 { let mut result = 0u8; let bytes = self.to_le_bytes(); @@ -174,6 +283,77 @@ impl Value128 { } Self::from_le_bytes(result_bytes) } + + pub const fn splat_f32(src: f32) -> Self { + Self::splat_i32(src.to_bits() as i32) + } + + pub const fn splat_f64(src: f64) -> Self { + Self::splat_i64(src.to_bits() as i64) + } + + pub const fn extract_lane_i8(self, lane: u8) -> i8 { + debug_assert!(lane < 16); + let lane = lane as usize; + let bytes = self.to_le_bytes(); + bytes[lane] as i8 + } + + pub const fn extract_lane_u8(self, lane: u8) -> u8 { + debug_assert!(lane < 16); + let lane = lane as usize; + let bytes = self.to_le_bytes(); + bytes[lane] + } + + pub const fn extract_lane_i16(self, lane: u8) -> i16 { + debug_assert!(lane < 8); + let lane = lane as usize; + let bytes = self.to_le_bytes(); + let start = lane * 2; + i16::from_le_bytes([bytes[start], bytes[start + 1]]) + } + + pub const fn extract_lane_u16(self, lane: u8) -> u16 { + debug_assert!(lane < 8); + let lane = lane as usize; + let bytes = self.to_le_bytes(); + let start = lane * 2; + u16::from_le_bytes([bytes[start], bytes[start + 1]]) + } + + pub const fn extract_lane_i32(self, lane: u8) -> i32 { + debug_assert!(lane < 4); + let lane = lane as usize; + let bytes = self.to_le_bytes(); + let start = lane * 4; + i32::from_le_bytes([bytes[start], bytes[start + 1], bytes[start + 2], bytes[start + 3]]) + } + + pub const fn extract_lane_i64(self, lane: u8) -> i64 { + debug_assert!(lane < 2); + let lane = lane as usize; + let bytes = self.to_le_bytes(); + let start = lane * 8; + i64::from_le_bytes([ + bytes[start], + bytes[start + 1], + bytes[start + 2], + bytes[start + 3], + bytes[start + 4], + bytes[start + 5], + bytes[start + 6], + bytes[start + 7], + ]) + } + + pub const fn extract_lane_f32(self, lane: u8) -> f32 { + f32::from_bits(self.extract_lane_i32(lane) as u32) + } + + pub const fn extract_lane_f64(self, lane: u8) -> f64 { + f64::from_bits(self.extract_lane_i64(lane) as u64) + } } impl From<Value128> for i128 { diff --git a/crates/tinywasm/tests/generated/wasm-simd.csv b/crates/tinywasm/tests/generated/wasm-simd.csv index f87cc69..5603ed0 100644 --- a/crates/tinywasm/tests/generated/wasm-simd.csv +++ b/crates/tinywasm/tests/generated/wasm-simd.csv @@ -1,2 +1,2 @@ 0.8.0,1300,24679,[{"name":"simd_address.wast","passed":4,"failed":45},{"name":"simd_align.wast","passed":46,"failed":54},{"name":"simd_bit_shift.wast","passed":39,"failed":213},{"name":"simd_bitwise.wast","passed":28,"failed":141},{"name":"simd_boolean.wast","passed":16,"failed":261},{"name":"simd_const.wast","passed":301,"failed":456},{"name":"simd_conversions.wast","passed":48,"failed":234},{"name":"simd_f32x4.wast","passed":16,"failed":774},{"name":"simd_f32x4_arith.wast","passed":16,"failed":1806},{"name":"simd_f32x4_cmp.wast","passed":24,"failed":2583},{"name":"simd_f32x4_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f32x4_rounding.wast","passed":24,"failed":177},{"name":"simd_f64x2.wast","passed":8,"failed":795},{"name":"simd_f64x2_arith.wast","passed":16,"failed":1809},{"name":"simd_f64x2_cmp.wast","passed":24,"failed":2661},{"name":"simd_f64x2_pmin_pmax.wast","passed":14,"failed":3873},{"name":"simd_f64x2_rounding.wast","passed":24,"failed":177},{"name":"simd_i16x8_arith.wast","passed":11,"failed":183},{"name":"simd_i16x8_arith2.wast","passed":19,"failed":153},{"name":"simd_i16x8_cmp.wast","passed":30,"failed":435},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":4,"failed":17},{"name":"simd_i16x8_extmul_i8x16.wast","passed":12,"failed":105},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":3,"failed":27},{"name":"simd_i16x8_sat_arith.wast","passed":16,"failed":206},{"name":"simd_i32x4_arith.wast","passed":11,"failed":183},{"name":"simd_i32x4_arith2.wast","passed":26,"failed":123},{"name":"simd_i32x4_cmp.wast","passed":40,"failed":435},{"name":"simd_i32x4_dot_i16x8.wast","passed":3,"failed":27},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":4,"failed":17},{"name":"simd_i32x4_extmul_i16x8.wast","passed":12,"failed":105},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":4,"failed":103},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":4,"failed":103},{"name":"simd_i64x2_arith.wast","passed":11,"failed":189},{"name":"simd_i64x2_arith2.wast","passed":2,"failed":23},{"name":"simd_i64x2_cmp.wast","passed":10,"failed":103},{"name":"simd_i64x2_extmul_i32x4.wast","passed":12,"failed":105},{"name":"simd_i8x16_arith.wast","passed":8,"failed":123},{"name":"simd_i8x16_arith2.wast","passed":25,"failed":186},{"name":"simd_i8x16_cmp.wast","passed":30,"failed":415},{"name":"simd_i8x16_sat_arith.wast","passed":24,"failed":190},{"name":"simd_int_to_int_extend.wast","passed":24,"failed":229},{"name":"simd_lane.wast","passed":189,"failed":286},{"name":"simd_linking.wast","passed":0,"failed":3},{"name":"simd_load.wast","passed":8,"failed":31},{"name":"simd_load16_lane.wast","passed":3,"failed":33},{"name":"simd_load32_lane.wast","passed":3,"failed":21},{"name":"simd_load64_lane.wast","passed":3,"failed":13},{"name":"simd_load8_lane.wast","passed":3,"failed":49},{"name":"simd_load_extend.wast","passed":18,"failed":86},{"name":"simd_load_splat.wast","passed":12,"failed":114},{"name":"simd_load_zero.wast","passed":10,"failed":29},{"name":"simd_splat.wast","passed":23,"failed":162},{"name":"simd_store.wast","passed":9,"failed":19},{"name":"simd_store16_lane.wast","passed":3,"failed":33},{"name":"simd_store32_lane.wast","passed":3,"failed":21},{"name":"simd_store64_lane.wast","passed":3,"failed":13},{"name":"simd_store8_lane.wast","passed":3,"failed":49}] -0.9.0-alpha.0,2460,23529,[{"name":"simd_address.wast","passed":49,"failed":0},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":41,"failed":211},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":139,"failed":138},{"name":"simd_const.wast","passed":755,"failed":2},{"name":"simd_conversions.wast","passed":50,"failed":232},{"name":"simd_f32x4.wast","passed":18,"failed":772},{"name":"simd_f32x4_arith.wast","passed":19,"failed":1803},{"name":"simd_f32x4_cmp.wast","passed":26,"failed":2581},{"name":"simd_f32x4_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f32x4_rounding.wast","passed":25,"failed":176},{"name":"simd_f64x2.wast","passed":10,"failed":793},{"name":"simd_f64x2_arith.wast","passed":19,"failed":1806},{"name":"simd_f64x2_cmp.wast","passed":26,"failed":2659},{"name":"simd_f64x2_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f64x2_rounding.wast","passed":25,"failed":176},{"name":"simd_i16x8_arith.wast","passed":13,"failed":181},{"name":"simd_i16x8_arith2.wast","passed":21,"failed":151},{"name":"simd_i16x8_cmp.wast","passed":32,"failed":433},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":4,"failed":26},{"name":"simd_i16x8_sat_arith.wast","passed":18,"failed":204},{"name":"simd_i32x4_arith.wast","passed":13,"failed":181},{"name":"simd_i32x4_arith2.wast","passed":28,"failed":121},{"name":"simd_i32x4_cmp.wast","passed":42,"failed":433},{"name":"simd_i32x4_dot_i16x8.wast","passed":4,"failed":28},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":5,"failed":102},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":13,"failed":187},{"name":"simd_i64x2_arith2.wast","passed":4,"failed":21},{"name":"simd_i64x2_cmp.wast","passed":11,"failed":102},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":10,"failed":121},{"name":"simd_i8x16_arith2.wast","passed":27,"failed":184},{"name":"simd_i8x16_cmp.wast","passed":32,"failed":413},{"name":"simd_i8x16_sat_arith.wast","passed":26,"failed":188},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":213,"failed":262},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":29,"failed":10},{"name":"simd_load16_lane.wast","passed":4,"failed":32},{"name":"simd_load32_lane.wast","passed":4,"failed":20},{"name":"simd_load64_lane.wast","passed":4,"failed":12},{"name":"simd_load8_lane.wast","passed":4,"failed":48},{"name":"simd_load_extend.wast","passed":30,"failed":74},{"name":"simd_load_splat.wast","passed":122,"failed":4},{"name":"simd_load_zero.wast","passed":37,"failed":2},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_select.wast","passed":7,"failed":0},{"name":"simd_splat.wast","passed":27,"failed":158},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":4,"failed":32},{"name":"simd_store32_lane.wast","passed":4,"failed":20},{"name":"simd_store64_lane.wast","passed":4,"failed":12},{"name":"simd_store8_lane.wast","passed":52,"failed":0}] +0.9.0-alpha.0,2867,23122,[{"name":"simd_address.wast","passed":49,"failed":0},{"name":"simd_align.wast","passed":100,"failed":0},{"name":"simd_bit_shift.wast","passed":41,"failed":211},{"name":"simd_bitwise.wast","passed":169,"failed":0},{"name":"simd_boolean.wast","passed":139,"failed":138},{"name":"simd_const.wast","passed":755,"failed":2},{"name":"simd_conversions.wast","passed":50,"failed":232},{"name":"simd_f32x4.wast","passed":18,"failed":772},{"name":"simd_f32x4_arith.wast","passed":19,"failed":1803},{"name":"simd_f32x4_cmp.wast","passed":26,"failed":2581},{"name":"simd_f32x4_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f32x4_rounding.wast","passed":25,"failed":176},{"name":"simd_f64x2.wast","passed":10,"failed":793},{"name":"simd_f64x2_arith.wast","passed":19,"failed":1806},{"name":"simd_f64x2_cmp.wast","passed":26,"failed":2659},{"name":"simd_f64x2_pmin_pmax.wast","passed":15,"failed":3872},{"name":"simd_f64x2_rounding.wast","passed":25,"failed":176},{"name":"simd_i16x8_arith.wast","passed":13,"failed":181},{"name":"simd_i16x8_arith2.wast","passed":21,"failed":151},{"name":"simd_i16x8_cmp.wast","passed":32,"failed":433},{"name":"simd_i16x8_extadd_pairwise_i8x16.wast","passed":5,"failed":16},{"name":"simd_i16x8_extmul_i8x16.wast","passed":13,"failed":104},{"name":"simd_i16x8_q15mulr_sat_s.wast","passed":30,"failed":0},{"name":"simd_i16x8_sat_arith.wast","passed":18,"failed":204},{"name":"simd_i32x4_arith.wast","passed":13,"failed":181},{"name":"simd_i32x4_arith2.wast","passed":28,"failed":121},{"name":"simd_i32x4_cmp.wast","passed":42,"failed":433},{"name":"simd_i32x4_dot_i16x8.wast","passed":14,"failed":18},{"name":"simd_i32x4_extadd_pairwise_i16x8.wast","passed":5,"failed":16},{"name":"simd_i32x4_extmul_i16x8.wast","passed":13,"failed":104},{"name":"simd_i32x4_trunc_sat_f32x4.wast","passed":5,"failed":102},{"name":"simd_i32x4_trunc_sat_f64x2.wast","passed":5,"failed":102},{"name":"simd_i64x2_arith.wast","passed":13,"failed":187},{"name":"simd_i64x2_arith2.wast","passed":4,"failed":21},{"name":"simd_i64x2_cmp.wast","passed":11,"failed":102},{"name":"simd_i64x2_extmul_i32x4.wast","passed":13,"failed":104},{"name":"simd_i8x16_arith.wast","passed":10,"failed":121},{"name":"simd_i8x16_arith2.wast","passed":27,"failed":184},{"name":"simd_i8x16_cmp.wast","passed":32,"failed":413},{"name":"simd_i8x16_sat_arith.wast","passed":26,"failed":188},{"name":"simd_int_to_int_extend.wast","passed":25,"failed":228},{"name":"simd_lane.wast","passed":328,"failed":147},{"name":"simd_linking.wast","passed":3,"failed":0},{"name":"simd_load.wast","passed":30,"failed":9},{"name":"simd_load16_lane.wast","passed":36,"failed":0},{"name":"simd_load32_lane.wast","passed":24,"failed":0},{"name":"simd_load64_lane.wast","passed":16,"failed":0},{"name":"simd_load8_lane.wast","passed":52,"failed":0},{"name":"simd_load_extend.wast","passed":36,"failed":68},{"name":"simd_load_splat.wast","passed":126,"failed":0},{"name":"simd_load_zero.wast","passed":39,"failed":0},{"name":"simd_memory-multi.wast","passed":1,"failed":0},{"name":"simd_select.wast","passed":7,"failed":0},{"name":"simd_splat.wast","passed":158,"failed":27},{"name":"simd_store.wast","passed":28,"failed":0},{"name":"simd_store16_lane.wast","passed":4,"failed":32},{"name":"simd_store32_lane.wast","passed":4,"failed":20},{"name":"simd_store64_lane.wast","passed":4,"failed":12},{"name":"simd_store8_lane.wast","passed":52,"failed":0}] |
