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