Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit d0264fc

Browse files
wip: initial simd support
Signed-off-by: Henry Gressmann <[email protected]>
1 parent 60bea1e commit d0264fc

File tree

10 files changed

+150
-12
lines changed

10 files changed

+150
-12
lines changed

crates/cli/src/args.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ impl FromStr for WasmArg {
2525
"i64" => val.parse::<i64>().map_err(|e| format!("invalid argument value for i64: {e:?}"))?.into(),
2626
"f32" => val.parse::<f32>().map_err(|e| format!("invalid argument value for f32: {e:?}"))?.into(),
2727
"f64" => val.parse::<f64>().map_err(|e| format!("invalid argument value for f64: {e:?}"))?.into(),
28+
"v128" => val.parse::<u128>().map_err(|e| format!("invalid argument value for v128: {e:?}"))?.into(),
2829
t => return Err(format!("Invalid arg type: {t}")),
2930
};
3031

crates/tinywasm/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,12 @@ serde_json={version="1.0"}
3232
serde={version="1.0", features=["derive"]}
3333

3434
[features]
35-
default=["std", "parser", "logging", "archive"]
35+
default=["std", "parser", "logging", "archive", "simd"]
3636
logging=["log", "tinywasm-parser?/logging", "tinywasm-types/logging"]
3737
std=["tinywasm-parser?/std", "tinywasm-types/std"]
3838
parser=["dep:tinywasm-parser"]
3939
archive=["tinywasm-types/archive"]
40+
simd=[]
4041

4142
[[test]]
4243
name="test-wasm-1"

crates/tinywasm/src/interpreter/executor.rs

Lines changed: 77 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,15 @@
33
use super::no_std_floats::NoStdFloatExt;
44

55
use alloc::{format, rc::Rc, string::ToString};
6-
use core::ops::ControlFlow;
6+
use core::ops::{ControlFlow, Not};
7+
use core::simd::cmp::{SimdPartialEq, SimdPartialOrd};
8+
use core::simd::num::SimdUint;
79
use interpreter::stack::CallFrame;
810
use tinywasm_types::*;
911

12+
#[cfg(feature = "simd")]
13+
use super::simd::*;
14+
1015
use super::num_helpers::*;
1116
use super::stack::{BlockFrame, BlockType, Stack};
1217
use super::values::*;
@@ -41,6 +46,8 @@ impl<'store, 'stack> Executor<'store, 'stack> {
4146
#[inline(always)]
4247
fn exec_next(&mut self) -> ControlFlow<Option<Error>> {
4348
use tinywasm_types::Instruction::*;
49+
50+
#[rustfmt::skip]
4451
match self.cf.fetch_instr() {
4552
Nop | BrLabel(_) | I32ReinterpretF32 | I64ReinterpretF64 | F32ReinterpretI32 | F64ReinterpretI64 => {}
4653
Unreachable => self.exec_unreachable()?,
@@ -302,6 +309,75 @@ impl<'store, 'stack> Executor<'store, 'stack> {
302309
LocalCopy128(from, to) => self.exec_local_copy::<Value128>(*from, *to),
303310
LocalCopyRef(from, to) => self.exec_local_copy::<ValueRef>(*from, *to),
304311

312+
V128Not => self.stack.values.replace_top_same::<Value128>(|v| Ok(!v)).to_cf()?,
313+
V128And => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a & b)).to_cf()?,
314+
V128AndNot => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a & (!b))).to_cf()?,
315+
V128Or => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a | b)).to_cf()?,
316+
V128Xor => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a ^ b)).to_cf()?,
317+
V128Bitselect => self.stack.values.calculate_same_3::<Value128>(|v1, v2, c| Ok((v1 & c) | (v2 & !c))).to_cf()?,
318+
V128AnyTrue => self.stack.values.replace_top::<Value128, i32>(|v| Ok((v.reduce_sum() != 0) as i32)).to_cf()?,
319+
320+
I8x16Swizzle => self.stack.values.calculate_same::<Value128>(|a, s| Ok(a.swizzle_dyn(s))).to_cf()?,
321+
322+
I8x16Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Simd::<i8, 16>::splat(v as i8).to_ne_bytes())).to_cf()?,
323+
I16x8Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Simd::<i16, 8>::splat(v as i16).to_ne_bytes())).to_cf()?,
324+
I32x4Splat => self.stack.values.replace_top::<i32, Value128>(|v| Ok(Simd::<i32, 4>::splat(v).to_ne_bytes())).to_cf()?,
325+
I64x2Splat => self.stack.values.replace_top::<i64, Value128>(|v| Ok(Simd::<i64, 2>::splat(v).to_ne_bytes())).to_cf()?,
326+
F32x4Splat => self.stack.values.replace_top::<f32, Value128>(|v| Ok(Simd::<f32, 4>::splat(v).to_ne_bytes())).to_cf()?,
327+
F64x2Splat => self.stack.values.replace_top::<f64, Value128>(|v| Ok(Simd::<f64, 2>::splat(v).to_ne_bytes())).to_cf()?,
328+
329+
I8x16Eq => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?,
330+
I16x8Eq => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?,
331+
I32x4Eq => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?,
332+
F32x4Eq => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?,
333+
F64x2Eq => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_eq(b).to_int().to_ne_bytes())).to_cf()?,
334+
335+
I8x16Ne => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?,
336+
I16x8Ne => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?,
337+
I32x4Ne => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?,
338+
F32x4Ne => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?,
339+
F64x2Ne => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_ne(b).to_int().to_ne_bytes())).to_cf()?,
340+
341+
I8x16LtS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?,
342+
I16x8LtS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?,
343+
I32x4LtS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?,
344+
I64x2LtS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?,
345+
F32x4Lt => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?,
346+
F64x2Lt => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?,
347+
348+
I8x16LtU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?,
349+
I16x8LtU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?,
350+
I32x4LtU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_lt(b).to_int().to_ne_bytes())).to_cf()?,
351+
I64x2GtS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?,
352+
F32x4Gt => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?,
353+
F64x2Gt => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?,
354+
355+
I8x16GtS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?,
356+
I16x8GtS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?,
357+
I32x4GtS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?,
358+
I64x2LeS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?,
359+
F32x4Le => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?,
360+
F64x2Le => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?,
361+
362+
I8x16GtU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?,
363+
I16x8GtU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?,
364+
I32x4GtU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_gt(b).to_int().to_ne_bytes())).to_cf()?,
365+
I64x2GeS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?,
366+
F32x4Ge => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?,
367+
F64x2Ge => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?,
368+
369+
I8x16LeS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?,
370+
I16x8LeS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?,
371+
I32x4LeS => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?,
372+
373+
I8x16LeU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?,
374+
I16x8LeU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?,
375+
I32x4LeU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_le(b).to_int().to_ne_bytes())).to_cf()?,
376+
377+
I8x16GeU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?,
378+
I16x8GeU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?,
379+
I32x4GeU => self.stack.values.calculate_same::<Value128>(|a, b| Ok(a.simd_ge(b).to_int().to_ne_bytes())).to_cf()?,
380+
305381
i => return ControlFlow::Break(Some(Error::UnsupportedFeature(format!("unimplemented opcode: {i:?}")))),
306382
};
307383

