summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/tinywasm/src/interpreter/executor.rs160
-rw-r--r--crates/tinywasm/src/interpreter/value128.rs180
-rw-r--r--crates/tinywasm/tests/generated/wasm-simd.csv2
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}]