Remove unsigned variants of DataValue (#6218)
* remove unsigned variants of DataValue * make value operation names more in-line with cranelift IR
This commit is contained in:
@@ -17,11 +17,6 @@ pub enum DataValue {
|
|||||||
I32(i32),
|
I32(i32),
|
||||||
I64(i64),
|
I64(i64),
|
||||||
I128(i128),
|
I128(i128),
|
||||||
U8(u8),
|
|
||||||
U16(u16),
|
|
||||||
U32(u32),
|
|
||||||
U64(u64),
|
|
||||||
U128(u128),
|
|
||||||
F32(Ieee32),
|
F32(Ieee32),
|
||||||
F64(Ieee64),
|
F64(Ieee64),
|
||||||
V128([u8; 16]),
|
V128([u8; 16]),
|
||||||
@@ -42,16 +37,6 @@ impl PartialEq for DataValue {
|
|||||||
(I64(_), _) => false,
|
(I64(_), _) => false,
|
||||||
(I128(l), I128(r)) => l == r,
|
(I128(l), I128(r)) => l == r,
|
||||||
(I128(_), _) => false,
|
(I128(_), _) => false,
|
||||||
(U8(l), U8(r)) => l == r,
|
|
||||||
(U8(_), _) => false,
|
|
||||||
(U16(l), U16(r)) => l == r,
|
|
||||||
(U16(_), _) => false,
|
|
||||||
(U32(l), U32(r)) => l == r,
|
|
||||||
(U32(_), _) => false,
|
|
||||||
(U64(l), U64(r)) => l == r,
|
|
||||||
(U64(_), _) => false,
|
|
||||||
(U128(l), U128(r)) => l == r,
|
|
||||||
(U128(_), _) => false,
|
|
||||||
(F32(l), F32(r)) => l.as_f32() == r.as_f32(),
|
(F32(l), F32(r)) => l.as_f32() == r.as_f32(),
|
||||||
(F32(_), _) => false,
|
(F32(_), _) => false,
|
||||||
(F64(l), F64(r)) => l.as_f64() == r.as_f64(),
|
(F64(l), F64(r)) => l.as_f64() == r.as_f64(),
|
||||||
@@ -81,11 +66,11 @@ impl DataValue {
|
|||||||
/// Return the Cranelift IR [Type] for this [DataValue].
|
/// Return the Cranelift IR [Type] for this [DataValue].
|
||||||
pub fn ty(&self) -> Type {
|
pub fn ty(&self) -> Type {
|
||||||
match self {
|
match self {
|
||||||
DataValue::I8(_) | DataValue::U8(_) => types::I8,
|
DataValue::I8(_) => types::I8,
|
||||||
DataValue::I16(_) | DataValue::U16(_) => types::I16,
|
DataValue::I16(_) => types::I16,
|
||||||
DataValue::I32(_) | DataValue::U32(_) => types::I32,
|
DataValue::I32(_) => types::I32,
|
||||||
DataValue::I64(_) | DataValue::U64(_) => types::I64,
|
DataValue::I64(_) => types::I64,
|
||||||
DataValue::I128(_) | DataValue::U128(_) => types::I128,
|
DataValue::I128(_) => types::I128,
|
||||||
DataValue::F32(_) => types::F32,
|
DataValue::F32(_) => types::F32,
|
||||||
DataValue::F64(_) => types::F64,
|
DataValue::F64(_) => types::F64,
|
||||||
DataValue::V128(_) => types::I8X16, // A default type.
|
DataValue::V128(_) => types::I8X16, // A default type.
|
||||||
@@ -108,11 +93,6 @@ impl DataValue {
|
|||||||
DataValue::I32(i) => DataValue::I32(i.swap_bytes()),
|
DataValue::I32(i) => DataValue::I32(i.swap_bytes()),
|
||||||
DataValue::I64(i) => DataValue::I64(i.swap_bytes()),
|
DataValue::I64(i) => DataValue::I64(i.swap_bytes()),
|
||||||
DataValue::I128(i) => DataValue::I128(i.swap_bytes()),
|
DataValue::I128(i) => DataValue::I128(i.swap_bytes()),
|
||||||
DataValue::U8(i) => DataValue::U8(i.swap_bytes()),
|
|
||||||
DataValue::U16(i) => DataValue::U16(i.swap_bytes()),
|
|
||||||
DataValue::U32(i) => DataValue::U32(i.swap_bytes()),
|
|
||||||
DataValue::U64(i) => DataValue::U64(i.swap_bytes()),
|
|
||||||
DataValue::U128(i) => DataValue::U128(i.swap_bytes()),
|
|
||||||
DataValue::F32(f) => DataValue::F32(Ieee32::with_bits(f.bits().swap_bytes())),
|
DataValue::F32(f) => DataValue::F32(Ieee32::with_bits(f.bits().swap_bytes())),
|
||||||
DataValue::F64(f) => DataValue::F64(Ieee64::with_bits(f.bits().swap_bytes())),
|
DataValue::F64(f) => DataValue::F64(Ieee64::with_bits(f.bits().swap_bytes())),
|
||||||
DataValue::V128(mut v) => {
|
DataValue::V128(mut v) => {
|
||||||
@@ -160,7 +140,6 @@ impl DataValue {
|
|||||||
DataValue::F64(f) => dst[..8].copy_from_slice(&f.bits().to_ne_bytes()[..]),
|
DataValue::F64(f) => dst[..8].copy_from_slice(&f.bits().to_ne_bytes()[..]),
|
||||||
DataValue::V128(v) => dst[..16].copy_from_slice(&v[..]),
|
DataValue::V128(v) => dst[..16].copy_from_slice(&v[..]),
|
||||||
DataValue::V64(v) => dst[..8].copy_from_slice(&v[..]),
|
DataValue::V64(v) => dst[..8].copy_from_slice(&v[..]),
|
||||||
_ => unimplemented!(),
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -258,18 +237,6 @@ impl DataValue {
|
|||||||
(DataValue::F32(a), DataValue::F32(b)) => a.bits() == b.bits(),
|
(DataValue::F32(a), DataValue::F32(b)) => a.bits() == b.bits(),
|
||||||
(DataValue::F64(a), DataValue::F64(b)) => a.bits() == b.bits(),
|
(DataValue::F64(a), DataValue::F64(b)) => a.bits() == b.bits(),
|
||||||
|
|
||||||
// when testing for bitwise equality, the sign information does not matter
|
|
||||||
(DataValue::I8(a), DataValue::U8(b)) => *a as u8 == *b,
|
|
||||||
(DataValue::U8(a), DataValue::I8(b)) => *a == *b as u8,
|
|
||||||
(DataValue::I16(a), DataValue::U16(b)) => *a as u16 == *b,
|
|
||||||
(DataValue::U16(a), DataValue::I16(b)) => *a == *b as u16,
|
|
||||||
(DataValue::I32(a), DataValue::U32(b)) => *a as u32 == *b,
|
|
||||||
(DataValue::U32(a), DataValue::I32(b)) => *a == *b as u32,
|
|
||||||
(DataValue::I64(a), DataValue::U64(b)) => *a as u64 == *b,
|
|
||||||
(DataValue::U64(a), DataValue::I64(b)) => *a == *b as u64,
|
|
||||||
(DataValue::I128(a), DataValue::U128(b)) => *a as u128 == *b,
|
|
||||||
(DataValue::U128(a), DataValue::I128(b)) => *a == *b as u128,
|
|
||||||
|
|
||||||
// We don't need to worry about F32x4 / F64x2 Since we compare V128 which is already the
|
// We don't need to worry about F32x4 / F64x2 Since we compare V128 which is already the
|
||||||
// raw bytes anyway
|
// raw bytes anyway
|
||||||
(a, b) => a == b,
|
(a, b) => a == b,
|
||||||
@@ -339,11 +306,6 @@ build_conversion_impl!(i16, I16, I16);
|
|||||||
build_conversion_impl!(i32, I32, I32);
|
build_conversion_impl!(i32, I32, I32);
|
||||||
build_conversion_impl!(i64, I64, I64);
|
build_conversion_impl!(i64, I64, I64);
|
||||||
build_conversion_impl!(i128, I128, I128);
|
build_conversion_impl!(i128, I128, I128);
|
||||||
build_conversion_impl!(u8, U8, I8);
|
|
||||||
build_conversion_impl!(u16, U16, I16);
|
|
||||||
build_conversion_impl!(u32, U32, I32);
|
|
||||||
build_conversion_impl!(u64, U64, I64);
|
|
||||||
build_conversion_impl!(u128, U128, I128);
|
|
||||||
build_conversion_impl!(Ieee32, F32, F32);
|
build_conversion_impl!(Ieee32, F32, F32);
|
||||||
build_conversion_impl!(Ieee64, F64, F64);
|
build_conversion_impl!(Ieee64, F64, F64);
|
||||||
build_conversion_impl!([u8; 16], V128, I8X16);
|
build_conversion_impl!([u8; 16], V128, I8X16);
|
||||||
@@ -362,11 +324,6 @@ impl Display for DataValue {
|
|||||||
DataValue::I32(dv) => write!(f, "{}", dv),
|
DataValue::I32(dv) => write!(f, "{}", dv),
|
||||||
DataValue::I64(dv) => write!(f, "{}", dv),
|
DataValue::I64(dv) => write!(f, "{}", dv),
|
||||||
DataValue::I128(dv) => write!(f, "{}", dv),
|
DataValue::I128(dv) => write!(f, "{}", dv),
|
||||||
DataValue::U8(dv) => write!(f, "{}", dv),
|
|
||||||
DataValue::U16(dv) => write!(f, "{}", dv),
|
|
||||||
DataValue::U32(dv) => write!(f, "{}", dv),
|
|
||||||
DataValue::U64(dv) => write!(f, "{}", dv),
|
|
||||||
DataValue::U128(dv) => write!(f, "{}", dv),
|
|
||||||
// The Ieee* wrappers here print the expected syntax.
|
// The Ieee* wrappers here print the expected syntax.
|
||||||
DataValue::F32(dv) => write!(f, "{}", dv),
|
DataValue::F32(dv) => write!(f, "{}", dv),
|
||||||
DataValue::F64(dv) => write!(f, "{}", dv),
|
DataValue::F64(dv) => write!(f, "{}", dv),
|
||||||
|
|||||||
@@ -185,9 +185,7 @@ impl TryFrom<DataValue> for Address {
|
|||||||
|
|
||||||
fn try_from(value: DataValue) -> Result<Self, Self::Error> {
|
fn try_from(value: DataValue) -> Result<Self, Self::Error> {
|
||||||
let addr = match value {
|
let addr = match value {
|
||||||
DataValue::U32(v) => v as u64,
|
|
||||||
DataValue::I32(v) => v as u32 as u64,
|
DataValue::I32(v) => v as u32 as u64,
|
||||||
DataValue::U64(v) => v,
|
|
||||||
DataValue::I64(v) => v as u64,
|
DataValue::I64(v) => v as u64,
|
||||||
_ => {
|
_ => {
|
||||||
return Err(MemoryError::InvalidAddress(value));
|
return Err(MemoryError::InvalidAddress(value));
|
||||||
@@ -195,8 +193,8 @@ impl TryFrom<DataValue> for Address {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let size = match value {
|
let size = match value {
|
||||||
DataValue::U32(_) | DataValue::I32(_) => AddressSize::_32,
|
DataValue::I32(_) => AddressSize::_32,
|
||||||
DataValue::U64(_) | DataValue::I64(_) => AddressSize::_64,
|
DataValue::I64(_) => AddressSize::_64,
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -217,9 +215,9 @@ impl TryFrom<u64> for Address {
|
|||||||
|
|
||||||
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
||||||
let dv = if value > u32::MAX as u64 {
|
let dv = if value > u32::MAX as u64 {
|
||||||
DataValue::U64(value)
|
DataValue::I64(value as i64)
|
||||||
} else {
|
} else {
|
||||||
DataValue::U32(value as u32)
|
DataValue::I32(value as i32)
|
||||||
};
|
};
|
||||||
|
|
||||||
Address::try_from(dv)
|
Address::try_from(dv)
|
||||||
|
|||||||
@@ -220,7 +220,7 @@ impl Default for InterpreterState<'_> {
|
|||||||
frame_stack: vec![],
|
frame_stack: vec![],
|
||||||
frame_offset: 0,
|
frame_offset: 0,
|
||||||
stack: Vec::with_capacity(1024),
|
stack: Vec::with_capacity(1024),
|
||||||
pinned_reg: DataValue::U64(0),
|
pinned_reg: DataValue::I64(0),
|
||||||
native_endianness,
|
native_endianness,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,12 +35,12 @@ fn validate_signature_params(sig: &[AbiParam], args: &[DataValue]) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Helper for summing a sequence of values.
|
// Helper for summing a sequence of values.
|
||||||
fn sum(head: DataValue, tail: SmallVec<[DataValue; 1]>) -> ValueResult<i128> {
|
fn sum_unsigned(head: DataValue, tail: SmallVec<[DataValue; 1]>) -> ValueResult<u128> {
|
||||||
let mut acc = head;
|
let mut acc = head;
|
||||||
for t in tail {
|
for t in tail {
|
||||||
acc = DataValueExt::add(acc, t)?;
|
acc = DataValueExt::add(acc, t)?;
|
||||||
}
|
}
|
||||||
acc.into_int()
|
acc.into_int_unsigned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interpret a single Cranelift instruction. Note that program traps and interpreter errors are
|
/// Interpret a single Cranelift instruction. Note that program traps and interpreter errors are
|
||||||
@@ -188,7 +188,7 @@ where
|
|||||||
.map(|v| v.convert(ValueConversionKind::ZeroExtend(addr_ty)))
|
.map(|v| v.convert(ValueConversionKind::ZeroExtend(addr_ty)))
|
||||||
.collect::<ValueResult<SmallVec<[DataValue; 1]>>>()?;
|
.collect::<ValueResult<SmallVec<[DataValue; 1]>>>()?;
|
||||||
|
|
||||||
Ok(sum(imm, args)? as u64)
|
Ok(sum_unsigned(imm, args)? as u64)
|
||||||
};
|
};
|
||||||
|
|
||||||
// Interpret a unary instruction with the given `op`, assigning the resulting value to the
|
// Interpret a unary instruction with the given `op`, assigning the resulting value to the
|
||||||
@@ -196,7 +196,7 @@ where
|
|||||||
let unary =
|
let unary =
|
||||||
|op: fn(DataValue) -> ValueResult<DataValue>, arg: DataValue| -> ValueResult<ControlFlow> {
|
|op: fn(DataValue) -> ValueResult<DataValue>, arg: DataValue| -> ValueResult<ControlFlow> {
|
||||||
let ctrl_ty = inst_context.controlling_type().unwrap();
|
let ctrl_ty = inst_context.controlling_type().unwrap();
|
||||||
let res = unary_arith(arg, ctrl_ty, op, false)?;
|
let res = unary_arith(arg, ctrl_ty, op)?;
|
||||||
Ok(assign(res))
|
Ok(assign(res))
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -207,20 +207,7 @@ where
|
|||||||
right: DataValue|
|
right: DataValue|
|
||||||
-> ValueResult<ControlFlow> {
|
-> ValueResult<ControlFlow> {
|
||||||
let ctrl_ty = inst_context.controlling_type().unwrap();
|
let ctrl_ty = inst_context.controlling_type().unwrap();
|
||||||
let res = binary_arith(left, right, ctrl_ty, op, false)?;
|
let res = binary_arith(left, right, ctrl_ty, op)?;
|
||||||
Ok(assign(res))
|
|
||||||
};
|
|
||||||
|
|
||||||
// Same as `binary_unsigned`, but converts the values to their unsigned form before the
|
|
||||||
// operation and back to signed form afterwards. Since Cranelift types have no notion of
|
|
||||||
// signedness, this enables operations that depend on sign.
|
|
||||||
let binary_unsigned = |op: fn(DataValue, DataValue) -> ValueResult<DataValue>,
|
|
||||||
left: DataValue,
|
|
||||||
right: DataValue|
|
|
||||||
-> ValueResult<ControlFlow> {
|
|
||||||
let ctrl_ty = inst_context.controlling_type().unwrap();
|
|
||||||
let res = binary_arith(left, right, ctrl_ty, op, true)
|
|
||||||
.and_then(|v| v.convert(ValueConversionKind::ToSigned))?;
|
|
||||||
Ok(assign(res))
|
Ok(assign(res))
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -230,20 +217,7 @@ where
|
|||||||
right: DataValue|
|
right: DataValue|
|
||||||
-> ValueResult<ControlFlow> {
|
-> ValueResult<ControlFlow> {
|
||||||
let ctrl_ty = inst_context.controlling_type().unwrap();
|
let ctrl_ty = inst_context.controlling_type().unwrap();
|
||||||
let res = binary_arith(left, right, ctrl_ty, op, false);
|
let res = binary_arith(left, right, ctrl_ty, op);
|
||||||
assign_or_trap(res)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Same as `binary_can_trap`, but converts the values to their unsigned form before the
|
|
||||||
// operation and back to signed form afterwards. Since Cranelift types have no notion of
|
|
||||||
// signedness, this enables operations that depend on sign.
|
|
||||||
let binary_unsigned_can_trap = |op: fn(DataValue, DataValue) -> ValueResult<DataValue>,
|
|
||||||
left: DataValue,
|
|
||||||
right: DataValue|
|
|
||||||
-> ValueResult<ControlFlow> {
|
|
||||||
let ctrl_ty = inst_context.controlling_type().unwrap();
|
|
||||||
let res = binary_arith(left, right, ctrl_ty, op, true)
|
|
||||||
.and_then(|v| v.convert(ValueConversionKind::ToSigned));
|
|
||||||
assign_or_trap(res)
|
assign_or_trap(res)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -364,7 +338,7 @@ where
|
|||||||
let jt_data = &state.get_current_function().stencil.dfg.jump_tables[table];
|
let jt_data = &state.get_current_function().stencil.dfg.jump_tables[table];
|
||||||
|
|
||||||
// Convert to usize to remove negative indexes from the following operations
|
// Convert to usize to remove negative indexes from the following operations
|
||||||
let jump_target = usize::try_from(arg(0).into_int()?)
|
let jump_target = usize::try_from(arg(0).into_int_unsigned()?)
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|i| jt_data.as_slice().get(i))
|
.and_then(|i| jt_data.as_slice().get(i))
|
||||||
.copied()
|
.copied()
|
||||||
@@ -419,7 +393,7 @@ where
|
|||||||
}
|
}
|
||||||
Opcode::CallIndirect | Opcode::ReturnCallIndirect => {
|
Opcode::CallIndirect | Opcode::ReturnCallIndirect => {
|
||||||
let args = args();
|
let args = args();
|
||||||
let addr_dv = DataValue::U64(arg(0).into_int()? as u64);
|
let addr_dv = DataValue::I64(arg(0).into_int_unsigned()? as i64);
|
||||||
let addr = Address::try_from(addr_dv.clone()).map_err(StepError::MemoryError)?;
|
let addr = Address::try_from(addr_dv.clone()).map_err(StepError::MemoryError)?;
|
||||||
|
|
||||||
let func = state
|
let func = state
|
||||||
@@ -530,7 +504,7 @@ where
|
|||||||
Opcode::StackLoad => {
|
Opcode::StackLoad => {
|
||||||
let load_ty = inst_context.controlling_type().unwrap();
|
let load_ty = inst_context.controlling_type().unwrap();
|
||||||
let slot = inst.stack_slot().unwrap();
|
let slot = inst.stack_slot().unwrap();
|
||||||
let offset = sum(imm(), args())? as u64;
|
let offset = sum_unsigned(imm(), args())? as u64;
|
||||||
let mem_flags = MemFlags::new();
|
let mem_flags = MemFlags::new();
|
||||||
assign_or_memtrap({
|
assign_or_memtrap({
|
||||||
state
|
state
|
||||||
@@ -541,7 +515,7 @@ where
|
|||||||
Opcode::StackStore => {
|
Opcode::StackStore => {
|
||||||
let arg = arg(0);
|
let arg = arg(0);
|
||||||
let slot = inst.stack_slot().unwrap();
|
let slot = inst.stack_slot().unwrap();
|
||||||
let offset = sum(imm(), args_range(1..)?)? as u64;
|
let offset = sum_unsigned(imm(), args_range(1..)?)? as u64;
|
||||||
let mem_flags = MemFlags::new();
|
let mem_flags = MemFlags::new();
|
||||||
continue_or_memtrap({
|
continue_or_memtrap({
|
||||||
state
|
state
|
||||||
@@ -552,7 +526,7 @@ where
|
|||||||
Opcode::StackAddr => {
|
Opcode::StackAddr => {
|
||||||
let load_ty = inst_context.controlling_type().unwrap();
|
let load_ty = inst_context.controlling_type().unwrap();
|
||||||
let slot = inst.stack_slot().unwrap();
|
let slot = inst.stack_slot().unwrap();
|
||||||
let offset = sum(imm(), args())? as u64;
|
let offset = sum_unsigned(imm(), args())? as u64;
|
||||||
assign_or_memtrap({
|
assign_or_memtrap({
|
||||||
AddressSize::try_from(load_ty).and_then(|addr_size| {
|
AddressSize::try_from(load_ty).and_then(|addr_size| {
|
||||||
let addr = state.stack_address(addr_size, slot, offset)?;
|
let addr = state.stack_address(addr_size, slot, offset)?;
|
||||||
@@ -599,7 +573,7 @@ where
|
|||||||
unreachable!()
|
unreachable!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::Iconst => assign(DataValueExt::int(imm().into_int()?, ctrl_ty)?),
|
Opcode::Iconst => assign(DataValueExt::int(imm().into_int_signed()?, ctrl_ty)?),
|
||||||
Opcode::F32const => assign(imm()),
|
Opcode::F32const => assign(imm()),
|
||||||
Opcode::F64const => assign(imm()),
|
Opcode::F64const => assign(imm()),
|
||||||
Opcode::Vconst => assign(imm()),
|
Opcode::Vconst => assign(imm()),
|
||||||
@@ -619,7 +593,7 @@ where
|
|||||||
let icmp = icmp(ctrl_ty, IntCC::SignedGreaterThan, &arg(1), &arg(0))?;
|
let icmp = icmp(ctrl_ty, IntCC::SignedGreaterThan, &arg(1), &arg(0))?;
|
||||||
assign(bitselect(icmp, arg(0), arg(1))?)
|
assign(bitselect(icmp, arg(0), arg(1))?)
|
||||||
} else {
|
} else {
|
||||||
choose(arg(1) > arg(0), arg(0), arg(1))
|
assign(arg(0).smin(arg(1))?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::Umin => {
|
Opcode::Umin => {
|
||||||
@@ -627,12 +601,7 @@ where
|
|||||||
let icmp = icmp(ctrl_ty, IntCC::UnsignedGreaterThan, &arg(1), &arg(0))?;
|
let icmp = icmp(ctrl_ty, IntCC::UnsignedGreaterThan, &arg(1), &arg(0))?;
|
||||||
assign(bitselect(icmp, arg(0), arg(1))?)
|
assign(bitselect(icmp, arg(0), arg(1))?)
|
||||||
} else {
|
} else {
|
||||||
choose(
|
assign(arg(0).umin(arg(1))?)
|
||||||
arg(1).convert(ValueConversionKind::ToUnsigned)?
|
|
||||||
> arg(0).convert(ValueConversionKind::ToUnsigned)?,
|
|
||||||
arg(0),
|
|
||||||
arg(1),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::Smax => {
|
Opcode::Smax => {
|
||||||
@@ -640,7 +609,7 @@ where
|
|||||||
let icmp = icmp(ctrl_ty, IntCC::SignedGreaterThan, &arg(0), &arg(1))?;
|
let icmp = icmp(ctrl_ty, IntCC::SignedGreaterThan, &arg(0), &arg(1))?;
|
||||||
assign(bitselect(icmp, arg(0), arg(1))?)
|
assign(bitselect(icmp, arg(0), arg(1))?)
|
||||||
} else {
|
} else {
|
||||||
choose(arg(0) > arg(1), arg(0), arg(1))
|
assign(arg(0).smax(arg(1))?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::Umax => {
|
Opcode::Umax => {
|
||||||
@@ -648,12 +617,7 @@ where
|
|||||||
let icmp = icmp(ctrl_ty, IntCC::UnsignedGreaterThan, &arg(0), &arg(1))?;
|
let icmp = icmp(ctrl_ty, IntCC::UnsignedGreaterThan, &arg(0), &arg(1))?;
|
||||||
assign(bitselect(icmp, arg(0), arg(1))?)
|
assign(bitselect(icmp, arg(0), arg(1))?)
|
||||||
} else {
|
} else {
|
||||||
choose(
|
assign(arg(0).umax(arg(1))?)
|
||||||
arg(0).convert(ValueConversionKind::ToUnsigned)?
|
|
||||||
> arg(1).convert(ValueConversionKind::ToUnsigned)?,
|
|
||||||
arg(0),
|
|
||||||
arg(1),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Opcode::AvgRound => {
|
Opcode::AvgRound => {
|
||||||
@@ -661,37 +625,33 @@ where
|
|||||||
let one = DataValueExt::int(1, arg(0).ty())?;
|
let one = DataValueExt::int(1, arg(0).ty())?;
|
||||||
let inc = DataValueExt::add(sum, one)?;
|
let inc = DataValueExt::add(sum, one)?;
|
||||||
let two = DataValueExt::int(2, arg(0).ty())?;
|
let two = DataValueExt::int(2, arg(0).ty())?;
|
||||||
binary(DataValueExt::div, inc, two)?
|
binary(DataValueExt::udiv, inc, two)?
|
||||||
}
|
}
|
||||||
Opcode::Iadd => binary(DataValueExt::add, arg(0), arg(1))?,
|
Opcode::Iadd => binary(DataValueExt::add, arg(0), arg(1))?,
|
||||||
Opcode::UaddSat => assign(binary_arith(
|
Opcode::UaddSat => assign(binary_arith(
|
||||||
arg(0),
|
arg(0),
|
||||||
arg(1),
|
arg(1),
|
||||||
ctrl_ty,
|
ctrl_ty,
|
||||||
DataValueExt::add_sat,
|
DataValueExt::uadd_sat,
|
||||||
true,
|
|
||||||
)?),
|
)?),
|
||||||
Opcode::SaddSat => assign(binary_arith(
|
Opcode::SaddSat => assign(binary_arith(
|
||||||
arg(0),
|
arg(0),
|
||||||
arg(1),
|
arg(1),
|
||||||
ctrl_ty,
|
ctrl_ty,
|
||||||
DataValueExt::add_sat,
|
DataValueExt::sadd_sat,
|
||||||
false,
|
|
||||||
)?),
|
)?),
|
||||||
Opcode::Isub => binary(DataValueExt::sub, arg(0), arg(1))?,
|
Opcode::Isub => binary(DataValueExt::sub, arg(0), arg(1))?,
|
||||||
Opcode::UsubSat => assign(binary_arith(
|
Opcode::UsubSat => assign(binary_arith(
|
||||||
arg(0),
|
arg(0),
|
||||||
arg(1),
|
arg(1),
|
||||||
ctrl_ty,
|
ctrl_ty,
|
||||||
DataValueExt::sub_sat,
|
DataValueExt::usub_sat,
|
||||||
true,
|
|
||||||
)?),
|
)?),
|
||||||
Opcode::SsubSat => assign(binary_arith(
|
Opcode::SsubSat => assign(binary_arith(
|
||||||
arg(0),
|
arg(0),
|
||||||
arg(1),
|
arg(1),
|
||||||
ctrl_ty,
|
ctrl_ty,
|
||||||
DataValueExt::sub_sat,
|
DataValueExt::ssub_sat,
|
||||||
false,
|
|
||||||
)?),
|
)?),
|
||||||
Opcode::Ineg => binary(DataValueExt::sub, DataValueExt::int(0, ctrl_ty)?, arg(0))?,
|
Opcode::Ineg => binary(DataValueExt::sub, DataValueExt::int(0, ctrl_ty)?, arg(0))?,
|
||||||
Opcode::Iabs => {
|
Opcode::Iabs => {
|
||||||
@@ -704,7 +664,7 @@ where
|
|||||||
if lane == min_val {
|
if lane == min_val {
|
||||||
Ok(min_val.clone())
|
Ok(min_val.clone())
|
||||||
} else {
|
} else {
|
||||||
DataValueExt::int(lane.into_int()?.abs(), ctrl_ty.lane_type())
|
DataValueExt::int(lane.into_int_signed()?.abs(), ctrl_ty.lane_type())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.collect::<ValueResult<SimdVec<DataValue>>>()?;
|
.collect::<ValueResult<SimdVec<DataValue>>>()?;
|
||||||
@@ -741,57 +701,39 @@ where
|
|||||||
|
|
||||||
assign(vectorizelanes(&res, ctrl_ty)?)
|
assign(vectorizelanes(&res, ctrl_ty)?)
|
||||||
}
|
}
|
||||||
Opcode::Udiv => binary_unsigned_can_trap(DataValueExt::div, arg(0), arg(1))?,
|
Opcode::Udiv => binary_can_trap(DataValueExt::udiv, arg(0), arg(1))?,
|
||||||
Opcode::Sdiv => binary_can_trap(DataValueExt::div, arg(0), arg(1))?,
|
Opcode::Sdiv => binary_can_trap(DataValueExt::sdiv, arg(0), arg(1))?,
|
||||||
Opcode::Urem => binary_unsigned_can_trap(DataValueExt::rem, arg(0), arg(1))?,
|
Opcode::Urem => binary_can_trap(DataValueExt::urem, arg(0), arg(1))?,
|
||||||
Opcode::Srem => binary_can_trap(DataValueExt::rem, arg(0), arg(1))?,
|
Opcode::Srem => binary_can_trap(DataValueExt::srem, arg(0), arg(1))?,
|
||||||
Opcode::IaddImm => binary(DataValueExt::add, arg(0), imm_as_ctrl_ty()?)?,
|
Opcode::IaddImm => binary(DataValueExt::add, arg(0), imm_as_ctrl_ty()?)?,
|
||||||
Opcode::ImulImm => binary(DataValueExt::mul, arg(0), imm_as_ctrl_ty()?)?,
|
Opcode::ImulImm => binary(DataValueExt::mul, arg(0), imm_as_ctrl_ty()?)?,
|
||||||
Opcode::UdivImm => binary_unsigned_can_trap(DataValueExt::div, arg(0), imm_as_ctrl_ty()?)?,
|
Opcode::UdivImm => binary_can_trap(DataValueExt::udiv, arg(0), imm_as_ctrl_ty()?)?,
|
||||||
Opcode::SdivImm => binary_can_trap(DataValueExt::div, arg(0), imm_as_ctrl_ty()?)?,
|
Opcode::SdivImm => binary_can_trap(DataValueExt::sdiv, arg(0), imm_as_ctrl_ty()?)?,
|
||||||
Opcode::UremImm => binary_unsigned_can_trap(DataValueExt::rem, arg(0), imm_as_ctrl_ty()?)?,
|
Opcode::UremImm => binary_can_trap(DataValueExt::urem, arg(0), imm_as_ctrl_ty()?)?,
|
||||||
Opcode::SremImm => binary_can_trap(DataValueExt::rem, arg(0), imm_as_ctrl_ty()?)?,
|
Opcode::SremImm => binary_can_trap(DataValueExt::srem, arg(0), imm_as_ctrl_ty()?)?,
|
||||||
Opcode::IrsubImm => binary(DataValueExt::sub, imm_as_ctrl_ty()?, arg(0))?,
|
Opcode::IrsubImm => binary(DataValueExt::sub, imm_as_ctrl_ty()?, arg(0))?,
|
||||||
Opcode::UaddOverflow => {
|
Opcode::UaddOverflow => {
|
||||||
let lhs = arg(0).convert(ValueConversionKind::ToUnsigned)?;
|
let (sum, carry) = arg(0).uadd_overflow(arg(1))?;
|
||||||
let rhs = arg(1).convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
let (mut sum, carry) = lhs.overflowing_add(rhs)?;
|
|
||||||
sum = sum.convert(ValueConversionKind::ToSigned)?;
|
|
||||||
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
||||||
}
|
}
|
||||||
Opcode::SaddOverflow => {
|
Opcode::SaddOverflow => {
|
||||||
let ty = arg(0).ty();
|
let (sum, carry) = arg(0).sadd_overflow(arg(1))?;
|
||||||
let lhs = arg(0).convert(ValueConversionKind::ToSigned)?;
|
|
||||||
let rhs = arg(1).convert(ValueConversionKind::ToSigned)?;
|
|
||||||
let (sum, carry) = lhs.overflowing_add(rhs)?;
|
|
||||||
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
||||||
}
|
}
|
||||||
Opcode::UsubOverflow => {
|
Opcode::UsubOverflow => {
|
||||||
let lhs = arg(0).convert(ValueConversionKind::ToUnsigned)?;
|
let (sum, carry) = arg(0).usub_overflow(arg(1))?;
|
||||||
let rhs = arg(1).convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
let (mut sum, carry) = lhs.overflowing_sub(rhs)?;
|
|
||||||
sum = sum.convert(ValueConversionKind::ToSigned)?;
|
|
||||||
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
||||||
}
|
}
|
||||||
Opcode::SsubOverflow => {
|
Opcode::SsubOverflow => {
|
||||||
let ty = arg(0).ty();
|
let (sum, carry) = arg(0).ssub_overflow(arg(1))?;
|
||||||
let lhs = arg(0).convert(ValueConversionKind::ToSigned)?;
|
|
||||||
let rhs = arg(1).convert(ValueConversionKind::ToSigned)?;
|
|
||||||
let (sum, carry) = lhs.overflowing_sub(rhs)?;
|
|
||||||
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
||||||
}
|
}
|
||||||
Opcode::UmulOverflow => {
|
Opcode::UmulOverflow => {
|
||||||
let lhs = arg(0).convert(ValueConversionKind::ToUnsigned)?;
|
let (sum, carry) = arg(0).umul_overflow(arg(1))?;
|
||||||
let rhs = arg(1).convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
let (mut sum, carry) = lhs.overflowing_mul(rhs)?;
|
|
||||||
sum = sum.convert(ValueConversionKind::ToSigned)?;
|
|
||||||
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
||||||
}
|
}
|
||||||
Opcode::SmulOverflow => {
|
Opcode::SmulOverflow => {
|
||||||
let ty = arg(0).ty();
|
let (sum, carry) = arg(0).smul_overflow(arg(1))?;
|
||||||
let lhs = arg(0).convert(ValueConversionKind::ToSigned)?;
|
|
||||||
let rhs = arg(1).convert(ValueConversionKind::ToSigned)?;
|
|
||||||
let (sum, carry) = lhs.overflowing_mul(rhs)?;
|
|
||||||
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
|
||||||
}
|
}
|
||||||
Opcode::IaddCin => choose(
|
Opcode::IaddCin => choose(
|
||||||
@@ -804,12 +746,12 @@ where
|
|||||||
),
|
),
|
||||||
Opcode::IaddCarry => {
|
Opcode::IaddCarry => {
|
||||||
let mut sum = DataValueExt::add(arg(0), arg(1))?;
|
let mut sum = DataValueExt::add(arg(0), arg(1))?;
|
||||||
let mut carry = arg(0).checked_add(arg(1))?.is_none();
|
let mut carry = arg(0).sadd_checked(arg(1))?.is_none();
|
||||||
|
|
||||||
if DataValueExt::into_bool(arg(2))? {
|
if DataValueExt::into_bool(arg(2))? {
|
||||||
carry |= sum
|
carry |= sum
|
||||||
.clone()
|
.clone()
|
||||||
.checked_add(DataValueExt::int(1, ctrl_ty)?)?
|
.sadd_checked(DataValueExt::int(1, ctrl_ty)?)?
|
||||||
.is_none();
|
.is_none();
|
||||||
sum = DataValueExt::add(sum, DataValueExt::int(1, ctrl_ty)?)?;
|
sum = DataValueExt::add(sum, DataValueExt::int(1, ctrl_ty)?)?;
|
||||||
}
|
}
|
||||||
@@ -858,11 +800,11 @@ where
|
|||||||
Opcode::RotlImm => binary(DataValueExt::rotl, arg(0), imm_as_ctrl_ty()?)?,
|
Opcode::RotlImm => binary(DataValueExt::rotl, arg(0), imm_as_ctrl_ty()?)?,
|
||||||
Opcode::RotrImm => binary(DataValueExt::rotr, arg(0), imm_as_ctrl_ty()?)?,
|
Opcode::RotrImm => binary(DataValueExt::rotr, arg(0), imm_as_ctrl_ty()?)?,
|
||||||
Opcode::Ishl => binary(DataValueExt::shl, arg(0), arg(1))?,
|
Opcode::Ishl => binary(DataValueExt::shl, arg(0), arg(1))?,
|
||||||
Opcode::Ushr => binary_unsigned(DataValueExt::ushr, arg(0), arg(1))?,
|
Opcode::Ushr => binary(DataValueExt::ushr, arg(0), arg(1))?,
|
||||||
Opcode::Sshr => binary(DataValueExt::ishr, arg(0), arg(1))?,
|
Opcode::Sshr => binary(DataValueExt::sshr, arg(0), arg(1))?,
|
||||||
Opcode::IshlImm => binary(DataValueExt::shl, arg(0), imm_as_ctrl_ty()?)?,
|
Opcode::IshlImm => binary(DataValueExt::shl, arg(0), imm_as_ctrl_ty()?)?,
|
||||||
Opcode::UshrImm => binary_unsigned(DataValueExt::ushr, arg(0), imm_as_ctrl_ty()?)?,
|
Opcode::UshrImm => binary(DataValueExt::ushr, arg(0), imm_as_ctrl_ty()?)?,
|
||||||
Opcode::SshrImm => binary(DataValueExt::ishr, arg(0), imm_as_ctrl_ty()?)?,
|
Opcode::SshrImm => binary(DataValueExt::sshr, arg(0), imm_as_ctrl_ty()?)?,
|
||||||
Opcode::Bitrev => unary(DataValueExt::reverse_bits, arg(0))?,
|
Opcode::Bitrev => unary(DataValueExt::reverse_bits, arg(0))?,
|
||||||
Opcode::Bswap => unary(DataValueExt::swap_bytes, arg(0))?,
|
Opcode::Bswap => unary(DataValueExt::swap_bytes, arg(0))?,
|
||||||
Opcode::Clz => unary(DataValueExt::leading_zeros, arg(0))?,
|
Opcode::Clz => unary(DataValueExt::leading_zeros, arg(0))?,
|
||||||
@@ -910,7 +852,7 @@ where
|
|||||||
Opcode::Fadd => binary(DataValueExt::add, arg(0), arg(1))?,
|
Opcode::Fadd => binary(DataValueExt::add, arg(0), arg(1))?,
|
||||||
Opcode::Fsub => binary(DataValueExt::sub, arg(0), arg(1))?,
|
Opcode::Fsub => binary(DataValueExt::sub, arg(0), arg(1))?,
|
||||||
Opcode::Fmul => binary(DataValueExt::mul, arg(0), arg(1))?,
|
Opcode::Fmul => binary(DataValueExt::mul, arg(0), arg(1))?,
|
||||||
Opcode::Fdiv => binary(DataValueExt::div, arg(0), arg(1))?,
|
Opcode::Fdiv => binary(DataValueExt::sdiv, arg(0), arg(1))?,
|
||||||
Opcode::Sqrt => unary(DataValueExt::sqrt, arg(0))?,
|
Opcode::Sqrt => unary(DataValueExt::sqrt, arg(0))?,
|
||||||
Opcode::Fma => {
|
Opcode::Fma => {
|
||||||
let arg0 = extractlanes(&arg(0), ctrl_ty)?;
|
let arg0 = extractlanes(&arg(0), ctrl_ty)?;
|
||||||
@@ -935,24 +877,24 @@ where
|
|||||||
(_, b) if b.is_nan()? => b,
|
(_, b) if b.is_nan()? => b,
|
||||||
(a, b) if a.is_zero()? && b.is_zero()? && a.is_negative()? => a,
|
(a, b) if a.is_zero()? && b.is_zero()? && a.is_negative()? => a,
|
||||||
(a, b) if a.is_zero()? && b.is_zero()? && b.is_negative()? => b,
|
(a, b) if a.is_zero()? && b.is_zero()? && b.is_negative()? => b,
|
||||||
(a, b) => a.min(b)?,
|
(a, b) => a.smin(b)?,
|
||||||
}),
|
}),
|
||||||
Opcode::FminPseudo => assign(match (arg(0), arg(1)) {
|
Opcode::FminPseudo => assign(match (arg(0), arg(1)) {
|
||||||
(a, b) if a.is_nan()? || b.is_nan()? => a,
|
(a, b) if a.is_nan()? || b.is_nan()? => a,
|
||||||
(a, b) if a.is_zero()? && b.is_zero()? => a,
|
(a, b) if a.is_zero()? && b.is_zero()? => a,
|
||||||
(a, b) => a.min(b)?,
|
(a, b) => a.smin(b)?,
|
||||||
}),
|
}),
|
||||||
Opcode::Fmax => assign(match (arg(0), arg(1)) {
|
Opcode::Fmax => assign(match (arg(0), arg(1)) {
|
||||||
(a, _) if a.is_nan()? => a,
|
(a, _) if a.is_nan()? => a,
|
||||||
(_, b) if b.is_nan()? => b,
|
(_, b) if b.is_nan()? => b,
|
||||||
(a, b) if a.is_zero()? && b.is_zero()? && a.is_negative()? => b,
|
(a, b) if a.is_zero()? && b.is_zero()? && a.is_negative()? => b,
|
||||||
(a, b) if a.is_zero()? && b.is_zero()? && b.is_negative()? => a,
|
(a, b) if a.is_zero()? && b.is_zero()? && b.is_negative()? => a,
|
||||||
(a, b) => a.max(b)?,
|
(a, b) => a.smax(b)?,
|
||||||
}),
|
}),
|
||||||
Opcode::FmaxPseudo => assign(match (arg(0), arg(1)) {
|
Opcode::FmaxPseudo => assign(match (arg(0), arg(1)) {
|
||||||
(a, b) if a.is_nan()? || b.is_nan()? => a,
|
(a, b) if a.is_nan()? || b.is_nan()? => a,
|
||||||
(a, b) if a.is_zero()? && b.is_zero()? => a,
|
(a, b) if a.is_zero()? && b.is_zero()? => a,
|
||||||
(a, b) => a.max(b)?,
|
(a, b) => a.smax(b)?,
|
||||||
}),
|
}),
|
||||||
Opcode::Ceil => unary(DataValueExt::ceil, arg(0))?,
|
Opcode::Ceil => unary(DataValueExt::ceil, arg(0))?,
|
||||||
Opcode::Floor => unary(DataValueExt::floor, arg(0))?,
|
Opcode::Floor => unary(DataValueExt::floor, arg(0))?,
|
||||||
@@ -982,22 +924,17 @@ where
|
|||||||
let arg1 = extractlanes(&arg(1), ctrl_ty)?;
|
let arg1 = extractlanes(&arg(1), ctrl_ty)?;
|
||||||
let new_type = ctrl_ty.split_lanes().unwrap();
|
let new_type = ctrl_ty.split_lanes().unwrap();
|
||||||
let (min, max) = new_type.bounds(inst.opcode() == Opcode::Snarrow);
|
let (min, max) = new_type.bounds(inst.opcode() == Opcode::Snarrow);
|
||||||
let mut min: DataValue = DataValueExt::int(min as i128, ctrl_ty.lane_type())?;
|
let min: DataValue = DataValueExt::int(min as i128, ctrl_ty.lane_type())?;
|
||||||
let mut max: DataValue = DataValueExt::int(max as i128, ctrl_ty.lane_type())?;
|
let max: DataValue = DataValueExt::int(max as i128, ctrl_ty.lane_type())?;
|
||||||
if inst.opcode() == Opcode::Uunarrow {
|
|
||||||
min = min.convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
max = max.convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
}
|
|
||||||
let narrow = |mut lane: DataValue| -> ValueResult<DataValue> {
|
let narrow = |mut lane: DataValue| -> ValueResult<DataValue> {
|
||||||
if inst.opcode() == Opcode::Uunarrow {
|
if inst.opcode() == Opcode::Uunarrow {
|
||||||
lane = lane.convert(ValueConversionKind::ToUnsigned)?;
|
lane = DataValueExt::umax(lane, min.clone())?;
|
||||||
|
lane = DataValueExt::umin(lane, max.clone())?;
|
||||||
|
} else {
|
||||||
|
lane = DataValueExt::smax(lane, min.clone())?;
|
||||||
|
lane = DataValueExt::smin(lane, max.clone())?;
|
||||||
}
|
}
|
||||||
lane = DataValueExt::max(lane, min.clone())?;
|
|
||||||
lane = DataValueExt::min(lane, max.clone())?;
|
|
||||||
lane = lane.convert(ValueConversionKind::Truncate(new_type.lane_type()))?;
|
lane = lane.convert(ValueConversionKind::Truncate(new_type.lane_type()))?;
|
||||||
if inst.opcode() == Opcode::Unarrow || inst.opcode() == Opcode::Uunarrow {
|
|
||||||
lane = lane.convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
}
|
|
||||||
Ok(lane)
|
Ok(lane)
|
||||||
};
|
};
|
||||||
let new_vec = arg0
|
let new_vec = arg0
|
||||||
@@ -1065,13 +1002,13 @@ where
|
|||||||
assign(vectorizelanes(&new_vector, ctrl_ty)?)
|
assign(vectorizelanes(&new_vector, ctrl_ty)?)
|
||||||
}
|
}
|
||||||
Opcode::Insertlane => {
|
Opcode::Insertlane => {
|
||||||
let idx = imm().into_int()? as usize;
|
let idx = imm().into_int_unsigned()? as usize;
|
||||||
let mut vector = extractlanes(&arg(0), ctrl_ty)?;
|
let mut vector = extractlanes(&arg(0), ctrl_ty)?;
|
||||||
vector[idx] = arg(1);
|
vector[idx] = arg(1);
|
||||||
assign(vectorizelanes(&vector, ctrl_ty)?)
|
assign(vectorizelanes(&vector, ctrl_ty)?)
|
||||||
}
|
}
|
||||||
Opcode::Extractlane => {
|
Opcode::Extractlane => {
|
||||||
let idx = imm().into_int()? as usize;
|
let idx = imm().into_int_unsigned()? as usize;
|
||||||
let lanes = extractlanes(&arg(0), ctrl_ty)?;
|
let lanes = extractlanes(&arg(0), ctrl_ty)?;
|
||||||
assign(lanes[idx].clone())
|
assign(lanes[idx].clone())
|
||||||
}
|
}
|
||||||
@@ -1080,12 +1017,12 @@ where
|
|||||||
// must be retrieved via `inst_context`.
|
// must be retrieved via `inst_context`.
|
||||||
let vector_type = inst_context.type_of(inst_context.args()[0]).unwrap();
|
let vector_type = inst_context.type_of(inst_context.args()[0]).unwrap();
|
||||||
let a = extractlanes(&arg(0), vector_type)?;
|
let a = extractlanes(&arg(0), vector_type)?;
|
||||||
let mut result: i128 = 0;
|
let mut result: u128 = 0;
|
||||||
for (i, val) in a.into_iter().enumerate() {
|
for (i, val) in a.into_iter().enumerate() {
|
||||||
let val = val.reverse_bits()?.into_int()?; // MSB -> LSB
|
let val = val.reverse_bits()?.into_int_unsigned()?; // MSB -> LSB
|
||||||
result |= (val & 1) << i;
|
result |= (val & 1) << i;
|
||||||
}
|
}
|
||||||
assign(DataValueExt::int(result, ctrl_ty)?)
|
assign(DataValueExt::int(result as i128, ctrl_ty)?)
|
||||||
}
|
}
|
||||||
Opcode::VanyTrue => {
|
Opcode::VanyTrue => {
|
||||||
let lane_ty = ctrl_ty.lane_type();
|
let lane_ty = ctrl_ty.lane_type();
|
||||||
@@ -1187,14 +1124,19 @@ where
|
|||||||
inst_context.type_of(inst_context.args()[0]).unwrap(),
|
inst_context.type_of(inst_context.args()[0]).unwrap(),
|
||||||
)?;
|
)?;
|
||||||
let bits = |x: DataValue| -> ValueResult<u64> {
|
let bits = |x: DataValue| -> ValueResult<u64> {
|
||||||
let x = if inst.opcode() == Opcode::FcvtFromUint {
|
|
||||||
x.convert(ValueConversionKind::ToUnsigned)?
|
|
||||||
} else {
|
|
||||||
x
|
|
||||||
};
|
|
||||||
Ok(match ctrl_ty.lane_type() {
|
Ok(match ctrl_ty.lane_type() {
|
||||||
types::F32 => (x.into_int()? as f32).to_bits() as u64,
|
types::F32 => (if inst.opcode() == Opcode::FcvtFromUint {
|
||||||
types::F64 => (x.into_int()? as f64).to_bits(),
|
x.into_int_unsigned()? as f32
|
||||||
|
} else {
|
||||||
|
x.into_int_signed()? as f32
|
||||||
|
})
|
||||||
|
.to_bits() as u64,
|
||||||
|
types::F64 => (if inst.opcode() == Opcode::FcvtFromUint {
|
||||||
|
x.into_int_unsigned()? as f64
|
||||||
|
} else {
|
||||||
|
x.into_int_signed()? as f64
|
||||||
|
})
|
||||||
|
.to_bits(),
|
||||||
_ => unimplemented!("unexpected conversion to {:?}", ctrl_ty.lane_type()),
|
_ => unimplemented!("unexpected conversion to {:?}", ctrl_ty.lane_type()),
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
@@ -1215,8 +1157,10 @@ where
|
|||||||
.map(|x| {
|
.map(|x| {
|
||||||
DataValue::float(
|
DataValue::float(
|
||||||
match ctrl_ty.lane_type() {
|
match ctrl_ty.lane_type() {
|
||||||
types::F32 => (x.to_owned().into_int()? as f32).to_bits() as u64,
|
types::F32 => {
|
||||||
types::F64 => (x.to_owned().into_int()? as f64).to_bits(),
|
(x.to_owned().into_int_signed()? as f32).to_bits() as u64
|
||||||
|
}
|
||||||
|
types::F64 => (x.to_owned().into_int_signed()? as f64).to_bits(),
|
||||||
_ => unimplemented!("unexpected promotion to {:?}", ctrl_ty),
|
_ => unimplemented!("unexpected promotion to {:?}", ctrl_ty),
|
||||||
},
|
},
|
||||||
ctrl_ty.lane_type(),
|
ctrl_ty.lane_type(),
|
||||||
@@ -1269,7 +1213,7 @@ where
|
|||||||
Opcode::AtomicRmw => {
|
Opcode::AtomicRmw => {
|
||||||
let op = inst.atomic_rmw_op().unwrap();
|
let op = inst.atomic_rmw_op().unwrap();
|
||||||
let val = arg(1);
|
let val = arg(1);
|
||||||
let addr = arg(0).into_int()? as u64;
|
let addr = arg(0).into_int_unsigned()? as u64;
|
||||||
let mem_flags = inst.memflags().expect("instruction to have memory flags");
|
let mem_flags = inst.memflags().expect("instruction to have memory flags");
|
||||||
let loaded = Address::try_from(addr)
|
let loaded = Address::try_from(addr)
|
||||||
.and_then(|addr| state.checked_load(addr, ctrl_ty, mem_flags));
|
.and_then(|addr| state.checked_load(addr, ctrl_ty, mem_flags));
|
||||||
@@ -1286,25 +1230,17 @@ where
|
|||||||
AtomicRmwOp::Or => DataValueExt::or(prev_val, val),
|
AtomicRmwOp::Or => DataValueExt::or(prev_val, val),
|
||||||
AtomicRmwOp::Xor => DataValueExt::xor(prev_val, val),
|
AtomicRmwOp::Xor => DataValueExt::xor(prev_val, val),
|
||||||
AtomicRmwOp::Nand => DataValueExt::and(prev_val, val).and_then(DataValue::not),
|
AtomicRmwOp::Nand => DataValueExt::and(prev_val, val).and_then(DataValue::not),
|
||||||
AtomicRmwOp::Smax => DataValueExt::max(prev_val, val),
|
AtomicRmwOp::Smax => DataValueExt::smax(prev_val, val),
|
||||||
AtomicRmwOp::Smin => DataValueExt::min(prev_val, val),
|
AtomicRmwOp::Smin => DataValueExt::smin(prev_val, val),
|
||||||
AtomicRmwOp::Umax => DataValueExt::max(
|
AtomicRmwOp::Umax => DataValueExt::umax(val, prev_val),
|
||||||
DataValueExt::convert(val, ValueConversionKind::ToUnsigned)?,
|
AtomicRmwOp::Umin => DataValueExt::umin(val, prev_val),
|
||||||
DataValueExt::convert(prev_val, ValueConversionKind::ToUnsigned)?,
|
|
||||||
)
|
|
||||||
.and_then(|v| DataValueExt::convert(v, ValueConversionKind::ToSigned)),
|
|
||||||
AtomicRmwOp::Umin => DataValueExt::min(
|
|
||||||
DataValueExt::convert(val, ValueConversionKind::ToUnsigned)?,
|
|
||||||
DataValueExt::convert(prev_val, ValueConversionKind::ToUnsigned)?,
|
|
||||||
)
|
|
||||||
.and_then(|v| DataValueExt::convert(v, ValueConversionKind::ToSigned)),
|
|
||||||
}?;
|
}?;
|
||||||
let stored = Address::try_from(addr)
|
let stored = Address::try_from(addr)
|
||||||
.and_then(|addr| state.checked_store(addr, replace, mem_flags));
|
.and_then(|addr| state.checked_store(addr, replace, mem_flags));
|
||||||
assign_or_memtrap(stored.map(|_| prev_val_to_assign))
|
assign_or_memtrap(stored.map(|_| prev_val_to_assign))
|
||||||
}
|
}
|
||||||
Opcode::AtomicCas => {
|
Opcode::AtomicCas => {
|
||||||
let addr = arg(0).into_int()? as u64;
|
let addr = arg(0).into_int_unsigned()? as u64;
|
||||||
let mem_flags = inst.memflags().expect("instruction to have memory flags");
|
let mem_flags = inst.memflags().expect("instruction to have memory flags");
|
||||||
let loaded = Address::try_from(addr)
|
let loaded = Address::try_from(addr)
|
||||||
.and_then(|addr| state.checked_load(addr, ctrl_ty, mem_flags));
|
.and_then(|addr| state.checked_load(addr, ctrl_ty, mem_flags));
|
||||||
@@ -1325,7 +1261,7 @@ where
|
|||||||
}
|
}
|
||||||
Opcode::AtomicLoad => {
|
Opcode::AtomicLoad => {
|
||||||
let load_ty = inst_context.controlling_type().unwrap();
|
let load_ty = inst_context.controlling_type().unwrap();
|
||||||
let addr = arg(0).into_int()? as u64;
|
let addr = arg(0).into_int_unsigned()? as u64;
|
||||||
let mem_flags = inst.memflags().expect("instruction to have memory flags");
|
let mem_flags = inst.memflags().expect("instruction to have memory flags");
|
||||||
// We are doing a regular load here, this isn't actually thread safe.
|
// We are doing a regular load here, this isn't actually thread safe.
|
||||||
assign_or_memtrap(
|
assign_or_memtrap(
|
||||||
@@ -1335,7 +1271,7 @@ where
|
|||||||
}
|
}
|
||||||
Opcode::AtomicStore => {
|
Opcode::AtomicStore => {
|
||||||
let val = arg(0);
|
let val = arg(0);
|
||||||
let addr = arg(1).into_int()? as u64;
|
let addr = arg(1).into_int_unsigned()? as u64;
|
||||||
let mem_flags = inst.memflags().expect("instruction to have memory flags");
|
let mem_flags = inst.memflags().expect("instruction to have memory flags");
|
||||||
// We are doing a regular store here, this isn't actually thread safe.
|
// We are doing a regular store here, this isn't actually thread safe.
|
||||||
continue_or_memtrap(
|
continue_or_memtrap(
|
||||||
@@ -1359,16 +1295,16 @@ where
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(arg1.into_iter())
|
.zip(arg1.into_iter())
|
||||||
.map(|(x, y)| {
|
.map(|(x, y)| {
|
||||||
let x = x.into_int()?;
|
let x = x.into_int_signed()?;
|
||||||
let y = y.into_int()?;
|
let y = y.into_int_signed()?;
|
||||||
// temporarily double width of the value to avoid overflow.
|
// temporarily double width of the value to avoid overflow.
|
||||||
let z: DataValue = DataValueExt::int(
|
let z: DataValue = DataValueExt::int(
|
||||||
(x * y + (1 << (lane_type.bits() - 2))) >> (lane_type.bits() - 1),
|
(x * y + (1 << (lane_type.bits() - 2))) >> (lane_type.bits() - 1),
|
||||||
double_width,
|
double_width,
|
||||||
)?;
|
)?;
|
||||||
// check bounds, saturate, and truncate to correct width.
|
// check bounds, saturate, and truncate to correct width.
|
||||||
let z = DataValueExt::min(z, max.clone())?;
|
let z = DataValueExt::smin(z, max.clone())?;
|
||||||
let z = DataValueExt::max(z, min.clone())?;
|
let z = DataValueExt::smax(z, min.clone())?;
|
||||||
let z = z.convert(ValueConversionKind::Truncate(lane_type))?;
|
let z = z.convert(ValueConversionKind::Truncate(lane_type))?;
|
||||||
Ok(z)
|
Ok(z)
|
||||||
})
|
})
|
||||||
@@ -1461,20 +1397,16 @@ fn icmp(
|
|||||||
IntCC::SignedLessThan => left < right,
|
IntCC::SignedLessThan => left < right,
|
||||||
IntCC::SignedLessThanOrEqual => left <= right,
|
IntCC::SignedLessThanOrEqual => left <= right,
|
||||||
IntCC::UnsignedGreaterThan => {
|
IntCC::UnsignedGreaterThan => {
|
||||||
left.clone().convert(ValueConversionKind::ToUnsigned)?
|
left.clone().into_int_unsigned()? > right.clone().into_int_unsigned()?
|
||||||
> right.clone().convert(ValueConversionKind::ToUnsigned)?
|
|
||||||
}
|
}
|
||||||
IntCC::UnsignedGreaterThanOrEqual => {
|
IntCC::UnsignedGreaterThanOrEqual => {
|
||||||
left.clone().convert(ValueConversionKind::ToUnsigned)?
|
left.clone().into_int_unsigned()? >= right.clone().into_int_unsigned()?
|
||||||
>= right.clone().convert(ValueConversionKind::ToUnsigned)?
|
|
||||||
}
|
}
|
||||||
IntCC::UnsignedLessThan => {
|
IntCC::UnsignedLessThan => {
|
||||||
left.clone().convert(ValueConversionKind::ToUnsigned)?
|
left.clone().into_int_unsigned()? < right.clone().into_int_unsigned()?
|
||||||
< right.clone().convert(ValueConversionKind::ToUnsigned)?
|
|
||||||
}
|
}
|
||||||
IntCC::UnsignedLessThanOrEqual => {
|
IntCC::UnsignedLessThanOrEqual => {
|
||||||
left.clone().convert(ValueConversionKind::ToUnsigned)?
|
left.clone().into_int_unsigned()? <= right.clone().into_int_unsigned()?
|
||||||
<= right.clone().convert(ValueConversionKind::ToUnsigned)?
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
ctrl_ty.is_vector(),
|
ctrl_ty.is_vector(),
|
||||||
@@ -1579,7 +1511,7 @@ fn vectorizelanes_all(x: &[DataValue], vector_type: types::Type) -> ValueResult<
|
|||||||
let lane_val: i128 = val
|
let lane_val: i128 = val
|
||||||
.clone()
|
.clone()
|
||||||
.convert(ValueConversionKind::Exact(lane_type.as_int()))?
|
.convert(ValueConversionKind::Exact(lane_type.as_int()))?
|
||||||
.into_int()?;
|
.into_int_unsigned()? as i128;
|
||||||
|
|
||||||
for j in 0..iterations {
|
for j in 0..iterations {
|
||||||
result[(i * iterations) + j] = (lane_val >> (8 * j)) as u8;
|
result[(i * iterations) + j] = (lane_val >> (8 * j)) as u8;
|
||||||
@@ -1597,12 +1529,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Performs the supplied unary arithmetic `op` on a Value, either Vector or Scalar.
|
/// Performs the supplied unary arithmetic `op` on a Value, either Vector or Scalar.
|
||||||
fn unary_arith<F>(
|
fn unary_arith<F>(x: DataValue, vector_type: types::Type, op: F) -> ValueResult<DataValue>
|
||||||
x: DataValue,
|
|
||||||
vector_type: types::Type,
|
|
||||||
op: F,
|
|
||||||
unsigned: bool,
|
|
||||||
) -> ValueResult<DataValue>
|
|
||||||
where
|
where
|
||||||
F: Fn(DataValue) -> ValueResult<DataValue>,
|
F: Fn(DataValue) -> ValueResult<DataValue>,
|
||||||
{
|
{
|
||||||
@@ -1610,12 +1537,7 @@ where
|
|||||||
|
|
||||||
let result = arg
|
let result = arg
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|mut arg| {
|
.map(|arg| Ok(op(arg)?))
|
||||||
if unsigned {
|
|
||||||
arg = arg.convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
}
|
|
||||||
Ok(op(arg)?)
|
|
||||||
})
|
|
||||||
.collect::<ValueResult<SimdVec<DataValue>>>()?;
|
.collect::<ValueResult<SimdVec<DataValue>>>()?;
|
||||||
|
|
||||||
vectorizelanes(&result, vector_type)
|
vectorizelanes(&result, vector_type)
|
||||||
@@ -1627,7 +1549,6 @@ fn binary_arith<F>(
|
|||||||
y: DataValue,
|
y: DataValue,
|
||||||
vector_type: types::Type,
|
vector_type: types::Type,
|
||||||
op: F,
|
op: F,
|
||||||
unsigned: bool,
|
|
||||||
) -> ValueResult<DataValue>
|
) -> ValueResult<DataValue>
|
||||||
where
|
where
|
||||||
F: Fn(DataValue, DataValue) -> ValueResult<DataValue>,
|
F: Fn(DataValue, DataValue) -> ValueResult<DataValue>,
|
||||||
@@ -1638,13 +1559,7 @@ where
|
|||||||
let result = arg0
|
let result = arg0
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.zip(arg1)
|
.zip(arg1)
|
||||||
.map(|(mut lhs, mut rhs)| {
|
.map(|(lhs, rhs)| Ok(op(lhs, rhs)?))
|
||||||
if unsigned {
|
|
||||||
lhs = lhs.convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
rhs = rhs.convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
}
|
|
||||||
Ok(op(lhs, rhs)?)
|
|
||||||
})
|
|
||||||
.collect::<ValueResult<SimdVec<DataValue>>>()?;
|
.collect::<ValueResult<SimdVec<DataValue>>>()?;
|
||||||
|
|
||||||
vectorizelanes(&result, vector_type)
|
vectorizelanes(&result, vector_type)
|
||||||
|
|||||||
@@ -13,7 +13,8 @@ pub type ValueResult<T> = Result<T, ValueError>;
|
|||||||
pub trait DataValueExt: Sized {
|
pub trait DataValueExt: Sized {
|
||||||
// Identity.
|
// Identity.
|
||||||
fn int(n: i128, ty: Type) -> ValueResult<Self>;
|
fn int(n: i128, ty: Type) -> ValueResult<Self>;
|
||||||
fn into_int(self) -> ValueResult<i128>;
|
fn into_int_signed(self) -> ValueResult<i128>;
|
||||||
|
fn into_int_unsigned(self) -> ValueResult<u128>;
|
||||||
fn float(n: u64, ty: Type) -> ValueResult<Self>;
|
fn float(n: u64, ty: Type) -> ValueResult<Self>;
|
||||||
fn into_float(self) -> ValueResult<f64>;
|
fn into_float(self) -> ValueResult<f64>;
|
||||||
fn is_float(&self) -> bool;
|
fn is_float(&self) -> bool;
|
||||||
@@ -28,8 +29,10 @@ pub trait DataValueExt: Sized {
|
|||||||
fn is_negative(&self) -> ValueResult<bool>;
|
fn is_negative(&self) -> ValueResult<bool>;
|
||||||
fn is_zero(&self) -> ValueResult<bool>;
|
fn is_zero(&self) -> ValueResult<bool>;
|
||||||
|
|
||||||
fn max(self, other: Self) -> ValueResult<Self>;
|
fn umax(self, other: Self) -> ValueResult<Self>;
|
||||||
fn min(self, other: Self) -> ValueResult<Self>;
|
fn smax(self, other: Self) -> ValueResult<Self>;
|
||||||
|
fn umin(self, other: Self) -> ValueResult<Self>;
|
||||||
|
fn smin(self, other: Self) -> ValueResult<Self>;
|
||||||
|
|
||||||
// Comparison.
|
// Comparison.
|
||||||
fn uno(&self, other: &Self) -> ValueResult<bool>;
|
fn uno(&self, other: &Self) -> ValueResult<bool>;
|
||||||
@@ -38,15 +41,21 @@ pub trait DataValueExt: Sized {
|
|||||||
fn add(self, other: Self) -> ValueResult<Self>;
|
fn add(self, other: Self) -> ValueResult<Self>;
|
||||||
fn sub(self, other: Self) -> ValueResult<Self>;
|
fn sub(self, other: Self) -> ValueResult<Self>;
|
||||||
fn mul(self, other: Self) -> ValueResult<Self>;
|
fn mul(self, other: Self) -> ValueResult<Self>;
|
||||||
fn div(self, other: Self) -> ValueResult<Self>;
|
fn udiv(self, other: Self) -> ValueResult<Self>;
|
||||||
fn rem(self, other: Self) -> ValueResult<Self>;
|
fn sdiv(self, other: Self) -> ValueResult<Self>;
|
||||||
|
fn urem(self, other: Self) -> ValueResult<Self>;
|
||||||
|
fn srem(self, other: Self) -> ValueResult<Self>;
|
||||||
fn sqrt(self) -> ValueResult<Self>;
|
fn sqrt(self) -> ValueResult<Self>;
|
||||||
fn fma(self, a: Self, b: Self) -> ValueResult<Self>;
|
fn fma(self, a: Self, b: Self) -> ValueResult<Self>;
|
||||||
fn abs(self) -> ValueResult<Self>;
|
fn abs(self) -> ValueResult<Self>;
|
||||||
fn checked_add(self, other: Self) -> ValueResult<Option<Self>>;
|
fn uadd_checked(self, other: Self) -> ValueResult<Option<Self>>;
|
||||||
fn overflowing_add(self, other: Self) -> ValueResult<(Self, bool)>;
|
fn sadd_checked(self, other: Self) -> ValueResult<Option<Self>>;
|
||||||
fn overflowing_sub(self, other: Self) -> ValueResult<(Self, bool)>;
|
fn uadd_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
|
||||||
fn overflowing_mul(self, other: Self) -> ValueResult<(Self, bool)>;
|
fn sadd_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
|
||||||
|
fn usub_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
|
||||||
|
fn ssub_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
|
||||||
|
fn umul_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
|
||||||
|
fn smul_overflow(self, other: Self) -> ValueResult<(Self, bool)>;
|
||||||
|
|
||||||
// Float operations
|
// Float operations
|
||||||
fn neg(self) -> ValueResult<Self>;
|
fn neg(self) -> ValueResult<Self>;
|
||||||
@@ -57,13 +66,15 @@ pub trait DataValueExt: Sized {
|
|||||||
fn nearest(self) -> ValueResult<Self>;
|
fn nearest(self) -> ValueResult<Self>;
|
||||||
|
|
||||||
// Saturating arithmetic.
|
// Saturating arithmetic.
|
||||||
fn add_sat(self, other: Self) -> ValueResult<Self>;
|
fn uadd_sat(self, other: Self) -> ValueResult<Self>;
|
||||||
fn sub_sat(self, other: Self) -> ValueResult<Self>;
|
fn sadd_sat(self, other: Self) -> ValueResult<Self>;
|
||||||
|
fn usub_sat(self, other: Self) -> ValueResult<Self>;
|
||||||
|
fn ssub_sat(self, other: Self) -> ValueResult<Self>;
|
||||||
|
|
||||||
// Bitwise.
|
// Bitwise.
|
||||||
fn shl(self, other: Self) -> ValueResult<Self>;
|
fn shl(self, other: Self) -> ValueResult<Self>;
|
||||||
fn ushr(self, other: Self) -> ValueResult<Self>;
|
fn ushr(self, other: Self) -> ValueResult<Self>;
|
||||||
fn ishr(self, other: Self) -> ValueResult<Self>;
|
fn sshr(self, other: Self) -> ValueResult<Self>;
|
||||||
fn rotl(self, other: Self) -> ValueResult<Self>;
|
fn rotl(self, other: Self) -> ValueResult<Self>;
|
||||||
fn rotr(self, other: Self) -> ValueResult<Self>;
|
fn rotr(self, other: Self) -> ValueResult<Self>;
|
||||||
fn and(self, other: Self) -> ValueResult<Self>;
|
fn and(self, other: Self) -> ValueResult<Self>;
|
||||||
@@ -132,12 +143,6 @@ pub enum ValueConversionKind {
|
|||||||
/// Convert to a larger integer type, extending with zeroes; e.g. in `i8` to `i16`, `0xff`
|
/// Convert to a larger integer type, extending with zeroes; e.g. in `i8` to `i16`, `0xff`
|
||||||
/// becomes `0x00ff`.
|
/// becomes `0x00ff`.
|
||||||
ZeroExtend(Type),
|
ZeroExtend(Type),
|
||||||
/// Convert a signed integer to its unsigned value of the same size; e.g. in `i8` to `u8`,
|
|
||||||
/// `0xff` (`-1`) becomes `0xff` (`255`).
|
|
||||||
ToUnsigned,
|
|
||||||
/// Convert an unsigned integer to its signed value of the same size; e.g. in `u8` to `i8`,
|
|
||||||
/// `0xff` (`255`) becomes `0xff` (`-1`).
|
|
||||||
ToSigned,
|
|
||||||
/// Convert a floating point number by rounding to the nearest possible value with ties to even.
|
/// Convert a floating point number by rounding to the nearest possible value with ties to even.
|
||||||
/// See `fdemote`, e.g.
|
/// See `fdemote`, e.g.
|
||||||
RoundNearestEven(Type),
|
RoundNearestEven(Type),
|
||||||
@@ -178,17 +183,23 @@ macro_rules! binary_match {
|
|||||||
_ => unimplemented!()
|
_ => unimplemented!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
( option $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ] ) => {
|
( $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {
|
||||||
match ($arg1, $arg2) {
|
match ($arg1, $arg2) {
|
||||||
$( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => { Ok(a.$op(*b).map(DataValue::$data_value_ty)) } )*
|
$( (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 _)) } )*
|
||||||
_ => unimplemented!()
|
_ => unimplemented!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
( pair $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ] ) => {
|
( option $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {
|
||||||
|
match ($arg1, $arg2) {
|
||||||
|
$( (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 _))) } )*
|
||||||
|
_ => unimplemented!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
( pair $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {
|
||||||
match ($arg1, $arg2) {
|
match ($arg1, $arg2) {
|
||||||
$( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => {
|
$( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => {
|
||||||
let (f, s) = a.$op(*b);
|
let (f, s) = (*a as $op_type).$op(*b as $op_type);
|
||||||
Ok((DataValue::$data_value_ty(f), s))
|
Ok((DataValue::$data_value_ty(f as _), s))
|
||||||
} )*
|
} )*
|
||||||
_ => unimplemented!()
|
_ => unimplemented!()
|
||||||
}
|
}
|
||||||
@@ -199,9 +210,15 @@ macro_rules! binary_match {
|
|||||||
_ => unimplemented!()
|
_ => unimplemented!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
( $op:tt($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; rhs: $rhs:tt ) => {
|
( $op:tt($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $op_type:ty ),* ] ) => {
|
||||||
match ($arg1, $arg2) {
|
match ($arg1, $arg2) {
|
||||||
$( (DataValue::$data_value_ty(a), DataValue::$rhs(b)) => { Ok(DataValue::$data_value_ty(a.$op(*b))) } )*
|
$( (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 _)) } )*
|
||||||
|
_ => unimplemented!()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
( $op:tt($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; [ $( $a_type:ty ),* ]; rhs: $rhs:tt,$rhs_type:ty ) => {
|
||||||
|
match ($arg1, $arg2) {
|
||||||
|
$( (DataValue::$data_value_ty(a), DataValue::$rhs(b)) => { Ok(DataValue::$data_value_ty((*a as $a_type).$op(*b as $rhs_type) as _)) } )*
|
||||||
_ => unimplemented!()
|
_ => unimplemented!()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -248,18 +265,24 @@ impl DataValueExt for DataValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn into_int(self) -> ValueResult<i128> {
|
fn into_int_signed(self) -> ValueResult<i128> {
|
||||||
match self {
|
match self {
|
||||||
DataValue::I8(n) => Ok(n as i128),
|
DataValue::I8(n) => Ok(n as i128),
|
||||||
DataValue::I16(n) => Ok(n as i128),
|
DataValue::I16(n) => Ok(n as i128),
|
||||||
DataValue::I32(n) => Ok(n as i128),
|
DataValue::I32(n) => Ok(n as i128),
|
||||||
DataValue::I64(n) => Ok(n as i128),
|
DataValue::I64(n) => Ok(n as i128),
|
||||||
DataValue::I128(n) => Ok(n),
|
DataValue::I128(n) => Ok(n),
|
||||||
DataValue::U8(n) => Ok(n as i128),
|
_ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())),
|
||||||
DataValue::U16(n) => Ok(n as i128),
|
}
|
||||||
DataValue::U32(n) => Ok(n as i128),
|
}
|
||||||
DataValue::U64(n) => Ok(n as i128),
|
|
||||||
DataValue::U128(n) => Ok(n as i128),
|
fn into_int_unsigned(self) -> ValueResult<u128> {
|
||||||
|
match self {
|
||||||
|
DataValue::I8(n) => Ok(n as u8 as u128),
|
||||||
|
DataValue::I16(n) => Ok(n as u16 as u128),
|
||||||
|
DataValue::I32(n) => Ok(n as u32 as u128),
|
||||||
|
DataValue::I64(n) => Ok(n as u64 as u128),
|
||||||
|
DataValue::I128(n) => Ok(n as u128),
|
||||||
_ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())),
|
_ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,7 +384,7 @@ impl DataValueExt for DataValue {
|
|||||||
ValueConversionKind::Exact(ty) => match (self, ty) {
|
ValueConversionKind::Exact(ty) => match (self, ty) {
|
||||||
// TODO a lot to do here: from bmask to ireduce to bitcast...
|
// TODO a lot to do here: from bmask to ireduce to bitcast...
|
||||||
(val, ty) if val.ty().is_int() && ty.is_int() => {
|
(val, ty) if val.ty().is_int() && ty.is_int() => {
|
||||||
DataValue::from_integer(val.into_int()?, ty)?
|
DataValue::from_integer(val.into_int_signed()?, ty)?
|
||||||
}
|
}
|
||||||
(DataValue::I32(n), types::F32) => DataValue::F32(f32::from_bits(n as u32).into()),
|
(DataValue::I32(n), types::F32) => DataValue::F32(f32::from_bits(n as u32).into()),
|
||||||
(DataValue::I64(n), types::F64) => DataValue::F64(f64::from_bits(n as u64).into()),
|
(DataValue::I64(n), types::F64) => DataValue::F64(f64::from_bits(n as u64).into()),
|
||||||
@@ -380,7 +403,7 @@ impl DataValueExt for DataValue {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let mask = (1 << (ty.bytes() * 8)) - 1i128;
|
let mask = (1 << (ty.bytes() * 8)) - 1i128;
|
||||||
let truncated = self.into_int()? & mask;
|
let truncated = self.into_int_signed()? & mask;
|
||||||
Self::from_integer(truncated, ty)?
|
Self::from_integer(truncated, ty)?
|
||||||
}
|
}
|
||||||
ValueConversionKind::ExtractUpper(ty) => {
|
ValueConversionKind::ExtractUpper(ty) => {
|
||||||
@@ -395,88 +418,44 @@ impl DataValueExt for DataValue {
|
|||||||
let mask = (1 << (ty.bytes() * 8)) - 1i128;
|
let mask = (1 << (ty.bytes() * 8)) - 1i128;
|
||||||
let shifted_mask = mask << shift_amt;
|
let shifted_mask = mask << shift_amt;
|
||||||
|
|
||||||
let extracted = (self.into_int()? & shifted_mask) >> shift_amt;
|
let extracted = (self.into_int_signed()? & shifted_mask) >> shift_amt;
|
||||||
Self::from_integer(extracted, ty)?
|
Self::from_integer(extracted, ty)?
|
||||||
}
|
}
|
||||||
ValueConversionKind::SignExtend(ty) => match (self, ty) {
|
ValueConversionKind::SignExtend(ty) => match (self, ty) {
|
||||||
(DataValue::U8(n), types::I16) => DataValue::U16(n as u16),
|
|
||||||
(DataValue::U8(n), types::I32) => DataValue::U32(n as u32),
|
|
||||||
(DataValue::U8(n), types::I64) => DataValue::U64(n as u64),
|
|
||||||
(DataValue::U8(n), types::I128) => DataValue::U128(n as u128),
|
|
||||||
(DataValue::I8(n), types::I16) => DataValue::I16(n as i16),
|
(DataValue::I8(n), types::I16) => DataValue::I16(n as i16),
|
||||||
(DataValue::I8(n), types::I32) => DataValue::I32(n as i32),
|
(DataValue::I8(n), types::I32) => DataValue::I32(n as i32),
|
||||||
(DataValue::I8(n), types::I64) => DataValue::I64(n as i64),
|
(DataValue::I8(n), types::I64) => DataValue::I64(n as i64),
|
||||||
(DataValue::I8(n), types::I128) => DataValue::I128(n as i128),
|
(DataValue::I8(n), types::I128) => DataValue::I128(n as i128),
|
||||||
(DataValue::U16(n), types::I32) => DataValue::U32(n as u32),
|
|
||||||
(DataValue::U16(n), types::I64) => DataValue::U64(n as u64),
|
|
||||||
(DataValue::U16(n), types::I128) => DataValue::U128(n as u128),
|
|
||||||
(DataValue::I16(n), types::I32) => DataValue::I32(n as i32),
|
(DataValue::I16(n), types::I32) => DataValue::I32(n as i32),
|
||||||
(DataValue::I16(n), types::I64) => DataValue::I64(n as i64),
|
(DataValue::I16(n), types::I64) => DataValue::I64(n as i64),
|
||||||
(DataValue::I16(n), types::I128) => DataValue::I128(n as i128),
|
(DataValue::I16(n), types::I128) => DataValue::I128(n as i128),
|
||||||
(DataValue::U32(n), types::I64) => DataValue::U64(n as u64),
|
|
||||||
(DataValue::U32(n), types::I128) => DataValue::U128(n as u128),
|
|
||||||
(DataValue::I32(n), types::I64) => DataValue::I64(n as i64),
|
(DataValue::I32(n), types::I64) => DataValue::I64(n as i64),
|
||||||
(DataValue::I32(n), types::I128) => DataValue::I128(n as i128),
|
(DataValue::I32(n), types::I128) => DataValue::I128(n as i128),
|
||||||
(DataValue::U64(n), types::I128) => DataValue::U128(n as u128),
|
|
||||||
(DataValue::I64(n), types::I128) => DataValue::I128(n as i128),
|
(DataValue::I64(n), types::I128) => DataValue::I128(n as i128),
|
||||||
(dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),
|
(dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),
|
||||||
},
|
},
|
||||||
ValueConversionKind::ZeroExtend(ty) => match (self, ty) {
|
ValueConversionKind::ZeroExtend(ty) => match (self, ty) {
|
||||||
(DataValue::U8(n), types::I16) => DataValue::U16(n as u16),
|
|
||||||
(DataValue::U8(n), types::I32) => DataValue::U32(n as u32),
|
|
||||||
(DataValue::U8(n), types::I64) => DataValue::U64(n as u64),
|
|
||||||
(DataValue::U8(n), types::I128) => DataValue::U128(n as u128),
|
|
||||||
(DataValue::I8(n), types::I16) => DataValue::I16(n as u8 as i16),
|
(DataValue::I8(n), types::I16) => DataValue::I16(n as u8 as i16),
|
||||||
(DataValue::I8(n), types::I32) => DataValue::I32(n as u8 as i32),
|
(DataValue::I8(n), types::I32) => DataValue::I32(n as u8 as i32),
|
||||||
(DataValue::I8(n), types::I64) => DataValue::I64(n as u8 as i64),
|
(DataValue::I8(n), types::I64) => DataValue::I64(n as u8 as i64),
|
||||||
(DataValue::I8(n), types::I128) => DataValue::I128(n as u8 as i128),
|
(DataValue::I8(n), types::I128) => DataValue::I128(n as u8 as i128),
|
||||||
(DataValue::U16(n), types::I32) => DataValue::U32(n as u32),
|
|
||||||
(DataValue::U16(n), types::I64) => DataValue::U64(n as u64),
|
|
||||||
(DataValue::U16(n), types::I128) => DataValue::U128(n as u128),
|
|
||||||
(DataValue::I16(n), types::I32) => DataValue::I32(n as u16 as i32),
|
(DataValue::I16(n), types::I32) => DataValue::I32(n as u16 as i32),
|
||||||
(DataValue::I16(n), types::I64) => DataValue::I64(n as u16 as i64),
|
(DataValue::I16(n), types::I64) => DataValue::I64(n as u16 as i64),
|
||||||
(DataValue::I16(n), types::I128) => DataValue::I128(n as u16 as i128),
|
(DataValue::I16(n), types::I128) => DataValue::I128(n as u16 as i128),
|
||||||
(DataValue::U32(n), types::I64) => DataValue::U64(n as u64),
|
|
||||||
(DataValue::U32(n), types::I128) => DataValue::U128(n as u128),
|
|
||||||
(DataValue::I32(n), types::I64) => DataValue::I64(n as u32 as i64),
|
(DataValue::I32(n), types::I64) => DataValue::I64(n as u32 as i64),
|
||||||
(DataValue::I32(n), types::I128) => DataValue::I128(n as u32 as i128),
|
(DataValue::I32(n), types::I128) => DataValue::I128(n as u32 as i128),
|
||||||
(DataValue::U64(n), types::I128) => DataValue::U128(n as u128),
|
|
||||||
(DataValue::I64(n), types::I128) => DataValue::I128(n as u64 as i128),
|
(DataValue::I64(n), types::I128) => DataValue::I128(n as u64 as i128),
|
||||||
(from, to) if from.ty() == to => from,
|
(from, to) if from.ty() == to => from,
|
||||||
(dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),
|
(dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind),
|
||||||
},
|
},
|
||||||
ValueConversionKind::ToUnsigned => match self {
|
|
||||||
DataValue::I8(n) => DataValue::U8(n as u8),
|
|
||||||
DataValue::I16(n) => DataValue::U16(n as u16),
|
|
||||||
DataValue::I32(n) => DataValue::U32(n as u32),
|
|
||||||
DataValue::I64(n) => DataValue::U64(n as u64),
|
|
||||||
DataValue::I128(n) => DataValue::U128(n as u128),
|
|
||||||
DataValue::U8(_) => self,
|
|
||||||
DataValue::U16(_) => self,
|
|
||||||
DataValue::U32(_) => self,
|
|
||||||
DataValue::U64(_) => self,
|
|
||||||
DataValue::U128(_) => self,
|
|
||||||
_ => unimplemented!("conversion: {} -> {:?}", self.ty(), kind),
|
|
||||||
},
|
|
||||||
ValueConversionKind::ToSigned => match self {
|
|
||||||
DataValue::U8(n) => DataValue::I8(n as i8),
|
|
||||||
DataValue::U16(n) => DataValue::I16(n as i16),
|
|
||||||
DataValue::U32(n) => DataValue::I32(n as i32),
|
|
||||||
DataValue::U64(n) => DataValue::I64(n as i64),
|
|
||||||
DataValue::U128(n) => DataValue::I128(n as i128),
|
|
||||||
DataValue::I8(_) => self,
|
|
||||||
DataValue::I16(_) => self,
|
|
||||||
DataValue::I32(_) => self,
|
|
||||||
DataValue::I64(_) => self,
|
|
||||||
DataValue::I128(_) => self,
|
|
||||||
_ => unimplemented!("conversion: {} -> {:?}", self.ty(), kind),
|
|
||||||
},
|
|
||||||
ValueConversionKind::RoundNearestEven(ty) => match (self, ty) {
|
ValueConversionKind::RoundNearestEven(ty) => match (self, ty) {
|
||||||
(DataValue::F64(n), types::F32) => DataValue::F32(Ieee32::from(n.as_f64() as f32)),
|
(DataValue::F64(n), types::F32) => DataValue::F32(Ieee32::from(n.as_f64() as f32)),
|
||||||
(s, _) => unimplemented!("conversion: {} -> {:?}", s.ty(), kind),
|
(s, _) => unimplemented!("conversion: {} -> {:?}", s.ty(), kind),
|
||||||
},
|
},
|
||||||
ValueConversionKind::ToBoolean => match self.ty() {
|
ValueConversionKind::ToBoolean => match self.ty() {
|
||||||
ty if ty.is_int() => DataValue::I8(if self.into_int()? != 0 { 1 } else { 0 }),
|
ty if ty.is_int() => {
|
||||||
|
DataValue::I8(if self.into_int_signed()? != 0 { 1 } else { 0 })
|
||||||
|
}
|
||||||
ty => unimplemented!("conversion: {} -> {:?}", ty, kind),
|
ty => unimplemented!("conversion: {} -> {:?}", ty, kind),
|
||||||
},
|
},
|
||||||
ValueConversionKind::Mask(ty) => {
|
ValueConversionKind::Mask(ty) => {
|
||||||
@@ -511,7 +490,17 @@ impl DataValueExt for DataValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn max(self, other: Self) -> ValueResult<Self> {
|
fn umax(self, other: Self) -> ValueResult<Self> {
|
||||||
|
let lhs = self.clone().into_int_unsigned()?;
|
||||||
|
let rhs = other.clone().into_int_unsigned()?;
|
||||||
|
if lhs > rhs {
|
||||||
|
Ok(self)
|
||||||
|
} else {
|
||||||
|
Ok(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn smax(self, other: Self) -> ValueResult<Self> {
|
||||||
if self > other {
|
if self > other {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
} else {
|
} else {
|
||||||
@@ -519,7 +508,17 @@ impl DataValueExt for DataValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn min(self, other: Self) -> ValueResult<Self> {
|
fn umin(self, other: Self) -> ValueResult<Self> {
|
||||||
|
let lhs = self.clone().into_int_unsigned()?;
|
||||||
|
let rhs = other.clone().into_int_unsigned()?;
|
||||||
|
if lhs < rhs {
|
||||||
|
Ok(self)
|
||||||
|
} else {
|
||||||
|
Ok(other)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn smin(self, other: Self) -> ValueResult<Self> {
|
||||||
if self < other {
|
if self < other {
|
||||||
Ok(self)
|
Ok(self)
|
||||||
} else {
|
} else {
|
||||||
@@ -535,7 +534,7 @@ impl DataValueExt for DataValue {
|
|||||||
if self.is_float() {
|
if self.is_float() {
|
||||||
binary_match!(+(self, other); [F32, F64])
|
binary_match!(+(self, other); [F32, F64])
|
||||||
} else {
|
} else {
|
||||||
binary_match!(wrapping_add(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
binary_match!(wrapping_add(&self, &other); [I8, I16, I32, I64, I128])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -555,12 +554,12 @@ impl DataValueExt for DataValue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn div(self, other: Self) -> ValueResult<Self> {
|
fn sdiv(self, other: Self) -> ValueResult<Self> {
|
||||||
if self.is_float() {
|
if self.is_float() {
|
||||||
return binary_match!(/(self, other); [F32, F64]);
|
return binary_match!(/(self, other); [F32, F64]);
|
||||||
}
|
}
|
||||||
|
|
||||||
let denominator = other.clone().into_int()?;
|
let denominator = other.clone().into_int_signed()?;
|
||||||
|
|
||||||
// Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.
|
// Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.
|
||||||
let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?;
|
let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?;
|
||||||
@@ -572,11 +571,25 @@ impl DataValueExt for DataValue {
|
|||||||
return Err(ValueError::IntegerDivisionByZero);
|
return Err(ValueError::IntegerDivisionByZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
binary_match!(/(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
binary_match!(/(&self, &other); [I8, I16, I32, I64, I128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rem(self, other: Self) -> ValueResult<Self> {
|
fn udiv(self, other: Self) -> ValueResult<Self> {
|
||||||
let denominator = other.clone().into_int()?;
|
if self.is_float() {
|
||||||
|
return binary_match!(/(self, other); [F32, F64]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let denominator = other.clone().into_int_unsigned()?;
|
||||||
|
|
||||||
|
if denominator == 0 {
|
||||||
|
return Err(ValueError::IntegerDivisionByZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
binary_match!(/(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn srem(self, other: Self) -> ValueResult<Self> {
|
||||||
|
let denominator = other.clone().into_int_signed()?;
|
||||||
|
|
||||||
// Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.
|
// Check if we are dividing INT_MIN / -1. This causes an integer overflow trap.
|
||||||
let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?;
|
let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?;
|
||||||
@@ -588,7 +601,17 @@ impl DataValueExt for DataValue {
|
|||||||
return Err(ValueError::IntegerDivisionByZero);
|
return Err(ValueError::IntegerDivisionByZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
binary_match!(%(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
binary_match!(%(&self, &other); [I8, I16, I32, I64, I128])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn urem(self, other: Self) -> ValueResult<Self> {
|
||||||
|
let denominator = other.clone().into_int_unsigned()?;
|
||||||
|
|
||||||
|
if denominator == 0 {
|
||||||
|
return Err(ValueError::IntegerDivisionByZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
binary_match!(%(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sqrt(self) -> ValueResult<Self> {
|
fn sqrt(self) -> ValueResult<Self> {
|
||||||
@@ -633,20 +656,36 @@ impl DataValueExt for DataValue {
|
|||||||
unary_match!(abs(&self); [F32, F64])
|
unary_match!(abs(&self); [F32, F64])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn checked_add(self, other: Self) -> ValueResult<Option<Self>> {
|
fn sadd_checked(self, other: Self) -> ValueResult<Option<Self>> {
|
||||||
binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overflowing_add(self, other: Self) -> ValueResult<(Self, bool)> {
|
fn uadd_checked(self, other: Self) -> ValueResult<Option<Self>> {
|
||||||
binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overflowing_sub(self, other: Self) -> ValueResult<(Self, bool)> {
|
fn sadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
|
||||||
binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn overflowing_mul(self, other: Self) -> ValueResult<(Self, bool)> {
|
fn uadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
|
||||||
binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ssub_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
|
||||||
|
binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usub_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
|
||||||
|
binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn smul_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
|
||||||
|
binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn umul_overflow(self, other: Self) -> ValueResult<(Self, bool)> {
|
||||||
|
binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn neg(self) -> ValueResult<Self> {
|
fn neg(self) -> ValueResult<Self> {
|
||||||
@@ -673,47 +712,45 @@ impl DataValueExt for DataValue {
|
|||||||
unary_match!(round_ties_even(&self); [F32, F64])
|
unary_match!(round_ties_even(&self); [F32, F64])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_sat(self, other: Self) -> ValueResult<Self> {
|
fn sadd_sat(self, other: Self) -> ValueResult<Self> {
|
||||||
binary_match!(saturating_add(self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
binary_match!(saturating_add(self, &other); [I8, I16, I32, I64, I128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sub_sat(self, other: Self) -> ValueResult<Self> {
|
fn uadd_sat(self, other: Self) -> ValueResult<Self> {
|
||||||
binary_match!(saturating_sub(self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
binary_match!(saturating_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ssub_sat(self, other: Self) -> ValueResult<Self> {
|
||||||
|
binary_match!(saturating_sub(self, &other); [I8, I16, I32, I64, I128])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn usub_sat(self, other: Self) -> ValueResult<Self> {
|
||||||
|
binary_match!(saturating_sub(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn shl(self, other: Self) -> ValueResult<Self> {
|
fn shl(self, other: Self) -> ValueResult<Self> {
|
||||||
let amt = other
|
let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
|
||||||
.convert(ValueConversionKind::Exact(types::I32))?
|
binary_match!(wrapping_shl(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
|
||||||
.convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
binary_match!(wrapping_shl(&self, &amt); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]; rhs: U32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ushr(self, other: Self) -> ValueResult<Self> {
|
fn ushr(self, other: Self) -> ValueResult<Self> {
|
||||||
let amt = other
|
let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
|
||||||
.convert(ValueConversionKind::Exact(types::I32))?
|
binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128]; rhs: I32,u32)
|
||||||
.convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
binary_match!(wrapping_shr(&self, &amt); [U8, U16, U32, U64, U128]; rhs: U32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ishr(self, other: Self) -> ValueResult<Self> {
|
fn sshr(self, other: Self) -> ValueResult<Self> {
|
||||||
let amt = other
|
let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
|
||||||
.convert(ValueConversionKind::Exact(types::I32))?
|
binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
|
||||||
.convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; rhs: U32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotl(self, other: Self) -> ValueResult<Self> {
|
fn rotl(self, other: Self) -> ValueResult<Self> {
|
||||||
let amt = other
|
let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
|
||||||
.convert(ValueConversionKind::Exact(types::I32))?
|
binary_match!(rotate_left(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
|
||||||
.convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
binary_match!(rotate_left(&self, &amt); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]; rhs: U32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn rotr(self, other: Self) -> ValueResult<Self> {
|
fn rotr(self, other: Self) -> ValueResult<Self> {
|
||||||
let amt = other
|
let amt = other.convert(ValueConversionKind::Exact(types::I32))?;
|
||||||
.convert(ValueConversionKind::Exact(types::I32))?
|
binary_match!(rotate_right(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32)
|
||||||
.convert(ValueConversionKind::ToUnsigned)?;
|
|
||||||
binary_match!(rotate_right(&self, &amt); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]; rhs: U32)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn and(self, other: Self) -> ValueResult<Self> {
|
fn and(self, other: Self) -> ValueResult<Self> {
|
||||||
@@ -749,26 +786,26 @@ impl DataValueExt for DataValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn count_ones(self) -> ValueResult<Self> {
|
fn count_ones(self) -> ValueResult<Self> {
|
||||||
unary_match!(count_ones(&self); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]; [i8, i16, i32, i64, i128, u8, u16, u32, u64, u128])
|
unary_match!(count_ones(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leading_ones(self) -> ValueResult<Self> {
|
fn leading_ones(self) -> ValueResult<Self> {
|
||||||
unary_match!(leading_ones(&self); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]; [i8, i16, i32, i64, i128, u8, u16, u32, u64, u128])
|
unary_match!(leading_ones(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn leading_zeros(self) -> ValueResult<Self> {
|
fn leading_zeros(self) -> ValueResult<Self> {
|
||||||
unary_match!(leading_zeros(&self); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]; [i8, i16, i32, i64, i128, u8, u16, u32, u64, u128])
|
unary_match!(leading_zeros(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trailing_zeros(self) -> ValueResult<Self> {
|
fn trailing_zeros(self) -> ValueResult<Self> {
|
||||||
unary_match!(trailing_zeros(&self); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]; [i8, i16, i32, i64, i128, u8, u16, u32, u64, u128])
|
unary_match!(trailing_zeros(&self); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reverse_bits(self) -> ValueResult<Self> {
|
fn reverse_bits(self) -> ValueResult<Self> {
|
||||||
unary_match!(reverse_bits(&self); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
|
unary_match!(reverse_bits(&self); [I8, I16, I32, I64, I128])
|
||||||
}
|
}
|
||||||
|
|
||||||
fn swap_bytes(self) -> ValueResult<Self> {
|
fn swap_bytes(self) -> ValueResult<Self> {
|
||||||
unary_match!(swap_bytes(&self); [I16, I32, I64, I128, U16, U32, U64, U128])
|
unary_match!(swap_bytes(&self); [I16, I32, I64, I128])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user