Path: blob/main/cranelift/interpreter/src/value.rs
3068 views
//! The [DataValueExt] trait is an extension trait for [DataValue]. It provides a lot of functions1//! used by the rest of the interpreter.23#![expect(trivial_numeric_casts, reason = "macro-generated code")]45use core::fmt::{self, Display, Formatter};6use core::ops::Neg;7use cranelift_codegen::data_value::{DataValue, DataValueCastFailure};8use cranelift_codegen::ir::immediates::{Ieee16, Ieee32, Ieee64, Ieee128};9use cranelift_codegen::ir::{Type, types};10use thiserror::Error;1112use crate::step::{SimdVec, extractlanes};1314pub type ValueResult<T> = Result<T, ValueError>;1516pub trait DataValueExt: Sized {17// Identity.18fn int(n: i128, ty: Type) -> ValueResult<Self>;19fn into_int_signed(self) -> ValueResult<i128>;20fn into_int_unsigned(self) -> ValueResult<u128>;21fn float(n: u64, ty: Type) -> ValueResult<Self>;22fn into_float(self) -> ValueResult<f64>;23fn is_float(&self) -> bool;24fn is_nan(&self) -> ValueResult<bool>;25fn bool(b: bool, vec_elem: bool, ty: Type) -> ValueResult<Self>;26fn into_bool(self) -> ValueResult<bool>;27fn vector(v: [u8; 16], ty: Type) -> ValueResult<Self>;28fn into_array(&self) -> ValueResult<[u8; 16]>;29fn convert(self, kind: ValueConversionKind) -> ValueResult<Self>;30fn concat(self, other: Self) -> ValueResult<Self>;3132fn is_negative(&self) -> ValueResult<bool>;33fn is_zero(&self) -> ValueResult<bool>;3435fn umax(self, other: Self) -> ValueResult<Self>;36fn smax(self, other: Self) -> ValueResult<Self>;37fn umin(self, other: Self) -> ValueResult<Self>;38fn smin(self, other: Self) -> ValueResult<Self>;3940// Comparison.41fn uno(&self, other: &Self) -> ValueResult<bool>;4243// Arithmetic.44fn add(self, other: Self) -> ValueResult<Self>;45fn sub(self, other: Self) -> ValueResult<Self>;46fn mul(self, other: Self) -> ValueResult<Self>;47fn udiv(self, other: Self) -> ValueResult<Self>;48fn sdiv(self, other: Self) -> ValueResult<Self>;49fn urem(self, other: Self) -> ValueResult<Self>;50fn srem(self, other: Self) -> ValueResult<Self>;51fn sqrt(self) -> ValueResult<Self>;52fn fma(self, a: Self, b: Self) -> ValueResult<Self>;53fn abs(self) -> ValueResult<Self>;54fn uadd_checked(self, other: Self) -> ValueResult<Option<Self>>;55fn sadd_checked(self, other: Self) -> ValueResult<Option<Self>>;56fn uadd_overflow(self, other: Self) -> ValueResult<(Self, bool)>;57fn sadd_overflow(self, other: Self) -> ValueResult<(Self, bool)>;58fn usub_overflow(self, other: Self) -> ValueResult<(Self, bool)>;59fn ssub_overflow(self, other: Self) -> ValueResult<(Self, bool)>;60fn umul_overflow(self, other: Self) -> ValueResult<(Self, bool)>;61fn smul_overflow(self, other: Self) -> ValueResult<(Self, bool)>;6263// Float operations64fn neg(self) -> ValueResult<Self>;65fn copysign(self, sign: Self) -> ValueResult<Self>;66fn ceil(self) -> ValueResult<Self>;67fn floor(self) -> ValueResult<Self>;68fn trunc(self) -> ValueResult<Self>;69fn nearest(self) -> ValueResult<Self>;7071// Saturating arithmetic.72fn uadd_sat(self, other: Self) -> ValueResult<Self>;73fn sadd_sat(self, other: Self) -> ValueResult<Self>;74fn usub_sat(self, other: Self) -> ValueResult<Self>;75fn ssub_sat(self, other: Self) -> ValueResult<Self>;7677// Bitwise.78fn shl(self, other: Self) -> ValueResult<Self>;79fn ushr(self, other: Self) -> ValueResult<Self>;80fn sshr(self, other: Self) -> ValueResult<Self>;81fn rotl(self, other: Self) -> ValueResult<Self>;82fn rotr(self, other: Self) -> ValueResult<Self>;83fn and(self, other: Self) -> ValueResult<Self>;84fn or(self, other: Self) -> ValueResult<Self>;85fn xor(self, other: Self) -> ValueResult<Self>;86fn not(self) -> ValueResult<Self>;8788// Bit counting.89fn count_ones(self) -> ValueResult<Self>;90fn leading_ones(self) -> ValueResult<Self>;91fn leading_zeros(self) -> ValueResult<Self>;92fn trailing_zeros(self) -> ValueResult<Self>;93fn reverse_bits(self) -> ValueResult<Self>;94fn swap_bytes(self) -> ValueResult<Self>;9596// An iterator over the lanes of a SIMD type97fn iter_lanes(&self, ty: Type) -> ValueResult<DataValueIterator>;98}99100#[derive(Error, Debug, PartialEq)]101pub enum ValueError {102#[error("unable to convert type {1} into class {0}")]103InvalidType(ValueTypeClass, Type),104#[error("unable to convert value into type {0}")]105InvalidValue(Type),106#[error("unable to convert to primitive integer")]107InvalidInteger(#[from] std::num::TryFromIntError),108#[error("unable to cast data value")]109InvalidDataValueCast(#[from] DataValueCastFailure),110#[error("performed a division by zero")]111IntegerDivisionByZero,112#[error("performed a operation that overflowed this integer type")]113IntegerOverflow,114}115116#[derive(Debug, PartialEq)]117pub enum ValueTypeClass {118Integer,119Boolean,120Float,121Vector,122}123124impl Display for ValueTypeClass {125fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {126match self {127ValueTypeClass::Integer => write!(f, "integer"),128ValueTypeClass::Boolean => write!(f, "boolean"),129ValueTypeClass::Float => write!(f, "float"),130ValueTypeClass::Vector => write!(f, "vector"),131}132}133}134135#[derive(Debug, Clone)]136pub enum ValueConversionKind {137/// Throw a [ValueError] if an exact conversion to [Type] is not possible; e.g. in `i32` to138/// `i16`, convert `0x00001234` to `0x1234`.139Exact(Type),140/// Truncate the value to fit into the specified [Type]; e.g. in `i16` to `i8`, `0x1234` becomes141/// `0x34`.142Truncate(Type),143/// Similar to Truncate, but extracts from the top of the value; e.g. in a `i32` to `u8`,144/// `0x12345678` becomes `0x12`.145ExtractUpper(Type),146/// Convert to a larger integer type, extending the sign bit; e.g. in `i8` to `i16`, `0xff`147/// becomes `0xffff`.148SignExtend(Type),149/// Convert to a larger integer type, extending with zeroes; e.g. in `i8` to `i16`, `0xff`150/// becomes `0x00ff`.151ZeroExtend(Type),152/// Convert a floating point number by rounding to the nearest possible value with ties to even.153/// See `fdemote`, e.g.154RoundNearestEven(Type),155/// Converts an integer into a boolean, zero integers are converted into a156/// `false`, while other integers are converted into `true`. Booleans are passed through.157ToBoolean,158/// Converts an integer into either -1 or zero.159Mask(Type),160}161162/// Helper for creating match expressions over [DataValue].163macro_rules! unary_match {164( $op:ident($arg1:expr); [ $( $data_value_ty:ident ),* ]; [ $( $return_value_ty:ident ),* ] ) => {165match $arg1 {166$( DataValue::$data_value_ty(a) => {167Ok(DataValue::$data_value_ty($return_value_ty::try_from(a.$op()).unwrap()))168} )*169_ => unimplemented!()170}171};172( $op:ident($arg1:expr); [ $( $data_value_ty:ident ),* ] ) => {173match $arg1 {174$( DataValue::$data_value_ty(a) => { Ok(DataValue::$data_value_ty(a.$op())) } )*175_ => unimplemented!()176}177};178}179macro_rules! binary_match {180( $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ] ) => {181match ($arg1, $arg2) {182$( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => { Ok(DataValue::$data_value_ty(a.$op(*b))) } )*183_ => unimplemented!()184}185};186( $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {187match ($arg1, $arg2) {188$( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => { Ok(DataValue::$data_value_ty((*a as $op_type).$op(*b as $op_type) as _)) } )*189_ => unimplemented!()190}191};192( option $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {193match ($arg1, $arg2) {194$( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => { Ok((*a as $op_type).$op(*b as $op_type).map(|v| DataValue::$data_value_ty(v as _))) } )*195_ => unimplemented!()196}197};198( pair $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {199match ($arg1, $arg2) {200$( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => {201let (f, s) = (*a as $op_type).$op(*b as $op_type);202Ok((DataValue::$data_value_ty(f as _), s))203} )*204_ => unimplemented!()205}206};207( $op:tt($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ] ) => {208match ($arg1, $arg2) {209$( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => { Ok(DataValue::$data_value_ty(a $op b)) } )*210_ => unimplemented!()211}212};213( $op:tt($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {214match ($arg1, $arg2) {215$( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => { Ok(DataValue::$data_value_ty(((*a as $op_type) $op (*b as $op_type)) as _)) } )*216_ => unimplemented!()217}218};219( $op:tt($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $a_type:ty ),* ]; rhs: $rhs:tt,$rhs_type:ty ) => {220match ($arg1, $arg2) {221$( (DataValue::$data_value_ty(a), DataValue::$rhs(b)) => { Ok(DataValue::$data_value_ty((*a as $a_type).$op(*b as $rhs_type) as _)) } )*222_ => unimplemented!()223}224};225}226227macro_rules! bitop {228( $op:tt($arg1:expr, $arg2:expr) ) => {229Ok(match ($arg1, $arg2) {230(DataValue::I8(a), DataValue::I8(b)) => DataValue::I8(a $op b),231(DataValue::I16(a), DataValue::I16(b)) => DataValue::I16(a $op b),232(DataValue::I32(a), DataValue::I32(b)) => DataValue::I32(a $op b),233(DataValue::I64(a), DataValue::I64(b)) => DataValue::I64(a $op b),234(DataValue::I128(a), DataValue::I128(b)) => DataValue::I128(a $op b),235(DataValue::F32(a), DataValue::F32(b)) => DataValue::F32(a $op b),236(DataValue::F64(a), DataValue::F64(b)) => DataValue::F64(a $op b),237(DataValue::V64(a), DataValue::V64(b)) => {238let mut a2 = a.clone();239for (a, b) in a2.iter_mut().zip(b.iter()) {240*a = *a $op *b;241}242DataValue::V64(a2)243}244(DataValue::V128(a), DataValue::V128(b)) => {245let mut a2 = a.clone();246for (a, b) in a2.iter_mut().zip(b.iter()) {247*a = *a $op *b;248}249DataValue::V128(a2)250}251_ => unimplemented!(),252})253};254}255256impl DataValueExt for DataValue {257fn int(n: i128, ty: Type) -> ValueResult<Self> {258if ty.is_vector() {259// match ensures graceful failure since read_from_slice_ne()260// panics on anything other than 8 and 16 bytes261match ty.bytes() {2628 | 16 => Ok(DataValue::read_from_slice_ne(&n.to_ne_bytes(), ty)),263_ => Err(ValueError::InvalidType(ValueTypeClass::Vector, ty)),264}265} else if ty.is_int() {266DataValue::from_integer(n, ty).map_err(|_| ValueError::InvalidValue(ty))267} else {268Err(ValueError::InvalidType(ValueTypeClass::Integer, ty))269}270}271272fn into_int_signed(self) -> ValueResult<i128> {273match self {274DataValue::I8(n) => Ok(n as i128),275DataValue::I16(n) => Ok(n as i128),276DataValue::I32(n) => Ok(n as i128),277DataValue::I64(n) => Ok(n as i128),278DataValue::I128(n) => Ok(n),279_ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())),280}281}282283fn into_int_unsigned(self) -> ValueResult<u128> {284match self {285DataValue::I8(n) => Ok(n as u8 as u128),286DataValue::I16(n) => Ok(n as u16 as u128),287DataValue::I32(n) => Ok(n as u32 as u128),288DataValue::I64(n) => Ok(n as u64 as u128),289DataValue::I128(n) => Ok(n as u128),290_ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())),291}292}293294fn float(bits: u64, ty: Type) -> ValueResult<Self> {295match ty {296types::F32 => Ok(DataValue::F32(Ieee32::with_bits(u32::try_from(bits)?))),297types::F64 => Ok(DataValue::F64(Ieee64::with_bits(bits))),298_ => Err(ValueError::InvalidType(ValueTypeClass::Float, ty)),299}300}301302fn into_float(self) -> ValueResult<f64> {303match self {304DataValue::F32(n) => Ok(n.as_f32() as f64),305DataValue::F64(n) => Ok(n.as_f64()),306_ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),307}308}309310fn is_float(&self) -> bool {311match self {312DataValue::F16(_) | DataValue::F32(_) | DataValue::F64(_) | DataValue::F128(_) => true,313_ => false,314}315}316317fn is_nan(&self) -> ValueResult<bool> {318match self {319DataValue::F32(f) => Ok(f.is_nan()),320DataValue::F64(f) => Ok(f.is_nan()),321_ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),322}323}324325fn bool(b: bool, vec_elem: bool, ty: Type) -> ValueResult<Self> {326assert!(ty.is_int());327macro_rules! make_bool {328($ty:ident) => {329Ok(DataValue::$ty(if b {330if vec_elem { -1 } else { 1 }331} else {3320333}))334};335}336337match ty {338types::I8 => make_bool!(I8),339types::I16 => make_bool!(I16),340types::I32 => make_bool!(I32),341types::I64 => make_bool!(I64),342types::I128 => make_bool!(I128),343_ => Err(ValueError::InvalidType(ValueTypeClass::Integer, ty)),344}345}346347fn into_bool(self) -> ValueResult<bool> {348match self {349DataValue::I8(b) => Ok(b != 0),350DataValue::I16(b) => Ok(b != 0),351DataValue::I32(b) => Ok(b != 0),352DataValue::I64(b) => Ok(b != 0),353DataValue::I128(b) => Ok(b != 0),354_ => Err(ValueError::InvalidType(ValueTypeClass::Boolean, self.ty())),355}356}357358fn vector(v: [u8; 16], ty: Type) -> ValueResult<Self> {359assert!(ty.is_vector() && [2, 4, 8, 16].contains(&ty.bytes()));360match ty.bytes() {36116 => Ok(DataValue::V128(v)),3628 => Ok(DataValue::V64(v[..8].try_into().unwrap())),3634 => Ok(DataValue::V32(v[..4].try_into().unwrap())),3642 => Ok(DataValue::V16(v[..2].try_into().unwrap())),365_ => unreachable!(),366}367}368369fn into_array(&self) -> ValueResult<[u8; 16]> {370match *self {371DataValue::V128(v) => Ok(v),372DataValue::V64(v) => {373let mut v128 = [0; 16];374v128[..8].clone_from_slice(&v);375Ok(v128)376}377DataValue::V32(v) => {378let mut v128 = [0; 16];379v128[..4].clone_from_slice(&v);380Ok(v128)381}382DataValue::V16(v) => {383let mut v128 = [0; 16];384v128[..2].clone_from_slice(&v);385Ok(v128)386}387_ => Err(ValueError::InvalidType(ValueTypeClass::Vector, self.ty())),388}389}390391fn convert(self, kind: ValueConversionKind) -> ValueResult<Self> {392Ok(match kind {393ValueConversionKind::Exact(ty) => match (self, ty) {394// TODO a lot to do here: from bmask to ireduce to bitcast...395(val, ty) if val.ty().is_int() && ty.is_int() => {396DataValue::from_integer(val.into_int_signed()?, ty)?397}398(DataValue::I16(n), types::F16) => DataValue::F16(Ieee16::with_bits(n as u16)),399(DataValue::I32(n), types::F32) => DataValue::F32(f32::from_bits(n as u32).into()),400(DataValue::I64(n), types::F64) => DataValue::F64(f64::from_bits(n as u64).into()),401(DataValue::I128(n), types::F128) => DataValue::F128(Ieee128::with_bits(n as u128)),402(DataValue::F16(n), types::I16) => DataValue::I16(n.bits() as i16),403(DataValue::F32(n), types::I32) => DataValue::I32(n.bits() as i32),404(DataValue::F64(n), types::I64) => DataValue::I64(n.bits() as i64),405(DataValue::F128(n), types::I128) => DataValue::I128(n.bits() as i128),406(DataValue::F32(n), types::F64) => DataValue::F64((n.as_f32() as f64).into()),407(dv, t) if (t.is_int() || t.is_float()) && dv.ty() == t => dv,408(dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),409},410ValueConversionKind::Truncate(ty) => {411assert!(412ty.is_int(),413"unimplemented conversion: {} -> {:?}",414self.ty(),415kind416);417418let mask = (1 << (ty.bytes() * 8)) - 1i128;419let truncated = self.into_int_signed()? & mask;420Self::from_integer(truncated, ty)?421}422ValueConversionKind::ExtractUpper(ty) => {423assert!(424ty.is_int(),425"unimplemented conversion: {} -> {:?}",426self.ty(),427kind428);429430let shift_amt = (self.ty().bytes() * 8) - (ty.bytes() * 8);431let mask = (1 << (ty.bytes() * 8)) - 1i128;432let shifted_mask = mask << shift_amt;433434let extracted = (self.into_int_signed()? & shifted_mask) >> shift_amt;435Self::from_integer(extracted, ty)?436}437ValueConversionKind::SignExtend(ty) => match (self, ty) {438(DataValue::I8(n), types::I16) => DataValue::I16(n as i16),439(DataValue::I8(n), types::I32) => DataValue::I32(n as i32),440(DataValue::I8(n), types::I64) => DataValue::I64(n as i64),441(DataValue::I8(n), types::I128) => DataValue::I128(n as i128),442(DataValue::I16(n), types::I32) => DataValue::I32(n as i32),443(DataValue::I16(n), types::I64) => DataValue::I64(n as i64),444(DataValue::I16(n), types::I128) => DataValue::I128(n as i128),445(DataValue::I32(n), types::I64) => DataValue::I64(n as i64),446(DataValue::I32(n), types::I128) => DataValue::I128(n as i128),447(DataValue::I64(n), types::I128) => DataValue::I128(n as i128),448(dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),449},450ValueConversionKind::ZeroExtend(ty) => match (self, ty) {451(DataValue::I8(n), types::I16) => DataValue::I16(n as u8 as i16),452(DataValue::I8(n), types::I32) => DataValue::I32(n as u8 as i32),453(DataValue::I8(n), types::I64) => DataValue::I64(n as u8 as i64),454(DataValue::I8(n), types::I128) => DataValue::I128(n as u8 as i128),455(DataValue::I16(n), types::I32) => DataValue::I32(n as u16 as i32),456(DataValue::I16(n), types::I64) => DataValue::I64(n as u16 as i64),457(DataValue::I16(n), types::I128) => DataValue::I128(n as u16 as i128),458(DataValue::I32(n), types::I64) => DataValue::I64(n as u32 as i64),459(DataValue::I32(n), types::I128) => DataValue::I128(n as u32 as i128),460(DataValue::I64(n), types::I128) => DataValue::I128(n as u64 as i128),461(from, to) if from.ty() == to => from,462(dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),463},464ValueConversionKind::RoundNearestEven(ty) => match (self, ty) {465(DataValue::F64(n), types::F32) => DataValue::F32(Ieee32::from(n.as_f64() as f32)),466(s, _) => unimplemented!("conversion: {} -> {:?}", s.ty(), kind),467},468ValueConversionKind::ToBoolean => match self.ty() {469ty if ty.is_int() => {470DataValue::I8(if self.into_int_signed()? != 0 { 1 } else { 0 })471}472ty => unimplemented!("conversion: {} -> {:?}", ty, kind),473},474ValueConversionKind::Mask(ty) => {475let b = self.into_bool()?;476Self::bool(b, true, ty).unwrap()477}478})479}480481fn concat(self, other: Self) -> ValueResult<Self> {482match (self, other) {483(DataValue::I64(lhs), DataValue::I64(rhs)) => Ok(DataValue::I128(484(((lhs as u64) as u128) | (((rhs as u64) as u128) << 64)) as i128,485)),486(lhs, rhs) => unimplemented!("concat: {} -> {}", lhs.ty(), rhs.ty()),487}488}489490fn is_negative(&self) -> ValueResult<bool> {491match self {492DataValue::F32(f) => Ok(f.is_negative()),493DataValue::F64(f) => Ok(f.is_negative()),494_ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),495}496}497498fn is_zero(&self) -> ValueResult<bool> {499match self {500DataValue::I8(f) => Ok(*f == 0),501DataValue::I16(f) => Ok(*f == 0),502DataValue::I32(f) => Ok(*f == 0),503DataValue::I64(f) => Ok(*f == 0),504DataValue::I128(f) => Ok(*f == 0),505DataValue::F16(f) => Ok(f.is_zero()),506DataValue::F32(f) => Ok(f.is_zero()),507DataValue::F64(f) => Ok(f.is_zero()),508DataValue::F128(f) => Ok(f.is_zero()),509DataValue::V16(_) | DataValue::V32(_) | DataValue::V64(_) | DataValue::V128(_) => {510Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty()))511}512}513}514515fn umax(self, other: Self) -> ValueResult<Self> {516let lhs = self.clone().into_int_unsigned()?;517let rhs = other.clone().into_int_unsigned()?;518if lhs > rhs { Ok(self) } else { Ok(other) }519}520521fn smax(self, other: Self) -> ValueResult<Self> {522if self > other { Ok(self) } else { Ok(other) }523}524525fn umin(self, other: Self) -> ValueResult<Self> {526let lhs = self.clone().into_int_unsigned()?;527let rhs = other.clone().into_int_unsigned()?;528if lhs < rhs { Ok(self) } else { Ok(other) }529}530531fn smin(self, other: Self) -> ValueResult<Self> {532if self < other { Ok(self) } else { Ok(other) }533}534535fn uno(&self, other: &Self) -> ValueResult<bool> {536Ok(self.is_nan()? || other.is_nan()?)537}538539fn add(self, other: Self) -> ValueResult<Self> {540if self.is_float() {541binary_match!(+(self, other); [F32, F64])542} else {543binary_match!(wrapping_add(&self, &other); [I8, I16, I32, I64, I128])544}545}546547fn sub(self, other: Self) -> ValueResult<Self> {548if self.is_float() {549binary_match!(-(self, other); [F32, F64])550} else {551binary_match!(wrapping_sub(&self, &other); [I8, I16, I32, I64, I128])552}553}554555fn mul(self, other: Self) -> ValueResult<Self> {556if self.is_float() {557binary_match!(*(self, other); [F32, F64])558} else {559binary_match!(wrapping_mul(&self, &other); [I8, I16, I32, I64, I128])560}561}562563fn sdiv(self, other: Self) -> ValueResult<Self> {564if self.is_float() {565return binary_match!(/(self, other); [F32, F64]);566}567568let denominator = other.clone().into_int_signed()?;569570// Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.571let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?;572if self == min && denominator == -1 {573return Err(ValueError::IntegerOverflow);574}575576if denominator == 0 {577return Err(ValueError::IntegerDivisionByZero);578}579580binary_match!(/(&self, &other); [I8, I16, I32, I64, I128])581}582583fn udiv(self, other: Self) -> ValueResult<Self> {584if self.is_float() {585return binary_match!(/(self, other); [F32, F64]);586}587588let denominator = other.clone().into_int_unsigned()?;589590if denominator == 0 {591return Err(ValueError::IntegerDivisionByZero);592}593594binary_match!(/(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])595}596597fn srem(self, other: Self) -> ValueResult<Self> {598let denominator = other.clone().into_int_signed()?;599600// Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.601let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?;602if self == min && denominator == -1 {603return Err(ValueError::IntegerOverflow);604}605606if denominator == 0 {607return Err(ValueError::IntegerDivisionByZero);608}609610binary_match!(%(&self, &other); [I8, I16, I32, I64, I128])611}612613fn urem(self, other: Self) -> ValueResult<Self> {614let denominator = other.clone().into_int_unsigned()?;615616if denominator == 0 {617return Err(ValueError::IntegerDivisionByZero);618}619620binary_match!(%(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])621}622623fn sqrt(self) -> ValueResult<Self> {624unary_match!(sqrt(&self); [F32, F64]; [Ieee32, Ieee64])625}626627fn fma(self, b: Self, c: Self) -> ValueResult<Self> {628match (self, b, c) {629(DataValue::F32(a), DataValue::F32(b), DataValue::F32(c)) => {630// The `fma` function for `x86_64-pc-windows-gnu` is incorrect. Use `libm`'s instead.631// See: https://github.com/bytecodealliance/wasmtime/issues/4512632#[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "gnu"))]633let res = libm::fmaf(a.as_f32(), b.as_f32(), c.as_f32());634635#[cfg(not(all(636target_arch = "x86_64",637target_os = "windows",638target_env = "gnu"639)))]640let res = a.as_f32().mul_add(b.as_f32(), c.as_f32());641642Ok(DataValue::F32(res.into()))643}644(DataValue::F64(a), DataValue::F64(b), DataValue::F64(c)) => {645#[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "gnu"))]646let res = libm::fma(a.as_f64(), b.as_f64(), c.as_f64());647648#[cfg(not(all(649target_arch = "x86_64",650target_os = "windows",651target_env = "gnu"652)))]653let res = a.as_f64().mul_add(b.as_f64(), c.as_f64());654655Ok(DataValue::F64(res.into()))656}657(a, _b, _c) => Err(ValueError::InvalidType(ValueTypeClass::Float, a.ty())),658}659}660661fn abs(self) -> ValueResult<Self> {662unary_match!(abs(&self); [F32, F64])663}664665fn sadd_checked(self, other: Self) -> ValueResult<Option<Self>> {666binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])667}668669fn uadd_checked(self, other: Self) -> ValueResult<Option<Self>> {670binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])671}672673fn sadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> {674binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])675}676677fn uadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> {678binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])679}680681fn ssub_overflow(self, other: Self) -> ValueResult<(Self, bool)> {682binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])683}684685fn usub_overflow(self, other: Self) -> ValueResult<(Self, bool)> {686binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])687}688689fn smul_overflow(self, other: Self) -> ValueResult<(Self, bool)> {690binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])691}692693fn umul_overflow(self, other: Self) -> ValueResult<(Self, bool)> {694binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])695}696697fn neg(self) -> ValueResult<Self> {698unary_match!(neg(&self); [F32, F64])699}700701fn copysign(self, sign: Self) -> ValueResult<Self> {702binary_match!(copysign(&self, &sign); [F32, F64])703}704705fn ceil(self) -> ValueResult<Self> {706unary_match!(ceil(&self); [F32, F64])707}708709fn floor(self) -> ValueResult<Self> {710unary_match!(floor(&self); [F32, F64])711}712713fn trunc(self) -> ValueResult<Self> {714unary_match!(trunc(&self); [F32, F64])715}716717fn nearest(self) -> ValueResult<Self> {718unary_match!(round_ties_even(&self); [F32, F64])719}720721fn sadd_sat(self, other: Self) -> ValueResult<Self> {722binary_match!(saturating_add(self, &other); [I8, I16, I32, I64, I128])723}724725fn uadd_sat(self, other: Self) -> ValueResult<Self> {726binary_match!(saturating_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])727}728729fn ssub_sat(self, other: Self) -> ValueResult<Self> {730binary_match!(saturating_sub(self, &other); [I8, I16, I32, I64, I128])731}732733fn usub_sat(self, other: Self) -> ValueResult<Self> {734binary_match!(saturating_sub(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])735}736737fn shl(self, other: Self) -> ValueResult<Self> {738let amt = other.convert(ValueConversionKind::Exact(types::I32))?;739binary_match!(wrapping_shl(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)740}741742fn ushr(self, other: Self) -> ValueResult<Self> {743let amt = other.convert(ValueConversionKind::Exact(types::I32))?;744binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128]; rhs: I32,u32)745}746747fn sshr(self, other: Self) -> ValueResult<Self> {748let amt = other.convert(ValueConversionKind::Exact(types::I32))?;749binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)750}751752fn rotl(self, other: Self) -> ValueResult<Self> {753let amt = other.convert(ValueConversionKind::Exact(types::I32))?;754binary_match!(rotate_left(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)755}756757fn rotr(self, other: Self) -> ValueResult<Self> {758let amt = other.convert(ValueConversionKind::Exact(types::I32))?;759binary_match!(rotate_right(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)760}761762fn and(self, other: Self) -> ValueResult<Self> {763bitop!(&(self, other))764}765766fn or(self, other: Self) -> ValueResult<Self> {767bitop!(|(self, other))768}769770fn xor(self, other: Self) -> ValueResult<Self> {771bitop!(^(self, other))772}773774fn not(self) -> ValueResult<Self> {775Ok(match self {776DataValue::I8(a) => DataValue::I8(!a),777DataValue::I16(a) => DataValue::I16(!a),778DataValue::I32(a) => DataValue::I32(!a),779DataValue::I64(a) => DataValue::I64(!a),780DataValue::I128(a) => DataValue::I128(!a),781DataValue::F32(a) => DataValue::F32(!a),782DataValue::F64(a) => DataValue::F64(!a),783DataValue::V64(mut a) => {784for byte in a.iter_mut() {785*byte = !*byte;786}787DataValue::V64(a)788}789DataValue::V128(mut a) => {790for byte in a.iter_mut() {791*byte = !*byte;792}793DataValue::V128(a)794}795_ => unimplemented!(),796})797}798799fn count_ones(self) -> ValueResult<Self> {800unary_match!(count_ones(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])801}802803fn leading_ones(self) -> ValueResult<Self> {804unary_match!(leading_ones(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])805}806807fn leading_zeros(self) -> ValueResult<Self> {808unary_match!(leading_zeros(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])809}810811fn trailing_zeros(self) -> ValueResult<Self> {812unary_match!(trailing_zeros(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])813}814815fn reverse_bits(self) -> ValueResult<Self> {816unary_match!(reverse_bits(&self); [I8, I16, I32, I64, I128])817}818819fn swap_bytes(self) -> ValueResult<Self> {820unary_match!(swap_bytes(&self); [I16, I32, I64, I128])821}822823fn iter_lanes(&self, ty: Type) -> ValueResult<DataValueIterator> {824DataValueIterator::new(self, ty)825}826}827828/// Iterator for DataValue's829pub struct DataValueIterator {830ty: Type,831v: SimdVec<DataValue>,832idx: usize,833}834835impl DataValueIterator {836fn new(dv: &DataValue, ty: Type) -> Result<Self, ValueError> {837match extractlanes(dv, ty) {838Ok(v) => return Ok(Self { ty, v, idx: 0 }),839Err(err) => return Err(err),840}841}842}843844impl Iterator for DataValueIterator {845type Item = DataValue;846847fn next(&mut self) -> Option<Self::Item> {848if self.idx >= self.ty.lane_count() as usize {849return None;850}851852let dv = self.v[self.idx].clone();853self.idx += 1;854Some(dv)855}856}857858#[cfg(test)]859mod test {860use super::*;861862#[test]863fn test_iterator_v128() {864let dv = DataValue::V128([99, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);865assert_eq!(simd_sum(dv, types::I8X16), 219);866}867868#[test]869fn test_iterator_v128_empty() {870let dv = DataValue::V128([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);871assert_eq!(simd_sum(dv, types::I8X16), 0);872}873874#[test]875fn test_iterator_v128_ones() {876let dv = DataValue::V128([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);877assert_eq!(simd_sum(dv, types::I8X16), 16);878}879880#[test]881fn test_iterator_v64_empty() {882let dv = DataValue::V64([0, 0, 0, 0, 0, 0, 0, 0]);883assert_eq!(simd_sum(dv, types::I8X8), 0);884}885#[test]886fn test_iterator_v64_ones() {887let dv = DataValue::V64([1, 1, 1, 1, 1, 1, 1, 1]);888assert_eq!(simd_sum(dv, types::I8X8), 8);889}890#[test]891fn test_iterator_v64() {892let dv = DataValue::V64([10, 20, 30, 40, 50, 60, 70, 80]);893assert_eq!(simd_sum(dv, types::I8X8), 360);894}895896fn simd_sum(dv: DataValue, ty: types::Type) -> i128 {897let itr = dv.iter_lanes(ty).unwrap();898899itr.map(|e| {900if let Some(v) = e.into_int_signed().ok() {901v902} else {9030904}905})906.sum()907}908}909910911