Skip to content
Merged
6 changes: 6 additions & 0 deletions crates/core/src/simd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ macro_rules! impl_imm_lane_id {
}
}

impl From<$name> for u8 {
fn from(lane: $name) -> u8 {
lane.get()
}
}

impl TryFrom<u8> for $name {
type Error = OutOfBoundsLaneIdx;

Expand Down
24 changes: 24 additions & 0 deletions crates/ir/src/enum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,30 @@
}
Err(self)
}

/// Creates a new [`Instruction::Imm16AndImm32`] from the given `lane` and `memory` index.
pub fn lane_and_memory_index(value: impl Into<u8>, memory: Memory) -> Self {
Self::imm16_and_imm32(u16::from(value.into()), u32::from(memory))
}

/// Returns `Some` lane and [`index::Memory`] if encoded properly.
///
/// # Errors
///
/// Returns back `self` if it was an incorrect [`Instruction`].
/// This allows for a better error message to inform the user.
pub fn filter_lane_and_memory<LaneType>(self) -> Result<(LaneType, index::Memory), Self>
where
LaneType: TryFrom<u8>,
{
if let Instruction::Imm16AndImm32 { imm16, imm32 } = self {
let Ok(lane) = LaneType::try_from(i16::from(imm16) as u16 as u8) else {
return Err(self);

Check warning on line 284 in crates/ir/src/enum.rs

View check run for this annotation

Codecov / codecov/patch

crates/ir/src/enum.rs#L284

Added line #L284 was not covered by tests
};
return Ok((lane, index::Memory::from(u32::from(imm32))));
}
Err(self)

Check warning on line 288 in crates/ir/src/enum.rs

View check run for this annotation

Codecov / codecov/patch

crates/ir/src/enum.rs#L288

Added line #L288 was not covered by tests
}
}

#[test]
Expand Down
64 changes: 52 additions & 12 deletions crates/wasmi/src/engine/executor/instrs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1976,49 +1976,89 @@
self.execute_v128_store_at(&mut store.inner, address, value)?
}
#[cfg(feature = "simd")]
Instr::V128Store8Lane { ptr, offset_lo } => todo!(),
Instr::V128Store8Lane { ptr, offset_lo } => {
self.execute_v128_store8_lane(&mut store.inner, ptr, offset_lo)?

Check warning on line 1980 in crates/wasmi/src/engine/executor/instrs.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs.rs#L1979-L1980

Added lines #L1979 - L1980 were not covered by tests
}
#[cfg(feature = "simd")]
Instr::V128Store8LaneOffset8 {
ptr,
value,
offset,
lane,
} => todo!(),
} => self.execute_v128_store8_lane_offset8(
&mut store.inner,
ptr,
value,
offset,
lane,

Check warning on line 1993 in crates/wasmi/src/engine/executor/instrs.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs.rs#L1988-L1993

Added lines #L1988 - L1993 were not covered by tests
)?,
#[cfg(feature = "simd")]
Instr::V128Store8LaneAt { value, address } => todo!(),
Instr::V128Store8LaneAt { value, address } => {
self.execute_v128_store8_lane_at(&mut store.inner, value, address)?
}
#[cfg(feature = "simd")]
Instr::V128Store16Lane { ptr, offset_lo } => todo!(),
Instr::V128Store16Lane { ptr, offset_lo } => {
self.execute_v128_store16_lane(&mut store.inner, ptr, offset_lo)?

Check warning on line 2001 in crates/wasmi/src/engine/executor/instrs.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs.rs#L2000-L2001

Added lines #L2000 - L2001 were not covered by tests
}
#[cfg(feature = "simd")]
Instr::V128Store16LaneOffset8 {
ptr,
value,
offset,
lane,
} => todo!(),
} => self.execute_v128_store16_lane_offset8(
&mut store.inner,
ptr,
value,
offset,
lane,

Check warning on line 2014 in crates/wasmi/src/engine/executor/instrs.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs.rs#L2009-L2014

Added lines #L2009 - L2014 were not covered by tests
)?,
#[cfg(feature = "simd")]
Instr::V128Store16LaneAt { value, address } => todo!(),
Instr::V128Store16LaneAt { value, address } => {
self.execute_v128_store16_lane_at(&mut store.inner, value, address)?
}
#[cfg(feature = "simd")]
Instr::V128Store32Lane { ptr, offset_lo } => todo!(),
Instr::V128Store32Lane { ptr, offset_lo } => {
self.execute_v128_store32_lane(&mut store.inner, ptr, offset_lo)?

Check warning on line 2022 in crates/wasmi/src/engine/executor/instrs.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs.rs#L2021-L2022

Added lines #L2021 - L2022 were not covered by tests
}
#[cfg(feature = "simd")]
Instr::V128Store32LaneOffset8 {
ptr,
value,
offset,
lane,
} => todo!(),
} => self.execute_v128_store32_lane_offset8(
&mut store.inner,
ptr,
value,
offset,
lane,

Check warning on line 2035 in crates/wasmi/src/engine/executor/instrs.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs.rs#L2030-L2035

Added lines #L2030 - L2035 were not covered by tests
)?,
#[cfg(feature = "simd")]
Instr::V128Store32LaneAt { value, address } => todo!(),
Instr::V128Store32LaneAt { value, address } => {
self.execute_v128_store32_lane_at(&mut store.inner, value, address)?
}
#[cfg(feature = "simd")]
Instr::V128Store64Lane { ptr, offset_lo } => todo!(),
Instr::V128Store64Lane { ptr, offset_lo } => {
self.execute_v128_store64_lane(&mut store.inner, ptr, offset_lo)?

Check warning on line 2043 in crates/wasmi/src/engine/executor/instrs.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs.rs#L2042-L2043

Added lines #L2042 - L2043 were not covered by tests
}
#[cfg(feature = "simd")]
Instr::V128Store64LaneOffset8 {
ptr,
value,
offset,
lane,
} => todo!(),
} => self.execute_v128_store64_lane_offset8(
&mut store.inner,
ptr,
value,
offset,
lane,

Check warning on line 2056 in crates/wasmi/src/engine/executor/instrs.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs.rs#L2051-L2056

Added lines #L2051 - L2056 were not covered by tests
)?,
#[cfg(feature = "simd")]
Instr::V128Store64LaneAt { value, address } => todo!(),
Instr::V128Store64LaneAt { value, address } => {
self.execute_v128_store64_lane_at(&mut store.inner, value, address)?
}
#[cfg(feature = "simd")]
Instr::V128Load { result, offset_lo } => {
self.execute_v128_load(&store.inner, result, offset_lo)?
Expand Down
184 changes: 181 additions & 3 deletions crates/wasmi/src/engine/executor/instrs/simd.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
use super::Executor;
use crate::{
core::{
simd,
simd::{ImmLaneIdx16, ImmLaneIdx2, ImmLaneIdx32, ImmLaneIdx4, ImmLaneIdx8},
simd::{self, ImmLaneIdx16, ImmLaneIdx2, ImmLaneIdx32, ImmLaneIdx4, ImmLaneIdx8},
TrapCode,
UntypedVal,
WriteAs,
V128,
},
engine::{executor::InstructionPtr, utils::unreachable_unchecked},
ir::{AnyConst32, Instruction, Reg, ShiftAmount},
ir::{
index,
Address32,
AnyConst32,
Instruction,
Offset64,
Offset64Lo,
Offset8,
Reg,
ShiftAmount,
},
store::StoreInner,
Error,
};

impl Executor<'_> {
Expand Down Expand Up @@ -491,3 +503,169 @@
(Instruction::I64x2ShrUBy, execute_i64x2_shr_u_by, simd::i64x2_shr_u),
}
}

