Path: blob/main/cranelift/interpreter/src/value.rs
1692 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::V128(a), DataValue::V128(b)) => {238let mut a2 = a.clone();239for (a, b) in a2.iter_mut().zip(b.iter()) {240*a = *a $op *b;241}242DataValue::V128(a2)243}244_ => unimplemented!(),245})246};247}248249impl DataValueExt for DataValue {250fn int(n: i128, ty: Type) -> ValueResult<Self> {251if ty.is_vector() {252// match ensures graceful failure since read_from_slice_ne()253// panics on anything other than 8 and 16 bytes254match ty.bytes() {2558 | 16 => Ok(DataValue::read_from_slice_ne(&n.to_ne_bytes(), ty)),256_ => Err(ValueError::InvalidType(ValueTypeClass::Vector, ty)),257}258} else if ty.is_int() {259DataValue::from_integer(n, ty).map_err(|_| ValueError::InvalidValue(ty))260} else {261Err(ValueError::InvalidType(ValueTypeClass::Integer, ty))262}263}264265fn into_int_signed(self) -> ValueResult<i128> {266match self {267DataValue::I8(n) => Ok(n as i128),268DataValue::I16(n) => Ok(n as i128),269DataValue::I32(n) => Ok(n as i128),270DataValue::I64(n) => Ok(n as i128),271DataValue::I128(n) => Ok(n),272_ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())),273}274}275276fn into_int_unsigned(self) -> ValueResult<u128> {277match self {278DataValue::I8(n) => Ok(n as u8 as u128),279DataValue::I16(n) => Ok(n as u16 as u128),280DataValue::I32(n) => Ok(n as u32 as u128),281DataValue::I64(n) => Ok(n as u64 as u128),282DataValue::I128(n) => Ok(n as u128),283_ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())),284}285}286287fn float(bits: u64, ty: Type) -> ValueResult<Self> {288match ty {289types::F32 => Ok(DataValue::F32(Ieee32::with_bits(u32::try_from(bits)?))),290types::F64 => Ok(DataValue::F64(Ieee64::with_bits(bits))),291_ => Err(ValueError::InvalidType(ValueTypeClass::Float, ty)),292}293}294295fn into_float(self) -> ValueResult<f64> {296match self {297DataValue::F32(n) => Ok(n.as_f32() as f64),298DataValue::F64(n) => Ok(n.as_f64()),299_ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),300}301}302303fn is_float(&self) -> bool {304match self {305DataValue::F16(_) | DataValue::F32(_) | DataValue::F64(_) | DataValue::F128(_) => true,306_ => false,307}308}309310fn is_nan(&self) -> ValueResult<bool> {311match self {312DataValue::F32(f) => Ok(f.is_nan()),313DataValue::F64(f) => Ok(f.is_nan()),314_ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),315}316}317318fn bool(b: bool, vec_elem: bool, ty: Type) -> ValueResult<Self> {319assert!(ty.is_int());320macro_rules! make_bool {321($ty:ident) => {322Ok(DataValue::$ty(if b {323if vec_elem { -1 } else { 1 }324} else {3250326}))327};328}329330match ty {331types::I8 => make_bool!(I8),332types::I16 => make_bool!(I16),333types::I32 => make_bool!(I32),334types::I64 => make_bool!(I64),335types::I128 => make_bool!(I128),336_ => Err(ValueError::InvalidType(ValueTypeClass::Integer, ty)),337}338}339340fn into_bool(self) -> ValueResult<bool> {341match self {342DataValue::I8(b) => Ok(b != 0),343DataValue::I16(b) => Ok(b != 0),344DataValue::I32(b) => Ok(b != 0),345DataValue::I64(b) => Ok(b != 0),346DataValue::I128(b) => Ok(b != 0),347_ => Err(ValueError::InvalidType(ValueTypeClass::Boolean, self.ty())),348}349}350351fn vector(v: [u8; 16], ty: Type) -> ValueResult<Self> {352assert!(ty.is_vector() && [2, 4, 8, 16].contains(&ty.bytes()));353match ty.bytes() {35416 => Ok(DataValue::V128(v)),3558 => Ok(DataValue::V64(v[..8].try_into().unwrap())),3564 => Ok(DataValue::V32(v[..4].try_into().unwrap())),3572 => Ok(DataValue::V16(v[..2].try_into().unwrap())),358_ => unreachable!(),359}360}361362fn into_array(&self) -> ValueResult<[u8; 16]> {363match *self {364DataValue::V128(v) => Ok(v),365DataValue::V64(v) => {366let mut v128 = [0; 16];367v128[..8].clone_from_slice(&v);368Ok(v128)369}370DataValue::V32(v) => {371let mut v128 = [0; 16];372v128[..4].clone_from_slice(&v);373Ok(v128)374}375DataValue::V16(v) => {376let mut v128 = [0; 16];377v128[..2].clone_from_slice(&v);378Ok(v128)379}380_ => Err(ValueError::InvalidType(ValueTypeClass::Vector, self.ty())),381}382}383384fn convert(self, kind: ValueConversionKind) -> ValueResult<Self> {385Ok(match kind {386ValueConversionKind::Exact(ty) => match (self, ty) {387// TODO a lot to do here: from bmask to ireduce to bitcast...388(val, ty) if val.ty().is_int() && ty.is_int() => {389DataValue::from_integer(val.into_int_signed()?, ty)?390}391(DataValue::I16(n), types::F16) => DataValue::F16(Ieee16::with_bits(n as u16)),392(DataValue::I32(n), types::F32) => DataValue::F32(f32::from_bits(n as u32).into()),393(DataValue::I64(n), types::F64) => DataValue::F64(f64::from_bits(n as u64).into()),394(DataValue::I128(n), types::F128) => DataValue::F128(Ieee128::with_bits(n as u128)),395(DataValue::F16(n), types::I16) => DataValue::I16(n.bits() as i16),396(DataValue::F32(n), types::I32) => DataValue::I32(n.bits() as i32),397(DataValue::F64(n), types::I64) => DataValue::I64(n.bits() as i64),398(DataValue::F128(n), types::I128) => DataValue::I128(n.bits() as i128),399(DataValue::F32(n), types::F64) => DataValue::F64((n.as_f32() as f64).into()),400(dv, t) if (t.is_int() || t.is_float()) && dv.ty() == t => dv,401(dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),402},403ValueConversionKind::Truncate(ty) => {404assert!(405ty.is_int(),406"unimplemented conversion: {} -> {:?}",407self.ty(),408kind409);410411let mask = (1 << (ty.bytes() * 8)) - 1i128;412let truncated = self.into_int_signed()? & mask;413Self::from_integer(truncated, ty)?414}415ValueConversionKind::ExtractUpper(ty) => {416assert!(417ty.is_int(),418"unimplemented conversion: {} -> {:?}",419self.ty(),420kind421);422423let shift_amt = (self.ty().bytes() * 8) - (ty.bytes() * 8);424let mask = (1 << (ty.bytes() * 8)) - 1i128;425let shifted_mask = mask << shift_amt;426427let extracted = (self.into_int_signed()? & shifted_mask) >> shift_amt;428Self::from_integer(extracted, ty)?429}430ValueConversionKind::SignExtend(ty) => match (self, ty) {431(DataValue::I8(n), types::I16) => DataValue::I16(n as i16),432(DataValue::I8(n), types::I32) => DataValue::I32(n as i32),433(DataValue::I8(n), types::I64) => DataValue::I64(n as i64),434(DataValue::I8(n), types::I128) => DataValue::I128(n as i128),435(DataValue::I16(n), types::I32) => DataValue::I32(n as i32),436(DataValue::I16(n), types::I64) => DataValue::I64(n as i64),437(DataValue::I16(n), types::I128) => DataValue::I128(n as i128),438(DataValue::I32(n), types::I64) => DataValue::I64(n as i64),439(DataValue::I32(n), types::I128) => DataValue::I128(n as i128),440(DataValue::I64(n), types::I128) => DataValue::I128(n as i128),441(dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),442},443ValueConversionKind::ZeroExtend(ty) => match (self, ty) {444(DataValue::I8(n), types::I16) => DataValue::I16(n as u8 as i16),445(DataValue::I8(n), types::I32) => DataValue::I32(n as u8 as i32),446(DataValue::I8(n), types::I64) => DataValue::I64(n as u8 as i64),447(DataValue::I8(n), types::I128) => DataValue::I128(n as u8 as i128),448(DataValue::I16(n), types::I32) => DataValue::I32(n as u16 as i32),449(DataValue::I16(n), types::I64) => DataValue::I64(n as u16 as i64),450(DataValue::I16(n), types::I128) => DataValue::I128(n as u16 as i128),451(DataValue::I32(n), types::I64) => DataValue::I64(n as u32 as i64),452(DataValue::I32(n), types::I128) => DataValue::I128(n as u32 as i128),453(DataValue::I64(n), types::I128) => DataValue::I128(n as u64 as i128),454(from, to) if from.ty() == to => from,455(dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),456},457ValueConversionKind::RoundNearestEven(ty) => match (self, ty) {458(DataValue::F64(n), types::F32) => DataValue::F32(Ieee32::from(n.as_f64() as f32)),459(s, _) => unimplemented!("conversion: {} -> {:?}", s.ty(), kind),460},461ValueConversionKind::ToBoolean => match self.ty() {462ty if ty.is_int() => {463DataValue::I8(if self.into_int_signed()? != 0 { 1 } else { 0 })464}465ty => unimplemented!("conversion: {} -> {:?}", ty, kind),466},467ValueConversionKind::Mask(ty) => {468let b = self.into_bool()?;469Self::bool(b, true, ty).unwrap()470}471})472}473474fn concat(self, other: Self) -> ValueResult<Self> {475match (self, other) {476(DataValue::I64(lhs), DataValue::I64(rhs)) => Ok(DataValue::I128(477(((lhs as u64) as u128) | (((rhs as u64) as u128) << 64)) as i128,478)),479(lhs, rhs) => unimplemented!("concat: {} -> {}", lhs.ty(), rhs.ty()),480}481}482483fn is_negative(&self) -> ValueResult<bool> {484match self {485DataValue::F32(f) => Ok(f.is_negative()),486DataValue::F64(f) => Ok(f.is_negative()),487_ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),488}489}490491fn is_zero(&self) -> ValueResult<bool> {492match self {493DataValue::I8(f) => Ok(*f == 0),494DataValue::I16(f) => Ok(*f == 0),495DataValue::I32(f) => Ok(*f == 0),496DataValue::I64(f) => Ok(*f == 0),497DataValue::I128(f) => Ok(*f == 0),498DataValue::F16(f) => Ok(f.is_zero()),499DataValue::F32(f) => Ok(f.is_zero()),500DataValue::F64(f) => Ok(f.is_zero()),501DataValue::F128(f) => Ok(f.is_zero()),502DataValue::V16(_) | DataValue::V32(_) | DataValue::V64(_) | DataValue::V128(_) => {503Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty()))504}505}506}507508fn umax(self, other: Self) -> ValueResult<Self> {509let lhs = self.clone().into_int_unsigned()?;510let rhs = other.clone().into_int_unsigned()?;511if lhs > rhs { Ok(self) } else { Ok(other) }512}513514fn smax(self, other: Self) -> ValueResult<Self> {515if self > other { Ok(self) } else { Ok(other) }516}517518fn umin(self, other: Self) -> ValueResult<Self> {519let lhs = self.clone().into_int_unsigned()?;520let rhs = other.clone().into_int_unsigned()?;521if lhs < rhs { Ok(self) } else { Ok(other) }522}523524fn smin(self, other: Self) -> ValueResult<Self> {525if self < other { Ok(self) } else { Ok(other) }526}527528fn uno(&self, other: &Self) -> ValueResult<bool> {529Ok(self.is_nan()? || other.is_nan()?)530}531532fn add(self, other: Self) -> ValueResult<Self> {533if self.is_float() {534binary_match!(+(self, other); [F32, F64])535} else {536binary_match!(wrapping_add(&self, &other); [I8, I16, I32, I64, I128])537}538}539540fn sub(self, other: Self) -> ValueResult<Self> {541if self.is_float() {542binary_match!(-(self, other); [F32, F64])543} else {544binary_match!(wrapping_sub(&self, &other); [I8, I16, I32, I64, I128])545}546}547548fn mul(self, other: Self) -> ValueResult<Self> {549if self.is_float() {550binary_match!(*(self, other); [F32, F64])551} else {552binary_match!(wrapping_mul(&self, &other); [I8, I16, I32, I64, I128])553}554}555556fn sdiv(self, other: Self) -> ValueResult<Self> {557if self.is_float() {558return binary_match!(/(self, other); [F32, F64]);559}560561let denominator = other.clone().into_int_signed()?;562563// Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.564let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?;565if self == min && denominator == -1 {566return Err(ValueError::IntegerOverflow);567}568569if denominator == 0 {570return Err(ValueError::IntegerDivisionByZero);571}572573binary_match!(/(&self, &other); [I8, I16, I32, I64, I128])574}575576fn udiv(self, other: Self) -> ValueResult<Self> {577if self.is_float() {578return binary_match!(/(self, other); [F32, F64]);579}580581let denominator = other.clone().into_int_unsigned()?;582583if denominator == 0 {584return Err(ValueError::IntegerDivisionByZero);585}586587binary_match!(/(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])588}589590fn srem(self, other: Self) -> ValueResult<Self> {591let denominator = other.clone().into_int_signed()?;592593// Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.594let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?;595if self == min && denominator == -1 {596return Err(ValueError::IntegerOverflow);597}598599if denominator == 0 {600return Err(ValueError::IntegerDivisionByZero);601}602603binary_match!(%(&self, &other); [I8, I16, I32, I64, I128])604}605606fn urem(self, other: Self) -> ValueResult<Self> {607let denominator = other.clone().into_int_unsigned()?;608609if denominator == 0 {610return Err(ValueError::IntegerDivisionByZero);611}612613binary_match!(%(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])614}615616fn sqrt(self) -> ValueResult<Self> {617unary_match!(sqrt(&self); [F32, F64]; [Ieee32, Ieee64])618}619620fn fma(self, b: Self, c: Self) -> ValueResult<Self> {621match (self, b, c) {622(DataValue::F32(a), DataValue::F32(b), DataValue::F32(c)) => {623// The `fma` function for `x86_64-pc-windows-gnu` is incorrect. Use `libm`'s instead.624// See: https://github.com/bytecodealliance/wasmtime/issues/4512625#[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "gnu"))]626let res = libm::fmaf(a.as_f32(), b.as_f32(), c.as_f32());627628#[cfg(not(all(629target_arch = "x86_64",630target_os = "windows",631target_env = "gnu"632)))]633let res = a.as_f32().mul_add(b.as_f32(), c.as_f32());634635Ok(DataValue::F32(res.into()))636}637(DataValue::F64(a), DataValue::F64(b), DataValue::F64(c)) => {638#[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "gnu"))]639let res = libm::fma(a.as_f64(), b.as_f64(), c.as_f64());640641#[cfg(not(all(642target_arch = "x86_64",643target_os = "windows",644target_env = "gnu"645)))]646let res = a.as_f64().mul_add(b.as_f64(), c.as_f64());647648Ok(DataValue::F64(res.into()))649}650(a, _b, _c) => Err(ValueError::InvalidType(ValueTypeClass::Float, a.ty())),651}652}653654fn abs(self) -> ValueResult<Self> {655unary_match!(abs(&self); [F32, F64])656}657658fn sadd_checked(self, other: Self) -> ValueResult<Option<Self>> {659binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])660}661662fn uadd_checked(self, other: Self) -> ValueResult<Option<Self>> {663binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])664}665666fn sadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> {667binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])668}669670fn uadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> {671binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])672}673674fn ssub_overflow(self, other: Self) -> ValueResult<(Self, bool)> {675binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])676}677678fn usub_overflow(self, other: Self) -> ValueResult<(Self, bool)> {679binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])680}681682fn smul_overflow(self, other: Self) -> ValueResult<(Self, bool)> {683binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])684}685686fn umul_overflow(self, other: Self) -> ValueResult<(Self, bool)> {687binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])688}689690fn neg(self) -> ValueResult<Self> {691unary_match!(neg(&self); [F32, F64])692}693694fn copysign(self, sign: Self) -> ValueResult<Self> {695binary_match!(copysign(&self, &sign); [F32, F64])696}697698fn ceil(self) -> ValueResult<Self> {699unary_match!(ceil(&self); [F32, F64])700}701702fn floor(self) -> ValueResult<Self> {703unary_match!(floor(&self); [F32, F64])704}705706fn trunc(self) -> ValueResult<Self> {707unary_match!(trunc(&self); [F32, F64])708}709710fn nearest(self) -> ValueResult<Self> {711unary_match!(round_ties_even(&self); [F32, F64])712}713714fn sadd_sat(self, other: Self) -> ValueResult<Self> {715binary_match!(saturating_add(self, &other); [I8, I16, I32, I64, I128])716}717718fn uadd_sat(self, other: Self) -> ValueResult<Self> {719binary_match!(saturating_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])720}721722fn ssub_sat(self, other: Self) -> ValueResult<Self> {723binary_match!(saturating_sub(self, &other); [I8, I16, I32, I64, I128])724}725726fn usub_sat(self, other: Self) -> ValueResult<Self> {727binary_match!(saturating_sub(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])728}729730fn shl(self, other: Self) -> ValueResult<Self> {731let amt = other.convert(ValueConversionKind::Exact(types::I32))?;732binary_match!(wrapping_shl(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)733}734735fn ushr(self, other: Self) -> ValueResult<Self> {736let amt = other.convert(ValueConversionKind::Exact(types::I32))?;737binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128]; rhs: I32,u32)738}739740fn sshr(self, other: Self) -> ValueResult<Self> {741let amt = other.convert(ValueConversionKind::Exact(types::I32))?;742binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)743}744745fn rotl(self, other: Self) -> ValueResult<Self> {746let amt = other.convert(ValueConversionKind::Exact(types::I32))?;747binary_match!(rotate_left(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)748}749750fn rotr(self, other: Self) -> ValueResult<Self> {751let amt = other.convert(ValueConversionKind::Exact(types::I32))?;752binary_match!(rotate_right(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)753}754755fn and(self, other: Self) -> ValueResult<Self> {756bitop!(&(self, other))757}758759fn or(self, other: Self) -> ValueResult<Self> {760bitop!(|(self, other))761}762763fn xor(self, other: Self) -> ValueResult<Self> {764bitop!(^(self, other))765}766767fn not(self) -> ValueResult<Self> {768Ok(match self {769DataValue::I8(a) => DataValue::I8(!a),770DataValue::I16(a) => DataValue::I16(!a),771DataValue::I32(a) => DataValue::I32(!a),772DataValue::I64(a) => DataValue::I64(!a),773DataValue::I128(a) => DataValue::I128(!a),774DataValue::F32(a) => DataValue::F32(!a),775DataValue::F64(a) => DataValue::F64(!a),776DataValue::V128(mut a) => {777for byte in a.iter_mut() {778*byte = !*byte;779}780DataValue::V128(a)781}782_ => unimplemented!(),783})784}785786fn count_ones(self) -> ValueResult<Self> {787unary_match!(count_ones(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])788}789790fn leading_ones(self) -> ValueResult<Self> {791unary_match!(leading_ones(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])792}793794fn leading_zeros(self) -> ValueResult<Self> {795unary_match!(leading_zeros(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])796}797798fn trailing_zeros(self) -> ValueResult<Self> {799unary_match!(trailing_zeros(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])800}801802fn reverse_bits(self) -> ValueResult<Self> {803unary_match!(reverse_bits(&self); [I8, I16, I32, I64, I128])804}805806fn swap_bytes(self) -> ValueResult<Self> {807unary_match!(swap_bytes(&self); [I16, I32, I64, I128])808}809810fn iter_lanes(&self, ty: Type) -> ValueResult<DataValueIterator> {811DataValueIterator::new(self, ty)812}813}814815/// Iterator for DataValue's816pub struct DataValueIterator {817ty: Type,818v: SimdVec<DataValue>,819idx: usize,820}821822impl DataValueIterator {823fn new(dv: &DataValue, ty: Type) -> Result<Self, ValueError> {824match extractlanes(dv, ty) {825Ok(v) => return Ok(Self { ty, v, idx: 0 }),826Err(err) => return Err(err),827}828}829}830831impl Iterator for DataValueIterator {832type Item = DataValue;833834fn next(&mut self) -> Option<Self::Item> {835if self.idx >= self.ty.lane_count() as usize {836return None;837}838839let dv = self.v[self.idx].clone();840self.idx += 1;841Some(dv)842}843}844845#[cfg(test)]846mod test {847use super::*;848849#[test]850fn test_iterator_v128() {851let dv = DataValue::V128([99, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);852assert_eq!(simd_sum(dv, types::I8X16), 219);853}854855#[test]856fn test_iterator_v128_empty() {857let dv = DataValue::V128([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);858assert_eq!(simd_sum(dv, types::I8X16), 0);859}860861#[test]862fn test_iterator_v128_ones() {863let dv = DataValue::V128([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);864assert_eq!(simd_sum(dv, types::I8X16), 16);865}866867#[test]868fn test_iterator_v64_empty() {869let dv = DataValue::V64([0, 0, 0, 0, 0, 0, 0, 0]);870assert_eq!(simd_sum(dv, types::I8X8), 0);871}872#[test]873fn test_iterator_v64_ones() {874let dv = DataValue::V64([1, 1, 1, 1, 1, 1, 1, 1]);875assert_eq!(simd_sum(dv, types::I8X8), 8);876}877#[test]878fn test_iterator_v64() {879let dv = DataValue::V64([10, 20, 30, 40, 50, 60, 70, 80]);880assert_eq!(simd_sum(dv, types::I8X8), 360);881}882883fn simd_sum(dv: DataValue, ty: types::Type) -> i128 {884let itr = dv.iter_lanes(ty).unwrap();885886itr.map(|e| {887if let Some(v) = e.into_int_signed().ok() {888v889} else {8900891}892})893.sum()894}895}896897898