Skip to content

Commit

Permalink
implement Wasm proposal: non-trapping-float-to-int-conversions
Browse files Browse the repository at this point in the history
  • Loading branch information
Robbepop committed Feb 13, 2022
1 parent 8830ee3 commit 09752c3
Show file tree
Hide file tree
Showing 10 changed files with 171 additions and 8 deletions.
1 change: 1 addition & 0 deletions core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub use self::{
Integer,
LittleEndianConvert,
TransmuteInto,
TruncateSaturateInto,
TryTruncateInto,
Value,
ValueType,
Expand Down
44 changes: 44 additions & 0 deletions core/src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,11 +105,32 @@ pub trait WrapInto<T> {
}

/// Convert one type to another by rounding to the nearest integer towards zero.
///
/// # Errors
///
/// Traps when the input float cannot be represented by the target integer or
/// when the input float is NaN.
pub trait TryTruncateInto<T, E> {
/// Convert one type to another by rounding to the nearest integer towards zero.
fn try_truncate_into(self) -> Result<T, E>;
}

/// Convert one type to another by rounding to the nearest integer towards zero.
///
/// # Note
///
/// This has saturating semantics for when the integer cannot represent the float.
///
/// Returns
///
/// - `0` when the input is NaN.
/// - `int::MIN` when the input is -INF.
/// - `int::MAX` when the input is +INF.
pub trait TruncateSaturateInto<T> {
/// Convert one type to another by rounding to the nearest integer towards zero.
fn truncate_saturate_into(self) -> T;
}

/// Convert one type to another by extending with leading zeroes.
pub trait ExtendInto<T> {
/// Convert one type to another by extending with leading zeroes.
Expand Down Expand Up @@ -503,6 +524,22 @@ macro_rules! impl_try_truncate_into {
.ok_or(TrapCode::IntegerOverflow)
}
}

impl TruncateSaturateInto<$into> for $from {
#[inline]
fn truncate_saturate_into(self) -> $into {
if self.is_nan() {
return <$into as Default>::default();
}
if self.is_infinite() && self.is_sign_positive() {
return <$into>::MAX;
}
if self.is_infinite() && self.is_sign_negative() {
return <$into>::MIN;
}
self as _
}
}
};
(@wrapped $from:ident, $intermediate:ident, $into:ident) => {
impl TryTruncateInto<$into, TrapCode> for $from {
Expand All @@ -511,6 +548,13 @@ macro_rules! impl_try_truncate_into {
$intermediate::from(self).try_truncate_into()
}
}

impl TruncateSaturateInto<$into> for $from {
#[inline]
fn truncate_saturate_into(self) -> $into {
$intermediate::from(self).truncate_saturate_into()
}
}
};
}

Expand Down
9 changes: 9 additions & 0 deletions tests/spec/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ macro_rules! define_tests {
)*
};
}

mod non_trapping_float_to_int_conversions {
use super::*;

define_tests! {
fn wasm_conversions("proposals/nontrapping-float-to-int-conversions/conversions");
}
}

