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