crates/tinywasm/src/interpreter/mod.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ mod values;
66
#[cfg(not(feature = "std"))]
77
mod no_std_floats;
88

9+
#[cfg(feature = "simd")]
10+
mod simd;
11+
912
use crate::{Result, Store};
1013
pub use values::*;
1114

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
pub(super) use core::ops::Neg;
2+
3+
pub(super) use core::simd::Simd;
4+
pub(super) use core::simd::ToBytes;
5+
pub(super) use core::simd::num::SimdFloat;
6+
pub(super) use core::simd::num::SimdInt;
7+
8+
macro_rules! impl_wasm_simd_val {
9+
($($v:ident),*) => {
10+
$(
11+
pub(super) fn $v(f: core::simd::u8x16) -> core::simd::$v {
12+
core::simd::$v::from_ne_bytes(f)
13+
}
14+
)*
15+
};
16+
}
17+
18+
impl_wasm_simd_val!(i8x16, i16x8, i32x4, i64x2, f32x4, f64x2);

crates/tinywasm/src/interpreter/stack/value_stack.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ impl ValueStack {
7171
T::stack_calculate(self, func)
7272
}
7373

74+
#[inline]
75+
pub(crate) fn calculate_same_3<T: InternalValue>(&mut self, func: impl FnOnce(T, T, T) -> Result<T>) -> Result<()> {
76+
T::stack_calculate3(self, func)
77+
}
78+
7479
#[inline]
7580
pub(crate) fn calculate<T: InternalValue, U: InternalValue>(
7681
&mut self,
@@ -170,11 +175,16 @@ impl ValueStack {
170175
match val_type {
171176
ValType::I32 => WasmValue::I32(self.pop()),
172177
ValType::I64 => WasmValue::I64(self.pop()),
173-
ValType::V128 => WasmValue::V128(self.pop()),
174178
ValType::F32 => WasmValue::F32(self.pop()),
175179
ValType::F64 => WasmValue::F64(self.pop()),
176180
ValType::RefExtern => WasmValue::RefExtern(ExternRef::new(self.pop())),
177181
ValType::RefFunc => WasmValue::RefFunc(FuncRef::new(self.pop())),
182+
183+
#[cfg(not(feature = "simd"))]
184+
ValType::V128 => WasmValue::V128(self.pop()),
185+
186+
#[cfg(feature = "simd")]
187+
ValType::V128 => WasmValue::V128(u128::from_ne_bytes(self.pop::<Value128>().to_array())),
178188
}
179189
}
180190

crates/tinywasm/src/interpreter/values.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@ use super::stack::{Locals, ValueStack};
55

66
pub(crate) type Value32 = u32;
77
pub(crate) type Value64 = u64;
8-
pub(crate) type Value128 = u128;
98
pub(crate) type ValueRef = Option<u32>;
109

10+
#[cfg(feature = "simd")]
11+
pub(crate) type Value128 = core::simd::u8x16;
12+
#[cfg(not(feature = "simd"))]
13+
pub(crate) type Value128 = u128;
14+
1115
#[derive(Debug, Clone, Copy, PartialEq)]
1216
/// A untyped WebAssembly value
1317
pub enum TinyWasmValue {
@@ -106,9 +110,14 @@ impl TinyWasmValue {
106110
ValType::I64 => WasmValue::I64(self.unwrap_64() as i64),
107111
ValType::F32 => WasmValue::F32(f32::from_bits(self.unwrap_32())),
108112
ValType::F64 => WasmValue::F64(f64::from_bits(self.unwrap_64())),
109-
ValType::V128 => WasmValue::V128(self.unwrap_128()),
110113
ValType::RefExtern => WasmValue::RefExtern(ExternRef::new(self.unwrap_ref())),
111114
ValType::RefFunc => WasmValue::RefFunc(FuncRef::new(self.unwrap_ref())),
115+
116+
#[cfg(feature = "simd")]
117+
ValType::V128 => WasmValue::V128(u128::from_ne_bytes(self.unwrap_128().to_array())),
118+
119+
#[cfg(not(feature = "simd"))]
120+
ValType::V128 => WasmValue::V128(self.unwrap_128()),
112121
}
113122
}
114123
}
@@ -118,11 +127,16 @@ impl From<&WasmValue> for TinyWasmValue {
118127
match value {
119128
WasmValue::I32(v) => TinyWasmValue::Value32(*v as u32),
120129
WasmValue::I64(v) => TinyWasmValue::Value64(*v as u64),
121-
WasmValue::V128(v) => TinyWasmValue::Value128(*v),
122130
WasmValue::F32(v) => TinyWasmValue::Value32(v.to_bits()),
123131
WasmValue::F64(v) => TinyWasmValue::Value64(v.to_bits()),
124132
WasmValue::RefExtern(v) => TinyWasmValue::ValueRef(v.addr()),
125133
WasmValue::RefFunc(v) => TinyWasmValue::ValueRef(v.addr()),
134+
135+
#[cfg(not(feature = "simd"))]
136+
WasmValue::V128(v) => TinyWasmValue::Value128(*v),
137+
138+
#[cfg(feature = "simd")]
139+
WasmValue::V128(v) => TinyWasmValue::Value128(v.to_ne_bytes().into()),
126140
}
127141
}
128142
}
@@ -144,6 +158,9 @@ pub(crate) trait InternalValue: sealed::Sealed + Into<TinyWasmValue> {
144158
where
145159
Self: Sized;
146160
fn stack_calculate(stack: &mut ValueStack, func: impl FnOnce(Self, Self) -> Result<Self>) -> Result<()>
161+
where
162+
Self: Sized;
163+
fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result<Self>) -> Result<()>
147164
where
148165
Self: Sized;
149166