define_tests! {
fn wasm_address("address");
fn wasm_align("align");
Expand Down
8 changes: 8 additions & 0 deletions wasmi_v1/src/engine/bytecode/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,14 @@ pub enum Instruction {
I64ReinterpretF64,
F32ReinterpretI32,
F64ReinterpretI64,
I32TruncSatF32S,
I32TruncSatF32U,
I32TruncSatF64S,
I32TruncSatF64U,
I64TruncSatF32S,
I64TruncSatF32U,
I64TruncSatF64S,
I64TruncSatF64U,

/// The start of a Wasm function body.
///
Expand Down
9 changes: 9 additions & 0 deletions wasmi_v1/src/engine/bytecode/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -169,4 +169,13 @@ pub trait VisitInstruction {
fn visit_i64_reinterpret_f64(&mut self) -> Self::Outcome;
fn visit_f32_reinterpret_i32(&mut self) -> Self::Outcome;
fn visit_f64_reinterpret_i64(&mut self) -> Self::Outcome;

fn visit_i32_trunc_sat_f32(&mut self) -> Self::Outcome;
fn visit_u32_trunc_sat_f32(&mut self) -> Self::Outcome;
fn visit_i32_trunc_sat_f64(&mut self) -> Self::Outcome;
fn visit_u32_trunc_sat_f64(&mut self) -> Self::Outcome;
fn visit_i64_trunc_sat_f32(&mut self) -> Self::Outcome;
fn visit_u64_trunc_sat_f32(&mut self) -> Self::Outcome;
fn visit_i64_trunc_sat_f64(&mut self) -> Self::Outcome;
fn visit_u64_trunc_sat_f64(&mut self) -> Self::Outcome;
}
8 changes: 8 additions & 0 deletions wasmi_v1/src/engine/code_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,14 @@ impl<'a> ResolvedFuncBody<'a> {
Instruction::I64ReinterpretF64 => visitor.visit_i64_reinterpret_f64(),
Instruction::F32ReinterpretI32 => visitor.visit_f32_reinterpret_i32(),
Instruction::F64ReinterpretI64 => visitor.visit_f64_reinterpret_i64(),
Instruction::I32TruncSatF32S => visitor.visit_i32_trunc_sat_f32(),
Instruction::I32TruncSatF32U => visitor.visit_u32_trunc_sat_f32(),
Instruction::I32TruncSatF64S => visitor.visit_i32_trunc_sat_f64(),
Instruction::I32TruncSatF64U => visitor.visit_u32_trunc_sat_f64(),
Instruction::I64TruncSatF32S => visitor.visit_i64_trunc_sat_f32(),
Instruction::I64TruncSatF32U => visitor.visit_u64_trunc_sat_f32(),
Instruction::I64TruncSatF64S => visitor.visit_i64_trunc_sat_f64(),
Instruction::I64TruncSatF64U => visitor.visit_u64_trunc_sat_f64(),
Instruction::FuncBodyStart { .. } | Instruction::FuncBodyEnd => panic!(
"expected start of a new instruction at index {} but found: {:?}",
index, inst
Expand Down
43 changes: 43 additions & 0 deletions wasmi_v1/src/engine/exec_context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ use wasmi_core::{
Float,
Integer,
LittleEndianConvert,
TruncateSaturateInto,
TryTruncateInto,
WrapInto,
};
Expand Down Expand Up @@ -646,6 +647,17 @@ where
Ok(ExecutionOutcome::Continue)
}

fn execute_trunc_sat_to_int<T, U>(&mut self) -> Result<ExecutionOutcome, Trap>
where
StackEntry: From<U>,
T: TruncateSaturateInto<U> + FromStackEntry,
{
let entry = self.value_stack.last_mut();
let value = T::from_stack_entry(*entry).truncate_saturate_into();
*entry = value.into();
Ok(ExecutionOutcome::Continue)
}

fn execute_reinterpret<T, U>(&mut self) -> Result<ExecutionOutcome, Trap>
where
StackEntry: From<U>,
Expand Down Expand Up @@ -1409,4 +1421,35 @@ where
fn visit_f64_reinterpret_i64(&mut self) -> Self::Outcome {
self.execute_reinterpret::<i64, F64>()
}

fn visit_i32_trunc_sat_f32(&mut self) -> Self::Outcome {
self.execute_trunc_sat_to_int::<F32, i32>()
}

fn visit_u32_trunc_sat_f32(&mut self) -> Self::Outcome {
self.execute_trunc_sat_to_int::<F32, u32>()
}

fn visit_i32_trunc_sat_f64(&mut self) -> Self::Outcome {
self.execute_trunc_sat_to_int::<F64, i32>()
}

fn visit_u32_trunc_sat_f64(&mut self) -> Self::Outcome {
self.execute_trunc_sat_to_int::<F64, u32>()
}
fn visit_i64_trunc_sat_f32(&mut self) -> Self::Outcome {
self.execute_trunc_sat_to_int::<F32, i64>()
}

fn visit_u64_trunc_sat_f32(&mut self) -> Self::Outcome {
self.execute_trunc_sat_to_int::<F32, u64>()
}

fn visit_i64_trunc_sat_f64(&mut self) -> Self::Outcome {
self.execute_trunc_sat_to_int::<F64, i64>()
}

fn visit_u64_trunc_sat_f64(&mut self) -> Self::Outcome {
self.execute_trunc_sat_to_int::<F64, u64>()
}
}
25 changes: 25 additions & 0 deletions wasmi_v1/src/engine/func_builder/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1874,4 +1874,29 @@ impl<'engine, 'parser> FunctionBuilder<'engine, 'parser> {
Instruction::F64ReinterpretI64,
)
}

pub fn translate_i32_truncate_saturate_f32(&mut self) -> Result<(), ModuleError> {
self.translate_conversion(ValueType::F32, ValueType::I32, Instruction::I32TruncSatF32S)
}
pub fn translate_u32_truncate_saturate_f32(&mut self) -> Result<(), ModuleError> {
self.translate_conversion(ValueType::F32, ValueType::I32, Instruction::I32TruncSatF32U)
}
pub fn translate_i32_truncate_saturate_f64(&mut self) -> Result<(), ModuleError> {
self.translate_conversion(ValueType::F64, ValueType::I32, Instruction::I32TruncSatF64S)
}
pub fn translate_u32_truncate_saturate_f64(&mut self) -> Result<(), ModuleError> {
self.translate_conversion(ValueType::F64, ValueType::I32, Instruction::I32TruncSatF64U)
}
pub fn translate_i64_truncate_saturate_f32(&mut self) -> Result<(), ModuleError> {
self.translate_conversion(ValueType::F32, ValueType::I64, Instruction::I64TruncSatF32S)
}
pub fn translate_u64_truncate_saturate_f32(&mut self) -> Result<(), ModuleError> {
self.translate_conversion(ValueType::F32, ValueType::I32, Instruction::I64TruncSatF32U)
}
pub fn translate_i64_truncate_saturate_f64(&mut self) -> Result<(), ModuleError> {
self.translate_conversion(ValueType::F64, ValueType::I64, Instruction::I64TruncSatF64S)
}
pub fn translate_u64_truncate_saturate_f64(&mut self) -> Result<(), ModuleError> {
self.translate_conversion(ValueType::F64, ValueType::I32, Instruction::I64TruncSatF64U)
}
}
16 changes: 8 additions & 8 deletions wasmi_v1/src/module/compile/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -302,19 +302,19 @@ impl<'engine, 'parser> FunctionTranslator<'engine, 'parser> {
Operator::I64ReinterpretF64 => self.translate_i64_reinterpret_f64(),
Operator::F32ReinterpretI32 => self.translate_f32_reinterpret_i32(),
Operator::F64ReinterpretI64 => self.translate_f64_reinterpret_i64(),
Operator::I32TruncSatF32S => self.translate_i32_truncate_saturate_f32(),
Operator::I32TruncSatF32U => self.translate_u32_truncate_saturate_f32(),
Operator::I32TruncSatF64S => self.translate_i32_truncate_saturate_f64(),
Operator::I32TruncSatF64U => self.translate_u32_truncate_saturate_f64(),
Operator::I64TruncSatF32S => self.translate_i64_truncate_saturate_f32(),
Operator::I64TruncSatF32U => self.translate_u64_truncate_saturate_f32(),
Operator::I64TruncSatF64S => self.translate_i64_truncate_saturate_f64(),
Operator::I64TruncSatF64U => self.translate_u64_truncate_saturate_f64(),
Operator::I32Extend8S
| Operator::I32Extend16S
| Operator::I64Extend8S
| Operator::I64Extend16S
| Operator::I64Extend32S
| Operator::I32TruncSatF32S
| Operator::I32TruncSatF32U
| Operator::I32TruncSatF64S
| Operator::I32TruncSatF64U
| Operator::I64TruncSatF32S
| Operator::I64TruncSatF32U
| Operator::I64TruncSatF64S
| Operator::I64TruncSatF64U
| Operator::MemoryInit { .. }
| Operator::DataDrop { .. }
| Operator::MemoryCopy { .. }
Expand Down
16 changes: 16 additions & 0 deletions wasmi_v1/src/module/compile/operator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -709,5 +709,21 @@ impl<'engine, 'parser> FunctionTranslator<'engine, 'parser> {
fn translate_f32_reinterpret_i32();
/// Translate a Wasm `f64_reinterpret_i64` instruction.
fn translate_f64_reinterpret_i64();
/// Translate a Wasm `i32.truncate_saturate_f32` instruction.
fn translate_i32_truncate_saturate_f32();
/// Translate a Wasm `u32.truncate_saturate_f32` instruction.
fn translate_u32_truncate_saturate_f32();
/// Translate a Wasm `i32.truncate_saturate_f64` instruction.
fn translate_i32_truncate_saturate_f64();
/// Translate a Wasm `u32.truncate_saturate_f64` instruction.
fn translate_u32_truncate_saturate_f64();
/// Translate a Wasm `i64.truncate_saturate_f32` instruction.
fn translate_i64_truncate_saturate_f32();
/// Translate a Wasm `u64.truncate_saturate_f32` instruction.
fn translate_u64_truncate_saturate_f32();
/// Translate a Wasm `i64.truncate_saturate_f64` instruction.
fn translate_i64_truncate_saturate_f64();
/// Translate a Wasm `u64.truncate_saturate_f64` instruction.
fn translate_u64_truncate_saturate_f64();
}
}

0 comments on commit 09752c3

Please sign in to comment.