From b7d4dd2d9461457e4ae1483a9bb429c8872daf32 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 3 Jul 2025 13:52:50 +0200 Subject: [PATCH 1/5] add reinterpret-like Wasm APIs --- crates/core/src/wasm.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crates/core/src/wasm.rs b/crates/core/src/wasm.rs index cc7dcc7967..3673068127 100644 --- a/crates/core/src/wasm.rs +++ b/crates/core/src/wasm.rs @@ -222,6 +222,7 @@ impl_untyped_val! { fn i32_wrap_i64(value: i64) -> i32 = |v| v as i32; fn i64_extend_i32_s(value: i32) -> i64 = i64::from; + fn i64_extend_i32_u(value: u32) -> u64 = u64::from; fn f32_demote_f64(value: f64) -> f32 = |v| v as f32; fn f64_promote_f32(value: f32) -> f64 = f64::from; @@ -487,3 +488,23 @@ pub fn i64_mul_wide_u(lhs: i64, rhs: i64) -> (i64, i64) { let result = lhs.wrapping_mul(rhs); split128(result as i128) } + +/// Execute an `i32.reinterpret_f32` Wasm instruction. +pub fn i32_reinterpret_f32(value: f32) -> i32 { + i32::from_ne_bytes(f32::to_ne_bytes(value)) +} + +/// Execute an `i64.reinterpret_f64` Wasm instruction. +pub fn i64_reinterpret_f64(value: f64) -> i64 { + i64::from_ne_bytes(f64::to_ne_bytes(value)) +} + +/// Execute an `f32.reinterpret_i32` Wasm instruction. +pub fn f32_reinterpret_i32(value: i32) -> f32 { + f32::from_ne_bytes(i32::to_ne_bytes(value)) +} + +/// Execute an `f64.reinterpret_i64` Wasm instruction. +pub fn f64_reinterpret_i64(value: i64) -> f64 { + f64::from_ne_bytes(i64::to_ne_bytes(value)) +} From 541af71734248231a32f6aaac537b171be30ed3e Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 3 Jul 2025 14:03:29 +0200 Subject: [PATCH 2/5] use macro to generate reinterpret functions --- crates/core/src/wasm.rs | 31 ++++++++++++++----------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/crates/core/src/wasm.rs b/crates/core/src/wasm.rs index 3673068127..281d372317 100644 --- a/crates/core/src/wasm.rs +++ b/crates/core/src/wasm.rs @@ -489,22 +489,19 @@ pub fn i64_mul_wide_u(lhs: i64, rhs: i64) -> (i64, i64) { split128(result as i128) } -/// Execute an `i32.reinterpret_f32` Wasm instruction. -pub fn i32_reinterpret_f32(value: f32) -> i32 { - i32::from_ne_bytes(f32::to_ne_bytes(value)) -} - -/// Execute an `i64.reinterpret_f64` Wasm instruction. -pub fn i64_reinterpret_f64(value: f64) -> i64 { - i64::from_ne_bytes(f64::to_ne_bytes(value)) -} - -/// Execute an `f32.reinterpret_i32` Wasm instruction. -pub fn f32_reinterpret_i32(value: i32) -> f32 { - f32::from_ne_bytes(i32::to_ne_bytes(value)) +macro_rules! impl_reinterpret_cast { + ( $(fn $name:ident($from:ty) -> $to:ty);* $(;)? ) => { + $( + #[doc = concat!("Execute the `", stringify!($name), "` Wasm instruction.")] + pub fn $name(value: $from) -> $to { + <$to>::from_ne_bytes(<$from>::to_ne_bytes(value)) + } + )* + }; } - -/// Execute an `f64.reinterpret_i64` Wasm instruction. -pub fn f64_reinterpret_i64(value: i64) -> f64 { - f64::from_ne_bytes(i64::to_ne_bytes(value)) +impl_reinterpret_cast! { + fn i32_reinterpret_f32(f32) -> i32; + fn i64_reinterpret_f64(f64) -> i64; + fn f32_reinterpret_i32(i32) -> f32; + fn f64_reinterpret_i64(i64) -> f64; } From 8caded2328f29f5263b906fb82f325e4009bb106 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 3 Jul 2025 14:04:35 +0200 Subject: [PATCH 3/5] move reinterpret funcs definitions up --- crates/core/src/wasm.rs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/crates/core/src/wasm.rs b/crates/core/src/wasm.rs index 281d372317..93dd0c338f 100644 --- a/crates/core/src/wasm.rs +++ b/crates/core/src/wasm.rs @@ -284,6 +284,23 @@ impl_untyped_val! { fn i64_trunc_sat_f64_u(value: f64) -> u64 = TruncateSaturateInto::truncate_saturate_into; } +macro_rules! impl_reinterpret_cast { + ( $(fn $name:ident($from:ty) -> $to:ty);* $(;)? ) => { + $( + #[doc = concat!("Execute the `", stringify!($name), "` Wasm instruction.")] + pub fn $name(value: $from) -> $to { + <$to>::from_ne_bytes(<$from>::to_ne_bytes(value)) + } + )* + }; +} +impl_reinterpret_cast! { + fn i32_reinterpret_f32(f32) -> i32; + fn i64_reinterpret_f64(f64) -> i64; + fn f32_reinterpret_i32(i32) -> f32; + fn f64_reinterpret_i64(i64) -> f64; +} + macro_rules! gen_load_extend_fn { ( $( (fn $load_fn:ident, fn $load_at_fn:ident, $wrapped:ty => $ty:ty); )* @@ -488,20 +505,3 @@ pub fn i64_mul_wide_u(lhs: i64, rhs: i64) -> (i64, i64) { let result = lhs.wrapping_mul(rhs); split128(result as i128) } - -macro_rules! impl_reinterpret_cast { - ( $(fn $name:ident($from:ty) -> $to:ty);* $(;)? ) => { - $( - #[doc = concat!("Execute the `", stringify!($name), "` Wasm instruction.")] - pub fn $name(value: $from) -> $to { - <$to>::from_ne_bytes(<$from>::to_ne_bytes(value)) - } - )* - }; -} -impl_reinterpret_cast! { - fn i32_reinterpret_f32(f32) -> i32; - fn i64_reinterpret_f64(f64) -> i64; - fn f32_reinterpret_i32(i32) -> f32; - fn f64_reinterpret_i64(i64) -> f64; -} From 0c8db3a5db0d33147192c272552005459410fa91 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 3 Jul 2025 14:11:57 +0200 Subject: [PATCH 4/5] use new reinterpret API in translator --- .../wasmi/src/engine/translator/func/mod.rs | 27 +++++-------------- .../wasmi/src/engine/translator/func/visit.rs | 10 +++---- 2 files changed, 11 insertions(+), 26 deletions(-) diff --git a/crates/wasmi/src/engine/translator/func/mod.rs b/crates/wasmi/src/engine/translator/func/mod.rs index 72b4e10d75..2c5772bd3f 100644 --- a/crates/wasmi/src/engine/translator/func/mod.rs +++ b/crates/wasmi/src/engine/translator/func/mod.rs @@ -1976,25 +1976,11 @@ impl FuncTranslator { } /// Translates a Wasm `reinterpret` instruction. - fn translate_reinterpret(&mut self, ty: ValType) -> Result<(), Error> { - bail_unreachable!(self); - if let TypedProvider::Register(_) = self.stack.peek() { - // Nothing to do. - // - // We try to not manipulate the emulation stack if not needed. - return Ok(()); - } - // Case: At this point we know that the top-most stack item is a constant value. - // We pop it, change its type and push it back onto the stack. - let TypedProvider::Const(value) = self.stack.pop() else { - panic!("the top-most stack item was asserted to be a constant value but a register was found") - }; - self.stack.push_const(value.reinterpret(ty)); - Ok(()) - } - - /// Translates a Wasm `i64.extend_i32_u` instruction. - fn translate_i64_extend_i32_u(&mut self) -> Result<(), Error> { + fn translate_reinterpret(&mut self, consteval: fn(T) -> R) -> Result<(), Error> + where + T: From, + R: Into, + { bail_unreachable!(self); if let TypedProvider::Register(_) = self.stack.peek() { // Nothing to do. @@ -2007,8 +1993,7 @@ impl FuncTranslator { let TypedProvider::Const(value) = self.stack.pop() else { panic!("the top-most stack item was asserted to be a constant value but a register was found") }; - debug_assert_eq!(value.ty(), ValType::I32); - self.stack.push_const(u64::from(u32::from(value))); + self.stack.push_const(consteval(value.into())); Ok(()) } diff --git a/crates/wasmi/src/engine/translator/func/visit.rs b/crates/wasmi/src/engine/translator/func/visit.rs index 64e0e1aa96..064a920650 100644 --- a/crates/wasmi/src/engine/translator/func/visit.rs +++ b/crates/wasmi/src/engine/translator/func/visit.rs @@ -2844,7 +2844,7 @@ impl<'a> VisitOperator<'a> for FuncTranslator { } fn visit_i64_extend_i32_u(&mut self) -> Self::Output { - self.translate_i64_extend_i32_u() + self.translate_reinterpret(wasm::i64_extend_i32_u) } fn visit_i64_trunc_f32_s(&mut self) -> Self::Output { @@ -2916,19 +2916,19 @@ impl<'a> VisitOperator<'a> for FuncTranslator { } fn visit_i32_reinterpret_f32(&mut self) -> Self::Output { - self.translate_reinterpret(ValType::I32) + self.translate_reinterpret(wasm::i32_reinterpret_f32) } fn visit_i64_reinterpret_f64(&mut self) -> Self::Output { - self.translate_reinterpret(ValType::I64) + self.translate_reinterpret(wasm::i64_reinterpret_f64) } fn visit_f32_reinterpret_i32(&mut self) -> Self::Output { - self.translate_reinterpret(ValType::F32) + self.translate_reinterpret(wasm::f32_reinterpret_i32) } fn visit_f64_reinterpret_i64(&mut self) -> Self::Output { - self.translate_reinterpret(ValType::F64) + self.translate_reinterpret(wasm::f64_reinterpret_i64) } fn visit_i32_extend8_s(&mut self) -> Self::Output { From 2ba7d5e3cd67aa8b1e98f98d5202faa179fcd793 Mon Sep 17 00:00:00 2001 From: Robin Freyler Date: Thu, 3 Jul 2025 14:15:27 +0200 Subject: [PATCH 5/5] remove TypedVal::reinterpret as it is no longer needed --- crates/core/src/typed.rs | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/crates/core/src/typed.rs b/crates/core/src/typed.rs index bdbd6a08db..94ab475ff3 100644 --- a/crates/core/src/typed.rs +++ b/crates/core/src/typed.rs @@ -66,16 +66,6 @@ impl TypedVal { pub fn untyped(&self) -> UntypedVal { self.value } - - /// Changes the [`ValType`] of `self` to `ty`. - /// - /// # Note - /// - /// This acts similar to a Wasm reinterpret cast and - /// the underlying `value` bits are unchanged. - pub fn reinterpret(self, ty: ValType) -> Self { - Self { ty, ..self } - } } impl From for TypedVal