impl Executor<'_> {
/// Returns the optional `memory` parameter for a `load_at` [`Instruction`].
///
/// # Note
///
/// - Returns the default [`index::Memory`] if the parameter is missing.
/// - Bumps `self.ip` if a [`Instruction::MemoryIndex`] parameter was found.
#[inline(always)]
fn fetch_lane_and_memory<LaneType>(&mut self, delta: usize) -> (LaneType, index::Memory)

Check warning on line 515 in crates/wasmi/src/engine/executor/instrs/simd.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/simd.rs#L515

Added line #L515 was not covered by tests
where
LaneType: TryFrom<u8>,
{
let mut addr: InstructionPtr = self.ip;
addr.add(delta);
match addr.get().filter_lane_and_memory() {
Ok(value) => value,
Err(instr) => unsafe {
unreachable_unchecked!(

Check warning on line 524 in crates/wasmi/src/engine/executor/instrs/simd.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/simd.rs#L524

Added line #L524 was not covered by tests
"expected an `Instruction::Imm16AndImm32` but found: {instr:?}"
)
},
}
}
}

macro_rules! impl_execute_v128_store_lane {
(
$( (Instruction::$op:ident, $lane_ty:ty, $exec:ident, $eval:expr) ),* $(,)?
) => {
$(
#[doc = concat!("Executes an [`Instruction::", stringify!($op), "`] instruction.")]
pub fn $exec(

Check warning on line 538 in crates/wasmi/src/engine/executor/instrs/simd.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/simd.rs#L538

Added line #L538 was not covered by tests
&mut self,
store: &mut StoreInner,
ptr: Reg,
offset_lo: Offset64Lo,
) -> Result<(), Error> {
self.execute_v128_store_lane::<$lane_ty>(store, ptr, offset_lo, $eval)

Check warning on line 544 in crates/wasmi/src/engine/executor/instrs/simd.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/simd.rs#L544

Added line #L544 was not covered by tests
}
)*
};
}

macro_rules! impl_execute_v128_store_lane_offset16 {
(
$( (Instruction::$op:ident, $lane_ty:ty, $exec:ident, $eval:expr) ),* $(,)?
) => {
$(
#[doc = concat!("Executes an [`Instruction::", stringify!($op), "`] instruction.")]
pub fn $exec(
&mut self,
store: &mut StoreInner,
ptr: Reg,
value: Reg,
offset: Offset8,
lane: $lane_ty,
) -> Result<(), Error> {
self.execute_v128_store_lane_offset8::<$lane_ty>(store, ptr, value, offset, lane, $eval)
}
)*
};
}

