Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/interpreter/src/value.rs
3068 views
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.
19
fn int(n: i128, ty: Type) -> ValueResult<Self>;
20
fn into_int_signed(self) -> ValueResult<i128>;
21
fn into_int_unsigned(self) -> ValueResult<u128>;
22
fn float(n: u64, ty: Type) -> ValueResult<Self>;
23
fn into_float(self) -> ValueResult<f64>;
24
fn is_float(&self) -> bool;
25
fn is_nan(&self) -> ValueResult<bool>;
26
fn bool(b: bool, vec_elem: bool, ty: Type) -> ValueResult<Self>;
27
fn into_bool(self) -> ValueResult<bool>;
28
fn vector(v: [u8; 16], ty: Type) -> ValueResult<Self>;
29
fn into_array(&self) -> ValueResult<[u8; 16]>;
30
fn convert(self, kind: ValueConversionKind) -> ValueResult<Self>;
31
fn concat(self, other: Self) -> ValueResult<Self>;
32
33
fn is_negative(&self) -> ValueResult<bool>;
34
fn is_zero(&self) -> ValueResult<bool>;
35
36
fn umax(self, other: Self) -> ValueResult<Self>;
37
fn smax(self, other: Self) -> ValueResult<Self>;
38
fn umin(self, other: Self) -> ValueResult<Self>;
39
fn smin(self, other: Self) -> ValueResult<Self>;
40
41
// Comparison.
42
fn uno(&self, other: &Self) -> ValueResult<bool>;
43
44
// Arithmetic.
45
fn add(self, other: Self) -> ValueResult<Self>;
46
fn sub(self, other: Self) -> ValueResult<Self>;
47
fn mul(self, other: Self) -> ValueResult<Self>;
48
fn udiv(self, other: Self) -> ValueResult<Self>;
49
fn sdiv(self, other: Self) -> ValueResult<Self>;
50
fn urem(self, other: Self) -> ValueResult<Self>;
51
fn srem(self, other: Self) -> ValueResult<Self>;
52
fn sqrt(self) -> ValueResult<Self>;
53
fn fma(self, a: Self, b: Self) -> ValueResult<Self>;
54
fn abs(self) -> ValueResult<Self>;
55
fn uadd_checked(self, other: Self) -> ValueResult<Option<Self>>;
56
fn sadd_checked(self, other: Self) -> ValueResult<Option<Self>>;
57
fn uadd_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
58
fn sadd_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
59
fn usub_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
60
fn ssub_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
61
fn umul_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
62
fn smul_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
63
64
// Float operations
65
fn neg(self) -> ValueResult<Self>;
66
fn copysign(self, sign: Self) -> ValueResult<Self>;
67
fn ceil(self) -> ValueResult<Self>;
68
fn floor(self) -> ValueResult<Self>;
69
fn trunc(self) -> ValueResult<Self>;
70
fn nearest(self) -> ValueResult<Self>;
71
72
// Saturating arithmetic.
73
fn uadd_sat(self, other: Self) -> ValueResult<Self>;
74
fn sadd_sat(self, other: Self) -> ValueResult<Self>;
75
fn usub_sat(self, other: Self) -> ValueResult<Self>;
76
fn ssub_sat(self, other: Self) -> ValueResult<Self>;
77
78
// Bitwise.
79
fn shl(self, other: Self) -> ValueResult<Self>;
80
fn ushr(self, other: Self) -> ValueResult<Self>;
81
fn sshr(self, other: Self) -> ValueResult<Self>;
82
fn rotl(self, other: Self) -> ValueResult<Self>;
83
fn rotr(self, other: Self) -> ValueResult<Self>;
84
fn and(self, other: Self) -> ValueResult<Self>;
85
fn or(self, other: Self) -> ValueResult<Self>;
86
fn xor(self, other: Self) -> ValueResult<Self>;
87
fn not(self) -> ValueResult<Self>;
88
89
// Bit counting.
90
fn count_ones(self) -> ValueResult<Self>;
91
fn leading_ones(self) -> ValueResult<Self>;
92
fn leading_zeros(self) -> ValueResult<Self>;
93
fn trailing_zeros(self) -> ValueResult<Self>;
94
fn reverse_bits(self) -> ValueResult<Self>;
95
fn swap_bytes(self) -> ValueResult<Self>;
96
97
// An iterator over the lanes of a SIMD type
98
fn iter_lanes(&self, ty: Type) -> ValueResult<DataValueIterator>;
99
}
100
101
#[derive(Error, Debug, PartialEq)]
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 {
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)]
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 {
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
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
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
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
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
311
fn is_float(&self) -> bool {
312
match self {
313
DataValue::F16(_) | DataValue::F32(_) | DataValue::F64(_) | DataValue::F128(_) => true,
314
_ => false,
315
}
316
}
317
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
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
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
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
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
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
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
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
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
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
522
fn smax(self, other: Self) -> ValueResult<Self> {
523
if self > other { Ok(self) } else { Ok(other) }
524
}
525
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
532
fn smin(self, other: Self) -> ValueResult<Self> {
533
if self < other { Ok(self) } else { Ok(other) }
534
}
535
536
fn uno(&self, other: &Self) -> ValueResult<bool> {
537
Ok(self.is_nan()? || other.is_nan()?)
538
}
539
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
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
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
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
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
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
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
624
fn sqrt(self) -> ValueResult<Self> {
625
unary_match!(sqrt(&self); [F32, F64]; [Ieee32, Ieee64])
626
}
627
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
662
fn abs(self) -> ValueResult<Self> {
663
unary_match!(abs(&self); [F32, F64])
664
}
665
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
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
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
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
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
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
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
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
698
fn neg(self) -> ValueResult<Self> {
699
unary_match!(neg(&self); [F32, F64])
700
}
701
702
fn copysign(self, sign: Self) -> ValueResult<Self> {
703
binary_match!(copysign(&self, &sign); [F32, F64])
704
}
705
706
fn ceil(self) -> ValueResult<Self> {
707
unary_match!(ceil(&self); [F32, F64])
708
}
709
710
fn floor(self) -> ValueResult<Self> {
711
unary_match!(floor(&self); [F32, F64])
712
}
713
714
fn trunc(self) -> ValueResult<Self> {
715
unary_match!(trunc(&self); [F32, F64])
716
}
717
718
fn nearest(self) -> ValueResult<Self> {
719
unary_match!(round_ties_even(&self); [F32, F64])
720
}
721
722
fn sadd_sat(self, other: Self) -> ValueResult<Self> {
723
binary_match!(saturating_add(self, &other); [I8, I16, I32, I64, I128])
724
}
725
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
730
fn ssub_sat(self, other: Self) -> ValueResult<Self> {
731
binary_match!(saturating_sub(self, &other); [I8, I16, I32, I64, I128])
732
}
733
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
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
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
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
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
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
763
fn and(self, other: Self) -> ValueResult<Self> {
764
bitop!(&(self, other))
765
}
766
767
fn or(self, other: Self) -> ValueResult<Self> {
768
bitop!(|(self, other))
769
}
770
771
fn xor(self, other: Self) -> ValueResult<Self> {
772
bitop!(^(self, other))
773
}
774
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
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
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
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
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
816
fn reverse_bits(self) -> ValueResult<Self> {
817
unary_match!(reverse_bits(&self); [I8, I16, I32, I64, I128])
818
}
819
820
fn swap_bytes(self) -> ValueResult<Self> {
821
unary_match!(swap_bytes(&self); [I16, I32, I64, I128])
822
}
823
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 {
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
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]
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]
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]
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]
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]
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]
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
897
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
911