Skip to content

Commit 33ff214

Browse files
authored
Add Val[Type]::V128 to Wasmi crates (#1418)
* re-design V128 constructors The V128 type now mirrors wasmtime's V128 type with respect to conversions from and to Rust primitives. Mainly this supports conversions between V128 and Rust's u128 primitive. * remove From<[u8;16]> impl for V128 As wasmtime's V128 type does not have this constructor, we shouldn't have it either. It is trivially replaceable with From<u128> impl for V128. * add V128 conversions with UntypedVal and TypedVal * add V128 variant to wasmi_core::ValType * adjust wasmi crate for ValType changes * add simd crate feature to wasmi_cli * adjust wasmi_cli for ValType changes with simd * add simd support for wasmi_fuzz and fuzz crates While simd is supported by Wasmi fuzzing it still is disabled. So no actual Wasm simd fuzzing will take place. This is because the wasmi crate does not yet fully support the Wasm simd proposal. * adjust Wasmi's C-API crates * make Val[Type] always include V128 variants This makes it a lot simpler to maintain dependencies to wasmi_core and also fixes some compilation problem with feature resolution in the workspace. Also this forces fewer `cfg` annotations across dependencies and the codebase as a whole. * make V128 From and {Read,Write}As impls conditional This is necessary to make `UntypedVal` 64-bit when `simd` is not enabled. We cannot really have those impls with just 64-bit wide `UntypedVal`s. This seems to be the least disruptive design since `ValType` and `Val` always have the same set of variants and `V128` always exists in `wasmi_core`'s crate root. * fix imports when building docs for wasmi_ir * apply rustfmt
1 parent dd36ab3 commit 33ff214

File tree

24 files changed

+172
-82
lines changed

24 files changed

+172
-82
lines changed

crates/c_api/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,3 +27,4 @@ doctest = false
2727
default = ["std"]
2828
std = []
2929
prefix-symbols = []
30+
simd = ["wasmi/simd"]

crates/c_api/artifact/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ wasmi_c_api_impl = { workspace = true }
2828
[features]
2929
default = ["std"]
3030
std = ["wasmi_c_api_impl/std"]
31+
simd = ["wasmi_c_api_impl/simd"]

crates/c_api/src/func.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ use crate::{
77
wasm_val_vec_t,
88
};
99
use alloc::{boxed::Box, string::String, vec, vec::Vec};
10-
use core::{any::Any, ffi::c_void, hint, iter, panic::AssertUnwindSafe, ptr, str};
10+
use core::{any::Any, ffi::c_void, hint, iter, ptr, str};
1111
use wasmi::{Error, Extern, Func, FuncRef, Val};
1212

13+
#[cfg(feature = "std")]
14+
use core::panic::AssertUnwindSafe;
15+
1316
/// A Wasm function.
1417
///
1518
/// Wraps [`Func`].

crates/c_api/src/types/val.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ pub enum wasm_valkind_t {
3434
///
3535
/// Wraps [`ValType::F64`].
3636
WASM_F64 = 3,
37+
/// A Wasm `v128` value type.
38+
///
39+
/// Wraps [`ValType::V128`].
40+
WASM_V128 = 4,
3741
/// A Wasm external reference type.
3842
///
3943
/// Wraps [`ValType::ExternRef`].
@@ -67,6 +71,7 @@ pub(crate) fn into_valtype(kind: wasm_valkind_t) -> ValType {
6771
wasm_valkind_t::WASM_I64 => ValType::I64,
6872
wasm_valkind_t::WASM_F32 => ValType::F32,
6973
wasm_valkind_t::WASM_F64 => ValType::F64,
74+
wasm_valkind_t::WASM_V128 => ValType::V128,
7075
wasm_valkind_t::WASM_EXTERNREF => ValType::ExternRef,
7176
wasm_valkind_t::WASM_FUNCREF => ValType::FuncRef,
7277
}
@@ -79,6 +84,7 @@ pub(crate) fn from_valtype(ty: &ValType) -> wasm_valkind_t {
7984
ValType::I64 => wasm_valkind_t::WASM_I64,
8085
ValType::F32 => wasm_valkind_t::WASM_F32,
8186
ValType::F64 => wasm_valkind_t::WASM_F64,
87+
ValType::V128 => wasm_valkind_t::WASM_V128,
8288
ValType::ExternRef => wasm_valkind_t::WASM_EXTERNREF,
8389
ValType::FuncRef => wasm_valkind_t::WASM_FUNCREF,
8490
}

crates/c_api/src/val.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::{
1010
use alloc::boxed::Box;
1111
use core::{mem::MaybeUninit, ptr};
1212
use wasmi::{
13-
core::{ValType, F32, F64},
13+
core::{ValType, F32, F64, V128},
1414
FuncRef,
1515
Val,
1616
};
@@ -42,6 +42,8 @@ pub union wasm_val_union {
4242
pub f32: f32,
4343
/// A Wasm 64-bit float.
4444
pub f64: f64,
45+
/// A Wasm `v128` value.
46+
pub v128: u128,
4547
/// A Wasm referenced object.
4648
pub ref_: *mut wasm_ref_t,
4749
}
@@ -101,6 +103,12 @@ impl From<Val> for wasm_val_t {
101103
u64: value.to_bits(),
102104
},
103105
},
106+
Val::V128(value) => Self {
107+
kind: from_valtype(&ValType::V128),
108+
of: wasm_val_union {
109+
v128: value.as_u128(),
110+
},
111+
},
104112
Val::FuncRef(funcref) => Self {
105113
kind: from_valtype(&ValType::FuncRef),
106114
of: wasm_val_union {
@@ -133,6 +141,7 @@ impl wasm_val_t {
133141
ValType::I64 => Val::from(unsafe { self.of.i64 }),
134142
ValType::F32 => Val::from(F32::from(unsafe { self.of.f32 })),
135143
ValType::F64 => Val::from(F64::from(unsafe { self.of.f64 })),
144+
ValType::V128 => Val::from(V128::from(unsafe { self.of.v128 })),
136145
ValType::FuncRef => match unsafe { self.of.ref_ }.is_null() {
137146
true => Val::FuncRef(FuncRef::null()),
138147
false => ref_to_val(unsafe { &*self.of.ref_ }),

crates/cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ assert_cmd = "2.0.7"
2626
default = []
2727
hash-collections = ["wasmi/hash-collections"]
2828
prefer-btree-collections = ["wasmi/prefer-btree-collections"]
29+
simd = ["wasmi/simd"]
2930

3031
# We need to put this [profile.release] section due to this bug in Cargo:
3132
# https://github.com/rust-lang/cargo/issues/8264

crates/cli/src/display.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ impl Display for DisplayValueType<'_> {
1818
ValType::I64 => write!(f, "i64"),
1919
ValType::F32 => write!(f, "f32"),
2020
ValType::F64 => write!(f, "f64"),
21+
ValType::V128 => write!(f, "v128"),
2122
ValType::FuncRef => write!(f, "funcref"),
2223
ValType::ExternRef => write!(f, "externref"),
2324
}
@@ -40,6 +41,7 @@ impl fmt::Display for DisplayValue<'_> {
4041
Val::I64(value) => write!(f, "{value}"),
4142
Val::F32(value) => write!(f, "{value}"),
4243
Val::F64(value) => write!(f, "{value}"),
44+
Val::V128(value) => write!(f, "0x{:032X}", value.as_u128()),
4345
Val::FuncRef(value) => panic!("cannot display funcref values but found {value:?}"),
4446
Val::ExternRef(value) => {
4547
panic!("cannot display externref values but found {value:?}")

crates/cli/src/utils.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::display::DisplayValueType;
22
use anyhow::{anyhow, bail, Error};
33
use wasmi::{
4-
core::{ValType, F32, F64},
4+
core::{ValType, F32, F64, V128},
55
FuncType,
66
Val,
77
};
@@ -56,6 +56,11 @@ pub fn decode_func_args(ty: &FuncType, args: &[String]) -> Result<Box<[Val]>, Er
5656
.map(F64::from)
5757
.map(Val::from)
5858
.map_err(make_err!()),
59+
ValType::V128 => arg
60+
.parse::<u128>()
61+
.map(V128::from)
62+
.map(Val::from)
63+
.map_err(make_err!()),
5964
ValType::FuncRef => {
6065
bail!("the wasmi CLI cannot take arguments of type funcref")
6166
}

crates/core/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,5 @@ pub use self::{
3535
trap::{Trap, TrapCode},
3636
typed::{Typed, TypedVal},
3737
untyped::{DecodeUntypedSlice, EncodeUntypedSlice, ReadAs, UntypedError, UntypedVal, WriteAs},
38-
value::ValType,
38+
value::{ValType, V128},
3939
};

crates/core/src/simd.rs

Lines changed: 14 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
1-
use crate::{memory, memory::ExtendInto, simd, wasm, ReadAs, TrapCode, UntypedVal, WriteAs};
1+
//! Defines the entire Wasm `simd` proposal API.
2+
3+
use crate::{
4+
memory::{self, ExtendInto},
5+
simd,
6+
wasm,
7+
TrapCode,
8+
V128,
9+
};
210
use core::{
311
array,
412
ops::{BitAnd, BitOr, BitXor, Neg, Not},
@@ -10,60 +18,6 @@ macro_rules! op {
1018
}};
1119
}
1220

13-
/// The Wasm `simd` proposal's `v128` type.
14-
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
15-
#[repr(transparent)]
16-
pub struct V128([u8; 16]);
17-
18-
impl From<[u8; 16]> for V128 {
19-
fn from(bytes: [u8; 16]) -> Self {
20-
Self(bytes)
21-
}
22-
}
23-
24-
impl From<i128> for V128 {
25-
fn from(value: i128) -> Self {
26-
Self(value.to_le_bytes())
27-
}
28-
}
29-
30-
impl V128 {
31-
/// Creates an `i128` value from the bytes of `self`.
32-
pub(crate) fn to_i128(self) -> i128 {
33-
i128::from_le_bytes(self.0)
34-
}
35-
}
36-
37-
impl From<UntypedVal> for V128 {
38-
fn from(value: UntypedVal) -> Self {
39-
let u128 = (u128::from(value.hi64) << 64) | (u128::from(value.lo64));
40-
Self(u128.to_le_bytes())
41-
}
42-
}
43-
44-
impl From<V128> for UntypedVal {
45-
fn from(value: V128) -> Self {
46-
let u128 = u128::from_le_bytes(value.0);
47-
let lo64 = u128 as u64;
48-
let hi64 = (u128 >> 64) as u64;
49-
Self { lo64, hi64 }
50-
}
51-
}
52-
53-
impl ReadAs<V128> for UntypedVal {
54-
fn read_as(&self) -> V128 {
55-
// Note: we can re-use the `From` impl since both types are of equal size.
56-
V128::from(*self)
57-
}
58-
}
59-
60-
impl WriteAs<V128> for UntypedVal {
61-
fn write_as(&mut self, value: V128) {
62-
// Note: we can re-use the `From` impl since both types are of equal size.
63-
*self = UntypedVal::from(value);
64-
}
65-
}
66-
6721
/// An error that may occur when constructing an out of bounds lane index.
6822
pub struct OutOfBoundsLaneIdx;
6923

@@ -1287,7 +1241,7 @@ impl_bitmask_ops! {
12871241

12881242
/// Executes a Wasm `v128.any_true` instruction.
12891243
pub fn v128_any_true(v128: V128) -> bool {
1290-
v128.to_i128() != 0
1244+
v128.as_u128() != 0
12911245
}
12921246

12931247
/// Executes a Wasm `i32x4.dot_i16x8_s` instruction.
@@ -1314,7 +1268,7 @@ pub fn v128_bitselect(v1: V128, v2: V128, c: V128) -> V128 {
13141268
/// - If `ptr + offset` overflows.
13151269
/// - If `ptr + offset` stores out of bounds from `memory`.
13161270
pub fn v128_store(memory: &mut [u8], ptr: u64, offset: u64, value: V128) -> Result<(), TrapCode> {
1317-
memory::store(memory, ptr, offset, value.to_i128())
1271+
memory::store(memory, ptr, offset, value.as_u128())
13181272
}
13191273

13201274
/// Executes a Wasm `v128.store` instruction.
@@ -1323,7 +1277,7 @@ pub fn v128_store(memory: &mut [u8], ptr: u64, offset: u64, value: V128) -> Resu
13231277
///
13241278
/// If `address` stores out of bounds from `memory`.
13251279
pub fn v128_store_at(memory: &mut [u8], address: usize, value: V128) -> Result<(), TrapCode> {
1326-
memory::store_at(memory, address, value.to_i128())
1280+
memory::store_at(memory, address, value.as_u128())
13271281
}
13281282

13291283
macro_rules! impl_v128_storeN_lane {
@@ -1424,7 +1378,7 @@ impl_v128_storeN_lane_at! {
14241378
/// - If `ptr + offset` overflows.
14251379
/// - If `ptr + offset` loads out of bounds from `memory`.
14261380
pub fn v128_load(memory: &[u8], ptr: u64, offset: u64) -> Result<V128, TrapCode> {
1427-
memory::load::<i128>(memory, ptr, offset).map(V128::from)
1381+
memory::load::<u128>(memory, ptr, offset).map(V128::from)
14281382
}
14291383

14301384
/// Executes a Wasmi `v128.load` instruction.
@@ -1433,7 +1387,7 @@ pub fn v128_load(memory: &[u8], ptr: u64, offset: u64) -> Result<V128, TrapCode>
14331387
///
14341388
/// If `address` loads out of bounds from `memory`.
14351389
pub fn v128_load_at(memory: &[u8], address: usize) -> Result<V128, TrapCode> {
1436-
memory::load_at::<i128>(memory, address).map(V128::from)
1390+
memory::load_at::<u128>(memory, address).map(V128::from)
14371391
}
14381392

14391393
macro_rules! impl_v128_loadN_zero_for {

0 commit comments

Comments
 (0)