macro_rules! impl_execute_v128_store_lane_at {
(
$( (Instruction::$op:ident, $lane_ty:ty, $exec:ident, $eval:expr) ),* $(,)?
) => {
$(
#[doc = concat!("Executes an [`Instruction::", stringify!($op), "`] instruction.")]
pub fn $exec(
&mut self,
store: &mut StoreInner,
value: Reg,
address: Address32,
) -> Result<(), Error> {
self.execute_v128_store_lane_at::<$lane_ty>(store, value, address, $eval)
}
)*
};
}

type V128StoreLane<LaneType> = fn(
memory: &mut [u8],
ptr: u64,
offset: u64,
value: V128,
lane: LaneType,
) -> Result<(), TrapCode>;

type V128StoreLaneAt<LaneType> =
fn(memory: &mut [u8], address: usize, value: V128, lane: LaneType) -> Result<(), TrapCode>;

impl Executor<'_> {
fn execute_v128_store_lane<LaneType>(

Check warning on line 600 in crates/wasmi/src/engine/executor/instrs/simd.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/simd.rs#L600

Added line #L600 was not covered by tests
&mut self,
store: &mut StoreInner,
ptr: Reg,
offset_lo: Offset64Lo,
eval: V128StoreLane<LaneType>,
) -> Result<(), Error> {
let (value, offset_hi) = self.fetch_value_and_offset_hi();
let (lane, memory) = self.fetch_lane_and_memory(2);
let offset = Offset64::combine(offset_hi, offset_lo);
let ptr = self.get_register_as::<u64>(ptr);
let v128 = self.get_register_as::<V128>(value);
let memory = self.fetch_memory_bytes_mut(memory, store);
simd::v128_store8_lane(memory, ptr, u64::from(offset), v128, lane)?;
self.try_next_instr_at(3)

Check warning on line 614 in crates/wasmi/src/engine/executor/instrs/simd.rs

View check run for this annotation

Codecov / codecov/patch

crates/wasmi/src/engine/executor/instrs/simd.rs#L607-L614

Added lines #L607 - L614 were not covered by tests
}

impl_execute_v128_store_lane! {
(Instruction::V128Store8Lane, ImmLaneIdx16, execute_v128_store8_lane, simd::v128_store8_lane),
(Instruction::V128Store16Lane, ImmLaneIdx8, execute_v128_store16_lane, simd::v128_store16_lane),
(Instruction::V128Store32Lane, ImmLaneIdx4, execute_v128_store32_lane, simd::v128_store32_lane),
(Instruction::V128Store64Lane, ImmLaneIdx2, execute_v128_store64_lane, simd::v128_store64_lane),
}

fn execute_v128_store_lane_offset8<LaneType>(
&mut self,
store: &mut StoreInner,
ptr: Reg,
value: Reg,
offset: Offset8,
lane: LaneType,
eval: V128StoreLane<LaneType>,
) -> Result<(), Error> {
let ptr = self.get_register_as::<u64>(ptr);
let offset = u64::from(Offset64::from(offset));
let v128 = self.get_register_as::<V128>(value);
let memory = self.fetch_default_memory_bytes_mut();
eval(memory, ptr, offset, v128, lane)?;
self.try_next_instr()
}

impl_execute_v128_store_lane_offset16! {
(Instruction::V128Store8LaneOffset8, ImmLaneIdx16, execute_v128_store8_lane_offset8, simd::v128_store8_lane),
(Instruction::V128Store16LaneOffset8, ImmLaneIdx8, execute_v128_store16_lane_offset8, simd::v128_store16_lane),
(Instruction::V128Store32LaneOffset8, ImmLaneIdx4, execute_v128_store32_lane_offset8, simd::v128_store32_lane),
(Instruction::V128Store64LaneOffset8, ImmLaneIdx2, execute_v128_store64_lane_offset8, simd::v128_store64_lane),
}

fn execute_v128_store_lane_at<LaneType>(
&mut self,
store: &mut StoreInner,
value: Reg,
address: Address32,
eval: V128StoreLaneAt<LaneType>,
) -> Result<(), Error>
where
LaneType: TryFrom<u8> + Into<u8>,
{
let (lane, memory) = self.fetch_lane_and_memory::<LaneType>(1);
let v128 = self.get_register_as::<V128>(value);
let memory = self.fetch_memory_bytes_mut(memory, store);
eval(memory, usize::from(address), v128, lane)?;
self.try_next_instr_at(2)
}

impl_execute_v128_store_lane_at! {
(Instruction::V128Store8LaneAt, ImmLaneIdx16, execute_v128_store8_lane_at, simd::v128_store8_lane_at),
(Instruction::V128Store16LaneAt, ImmLaneIdx8, execute_v128_store16_lane_at, simd::v128_store16_lane_at),
(Instruction::V128Store32LaneAt, ImmLaneIdx4, execute_v128_store32_lane_at, simd::v128_store32_lane_at),
(Instruction::V128Store64LaneAt, ImmLaneIdx2, execute_v128_store64_lane_at, simd::v128_store64_lane_at),
}
}
Loading