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