@@ -202,6 +219,19 @@ macro_rules! impl_internalvalue {
202219
return Ok(())
203220
}
204221

222+
#[inline(always)]
223+
fn stack_calculate3(stack: &mut ValueStack, func: impl FnOnce(Self, Self, Self) -> Result<Self>) -> Result<()> {
224+
let v3 = stack.$stack.pop();
225+
let v2 = stack.$stack.pop();
226+
let v1 = stack.$stack.last_mut();
227+
let (Some(v1), Some(v2), Some(v3)) = (v1, v2, v3) else {
228+
unreachable!("ValueStack underflow, this is a bug");
229+
};
230+
231+
*v1 = $to_internal(func($to_outer(*v1), $to_outer(v2), $to_outer(v3))?);
232+
return Ok(())
233+
}
234+
205235
#[inline(always)]
206236
fn replace_top(stack: &mut ValueStack, func: impl FnOnce(Self) -> Result<Self>) -> Result<()> {
207237
let Some(v) = stack.$stack.last_mut() else {

crates/tinywasm/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
))]
66
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms, unreachable_pub)]
77
#![forbid(unsafe_code)]
8-
// #![cfg_attr(feature = "nightly", feature(portable_simd))]
8+
#![cfg_attr(feature = "simd", feature(portable_simd))]
99

1010
//! A tiny WebAssembly Runtime written in Rust
1111
//!

0 commit comments

Comments
 (0)