1#![expect(trivial_numeric_casts, reason = "macro-generated code")]
5
6use core::fmt::{self, Display, Formatter};
7use core::ops::Neg;
8use cranelift_codegen::data_value::{DataValue, DataValueCastFailure};
9use cranelift_codegen::ir::immediates::{Ieee16, Ieee32, Ieee64, Ieee128};
10use cranelift_codegen::ir::{Type, types};
11use thiserror::Error;
12
13use crate::step::{SimdVec, extractlanes};
14
15pub type ValueResult<T> = Result<T, ValueError>;
16
17pub trait DataValueExt: Sized {
18 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 fn uno(&self, other: &Self) -> ValueResult<bool>;
43
44 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 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 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 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 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 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 Exact(Type),
141 Truncate(Type),
144 ExtractUpper(Type),
147 SignExtend(Type),
150 ZeroExtend(Type),
153 RoundNearestEven(Type),
156 ToBoolean,
159 Mask(Type),
161}
162
163macro_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::F16(a), DataValue::F16(b)) => DataValue::F16(a $op b),
237 (DataValue::F32(a), DataValue::F32(b)) => DataValue::F32(a $op b),
238 (DataValue::F64(a), DataValue::F64(b)) => DataValue::F64(a $op b),
239 (DataValue::F128(a), DataValue::F128(b)) => DataValue::F128(a $op b),
240 (DataValue::V64(a), DataValue::V64(b)) => {
241 let mut a2 = a.clone();
242 for (a, b) in a2.iter_mut().zip(b.iter()) {
243 *a = *a $op *b;
244 }
245 DataValue::V64(a2)
246 }
247 (DataValue::V128(a), DataValue::V128(b)) => {
248 let mut a2 = a.clone();
249 for (a, b) in a2.iter_mut().zip(b.iter()) {
250 *a = *a $op *b;
251 }
252 DataValue::V128(a2)
253 }
254 _ => unimplemented!(),
255 })
256 };
257}
258
259fn f16_binop(a: Ieee16, b: Ieee16, f: impl Fn(f32, f32) -> f32) -> DataValue {
261 DataValue::F16(Ieee16::from_f32_rne(f(a.to_f32(), b.to_f32())))
262}
263
264fn f16_unop(a: Ieee16, f: impl Fn(f32) -> f32) -> DataValue {
265 DataValue::F16(Ieee16::from_f32_rne(f(a.to_f32())))
266}
267
268impl DataValueExt for DataValue {
269 fn int(n: i128, ty: Type) -> ValueResult<Self> {
270 if ty.is_vector() {
271 match ty.bytes() {
274 8 | 16 => Ok(DataValue::read_from_slice_ne(&n.to_ne_bytes(), ty)),
275 _ => Err(ValueError::InvalidType(ValueTypeClass::Vector, ty)),
276 }
277 } else if ty.is_int() {
278 DataValue::from_integer(n, ty).map_err(|_| ValueError::InvalidValue(ty))
279 } else {
280 Err(ValueError::InvalidType(ValueTypeClass::Integer, ty))
281 }
282 }
283
284 fn into_int_signed(self) -> ValueResult<i128> {
285 match self {
286 DataValue::I8(n) => Ok(n as i128),
287 DataValue::I16(n) => Ok(n as i128),
288 DataValue::I32(n) => Ok(n as i128),
289 DataValue::I64(n) => Ok(n as i128),
290 DataValue::I128(n) => Ok(n),
291 _ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())),
292 }
293 }
294
295 fn into_int_unsigned(self) -> ValueResult<u128> {
296 match self {
297 DataValue::I8(n) => Ok(n as u8 as u128),
298 DataValue::I16(n) => Ok(n as u16 as u128),
299 DataValue::I32(n) => Ok(n as u32 as u128),
300 DataValue::I64(n) => Ok(n as u64 as u128),
301 DataValue::I128(n) => Ok(n as u128),
302 _ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())),
303 }
304 }
305
306 fn float(bits: u64, ty: Type) -> ValueResult<Self> {
307 match ty {
308 types::F16 => Ok(DataValue::F16(Ieee16::with_bits(u16::try_from(bits)?))),
309 types::F32 => Ok(DataValue::F32(Ieee32::with_bits(u32::try_from(bits)?))),
310 types::F64 => Ok(DataValue::F64(Ieee64::with_bits(bits))),
311 _ => Err(ValueError::InvalidType(ValueTypeClass::Float, ty)),
312 }
313 }
314
315 fn into_float(self) -> ValueResult<f64> {
316 match self {
317 DataValue::F16(n) => Ok(n.to_f32() as f64),
318 DataValue::F32(n) => Ok(n.as_f32() as f64),
319 DataValue::F64(n) => Ok(n.as_f64()),
320 _ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),
321 }
322 }
323
324 fn is_float(&self) -> bool {
325 match self {
326 DataValue::F16(_) | DataValue::F32(_) | DataValue::F64(_) | DataValue::F128(_) => true,
327 _ => false,
328 }
329 }
330
331 fn is_nan(&self) -> ValueResult<bool> {
332 match self {
333 DataValue::F16(f) => Ok(f.is_nan()),
334 DataValue::F32(f) => Ok(f.is_nan()),
335 DataValue::F64(f) => Ok(f.is_nan()),
336 _ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),
337 }
338 }
339
340 fn bool(b: bool, vec_elem: bool, ty: Type) -> ValueResult<Self> {
341 assert!(ty.is_int());
342 macro_rules! make_bool {
343 ($ty:ident) => {
344 Ok(DataValue::$ty(if b {
345 if vec_elem { -1 } else { 1 }
346 } else {
347 0
348 }))
349 };
350 }
351
352 match ty {
353 types::I8 => make_bool!(I8),
354 types::I16 => make_bool!(I16),
355 types::I32 => make_bool!(I32),
356 types::I64 => make_bool!(I64),
357 types::I128 => make_bool!(I128),
358 _ => Err(ValueError::InvalidType(ValueTypeClass::Integer, ty)),
359 }
360 }
361
362 fn into_bool(self) -> ValueResult<bool> {
363 match self {
364 DataValue::I8(b) => Ok(b != 0),
365 DataValue::I16(b) => Ok(b != 0),
366 DataValue::I32(b) => Ok(b != 0),
367 DataValue::I64(b) => Ok(b != 0),
368 DataValue::I128(b) => Ok(b != 0),
369 _ => Err(ValueError::InvalidType(ValueTypeClass::Boolean, self.ty())),
370 }
371 }
372
373 fn vector(v: [u8; 16], ty: Type) -> ValueResult<Self> {
374 assert!(ty.is_vector() && [2, 4, 8, 16].contains(&ty.bytes()));
375 match ty.bytes() {
376 16 => Ok(DataValue::V128(v)),
377 8 => Ok(DataValue::V64(v[..8].try_into().unwrap())),
378 4 => Ok(DataValue::V32(v[..4].try_into().unwrap())),
379 2 => Ok(DataValue::V16(v[..2].try_into().unwrap())),
380 _ => unreachable!(),
381 }
382 }
383
384 fn into_array(&self) -> ValueResult<[u8; 16]> {
385 match *self {
386 DataValue::V128(v) => Ok(v),
387 DataValue::V64(v) => {
388 let mut v128 = [0; 16];
389 v128[..8].clone_from_slice(&v);
390 Ok(v128)
391 }
392 DataValue::V32(v) => {
393 let mut v128 = [0; 16];
394 v128[..4].clone_from_slice(&v);
395 Ok(v128)
396 }
397 DataValue::V16(v) => {
398 let mut v128 = [0; 16];
399 v128[..2].clone_from_slice(&v);
400 Ok(v128)
401 }
402 _ => Err(ValueError::InvalidType(ValueTypeClass::Vector, self.ty())),
403 }
404 }
405
406 fn convert(self, kind: ValueConversionKind) -> ValueResult<Self> {
407 Ok(match kind {
408 ValueConversionKind::Exact(ty) => match (self, ty) {
409 (val, ty) if val.ty().is_int() && ty.is_int() => {
411 DataValue::from_integer(val.into_int_signed()?, ty)?
412 }
413 (DataValue::I16(n), types::F16) => DataValue::F16(Ieee16::with_bits(n as u16)),
414 (DataValue::I32(n), types::F32) => DataValue::F32(f32::from_bits(n as u32).into()),
415 (DataValue::I64(n), types::F64) => DataValue::F64(f64::from_bits(n as u64).into()),
416 (DataValue::I128(n), types::F128) => DataValue::F128(Ieee128::with_bits(n as u128)),
417 (DataValue::F16(n), types::I16) => DataValue::I16(n.bits() as i16),
418 (DataValue::F32(n), types::I32) => DataValue::I32(n.bits() as i32),
419 (DataValue::F64(n), types::I64) => DataValue::I64(n.bits() as i64),
420 (DataValue::F128(n), types::I128) => DataValue::I128(n.bits() as i128),
421 (DataValue::F16(n), types::F32) => DataValue::F32(n.to_f32().into()),
422 (DataValue::F16(n), types::F64) => DataValue::F64(f64::from(n.to_f32()).into()),
423 (DataValue::F32(n), types::F64) => DataValue::F64((n.as_f32() as f64).into()),
424 (dv, t) if (t.is_int() || t.is_float()) && dv.ty() == t => dv,
425 (dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),
426 },
427 ValueConversionKind::Truncate(ty) => {
428 assert!(
429 ty.is_int(),
430 "unimplemented conversion: {} -> {:?}",
431 self.ty(),
432 kind
433 );
434
435 let mask = (1 << (ty.bytes() * 8)) - 1i128;
436 let truncated = self.into_int_signed()? & mask;
437 Self::from_integer(truncated, ty)?
438 }
439 ValueConversionKind::ExtractUpper(ty) => {
440 assert!(
441 ty.is_int(),
442 "unimplemented conversion: {} -> {:?}",
443 self.ty(),
444 kind
445 );
446
447 let shift_amt = (self.ty().bytes() * 8) - (ty.bytes() * 8);
448 let mask = (1 << (ty.bytes() * 8)) - 1i128;
449 let shifted_mask = mask << shift_amt;
450
451 let extracted = (self.into_int_signed()? & shifted_mask) >> shift_amt;
452 Self::from_integer(extracted, ty)?
453 }
454 ValueConversionKind::SignExtend(ty) => match (self, ty) {
455 (DataValue::I8(n), types::I16) => DataValue::I16(n as i16),
456 (DataValue::I8(n), types::I32) => DataValue::I32(n as i32),
457 (DataValue::I8(n), types::I64) => DataValue::I64(n as i64),
458 (DataValue::I8(n), types::I128) => DataValue::I128(n as i128),
459 (DataValue::I16(n), types::I32) => DataValue::I32(n as i32),
460 (DataValue::I16(n), types::I64) => DataValue::I64(n as i64),
461 (DataValue::I16(n), types::I128) => DataValue::I128(n as i128),
462 (DataValue::I32(n), types::I64) => DataValue::I64(n as i64),
463 (DataValue::I32(n), types::I128) => DataValue::I128(n as i128),
464 (DataValue::I64(n), types::I128) => DataValue::I128(n as i128),
465 (dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),
466 },
467 ValueConversionKind::ZeroExtend(ty) => match (self, ty) {
468 (DataValue::I8(n), types::I16) => DataValue::I16(n as u8 as i16),
469 (DataValue::I8(n), types::I32) => DataValue::I32(n as u8 as i32),
470 (DataValue::I8(n), types::I64) => DataValue::I64(n as u8 as i64),
471 (DataValue::I8(n), types::I128) => DataValue::I128(n as u8 as i128),
472 (DataValue::I16(n), types::I32) => DataValue::I32(n as u16 as i32),
473 (DataValue::I16(n), types::I64) => DataValue::I64(n as u16 as i64),
474 (DataValue::I16(n), types::I128) => DataValue::I128(n as u16 as i128),
475 (DataValue::I32(n), types::I64) => DataValue::I64(n as u32 as i64),
476 (DataValue::I32(n), types::I128) => DataValue::I128(n as u32 as i128),
477 (DataValue::I64(n), types::I128) => DataValue::I128(n as u64 as i128),
478 (from, to) if from.ty() == to => from,
479 (dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),
480 },
481 ValueConversionKind::RoundNearestEven(ty) => match (self, ty) {
482 (DataValue::F64(n), types::F32) => DataValue::F32(Ieee32::from(n.as_f64() as f32)),
483 (DataValue::F32(n), types::F16) => DataValue::F16(Ieee16::from_f32_rne(n.as_f32())),
484 (DataValue::F64(n), types::F16) => DataValue::F16(Ieee16::from_f64_rne(n.as_f64())),
485 (s, _) => unimplemented!("conversion: {} -> {:?}", s.ty(), kind),
486 },
487 ValueConversionKind::ToBoolean => match self.ty() {
488 ty if ty.is_int() => {
489 DataValue::I8(if self.into_int_signed()? != 0 { 1 } else { 0 })
490 }
491 ty => unimplemented!("conversion: {} -> {:?}", ty, kind),
492 },
493 ValueConversionKind::Mask(ty) => {
494 let b = self.into_bool()?;
495 Self::bool(b, true, ty).unwrap()
496 }
497 })
498 }
499
500 fn concat(self, other: Self) -> ValueResult<Self> {
501 match (self, other) {
502 (DataValue::I64(lhs), DataValue::I64(rhs)) => Ok(DataValue::I128(
503 (((lhs as u64) as u128) | (((rhs as u64) as u128) << 64)) as i128,
504 )),
505 (lhs, rhs) => unimplemented!("concat: {} -> {}", lhs.ty(), rhs.ty()),
506 }
507 }
508
509 fn is_negative(&self) -> ValueResult<bool> {
510 match self {
511 DataValue::F16(f) => Ok(f.is_negative()),
512 DataValue::F32(f) => Ok(f.is_negative()),
513 DataValue::F64(f) => Ok(f.is_negative()),
514 _ => Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty())),
515 }
516 }
517
518 fn is_zero(&self) -> ValueResult<bool> {
519 match self {
520 DataValue::I8(f) => Ok(*f == 0),
521 DataValue::I16(f) => Ok(*f == 0),
522 DataValue::I32(f) => Ok(*f == 0),
523 DataValue::I64(f) => Ok(*f == 0),
524 DataValue::I128(f) => Ok(*f == 0),
525 DataValue::F16(f) => Ok(f.is_zero()),
526 DataValue::F32(f) => Ok(f.is_zero()),
527 DataValue::F64(f) => Ok(f.is_zero()),
528 DataValue::F128(f) => Ok(f.is_zero()),
529 DataValue::V16(_) | DataValue::V32(_) | DataValue::V64(_) | DataValue::V128(_) => {
530 Err(ValueError::InvalidType(ValueTypeClass::Float, self.ty()))
531 }
532 }
533 }
534
535 fn umax(self, other: Self) -> ValueResult<Self> {
536 let lhs = self.clone().into_int_unsigned()?;
537 let rhs = other.clone().into_int_unsigned()?;
538 if lhs > rhs { Ok(self) } else { Ok(other) }
539 }
540
541 fn smax(self, other: Self) -> ValueResult<Self> {
542 if self > other { Ok(self) } else { Ok(other) }
543 }
544
545 fn umin(self, other: Self) -> ValueResult<Self> {
546 let lhs = self.clone().into_int_unsigned()?;
547 let rhs = other.clone().into_int_unsigned()?;
548 if lhs < rhs { Ok(self) } else { Ok(other) }
549 }
550
551 fn smin(self, other: Self) -> ValueResult<Self> {
552 if self < other { Ok(self) } else { Ok(other) }
553 }
554
555 fn uno(&self, other: &Self) -> ValueResult<bool> {
556 Ok(self.is_nan()? || other.is_nan()?)
557 }
558
559 fn add(self, other: Self) -> ValueResult<Self> {
560 if self.is_float() {
561 if let (DataValue::F16(a), DataValue::F16(b)) = (&self, &other) {
562 return Ok(f16_binop(*a, *b, |x, y| x + y));
563 }
564 binary_match!(+(self, other); [F32, F64])
565 } else {
566 binary_match!(wrapping_add(&self, &other); [I8, I16, I32, I64, I128])
567 }
568 }
569
570 fn sub(self, other: Self) -> ValueResult<Self> {
571 if self.is_float() {
572 if let (DataValue::F16(a), DataValue::F16(b)) = (&self, &other) {
573 return Ok(f16_binop(*a, *b, |x, y| x - y));
574 }
575 binary_match!(-(self, other); [F32, F64])
576 } else {
577 binary_match!(wrapping_sub(&self, &other); [I8, I16, I32, I64, I128])
578 }
579 }
580
581 fn mul(self, other: Self) -> ValueResult<Self> {
582 if self.is_float() {
583 if let (DataValue::F16(a), DataValue::F16(b)) = (&self, &other) {
584 return Ok(f16_binop(*a, *b, |x, y| x * y));
585 }
586 binary_match!(*(self, other); [F32, F64])
587 } else {
588 binary_match!(wrapping_mul(&self, &other); [I8, I16, I32, I64, I128])
589 }
590 }
591
592 fn sdiv(self, other: Self) -> ValueResult<Self> {
593 if self.is_float() {
594 if let (DataValue::F16(a), DataValue::F16(b)) = (&self, &other) {
595 return Ok(f16_binop(*a, *b, |x, y| x / y));
596 }
597 return binary_match!(/(self, other); [F32, F64]);
598 }
599
600 let denominator = other.clone().into_int_signed()?;
601
602 let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?;
604 if self == min && denominator == -1 {
605 return Err(ValueError::IntegerOverflow);
606 }
607
608 if denominator == 0 {
609 return Err(ValueError::IntegerDivisionByZero);
610 }
611
612 binary_match!(/(&self, &other); [I8, I16, I32, I64, I128])
613 }
614
615 fn udiv(self, other: Self) -> ValueResult<Self> {
616 if self.is_float() {
617 if let (DataValue::F16(a), DataValue::F16(b)) = (&self, &other) {
618 return Ok(f16_binop(*a, *b, |x, y| x / y));
619 }
620 return binary_match!(/(self, other); [F32, F64]);
621 }
622
623 let denominator = other.clone().into_int_unsigned()?;
624
625 if denominator == 0 {
626 return Err(ValueError::IntegerDivisionByZero);
627 }
628
629 binary_match!(/(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
630 }
631
632 fn srem(self, other: Self) -> ValueResult<Self> {
633 let denominator = other.clone().into_int_signed()?;
634
635 if denominator == 0 {
636 return Err(ValueError::IntegerDivisionByZero);
637 }
638
639 if denominator == -1 {
643 return DataValueExt::int(0, self.ty());
644 }
645
646 binary_match!(%(&self, &other); [I8, I16, I32, I64, I128])
647 }
648
649 fn urem(self, other: Self) -> ValueResult<Self> {
650 let denominator = other.clone().into_int_unsigned()?;
651
652 if denominator == 0 {
653 return Err(ValueError::IntegerDivisionByZero);
654 }
655
656 binary_match!(%(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
657 }
658
659 fn sqrt(self) -> ValueResult<Self> {
660 if let DataValue::F16(a) = &self {
661 return Ok(f16_unop(*a, f32::sqrt));
662 }
663 unary_match!(sqrt(&self); [F32, F64]; [Ieee32, Ieee64])
664 }
665
666 fn fma(self, b: Self, c: Self) -> ValueResult<Self> {
667 match (self, b, c) {
668 (DataValue::F16(a), DataValue::F16(b), DataValue::F16(c)) => {
669 let (x, y, z) = (a.to_f32() as f64, b.to_f32() as f64, c.to_f32() as f64);
672
673 #[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "gnu"))]
674 let res = libm::fma(x, y, z);
675
676 #[cfg(not(all(
677 target_arch = "x86_64",
678 target_os = "windows",
679 target_env = "gnu"
680 )))]
681 let res = x.mul_add(y, z);
682
683 Ok(DataValue::F16(Ieee16::from_f64_rne(res)))
684 }
685 (DataValue::F32(a), DataValue::F32(b), DataValue::F32(c)) => {
686 #[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "gnu"))]
689 let res = libm::fmaf(a.as_f32(), b.as_f32(), c.as_f32());
690
691 #[cfg(not(all(
692 target_arch = "x86_64",
693 target_os = "windows",
694 target_env = "gnu"
695 )))]
696 let res = a.as_f32().mul_add(b.as_f32(), c.as_f32());
697
698 Ok(DataValue::F32(res.into()))
699 }
700 (DataValue::F64(a), DataValue::F64(b), DataValue::F64(c)) => {
701 #[cfg(all(target_arch = "x86_64", target_os = "windows", target_env = "gnu"))]
702 let res = libm::fma(a.as_f64(), b.as_f64(), c.as_f64());
703
704 #[cfg(not(all(
705 target_arch = "x86_64",
706 target_os = "windows",
707 target_env = "gnu"
708 )))]
709 let res = a.as_f64().mul_add(b.as_f64(), c.as_f64());
710
711 Ok(DataValue::F64(res.into()))
712 }
713 (a, _b, _c) => Err(ValueError::InvalidType(ValueTypeClass::Float, a.ty())),
714 }
715 }
716
717 fn abs(self) -> ValueResult<Self> {
718 unary_match!(abs(&self); [F16, F32, F64])
719 }
720
721 fn sadd_checked(self, other: Self) -> ValueResult<Option<Self>> {
722 binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
723 }
724
725 fn uadd_checked(self, other: Self) -> ValueResult<Option<Self>> {
726 binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
727 }
728
729 fn sadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
730 binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
731 }
732
733 fn uadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
734 binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
735 }
736
737 fn ssub_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
738 binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
739 }
740
741 fn usub_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
742 binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
743 }
744
745 fn smul_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
746 binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
747 }
748
749 fn umul_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
750 binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
751 }
752
753 fn neg(self) -> ValueResult<Self> {
754 unary_match!(neg(&self); [F16, F32, F64])
755 }
756
757 fn copysign(self, sign: Self) -> ValueResult<Self> {
758 binary_match!(copysign(&self, &sign); [F16, F32, F64])
759 }
760
761 fn ceil(self) -> ValueResult<Self> {
762 if let DataValue::F16(a) = &self {
763 return Ok(f16_unop(*a, f32::ceil));
764 }
765 unary_match!(ceil(&self); [F32, F64])
766 }
767
768 fn floor(self) -> ValueResult<Self> {
769 if let DataValue::F16(a) = &self {
770 return Ok(f16_unop(*a, f32::floor));
771 }
772 unary_match!(floor(&self); [F32, F64])
773 }
774
775 fn trunc(self) -> ValueResult<Self> {
776 if let DataValue::F16(a) = &self {
777 return Ok(f16_unop(*a, f32::trunc));
778 }
779 unary_match!(trunc(&self); [F32, F64])
780 }
781
782 fn nearest(self) -> ValueResult<Self> {
783 if let DataValue::F16(a) = &self {
784 return Ok(f16_unop(*a, f32::round_ties_even));
785 }
786 unary_match!(round_ties_even(&self); [F32, F64])
787 }
788
789 fn sadd_sat(self, other: Self) -> ValueResult<Self> {
790 binary_match!(saturating_add(self, &other); [I8, I16, I32, I64, I128])
791 }
792
793 fn uadd_sat(self, other: Self) -> ValueResult<Self> {
794 binary_match!(saturating_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
795 }
796
797 fn ssub_sat(self, other: Self) -> ValueResult<Self> {
798 binary_match!(saturating_sub(self, &other); [I8, I16, I32, I64, I128])
799 }
800
801 fn usub_sat(self, other: Self) -> ValueResult<Self> {
802 binary_match!(saturating_sub(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
803 }
804
805 fn shl(self, other: Self) -> ValueResult<Self> {
806 let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
807 binary_match!(wrapping_shl(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
808 }
809
810 fn ushr(self, other: Self) -> ValueResult<Self> {
811 let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
812 binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128]; rhs: I32,u32)
813 }
814
815 fn sshr(self, other: Self) -> ValueResult<Self> {
816 let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
817 binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
818 }
819
820 fn rotl(self, other: Self) -> ValueResult<Self> {
821 let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
822 binary_match!(rotate_left(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
823 }
824
825 fn rotr(self, other: Self) -> ValueResult<Self> {
826 let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
827 binary_match!(rotate_right(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
828 }
829
830 fn and(self, other: Self) -> ValueResult<Self> {
831 bitop!(&(self, other))
832 }
833
834 fn or(self, other: Self) -> ValueResult<Self> {
835 bitop!(|(self, other))
836 }
837
838 fn xor(self, other: Self) -> ValueResult<Self> {
839 bitop!(^(self, other))
840 }
841
842 fn not(self) -> ValueResult<Self> {
843 Ok(match self {
844 DataValue::I8(a) => DataValue::I8(!a),
845 DataValue::I16(a) => DataValue::I16(!a),
846 DataValue::I32(a) => DataValue::I32(!a),
847 DataValue::I64(a) => DataValue::I64(!a),
848 DataValue::I128(a) => DataValue::I128(!a),
849 DataValue::F16(a) => DataValue::F16(!a),
850 DataValue::F32(a) => DataValue::F32(!a),
851 DataValue::F64(a) => DataValue::F64(!a),
852 DataValue::F128(a) => DataValue::F128(!a),
853 DataValue::V64(mut a) => {
854 for byte in a.iter_mut() {
855 *byte = !*byte;
856 }
857 DataValue::V64(a)
858 }
859 DataValue::V128(mut a) => {
860 for byte in a.iter_mut() {
861 *byte = !*byte;
862 }
863 DataValue::V128(a)
864 }
865 _ => unimplemented!(),
866 })
867 }
868
869 fn count_ones(self) -> ValueResult<Self> {
870 unary_match!(count_ones(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
871 }
872
873 fn leading_ones(self) -> ValueResult<Self> {
874 unary_match!(leading_ones(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
875 }
876
877 fn leading_zeros(self) -> ValueResult<Self> {
878 unary_match!(leading_zeros(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
879 }
880
881 fn trailing_zeros(self) -> ValueResult<Self> {
882 unary_match!(trailing_zeros(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
883 }
884
885 fn reverse_bits(self) -> ValueResult<Self> {
886 unary_match!(reverse_bits(&self); [I8, I16, I32, I64, I128])
887 }
888
889 fn swap_bytes(self) -> ValueResult<Self> {
890 unary_match!(swap_bytes(&self); [I16, I32, I64, I128])
891 }
892
893 fn iter_lanes(&self, ty: Type) -> ValueResult<DataValueIterator> {
894 DataValueIterator::new(self, ty)
895 }
896}
897
898pub struct DataValueIterator {
900 ty: Type,
901 v: SimdVec<DataValue>,
902 idx: usize,
903}
904
905impl DataValueIterator {
906 fn new(dv: &DataValue, ty: Type) -> Result<Self, ValueError> {
907 match extractlanes(dv, ty) {
908 Ok(v) => return Ok(Self { ty, v, idx: 0 }),
909 Err(err) => return Err(err),
910 }
911 }
912}
913
914impl Iterator for DataValueIterator {
915 type Item = DataValue;
916
917 fn next(&mut self) -> Option<Self::Item> {
918 if self.idx >= self.ty.lane_count() as usize {
919 return None;
920 }
921
922 let dv = self.v[self.idx].clone();
923 self.idx += 1;
924 Some(dv)
925 }
926}
927
928#[cfg(test)]
929mod test {
930 use super::*;
931
932 #[test]
933 fn test_iterator_v128() {
934 let dv = DataValue::V128([99, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]);
935 assert_eq!(simd_sum(dv, types::I8X16), 219);
936 }
937
938 #[test]
939 fn test_iterator_v128_empty() {
940 let dv = DataValue::V128([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]);
941 assert_eq!(simd_sum(dv, types::I8X16), 0);
942 }
943
944 #[test]
945 fn test_iterator_v128_ones() {
946 let dv = DataValue::V128([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]);
947 assert_eq!(simd_sum(dv, types::I8X16), 16);
948 }
949
950 #[test]
951 fn test_iterator_v64_empty() {
952 let dv = DataValue::V64([0, 0, 0, 0, 0, 0, 0, 0]);
953 assert_eq!(simd_sum(dv, types::I8X8), 0);
954 }
955 #[test]
956 fn test_iterator_v64_ones() {
957 let dv = DataValue::V64([1, 1, 1, 1, 1, 1, 1, 1]);
958 assert_eq!(simd_sum(dv, types::I8X8), 8);
959 }
960 #[test]
961 fn test_iterator_v64() {
962 let dv = DataValue::V64([10, 20, 30, 40, 50, 60, 70, 80]);
963 assert_eq!(simd_sum(dv, types::I8X8), 360);
964 }
965
966 fn simd_sum(dv: DataValue, ty: types::Type) -> i128 {
967 let itr = dv.iter_lanes(ty).unwrap();
968
969 itr.map(|e| {
970 if let Some(v) = e.into_int_signed().ok() {
971 v
972 } else {
973 0
974 }
975 })
976 .sum()
977 }
978}