cranelift_interpreter/
value.rs

1//! The [DataValueExt] trait is an extension trait for [DataValue]. It provides a lot of functions
2//! used by the rest of the interpreter.
3
4#![allow(trivial_numeric_casts)]
5
6use core::fmt::{self, Display, Formatter};
7use core::ops::Neg;
8use cranelift_codegen::data_value::{DataValue, DataValueCastFailure};
9use cranelift_codegen::ir::immediates::{Ieee128, Ieee16, Ieee32, Ieee64};
10use cranelift_codegen::ir::{types, Type};
11use thiserror::Error;
12
13use crate::step::{extractlanes, SimdVec};
14
15pub type ValueResult<T> = Result<T, ValueError>;
16
17pub trait DataValueExt: Sized {
18    // Identity.
19    fn int(n: i128, ty: Type) -> ValueResult<Self>;
20    fn into_int_signed(self) -> ValueResult<i128>;
21    fn into_int_unsigned(self) -> ValueResult<u128>;
22    fn float(n: u64, ty: Type) -> ValueResult<Self>;
23    fn into_float(self) -> ValueResult<f64>;
24    fn is_float(&self) -> bool;
25    fn is_nan(&self) -> ValueResult<bool>;
26    fn bool(b: bool, vec_elem: bool, ty: Type) -> ValueResult<Self>;
27    fn into_bool(self) -> ValueResult<bool>;
28    fn vector(v: [u8; 16], ty: Type) -> ValueResult<Self>;
29    fn into_array(&self) -> ValueResult<[u8; 16]>;
30    fn convert(self, kind: ValueConversionKind) -> ValueResult<Self>;
31    fn concat(self, other: Self) -> ValueResult<Self>;
32
33    fn is_negative(&self) -> ValueResult<bool>;
34    fn is_zero(&self) -> ValueResult<bool>;
35
36    fn umax(self, other: Self) -> ValueResult<Self>;
37    fn smax(self, other: Self) -> ValueResult<Self>;
38    fn umin(self, other: Self) -> ValueResult<Self>;
39    fn smin(self, other: Self) -> ValueResult<Self>;
40
41    // Comparison.
42    fn uno(&self, other: &Self) -> ValueResult<bool>;
43
44    // Arithmetic.
45    fn add(self, other: Self) -> ValueResult<Self>;
46    fn sub(self, other: Self) -> ValueResult<Self>;
47    fn mul(self, other: Self) -> ValueResult<Self>;
48    fn udiv(self, other: Self) -> ValueResult<Self>;
49    fn sdiv(self, other: Self) -> ValueResult<Self>;
50    fn urem(self, other: Self) -> ValueResult<Self>;
51    fn srem(self, other: Self) -> ValueResult<Self>;
52    fn sqrt(self) -> ValueResult<Self>;
53    fn fma(self, a: Self, b: Self) -> ValueResult<Self>;
54    fn abs(self) -> ValueResult<Self>;
55    fn uadd_checked(self, other: Self) -> ValueResult<Option<Self>>;
56    fn sadd_checked(self, other: Self) -> ValueResult<Option<Self>>;
57    fn uadd_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
58    fn sadd_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
59    fn usub_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
60    fn ssub_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
61    fn umul_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
62    fn smul_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
63
64    // Float operations
65    fn neg(self) -> ValueResult<Self>;
66    fn copysign(self, sign: Self) -> ValueResult<Self>;
67    fn ceil(self) -> ValueResult<Self>;
68    fn floor(self) -> ValueResult<Self>;
69    fn trunc(self) -> ValueResult<Self>;
70    fn nearest(self) -> ValueResult<Self>;
71
72    // Saturating arithmetic.
73    fn uadd_sat(self, other: Self) -> ValueResult<Self>;
74    fn sadd_sat(self, other: Self) -> ValueResult<Self>;
75    fn usub_sat(self, other: Self) -> ValueResult<Self>;
76    fn ssub_sat(self, other: Self) -> ValueResult<Self>;
77
78    // Bitwise.
79    fn shl(self, other: Self) -> ValueResult<Self>;
80    fn ushr(self, other: Self) -> ValueResult<Self>;
81    fn sshr(self, other: Self) -> ValueResult<Self>;
82    fn rotl(self, other: Self) -> ValueResult<Self>;
83    fn rotr(self, other: Self) -> ValueResult<Self>;
84    fn and(self, other: Self) -> ValueResult<Self>;
85    fn or(self, other: Self) -> ValueResult<Self>;
86    fn xor(self, other: Self) -> ValueResult<Self>;
87    fn not(self) -> ValueResult<Self>;
88
89    // Bit counting.
90    fn count_ones(self) -> ValueResult<Self>;
91    fn leading_ones(self) -> ValueResult<Self>;
92    fn leading_zeros(self) -> ValueResult<Self>;
93    fn trailing_zeros(self) -> ValueResult<Self>;
94    fn reverse_bits(self) -> ValueResult<Self>;
95    fn swap_bytes(self) -> ValueResult<Self>;
96
97    // An iterator over the lanes of a SIMD type
98    fn iter_lanes(&self, ty: Type) -> ValueResult<DataValueIterator>;
99}
100
101#[derive(Error, Debug, PartialEq)]
102pub enum ValueError {
103    #[error("unable to convert type {1} into class {0}")]
104    InvalidType(ValueTypeClass, Type),
105    #[error("unable to convert value into type {0}")]
106    InvalidValue(Type),
107    #[error("unable to convert to primitive integer")]
108    InvalidInteger(#[from] std::num::TryFromIntError),
109    #[error("unable to cast data value")]
110    InvalidDataValueCast(#[from] DataValueCastFailure),
111    #[error("performed a division by zero")]
112    IntegerDivisionByZero,
113    #[error("performed a operation that overflowed this integer type")]
114    IntegerOverflow,
115}
116
117#[derive(Debug, PartialEq)]
118pub enum ValueTypeClass {
119    Integer,
120    Boolean,
121    Float,
122    Vector,
123}
124
125impl Display for ValueTypeClass {
126    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
127        match self {
128            ValueTypeClass::Integer => write!(f, "integer"),
129            ValueTypeClass::Boolean => write!(f, "boolean"),
130            ValueTypeClass::Float => write!(f, "float"),
131            ValueTypeClass::Vector => write!(f, "vector"),
132        }
133    }
134}
135
136#[derive(Debug, Clone)]
137pub enum ValueConversionKind {
138    /// Throw a [ValueError] if an exact conversion to [Type] is not possible; e.g. in `i32` to
139    /// `i16`, convert `0x00001234` to `0x1234`.
140    Exact(Type),
141    /// Truncate the value to fit into the specified [Type]; e.g. in `i16` to `i8`, `0x1234` becomes
142    /// `0x34`.
143    Truncate(Type),
144    ///  Similar to Truncate, but extracts from the top of the value; e.g. in a `i32` to `u8`,
145    /// `0x12345678` becomes `0x12`.
146    ExtractUpper(Type),
147    /// Convert to a larger integer type, extending the sign bit; e.g. in `i8` to `i16`, `0xff`
148    /// becomes `0xffff`.
149    SignExtend(Type),
150    /// Convert to a larger integer type, extending with zeroes; e.g. in `i8` to `i16`, `0xff`
151    /// becomes `0x00ff`.
152    ZeroExtend(Type),
153    /// Convert a floating point number by rounding to the nearest possible value with ties to even.
154    /// See `fdemote`, e.g.
155    RoundNearestEven(Type),
156    /// Converts an integer into a boolean, zero integers are converted into a
157    /// `false`, while other integers are converted into `true`. Booleans are passed through.
158    ToBoolean,
159    /// Converts an integer into either -1 or zero.
160    Mask(Type),
161}
162
163/// Helper for creating match expressions over [DataValue].
164macro_rules! unary_match {
165    ( $op:ident($arg1:expr); [ $( $data_value_ty:ident ),* ]; [ $( $return_value_ty:ident ),* ] ) => {
166        match $arg1 {
167            $( DataValue::$data_value_ty(a) => {
168                Ok(DataValue::$data_value_ty($return_value_ty::try_from(a.$op()).unwrap()))
169            } )*
170            _ => unimplemented!()
171        }
172    };
173    ( $op:ident($arg1:expr); [ $( $data_value_ty:ident ),* ] ) => {
174        match $arg1 {
175            $( DataValue::$data_value_ty(a) => { Ok(DataValue::$data_value_ty(a.$op())) } )*
176            _ => unimplemented!()
177        }
178    };
179}
180macro_rules! binary_match {
181    ( $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ] ) => {
182        match ($arg1, $arg2) {
183            $( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => { Ok(DataValue::$data_value_ty(a.$op(*b))) } )*
184            _ => unimplemented!()
185        }
186    };
187    ( $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {
188        match ($arg1, $arg2) {
189            $( (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 _)) } )*
190            _ => unimplemented!()
191        }
192    };
193    ( option $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {
194        match ($arg1, $arg2) {
195            $( (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 _))) } )*
196            _ => unimplemented!()
197        }
198    };
199    ( pair $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {
200        match ($arg1, $arg2) {
201            $( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => {
202                let (f, s) = (*a as $op_type).$op(*b as $op_type);
203                Ok((DataValue::$data_value_ty(f as _), s))
204            } )*
205            _ => unimplemented!()
206        }
207    };
208    ( $op:tt($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ] ) => {
209        match ($arg1, $arg2) {
210            $( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => { Ok(DataValue::$data_value_ty(a $op b)) } )*
211            _ => unimplemented!()
212        }
213    };
214    ( $op:tt($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {
215        match ($arg1, $arg2) {
216            $( (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 _)) } )*
217            _ => unimplemented!()
218        }
219    };
220    ( $op:tt($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $a_type:ty ),* ]; rhs: $rhs:tt,$rhs_type:ty ) => {
221        match ($arg1, $arg2) {
222            $( (DataValue::$data_value_ty(a), DataValue::$rhs(b)) => { Ok(DataValue::$data_value_ty((*a as $a_type).$op(*b as $rhs_type) as _)) } )*
223            _ => unimplemented!()
224        }
225    };
226}
227
228macro_rules! bitop {
229    ( $op:tt($arg1:expr, $arg2:expr) ) => {
230        Ok(match ($arg1, $arg2) {
231            (DataValue::I8(a), DataValue::I8(b)) => DataValue::I8(a $op b),
232            (DataValue::I16(a), DataValue::I16(b)) => DataValue::I16(a $op b),
233            (DataValue::I32(a), DataValue::I32(b)) => DataValue::I32(a $op b),
234            (DataValue::I64(a), DataValue::I64(b)) => DataValue::I64(a $op b),
235            (DataValue::I128(a), DataValue::I128(b)) => DataValue::I128(a $op b),
236            (DataValue::F32(a), DataValue::F32(b)) => DataValue::F32(a $op b),
237            (DataValue::F64(a), DataValue::F64(b)) => DataValue::F64(a $op b),
238            (DataValue::V128(a), DataValue::V128(b)) => {
239                let mut a2 = a.clone();
240                for (a, b) in a2.iter_mut().zip(b.iter()) {
241                    *a = *a $op *b;
242                }
243                DataValue::V128(a2)
244            }
245            _ => unimplemented!(),
246        })
247    };
248}
249
250impl DataValueExt for DataValue {
251    fn int(n: i128, ty: Type) -> ValueResult<Self> {
252        if ty.is_vector() {
253            // match ensures graceful failure since read_from_slice_ne()
254            // panics on anything other than 8 and 16 bytes
255            match ty.bytes() {
256                8 | 16 => Ok(DataValue::read_from_slice_ne(&n.to_ne_bytes(), ty)),
257                _ => Err(ValueError::InvalidType(ValueTypeClass::Vector, ty)),
258            }
259        } else if ty.is_int() {
260            DataValue::from_integer(n, ty).map_err(|_| ValueError::InvalidValue(ty))
261        } else {
262            Err(ValueError::InvalidType(ValueTypeClass::Integer, ty))
263        }
264    }
265
266    fn into_int_signed(self) -> ValueResult<i128> {
267        match self {
268            DataValue::I8(n) => Ok(n as i128),
269            DataValue::I16(n) => Ok(n as i128),
270            DataValue::I32(n) => Ok(n as i128),
271            DataValue::I64(n) => Ok(n as i128),
272            DataValue::I128(n) => Ok(n),
273            _ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())),
274        }
275    }
276
277    fn into_int_unsigned(self) -> ValueResult<u128> {
278        match self {
279            DataValue::I8(n) => Ok(n as u8 as u128),
280            DataValue::I16(n) => Ok(n as u16 as u128),
281            DataValue::I32(n) => Ok(n as u32 as u128),
282            DataValue::I64(n) => Ok(n as u64 as u128),
283            DataValue::I128(n) => Ok(n as u128),
284            _ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())),
285        }
286    }
287
288    fn float(bits: u64, ty: Type) -> ValueResult<Self> {
289        match ty {
290            types::F32 => Ok(DataValue::F32(Ieee32::with_bits(u32::try_from(bits)?))),
291            types::F64 => Ok(DataValue::F64(Ieee64::with_bits(bits))),
292            _ => Err(ValueError::InvalidType(ValueTypeClass::Float, ty)),
293        }
294    }
295
296    fn into_float(self) -> ValueResult<f64> {
297        match self {
298            DataValue::F32(n) => Ok(n.as_f32() as f64),
299            DataValue::F64(n) => Ok(n.as_f64()),
300            _ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),
301        }
302    }
303
304    fn is_float(&self) -> bool {
305        match self {
306            DataValue::F16(_) | DataValue::F32(_) | DataValue::F64(_) | DataValue::F128(_) => true,
307            _ => false,
308        }
309    }
310
311    fn is_nan(&self) -> ValueResult<bool> {
312        match self {
313            DataValue::F32(f) => Ok(f.is_nan()),
314            DataValue::F64(f) => Ok(f.is_nan()),
315            _ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),
316        }
317    }
318
319    fn bool(b: bool, vec_elem: bool, ty: Type) -> ValueResult<Self> {
320        assert!(ty.is_int());
321        macro_rules! make_bool {
322            ($ty:ident) => {
323                Ok(DataValue::$ty(if b {
324                    if vec_elem {
325                        -1
326                    } else {
327                        1
328                    }
329                } else {
330                    0
331                }))
332            };
333        }
334
335        match ty {
336            types::I8 => make_bool!(I8),
337            types::I16 => make_bool!(I16),
338            types::I32 => make_bool!(I32),
339            types::I64 => make_bool!(I64),
340            types::I128 => make_bool!(I128),
341            _ => Err(ValueError::InvalidType(ValueTypeClass::Integer, ty)),
342        }
343    }
344
345    fn into_bool(self) -> ValueResult<bool> {
346        match self {
347            DataValue::I8(b) => Ok(b != 0),
348            DataValue::I16(b) => Ok(b != 0),
349            DataValue::I32(b) => Ok(b != 0),
350            DataValue::I64(b) => Ok(b != 0),
351            DataValue::I128(b) => Ok(b != 0),
352            _ => Err(ValueError::InvalidType(ValueTypeClass::Boolean, self.ty())),
353        }
354    }
355
356    fn vector(v: [u8; 16], ty: Type) -> ValueResult<Self> {
357        assert!(ty.is_vector() && [8, 16].contains(&ty.bytes()));
358        if ty.bytes() == 16 {
359            Ok(DataValue::V128(v))
360        } else if ty.bytes() == 8 {
361            let v64: [u8; 8] = v[..8].try_into().unwrap();
362            Ok(DataValue::V64(v64))
363        } else {
364            unimplemented!()
365        }
366    }
367
368    fn into_array(&self) -> ValueResult<[u8; 16]> {
369        match *self {
370            DataValue::V128(v) => Ok(v),
371            DataValue::V64(v) => {
372                let mut v128 = [0; 16];
373                v128[..8].clone_from_slice(&v);
374                Ok(v128)
375            }
376            _ => Err(ValueError::InvalidType(ValueTypeClass::Vector, self.ty())),
377        }
378    }
379
380    fn convert(self, kind: ValueConversionKind) -> ValueResult<Self> {
381        Ok(match kind {
382            ValueConversionKind::Exact(ty) => match (self, ty) {
383                // TODO a lot to do here: from bmask to ireduce to bitcast...
384                (val, ty) if val.ty().is_int() && ty.is_int() => {
385                    DataValue::from_integer(val.into_int_signed()?, ty)?
386                }
387                (DataValue::I16(n), types::F16) => DataValue::F16(Ieee16::with_bits(n as u16)),
388                (DataValue::I32(n), types::F32) => DataValue::F32(f32::from_bits(n as u32).into()),
389                (DataValue::I64(n), types::F64) => DataValue::F64(f64::from_bits(n as u64).into()),
390                (DataValue::I128(n), types::F128) => DataValue::F128(Ieee128::with_bits(n as u128)),
391                (DataValue::F16(n), types::I16) => DataValue::I16(n.bits() as i16),
392                (DataValue::F32(n), types::I32) => DataValue::I32(n.bits() as i32),
393                (DataValue::F64(n), types::I64) => DataValue::I64(n.bits() as i64),
394                (DataValue::F128(n), types::I128) => DataValue::I128(n.bits() as i128),
395                (DataValue::F32(n), types::F64) => DataValue::F64((n.as_f32() as f64).into()),
396                (dv, t) if (t.is_int() || t.is_float()) && dv.ty() == t => dv,
397                (dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),
398            },
399            ValueConversionKind::Truncate(ty) => {
400                assert!(
401                    ty.is_int(),
402                    "unimplemented conversion: {} -> {:?}",
403                    self.ty(),
404                    kind
405                );
406
407                let mask = (1 << (ty.bytes() * 8)) - 1i128;
408                let truncated = self.into_int_signed()? & mask;
409                Self::from_integer(truncated, ty)?
410            }
411            ValueConversionKind::ExtractUpper(ty) => {
412                assert!(
413                    ty.is_int(),
414                    "unimplemented conversion: {} -> {:?}",
415                    self.ty(),
416                    kind
417                );
418
419                let shift_amt = (self.ty().bytes() * 8) - (ty.bytes() * 8);
420                let mask = (1 << (ty.bytes() * 8)) - 1i128;
421                let shifted_mask = mask << shift_amt;
422
423                let extracted = (self.into_int_signed()? & shifted_mask) >> shift_amt;
424                Self::from_integer(extracted, ty)?
425            }
426            ValueConversionKind::SignExtend(ty) => match (self, ty) {
427                (DataValue::I8(n), types::I16) => DataValue::I16(n as i16),
428                (DataValue::I8(n), types::I32) => DataValue::I32(n as i32),
429                (DataValue::I8(n), types::I64) => DataValue::I64(n as i64),
430                (DataValue::I8(n), types::I128) => DataValue::I128(n as i128),
431                (DataValue::I16(n), types::I32) => DataValue::I32(n as i32),
432                (DataValue::I16(n), types::I64) => DataValue::I64(n as i64),
433                (DataValue::I16(n), types::I128) => DataValue::I128(n as i128),
434                (DataValue::I32(n), types::I64) => DataValue::I64(n as i64),
435                (DataValue::I32(n), types::I128) => DataValue::I128(n as i128),
436                (DataValue::I64(n), types::I128) => DataValue::I128(n as i128),
437                (dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),
438            },
439            ValueConversionKind::ZeroExtend(ty) => match (self, ty) {
440                (DataValue::I8(n), types::I16) => DataValue::I16(n as u8 as i16),
441                (DataValue::I8(n), types::I32) => DataValue::I32(n as u8 as i32),
442                (DataValue::I8(n), types::I64) => DataValue::I64(n as u8 as i64),
443                (DataValue::I8(n), types::I128) => DataValue::I128(n as u8 as i128),
444                (DataValue::I16(n), types::I32) => DataValue::I32(n as u16 as i32),
445                (DataValue::I16(n), types::I64) => DataValue::I64(n as u16 as i64),
446                (DataValue::I16(n), types::I128) => DataValue::I128(n as u16 as i128),
447                (DataValue::I32(n), types::I64) => DataValue::I64(n as u32 as i64),
448                (DataValue::I32(n), types::I128) => DataValue::I128(n as u32 as i128),
449                (DataValue::I64(n), types::I128) => DataValue::I128(n as u64 as i128),
450                (from, to) if from.ty() == to => from,
451                (dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),
452            },
453            ValueConversionKind::RoundNearestEven(ty) => match (self, ty) {
454                (DataValue::F64(n), types::F32) => DataValue::F32(Ieee32::from(n.as_f64() as f32)),
455                (s, _) => unimplemented!("conversion: {} -> {:?}", s.ty(), kind),
456            },
457            ValueConversionKind::ToBoolean => match self.ty() {
458                ty if ty.is_int() => {
459                    DataValue::I8(if self.into_int_signed()? != 0 { 1 } else { 0 })
460                }
461                ty => unimplemented!("conversion: {} -> {:?}", ty, kind),
462            },
463            ValueConversionKind::Mask(ty) => {
464                let b = self.into_bool()?;
465                Self::bool(b, true, ty).unwrap()
466            }
467        })
468    }
469
470    fn concat(self, other: Self) -> ValueResult<Self> {
471        match (self, other) {
472            (DataValue::I64(lhs), DataValue::I64(rhs)) => Ok(DataValue::I128(
473                (((lhs as u64) as u128) | (((rhs as u64) as u128) << 64)) as i128,
474            )),
475            (lhs, rhs) => unimplemented!("concat: {} -> {}", lhs.ty(), rhs.ty()),
476        }
477    }
478
479    fn is_negative(&self) -> ValueResult<bool> {
480        match self {
481            DataValue::F32(f) => Ok(f.is_negative()),
482            DataValue::F64(f) => Ok(f.is_negative()),
483            _ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),
484        }
485    }
486
487    fn is_zero(&self) -> ValueResult<bool> {
488        match self {
489            DataValue::I8(f) => Ok(*f == 0),
490            DataValue::I16(f) => Ok(*f == 0),
491            DataValue::I32(f) => Ok(*f == 0),
492            DataValue::I64(f) => Ok(*f == 0),
493            DataValue::I128(f) => Ok(*f == 0),
494            DataValue::F16(f) => Ok(f.is_zero()),
495            DataValue::F32(f) => Ok(f.is_zero()),
496            DataValue::F64(f) => Ok(f.is_zero()),
497            DataValue::F128(f) => Ok(f.is_zero()),
498            DataValue::V64(_) | DataValue::V128(_) => {
499                Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty()))
500            }
501        }
502    }
503
504    fn umax(self, other: Self) -> ValueResult<Self> {
505        let lhs = self.clone().into_int_unsigned()?;
506        let rhs = other.clone().into_int_unsigned()?;
507        if lhs > rhs {
508            Ok(self)
509        } else {
510            Ok(other)
511        }
512    }
513
514    fn smax(self, other: Self) -> ValueResult<Self> {
515        if self > other {
516            Ok(self)
517        } else {
518            Ok(other)
519        }
520    }
521
522    fn umin(self, other: Self) -> ValueResult<Self> {
523        let lhs = self.clone().into_int_unsigned()?;
524        let rhs = other.clone().into_int_unsigned()?;
525        if lhs < rhs {
526            Ok(self)
527        } else {
528            Ok(other)
529        }
530    }
531
532    fn smin(self, other: Self) -> ValueResult<Self> {
533        if self < other {
534            Ok(self)
535        } else {
536            Ok(other)
537        }
538    }
539
540    fn uno(&self, other: &Self) -> ValueResult<bool> {
541        Ok(self.is_nan()? || other.is_nan()?)
542    }
543
544    fn add(self, other: Self) -> ValueResult<Self> {
545        if self.is_float() {
546            binary_match!(+(self, other); [F32, F64])
547        } else {
548            binary_match!(wrapping_add(&self, &other); [I8, I16, I32, I64, I128])
549        }
550    }
551
552    fn sub(self, other: Self) -> ValueResult<Self> {
553        if self.is_float() {
554            binary_match!(-(self, other); [F32, F64])
555        } else {
556            binary_match!(wrapping_sub(&self, &other); [I8, I16, I32, I64, I128])
557        }
558    }
559
560    fn mul(self, other: Self) -> ValueResult<Self> {
561        if self.is_float() {
562            binary_match!(*(self, other); [F32, F64])
563        } else {
564            binary_match!(wrapping_mul(&self, &other); [I8, I16, I32, I64, I128])
565        }
566    }
567
568    fn sdiv(self, other: Self) -> ValueResult<Self> {
569        if self.is_float() {
570            return binary_match!(/(self, other); [F32, F64]);
571        }
572
573        let denominator = other.clone().into_int_signed()?;
574
575        // Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.
576        let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?;
577        if self == min && denominator == -1 {
578            return Err(ValueError::IntegerOverflow);
579        }
580
581        if denominator == 0 {
582            return Err(ValueError::IntegerDivisionByZero);
583        }
584
585        binary_match!(/(&self, &other); [I8, I16, I32, I64, I128])
586    }
587
588    fn udiv(self, other: Self) -> ValueResult<Self> {
589        if self.is_float() {
590            return binary_match!(/(self, other); [F32, F64]);
591        }
592
593        let denominator = other.clone().into_int_unsigned()?;
594
595        if denominator == 0 {
596            return Err(ValueError::IntegerDivisionByZero);
597        }
598
599        binary_match!(/(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
600    }
601
602    fn srem(self, other: Self) -> ValueResult<Self> {
603        let denominator = other.clone().into_int_signed()?;
604
605        // Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.
606        let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?;
607        if self == min && denominator == -1 {
608            return Err(ValueError::IntegerOverflow);
609        }
610
611        if denominator == 0 {
612            return Err(ValueError::IntegerDivisionByZero);
613        }
614
615        binary_match!(%(&self, &other); [I8, I16, I32, I64, I128])
616    }
617
618    fn urem(self, other: Self) -> ValueResult<Self> {
619        let denominator = other.clone().into_int_unsigned()?;
620
621        if denominator == 0 {
622            return Err(ValueError::IntegerDivisionByZero);
623        }
624
625        binary_match!(%(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
626    }
627
628    fn sqrt(self) -> ValueResult<Self> {
629        unary_match!(sqrt(&self); [F32, F64]; [Ieee32, Ieee64])
630    }
631
632    fn fma(self, b: Self, c: Self) -> ValueResult<Self> {
633        match (self, b, c) {
634            (DataValue::F32(a), DataValue::F32(b), DataValue::F32(c)) => {
635                // The `fma` function for `x86_64-pc-windows-gnu` is incorrect. Use `libm`'s instead.
636                // See: https://github.com/bytecodealliance/wasmtime/issues/4512
637                #[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "gnu"))]
638                let res = libm::fmaf(a.as_f32(), b.as_f32(), c.as_f32());
639
640                #[cfg(not(all(
641                    target_arch = "x86_64",
642                    target_os = "windows",
643                    target_env = "gnu"
644                )))]
645                let res = a.as_f32().mul_add(b.as_f32(), c.as_f32());
646
647                Ok(DataValue::F32(res.into()))
648            }
649            (DataValue::F64(a), DataValue::F64(b), DataValue::F64(c)) => {
650                #[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "gnu"))]
651                let res = libm::fma(a.as_f64(), b.as_f64(), c.as_f64());
652
653                #[cfg(not(all(
654                    target_arch = "x86_64",
655                    target_os = "windows",
656                    target_env = "gnu"
657                )))]
658                let res = a.as_f64().mul_add(b.as_f64(), c.as_f64());
659
660                Ok(DataValue::F64(res.into()))
661            }
662            (a, _b, _c) => Err(ValueError::InvalidType(ValueTypeClass::Float, a.ty())),
663        }
664    }
665
666    fn abs(self) -> ValueResult<Self> {
667        unary_match!(abs(&self); [F32, F64])
668    }
669
670    fn sadd_checked(self, other: Self) -> ValueResult<Option<Self>> {
671        binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
672    }
673
674    fn uadd_checked(self, other: Self) -> ValueResult<Option<Self>> {
675        binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
676    }
677
678    fn sadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
679        binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
680    }
681
682    fn uadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
683        binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
684    }
685
686    fn ssub_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
687        binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
688    }
689
690    fn usub_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
691        binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
692    }
693
694    fn smul_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
695        binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
696    }
697
698    fn umul_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
699        binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
700    }
701
702    fn neg(self) -> ValueResult<Self> {
703        unary_match!(neg(&self); [F32, F64])
704    }
705
706    fn copysign(self, sign: Self) -> ValueResult<Self> {
707        binary_match!(copysign(&self, &sign); [F32, F64])
708    }
709
710    fn ceil(self) -> ValueResult<Self> {
711        unary_match!(ceil(&self); [F32, F64])
712    }
713
714    fn floor(self) -> ValueResult<Self> {
715        unary_match!(floor(&self); [F32, F64])
716    }
717
718    fn trunc(self) -> ValueResult<Self> {
719        unary_match!(trunc(&self); [F32, F64])
720    }
721
722    fn nearest(self) -> ValueResult<Self> {
723        unary_match!(round_ties_even(&self); [F32, F64])
724    }
725
726    fn sadd_sat(self, other: Self) -> ValueResult<Self> {
727        binary_match!(saturating_add(self, &other); [I8, I16, I32, I64, I128])
728    }
729
730    fn uadd_sat(self, other: Self) -> ValueResult<Self> {
731        binary_match!(saturating_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
732    }
733
734    fn ssub_sat(self, other: Self) -> ValueResult<Self> {
735        binary_match!(saturating_sub(self, &other); [I8, I16, I32, I64, I128])
736    }
737
738    fn usub_sat(self, other: Self) -> ValueResult<Self> {
739        binary_match!(saturating_sub(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
740    }
741
742    fn shl(self, other: Self) -> ValueResult<Self> {
743        let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
744        binary_match!(wrapping_shl(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
745    }
746
747    fn ushr(self, other: Self) -> ValueResult<Self> {
748        let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
749        binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128]; rhs: I32,u32)
750    }
751
752    fn sshr(self, other: Self) -> ValueResult<Self> {
753        let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
754        binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
755    }
756
757    fn rotl(self, other: Self) -> ValueResult<Self> {
758        let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
759        binary_match!(rotate_left(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
760    }
761
762    fn rotr(self, other: Self) -> ValueResult<Self> {
763        let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
764        binary_match!(rotate_right(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
765    }
766
767    fn and(self, other: Self) -> ValueResult<Self> {
768        bitop!(&(self, other))
769    }
770
771    fn or(self, other: Self) -> ValueResult<Self> {
772        bitop!(|(self, other))
773    }
774
775    fn xor(self, other: Self) -> ValueResult<Self> {
776        bitop!(^(self, other))
777    }
778
779    fn not(self) -> ValueResult<Self> {
780        Ok(match self {
781            DataValue::I8(a) => DataValue::I8(!a),
782            DataValue::I16(a) => DataValue::I16(!a),
783            DataValue::I32(a) => DataValue::I32(!a),
784            DataValue::I64(a) => DataValue::I64(!a),
785            DataValue::I128(a) => DataValue::I128(!a),
786            DataValue::F32(a) => DataValue::F32(!a),
787            DataValue::F64(a) => DataValue::F64(!a),
788            DataValue::V128(mut a) => {
789                for byte in a.iter_mut() {
790                    *byte = !*byte;
791                }
792                DataValue::V128(a)
793            }
794            _ => unimplemented!(),
795        })
796    }
797
798    fn count_ones(self) -> ValueResult<Self> {
799        unary_match!(count_ones(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
800    }
801
802    fn leading_ones(self) -> ValueResult<Self> {
803        unary_match!(leading_ones(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
804    }
805
806    fn leading_zeros(self) -> ValueResult<Self> {
807        unary_match!(leading_zeros(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
808    }
809
810    fn trailing_zeros(self) -> ValueResult<Self> {
811        unary_match!(trailing_zeros(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
812    }
813
814    fn reverse_bits(self) -> ValueResult<Self> {
815        unary_match!(reverse_bits(&self); [I8, I16, I32, I64, I128])
816    }
817
818    fn swap_bytes(self) -> ValueResult<Self> {
819        unary_match!(swap_bytes(&self); [I16, I32, I64, I128])
820    }
821
822    fn iter_lanes(&self, ty: Type) -> ValueResult<DataValueIterator> {
823        DataValueIterator::new(self, ty)
824    }
825}
826
827/// Iterator for DataValue's
828pub struct DataValueIterator {
829    ty: Type,
830    v: SimdVec<DataValue>,
831    idx: usize,
832}
833
834impl DataValueIterator {
835    fn new(dv: &DataValue, ty: Type) -> Result<Self, ValueError> {
836        match extractlanes(dv, ty) {
837            Ok(v) => return Ok(Self { ty, v, idx: 0 }),
838            Err(err) => return Err(err),
839        }
840    }
841}
842
843impl Iterator for DataValueIterator {
844    type Item = DataValue;
845
846    fn next(&mut self) -> Option<Self::Item> {
847        if self.idx >= self.ty.lane_count() as usize {
848            return None;
849        }
850
851        let dv = self.v[self.idx].clone();
852        self.idx += 1;
853        Some(dv)
854    }
855}
856
857#[cfg(test)]
858mod test {
859    use super::*;
860
861    #[test]
862    fn test_iterator_v128() {
863        let dv = DataValue::V128([99, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
864        assert_eq!(simd_sum(dv, types::I8X16), 219);
865    }
866
867    #[test]
868    fn test_iterator_v128_empty() {
869        let dv = DataValue::V128([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
870        assert_eq!(simd_sum(dv, types::I8X16), 0);
871    }
872
873    #[test]
874    fn test_iterator_v128_ones() {
875        let dv = DataValue::V128([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
876        assert_eq!(simd_sum(dv, types::I8X16), 16);
877    }
878
879    #[test]
880    fn test_iterator_v64_empty() {
881        let dv = DataValue::V64([0, 0, 0, 0, 0, 0, 0, 0]);
882        assert_eq!(simd_sum(dv, types::I8X8), 0);
883    }
884    #[test]
885    fn test_iterator_v64_ones() {
886        let dv = DataValue::V64([1, 1, 1, 1, 1, 1, 1, 1]);
887        assert_eq!(simd_sum(dv, types::I8X8), 8);
888    }
889    #[test]
890    fn test_iterator_v64() {
891        let dv = DataValue::V64([10, 20, 30, 40, 50, 60, 70, 80]);
892        assert_eq!(simd_sum(dv, types::I8X8), 360);
893    }
894
895    fn simd_sum(dv: DataValue, ty: types::Type) -> i128 {
896        let itr = dv.iter_lanes(ty).unwrap();
897
898        itr.map(|e| {
899            if let Some(v) = e.into_int_signed().ok() {
900                v
901            } else {
902                0
903            }
904        })
905        .sum()
906    }
907}