diff --git a/cranelift/codegen/src/data_value.rs b/cranelift/codegen/src/data_value.rs index f19e302d0b..af067b3671 100644 --- a/cranelift/codegen/src/data_value.rs +++ b/cranelift/codegen/src/data_value.rs @@ -17,11 +17,6 @@ pub enum DataValue { I32(i32), I64(i64), I128(i128), - U8(u8), - U16(u16), - U32(u32), - U64(u64), - U128(u128), F32(Ieee32), F64(Ieee64), V128([u8; 16]), @@ -42,16 +37,6 @@ impl PartialEq for DataValue { (I64(_), _) => false, (I128(l), I128(r)) => l == r, (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(_), _) => false, (F64(l), F64(r)) => l.as_f64() == r.as_f64(), @@ -81,11 +66,11 @@ impl DataValue { /// Return the Cranelift IR [Type] for this [DataValue]. pub fn ty(&self) -> Type { match self { - DataValue::I8(_) | DataValue::U8(_) => types::I8, - DataValue::I16(_) | DataValue::U16(_) => types::I16, - DataValue::I32(_) | DataValue::U32(_) => types::I32, - DataValue::I64(_) | DataValue::U64(_) => types::I64, - DataValue::I128(_) | DataValue::U128(_) => types::I128, + DataValue::I8(_) => types::I8, + DataValue::I16(_) => types::I16, + DataValue::I32(_) => types::I32, + DataValue::I64(_) => types::I64, + DataValue::I128(_) => types::I128, DataValue::F32(_) => types::F32, DataValue::F64(_) => types::F64, DataValue::V128(_) => types::I8X16, // A default type. @@ -108,11 +93,6 @@ impl DataValue { DataValue::I32(i) => DataValue::I32(i.swap_bytes()), DataValue::I64(i) => DataValue::I64(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::F64(f) => DataValue::F64(Ieee64::with_bits(f.bits().swap_bytes())), DataValue::V128(mut v) => { @@ -160,7 +140,6 @@ impl DataValue { DataValue::F64(f) => dst[..8].copy_from_slice(&f.bits().to_ne_bytes()[..]), DataValue::V128(v) => dst[..16].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::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 // raw bytes anyway (a, b) => a == b, @@ -339,11 +306,6 @@ build_conversion_impl!(i16, I16, I16); build_conversion_impl!(i32, I32, I32); build_conversion_impl!(i64, I64, I64); 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!(Ieee64, F64, F64); build_conversion_impl!([u8; 16], V128, I8X16); @@ -362,11 +324,6 @@ impl Display for DataValue { DataValue::I32(dv) => write!(f, "{}", dv), DataValue::I64(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. DataValue::F32(dv) => write!(f, "{}", dv), DataValue::F64(dv) => write!(f, "{}", dv), diff --git a/cranelift/interpreter/src/address.rs b/cranelift/interpreter/src/address.rs index 97d610d27f..126945517e 100644 --- a/cranelift/interpreter/src/address.rs +++ b/cranelift/interpreter/src/address.rs @@ -185,9 +185,7 @@ impl TryFrom for Address { fn try_from(value: DataValue) -> Result { let addr = match value { - DataValue::U32(v) => v as u64, DataValue::I32(v) => v as u32 as u64, - DataValue::U64(v) => v, DataValue::I64(v) => v as u64, _ => { return Err(MemoryError::InvalidAddress(value)); @@ -195,8 +193,8 @@ impl TryFrom for Address { }; let size = match value { - DataValue::U32(_) | DataValue::I32(_) => AddressSize::_32, - DataValue::U64(_) | DataValue::I64(_) => AddressSize::_64, + DataValue::I32(_) => AddressSize::_32, + DataValue::I64(_) => AddressSize::_64, _ => unreachable!(), }; @@ -217,9 +215,9 @@ impl TryFrom for Address { fn try_from(value: u64) -> Result { let dv = if value > u32::MAX as u64 { - DataValue::U64(value) + DataValue::I64(value as i64) } else { - DataValue::U32(value as u32) + DataValue::I32(value as i32) }; Address::try_from(dv) diff --git a/cranelift/interpreter/src/interpreter.rs b/cranelift/interpreter/src/interpreter.rs index 5c35bc5564..c685f0df1b 100644 --- a/cranelift/interpreter/src/interpreter.rs +++ b/cranelift/interpreter/src/interpreter.rs @@ -220,7 +220,7 @@ impl Default for InterpreterState<'_> { frame_stack: vec![], frame_offset: 0, stack: Vec::with_capacity(1024), - pinned_reg: DataValue::U64(0), + pinned_reg: DataValue::I64(0), native_endianness, } } diff --git a/cranelift/interpreter/src/step.rs b/cranelift/interpreter/src/step.rs index a4e46e1c84..1022ae175d 100644 --- a/cranelift/interpreter/src/step.rs +++ b/cranelift/interpreter/src/step.rs @@ -35,12 +35,12 @@ fn validate_signature_params(sig: &[AbiParam], args: &[DataValue]) -> bool { } // Helper for summing a sequence of values. -fn sum(head: DataValue, tail: SmallVec<[DataValue; 1]>) -> ValueResult { +fn sum_unsigned(head: DataValue, tail: SmallVec<[DataValue; 1]>) -> ValueResult { let mut acc = head; for t in tail { 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 @@ -188,7 +188,7 @@ where .map(|v| v.convert(ValueConversionKind::ZeroExtend(addr_ty))) .collect::>>()?; - 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 @@ -196,7 +196,7 @@ where let unary = |op: fn(DataValue) -> ValueResult, arg: DataValue| -> ValueResult { 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)) }; @@ -207,20 +207,7 @@ where right: DataValue| -> ValueResult { let ctrl_ty = inst_context.controlling_type().unwrap(); - let res = binary_arith(left, right, ctrl_ty, op, false)?; - 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, - left: DataValue, - right: DataValue| - -> ValueResult { - 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))?; + let res = binary_arith(left, right, ctrl_ty, op)?; Ok(assign(res)) }; @@ -230,20 +217,7 @@ where right: DataValue| -> ValueResult { let ctrl_ty = inst_context.controlling_type().unwrap(); - let res = binary_arith(left, right, ctrl_ty, op, false); - 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, - left: DataValue, - right: DataValue| - -> ValueResult { - 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)); + let res = binary_arith(left, right, ctrl_ty, op); assign_or_trap(res) }; @@ -364,7 +338,7 @@ where let jt_data = &state.get_current_function().stencil.dfg.jump_tables[table]; // 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() .and_then(|i| jt_data.as_slice().get(i)) .copied() @@ -419,7 +393,7 @@ where } Opcode::CallIndirect | Opcode::ReturnCallIndirect => { 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 func = state @@ -530,7 +504,7 @@ where Opcode::StackLoad => { let load_ty = inst_context.controlling_type().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(); assign_or_memtrap({ state @@ -541,7 +515,7 @@ where Opcode::StackStore => { let arg = arg(0); 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(); continue_or_memtrap({ state @@ -552,7 +526,7 @@ where Opcode::StackAddr => { let load_ty = inst_context.controlling_type().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({ AddressSize::try_from(load_ty).and_then(|addr_size| { let addr = state.stack_address(addr_size, slot, offset)?; @@ -599,7 +573,7 @@ where 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::F64const => assign(imm()), Opcode::Vconst => assign(imm()), @@ -619,7 +593,7 @@ where let icmp = icmp(ctrl_ty, IntCC::SignedGreaterThan, &arg(1), &arg(0))?; assign(bitselect(icmp, arg(0), arg(1))?) } else { - choose(arg(1) > arg(0), arg(0), arg(1)) + assign(arg(0).smin(arg(1))?) } } Opcode::Umin => { @@ -627,12 +601,7 @@ where let icmp = icmp(ctrl_ty, IntCC::UnsignedGreaterThan, &arg(1), &arg(0))?; assign(bitselect(icmp, arg(0), arg(1))?) } else { - choose( - arg(1).convert(ValueConversionKind::ToUnsigned)? - > arg(0).convert(ValueConversionKind::ToUnsigned)?, - arg(0), - arg(1), - ) + assign(arg(0).umin(arg(1))?) } } Opcode::Smax => { @@ -640,7 +609,7 @@ where let icmp = icmp(ctrl_ty, IntCC::SignedGreaterThan, &arg(0), &arg(1))?; assign(bitselect(icmp, arg(0), arg(1))?) } else { - choose(arg(0) > arg(1), arg(0), arg(1)) + assign(arg(0).smax(arg(1))?) } } Opcode::Umax => { @@ -648,12 +617,7 @@ where let icmp = icmp(ctrl_ty, IntCC::UnsignedGreaterThan, &arg(0), &arg(1))?; assign(bitselect(icmp, arg(0), arg(1))?) } else { - choose( - arg(0).convert(ValueConversionKind::ToUnsigned)? - > arg(1).convert(ValueConversionKind::ToUnsigned)?, - arg(0), - arg(1), - ) + assign(arg(0).umax(arg(1))?) } } Opcode::AvgRound => { @@ -661,37 +625,33 @@ where let one = DataValueExt::int(1, arg(0).ty())?; let inc = DataValueExt::add(sum, one)?; 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::UaddSat => assign(binary_arith( arg(0), arg(1), ctrl_ty, - DataValueExt::add_sat, - true, + DataValueExt::uadd_sat, )?), Opcode::SaddSat => assign(binary_arith( arg(0), arg(1), ctrl_ty, - DataValueExt::add_sat, - false, + DataValueExt::sadd_sat, )?), Opcode::Isub => binary(DataValueExt::sub, arg(0), arg(1))?, Opcode::UsubSat => assign(binary_arith( arg(0), arg(1), ctrl_ty, - DataValueExt::sub_sat, - true, + DataValueExt::usub_sat, )?), Opcode::SsubSat => assign(binary_arith( arg(0), arg(1), ctrl_ty, - DataValueExt::sub_sat, - false, + DataValueExt::ssub_sat, )?), Opcode::Ineg => binary(DataValueExt::sub, DataValueExt::int(0, ctrl_ty)?, arg(0))?, Opcode::Iabs => { @@ -704,7 +664,7 @@ where if lane == min_val { Ok(min_val.clone()) } else { - DataValueExt::int(lane.into_int()?.abs(), ctrl_ty.lane_type()) + DataValueExt::int(lane.into_int_signed()?.abs(), ctrl_ty.lane_type()) } }) .collect::>>()?; @@ -741,57 +701,39 @@ where assign(vectorizelanes(&res, ctrl_ty)?) } - Opcode::Udiv => binary_unsigned_can_trap(DataValueExt::div, arg(0), arg(1))?, - Opcode::Sdiv => binary_can_trap(DataValueExt::div, arg(0), arg(1))?, - Opcode::Urem => binary_unsigned_can_trap(DataValueExt::rem, arg(0), arg(1))?, - Opcode::Srem => binary_can_trap(DataValueExt::rem, arg(0), arg(1))?, + Opcode::Udiv => binary_can_trap(DataValueExt::udiv, arg(0), arg(1))?, + Opcode::Sdiv => binary_can_trap(DataValueExt::sdiv, arg(0), arg(1))?, + Opcode::Urem => binary_can_trap(DataValueExt::urem, 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::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::SdivImm => binary_can_trap(DataValueExt::div, arg(0), imm_as_ctrl_ty()?)?, - Opcode::UremImm => binary_unsigned_can_trap(DataValueExt::rem, arg(0), imm_as_ctrl_ty()?)?, - Opcode::SremImm => binary_can_trap(DataValueExt::rem, 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::sdiv, 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::srem, arg(0), imm_as_ctrl_ty()?)?, Opcode::IrsubImm => binary(DataValueExt::sub, imm_as_ctrl_ty()?, arg(0))?, Opcode::UaddOverflow => { - let lhs = arg(0).convert(ValueConversionKind::ToUnsigned)?; - let rhs = arg(1).convert(ValueConversionKind::ToUnsigned)?; - let (mut sum, carry) = lhs.overflowing_add(rhs)?; - sum = sum.convert(ValueConversionKind::ToSigned)?; + let (sum, carry) = arg(0).uadd_overflow(arg(1))?; assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?]) } Opcode::SaddOverflow => { - let ty = arg(0).ty(); - let lhs = arg(0).convert(ValueConversionKind::ToSigned)?; - let rhs = arg(1).convert(ValueConversionKind::ToSigned)?; - let (sum, carry) = lhs.overflowing_add(rhs)?; + let (sum, carry) = arg(0).sadd_overflow(arg(1))?; assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?]) } Opcode::UsubOverflow => { - let lhs = arg(0).convert(ValueConversionKind::ToUnsigned)?; - let rhs = arg(1).convert(ValueConversionKind::ToUnsigned)?; - let (mut sum, carry) = lhs.overflowing_sub(rhs)?; - sum = sum.convert(ValueConversionKind::ToSigned)?; + let (sum, carry) = arg(0).usub_overflow(arg(1))?; assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?]) } Opcode::SsubOverflow => { - let ty = arg(0).ty(); - let lhs = arg(0).convert(ValueConversionKind::ToSigned)?; - let rhs = arg(1).convert(ValueConversionKind::ToSigned)?; - let (sum, carry) = lhs.overflowing_sub(rhs)?; + let (sum, carry) = arg(0).ssub_overflow(arg(1))?; assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?]) } Opcode::UmulOverflow => { - let lhs = arg(0).convert(ValueConversionKind::ToUnsigned)?; - let rhs = arg(1).convert(ValueConversionKind::ToUnsigned)?; - let (mut sum, carry) = lhs.overflowing_mul(rhs)?; - sum = sum.convert(ValueConversionKind::ToSigned)?; + let (sum, carry) = arg(0).umul_overflow(arg(1))?; assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?]) } Opcode::SmulOverflow => { - let ty = arg(0).ty(); - let lhs = arg(0).convert(ValueConversionKind::ToSigned)?; - let rhs = arg(1).convert(ValueConversionKind::ToSigned)?; - let (sum, carry) = lhs.overflowing_mul(rhs)?; + let (sum, carry) = arg(0).smul_overflow(arg(1))?; assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?]) } Opcode::IaddCin => choose( @@ -804,12 +746,12 @@ where ), Opcode::IaddCarry => { 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))? { carry |= sum .clone() - .checked_add(DataValueExt::int(1, ctrl_ty)?)? + .sadd_checked(DataValueExt::int(1, ctrl_ty)?)? .is_none(); 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::RotrImm => binary(DataValueExt::rotr, arg(0), imm_as_ctrl_ty()?)?, Opcode::Ishl => binary(DataValueExt::shl, arg(0), arg(1))?, - Opcode::Ushr => binary_unsigned(DataValueExt::ushr, arg(0), arg(1))?, - Opcode::Sshr => binary(DataValueExt::ishr, arg(0), arg(1))?, + Opcode::Ushr => binary(DataValueExt::ushr, 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::UshrImm => binary_unsigned(DataValueExt::ushr, arg(0), imm_as_ctrl_ty()?)?, - Opcode::SshrImm => binary(DataValueExt::ishr, arg(0), imm_as_ctrl_ty()?)?, + Opcode::UshrImm => binary(DataValueExt::ushr, 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::Bswap => unary(DataValueExt::swap_bytes, 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::Fsub => binary(DataValueExt::sub, 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::Fma => { let arg0 = extractlanes(&arg(0), ctrl_ty)?; @@ -935,24 +877,24 @@ where (_, 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()? && b.is_negative()? => b, - (a, b) => a.min(b)?, + (a, b) => a.smin(b)?, }), Opcode::FminPseudo => assign(match (arg(0), arg(1)) { (a, b) if a.is_nan()? || b.is_nan()? => 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)) { (a, _) if a.is_nan()? => a, (_, 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()? && b.is_negative()? => a, - (a, b) => a.max(b)?, + (a, b) => a.smax(b)?, }), Opcode::FmaxPseudo => assign(match (arg(0), arg(1)) { (a, b) if a.is_nan()? || b.is_nan()? => 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::Floor => unary(DataValueExt::floor, arg(0))?, @@ -982,22 +924,17 @@ where let arg1 = extractlanes(&arg(1), ctrl_ty)?; let new_type = ctrl_ty.split_lanes().unwrap(); let (min, max) = new_type.bounds(inst.opcode() == Opcode::Snarrow); - let mut min: DataValue = DataValueExt::int(min as i128, ctrl_ty.lane_type())?; - let mut 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 min: DataValue = DataValueExt::int(min as i128, ctrl_ty.lane_type())?; + let max: DataValue = DataValueExt::int(max as i128, ctrl_ty.lane_type())?; let narrow = |mut lane: DataValue| -> ValueResult { 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()))?; - if inst.opcode() == Opcode::Unarrow || inst.opcode() == Opcode::Uunarrow { - lane = lane.convert(ValueConversionKind::ToUnsigned)?; - } Ok(lane) }; let new_vec = arg0 @@ -1065,13 +1002,13 @@ where assign(vectorizelanes(&new_vector, ctrl_ty)?) } 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)?; vector[idx] = arg(1); assign(vectorizelanes(&vector, ctrl_ty)?) } Opcode::Extractlane => { - let idx = imm().into_int()? as usize; + let idx = imm().into_int_unsigned()? as usize; let lanes = extractlanes(&arg(0), ctrl_ty)?; assign(lanes[idx].clone()) } @@ -1080,12 +1017,12 @@ where // must be retrieved via `inst_context`. let vector_type = inst_context.type_of(inst_context.args()[0]).unwrap(); 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() { - let val = val.reverse_bits()?.into_int()?; // MSB -> LSB + let val = val.reverse_bits()?.into_int_unsigned()?; // MSB -> LSB result |= (val & 1) << i; } - assign(DataValueExt::int(result, ctrl_ty)?) + assign(DataValueExt::int(result as i128, ctrl_ty)?) } Opcode::VanyTrue => { let lane_ty = ctrl_ty.lane_type(); @@ -1187,14 +1124,19 @@ where inst_context.type_of(inst_context.args()[0]).unwrap(), )?; let bits = |x: DataValue| -> ValueResult { - let x = if inst.opcode() == Opcode::FcvtFromUint { - x.convert(ValueConversionKind::ToUnsigned)? - } else { - x - }; Ok(match ctrl_ty.lane_type() { - types::F32 => (x.into_int()? as f32).to_bits() as u64, - types::F64 => (x.into_int()? as f64).to_bits(), + types::F32 => (if inst.opcode() == Opcode::FcvtFromUint { + 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()), }) }; @@ -1215,8 +1157,10 @@ where .map(|x| { DataValue::float( match ctrl_ty.lane_type() { - types::F32 => (x.to_owned().into_int()? as f32).to_bits() as u64, - types::F64 => (x.to_owned().into_int()? as f64).to_bits(), + types::F32 => { + (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), }, ctrl_ty.lane_type(), @@ -1269,7 +1213,7 @@ where Opcode::AtomicRmw => { let op = inst.atomic_rmw_op().unwrap(); 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 loaded = Address::try_from(addr) .and_then(|addr| state.checked_load(addr, ctrl_ty, mem_flags)); @@ -1286,25 +1230,17 @@ where AtomicRmwOp::Or => DataValueExt::or(prev_val, val), AtomicRmwOp::Xor => DataValueExt::xor(prev_val, val), AtomicRmwOp::Nand => DataValueExt::and(prev_val, val).and_then(DataValue::not), - AtomicRmwOp::Smax => DataValueExt::max(prev_val, val), - AtomicRmwOp::Smin => DataValueExt::min(prev_val, val), - AtomicRmwOp::Umax => DataValueExt::max( - DataValueExt::convert(val, ValueConversionKind::ToUnsigned)?, - 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)), + AtomicRmwOp::Smax => DataValueExt::smax(prev_val, val), + AtomicRmwOp::Smin => DataValueExt::smin(prev_val, val), + AtomicRmwOp::Umax => DataValueExt::umax(val, prev_val), + AtomicRmwOp::Umin => DataValueExt::umin(val, prev_val), }?; let stored = Address::try_from(addr) .and_then(|addr| state.checked_store(addr, replace, mem_flags)); assign_or_memtrap(stored.map(|_| prev_val_to_assign)) } 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 loaded = Address::try_from(addr) .and_then(|addr| state.checked_load(addr, ctrl_ty, mem_flags)); @@ -1325,7 +1261,7 @@ where } Opcode::AtomicLoad => { 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"); // We are doing a regular load here, this isn't actually thread safe. assign_or_memtrap( @@ -1335,7 +1271,7 @@ where } Opcode::AtomicStore => { 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"); // We are doing a regular store here, this isn't actually thread safe. continue_or_memtrap( @@ -1359,16 +1295,16 @@ where .into_iter() .zip(arg1.into_iter()) .map(|(x, y)| { - let x = x.into_int()?; - let y = y.into_int()?; + let x = x.into_int_signed()?; + let y = y.into_int_signed()?; // temporarily double width of the value to avoid overflow. let z: DataValue = DataValueExt::int( (x * y + (1 << (lane_type.bits() - 2))) >> (lane_type.bits() - 1), double_width, )?; // check bounds, saturate, and truncate to correct width. - let z = DataValueExt::min(z, max.clone())?; - let z = DataValueExt::max(z, min.clone())?; + let z = DataValueExt::smin(z, max.clone())?; + let z = DataValueExt::smax(z, min.clone())?; let z = z.convert(ValueConversionKind::Truncate(lane_type))?; Ok(z) }) @@ -1461,20 +1397,16 @@ fn icmp( IntCC::SignedLessThan => left < right, IntCC::SignedLessThanOrEqual => left <= right, IntCC::UnsignedGreaterThan => { - left.clone().convert(ValueConversionKind::ToUnsigned)? - > right.clone().convert(ValueConversionKind::ToUnsigned)? + left.clone().into_int_unsigned()? > right.clone().into_int_unsigned()? } IntCC::UnsignedGreaterThanOrEqual => { - left.clone().convert(ValueConversionKind::ToUnsigned)? - >= right.clone().convert(ValueConversionKind::ToUnsigned)? + left.clone().into_int_unsigned()? >= right.clone().into_int_unsigned()? } IntCC::UnsignedLessThan => { - left.clone().convert(ValueConversionKind::ToUnsigned)? - < right.clone().convert(ValueConversionKind::ToUnsigned)? + left.clone().into_int_unsigned()? < right.clone().into_int_unsigned()? } IntCC::UnsignedLessThanOrEqual => { - left.clone().convert(ValueConversionKind::ToUnsigned)? - <= right.clone().convert(ValueConversionKind::ToUnsigned)? + left.clone().into_int_unsigned()? <= right.clone().into_int_unsigned()? } }, ctrl_ty.is_vector(), @@ -1579,7 +1511,7 @@ fn vectorizelanes_all(x: &[DataValue], vector_type: types::Type) -> ValueResult< let lane_val: i128 = val .clone() .convert(ValueConversionKind::Exact(lane_type.as_int()))? - .into_int()?; + .into_int_unsigned()? as i128; for j in 0..iterations { 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. -fn unary_arith( - x: DataValue, - vector_type: types::Type, - op: F, - unsigned: bool, -) -> ValueResult +fn unary_arith(x: DataValue, vector_type: types::Type, op: F) -> ValueResult where F: Fn(DataValue) -> ValueResult, { @@ -1610,12 +1537,7 @@ where let result = arg .into_iter() - .map(|mut arg| { - if unsigned { - arg = arg.convert(ValueConversionKind::ToUnsigned)?; - } - Ok(op(arg)?) - }) + .map(|arg| Ok(op(arg)?)) .collect::>>()?; vectorizelanes(&result, vector_type) @@ -1627,7 +1549,6 @@ fn binary_arith( y: DataValue, vector_type: types::Type, op: F, - unsigned: bool, ) -> ValueResult where F: Fn(DataValue, DataValue) -> ValueResult, @@ -1638,13 +1559,7 @@ where let result = arg0 .into_iter() .zip(arg1) - .map(|(mut lhs, mut rhs)| { - if unsigned { - lhs = lhs.convert(ValueConversionKind::ToUnsigned)?; - rhs = rhs.convert(ValueConversionKind::ToUnsigned)?; - } - Ok(op(lhs, rhs)?) - }) + .map(|(lhs, rhs)| Ok(op(lhs, rhs)?)) .collect::>>()?; vectorizelanes(&result, vector_type) diff --git a/cranelift/interpreter/src/value.rs b/cranelift/interpreter/src/value.rs index d03d4a16ac..d75307fdd4 100644 --- a/cranelift/interpreter/src/value.rs +++ b/cranelift/interpreter/src/value.rs @@ -13,7 +13,8 @@ pub type ValueResult = Result; pub trait DataValueExt: Sized { // Identity. fn int(n: i128, ty: Type) -> ValueResult; - fn into_int(self) -> ValueResult; + fn into_int_signed(self) -> ValueResult; + fn into_int_unsigned(self) -> ValueResult; fn float(n: u64, ty: Type) -> ValueResult; fn into_float(self) -> ValueResult; fn is_float(&self) -> bool; @@ -28,8 +29,10 @@ pub trait DataValueExt: Sized { fn is_negative(&self) -> ValueResult; fn is_zero(&self) -> ValueResult; - fn max(self, other: Self) -> ValueResult; - fn min(self, other: Self) -> ValueResult; + fn umax(self, other: Self) -> ValueResult; + fn smax(self, other: Self) -> ValueResult; + fn umin(self, other: Self) -> ValueResult; + fn smin(self, other: Self) -> ValueResult; // Comparison. fn uno(&self, other: &Self) -> ValueResult; @@ -38,15 +41,21 @@ pub trait DataValueExt: Sized { fn add(self, other: Self) -> ValueResult; fn sub(self, other: Self) -> ValueResult; fn mul(self, other: Self) -> ValueResult; - fn div(self, other: Self) -> ValueResult; - fn rem(self, other: Self) -> ValueResult; + fn udiv(self, other: Self) -> ValueResult; + fn sdiv(self, other: Self) -> ValueResult; + fn urem(self, other: Self) -> ValueResult; + fn srem(self, other: Self) -> ValueResult; fn sqrt(self) -> ValueResult; fn fma(self, a: Self, b: Self) -> ValueResult; fn abs(self) -> ValueResult; - fn checked_add(self, other: Self) -> ValueResult>; - fn overflowing_add(self, other: Self) -> ValueResult<(Self, bool)>; - fn overflowing_sub(self, other: Self) -> ValueResult<(Self, bool)>; - fn overflowing_mul(self, other: Self) -> ValueResult<(Self, bool)>; + fn uadd_checked(self, other: Self) -> ValueResult>; + fn sadd_checked(self, other: Self) -> ValueResult>; + fn uadd_overflow(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 fn neg(self) -> ValueResult; @@ -57,13 +66,15 @@ pub trait DataValueExt: Sized { fn nearest(self) -> ValueResult; // Saturating arithmetic. - fn add_sat(self, other: Self) -> ValueResult; - fn sub_sat(self, other: Self) -> ValueResult; + fn uadd_sat(self, other: Self) -> ValueResult; + fn sadd_sat(self, other: Self) -> ValueResult; + fn usub_sat(self, other: Self) -> ValueResult; + fn ssub_sat(self, other: Self) -> ValueResult; // Bitwise. fn shl(self, other: Self) -> ValueResult; fn ushr(self, other: Self) -> ValueResult; - fn ishr(self, other: Self) -> ValueResult; + fn sshr(self, other: Self) -> ValueResult; fn rotl(self, other: Self) -> ValueResult; fn rotr(self, other: Self) -> ValueResult; fn and(self, other: Self) -> ValueResult; @@ -132,12 +143,6 @@ pub enum ValueConversionKind { /// Convert to a larger integer type, extending with zeroes; e.g. in `i8` to `i16`, `0xff` /// becomes `0x00ff`. 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. /// See `fdemote`, e.g. RoundNearestEven(Type), @@ -178,17 +183,23 @@ macro_rules! binary_match { _ => 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) { - $( (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!() } }; - ( 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) { $( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => { - let (f, s) = a.$op(*b); - Ok((DataValue::$data_value_ty(f), s)) + let (f, s) = (*a as $op_type).$op(*b as $op_type); + Ok((DataValue::$data_value_ty(f as _), s)) } )* _ => unimplemented!() } @@ -199,9 +210,15 @@ macro_rules! binary_match { _ => 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) { - $( (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!() } }; @@ -248,18 +265,24 @@ impl DataValueExt for DataValue { } } - fn into_int(self) -> ValueResult { + fn into_int_signed(self) -> ValueResult { match self { DataValue::I8(n) => Ok(n as i128), DataValue::I16(n) => Ok(n as i128), DataValue::I32(n) => Ok(n as i128), DataValue::I64(n) => Ok(n as i128), DataValue::I128(n) => Ok(n), - DataValue::U8(n) => Ok(n as i128), - 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), + _ => Err(ValueError::InvalidType(ValueTypeClass::Integer, self.ty())), + } + } + + fn into_int_unsigned(self) -> ValueResult { + 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())), } } @@ -361,7 +384,7 @@ impl DataValueExt for DataValue { ValueConversionKind::Exact(ty) => match (self, ty) { // TODO a lot to do here: from bmask to ireduce to bitcast... (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::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 truncated = self.into_int()? & mask; + let truncated = self.into_int_signed()? & mask; Self::from_integer(truncated, ty)? } ValueConversionKind::ExtractUpper(ty) => { @@ -395,88 +418,44 @@ impl DataValueExt for DataValue { let mask = (1 << (ty.bytes() * 8)) - 1i128; 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)? } 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::I32) => DataValue::I32(n as i32), (DataValue::I8(n), types::I64) => DataValue::I64(n as i64), (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::I64) => DataValue::I64(n as i64), (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::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), (dv, _) => unimplemented!("conversion: {} -> {:?}", dv.ty(), kind), }, 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::I32) => DataValue::I32(n as u8 as i32), (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::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::I64) => DataValue::I64(n as u16 as i64), (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::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), (from, to) if from.ty() == to => from, (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) { (DataValue::F64(n), types::F32) => DataValue::F32(Ieee32::from(n.as_f64() as f32)), (s, _) => unimplemented!("conversion: {} -> {:?}", s.ty(), kind), }, 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), }, ValueConversionKind::Mask(ty) => { @@ -511,7 +490,17 @@ impl DataValueExt for DataValue { } } - fn max(self, other: Self) -> ValueResult { + fn umax(self, other: Self) -> ValueResult { + 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 { if self > other { Ok(self) } else { @@ -519,7 +508,17 @@ impl DataValueExt for DataValue { } } - fn min(self, other: Self) -> ValueResult { + fn umin(self, other: Self) -> ValueResult { + 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 { if self < other { Ok(self) } else { @@ -535,7 +534,7 @@ impl DataValueExt for DataValue { if self.is_float() { binary_match!(+(self, other); [F32, F64]) } 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 { + fn sdiv(self, other: Self) -> ValueResult { if self.is_float() { 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. let min = DataValueExt::int(1i128 << (self.ty().bits() - 1), self.ty())?; @@ -572,11 +571,25 @@ impl DataValueExt for DataValue { 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 { - let denominator = other.clone().into_int()?; + fn udiv(self, other: Self) -> ValueResult { + 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 { + let denominator = other.clone().into_int_signed()?; // 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())?; @@ -588,7 +601,17 @@ impl DataValueExt for DataValue { 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 { + 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 { @@ -633,20 +656,36 @@ impl DataValueExt for DataValue { unary_match!(abs(&self); [F32, F64]) } - fn checked_add(self, other: Self) -> ValueResult> { - binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]) + fn sadd_checked(self, other: Self) -> ValueResult> { + 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)> { - binary_match!(pair overflowing_add(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]) + fn uadd_checked(self, other: Self) -> ValueResult> { + 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)> { - binary_match!(pair overflowing_sub(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]) + fn sadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> { + 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)> { - binary_match!(pair overflowing_mul(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]) + fn uadd_overflow(self, other: Self) -> ValueResult<(Self, bool)> { + 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 { @@ -673,47 +712,45 @@ impl DataValueExt for DataValue { unary_match!(round_ties_even(&self); [F32, F64]) } - fn add_sat(self, other: Self) -> ValueResult { - binary_match!(saturating_add(self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]) + fn sadd_sat(self, other: Self) -> ValueResult { + binary_match!(saturating_add(self, &other); [I8, I16, I32, I64, I128]) } - fn sub_sat(self, other: Self) -> ValueResult { - binary_match!(saturating_sub(self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]) + fn uadd_sat(self, other: Self) -> ValueResult { + binary_match!(saturating_add(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128]) + } + + fn ssub_sat(self, other: Self) -> ValueResult { + binary_match!(saturating_sub(self, &other); [I8, I16, I32, I64, I128]) + } + + fn usub_sat(self, other: Self) -> ValueResult { + binary_match!(saturating_sub(&self, &other); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128]) } fn shl(self, other: Self) -> ValueResult { - let amt = other - .convert(ValueConversionKind::Exact(types::I32))? - .convert(ValueConversionKind::ToUnsigned)?; - binary_match!(wrapping_shl(&self, &amt); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]; rhs: U32) + let amt = other.convert(ValueConversionKind::Exact(types::I32))?; + binary_match!(wrapping_shl(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32) } fn ushr(self, other: Self) -> ValueResult { - let amt = other - .convert(ValueConversionKind::Exact(types::I32))? - .convert(ValueConversionKind::ToUnsigned)?; - binary_match!(wrapping_shr(&self, &amt); [U8, U16, U32, U64, U128]; rhs: U32) + let amt = other.convert(ValueConversionKind::Exact(types::I32))?; + binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [u8, u16, u32, u64, u128]; rhs: I32,u32) } - fn ishr(self, other: Self) -> ValueResult { - let amt = other - .convert(ValueConversionKind::Exact(types::I32))? - .convert(ValueConversionKind::ToUnsigned)?; - binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; rhs: U32) + fn sshr(self, other: Self) -> ValueResult { + let amt = other.convert(ValueConversionKind::Exact(types::I32))?; + binary_match!(wrapping_shr(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32) } fn rotl(self, other: Self) -> ValueResult { - let amt = other - .convert(ValueConversionKind::Exact(types::I32))? - .convert(ValueConversionKind::ToUnsigned)?; - binary_match!(rotate_left(&self, &amt); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]; rhs: U32) + let amt = other.convert(ValueConversionKind::Exact(types::I32))?; + binary_match!(rotate_left(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32) } fn rotr(self, other: Self) -> ValueResult { - let amt = other - .convert(ValueConversionKind::Exact(types::I32))? - .convert(ValueConversionKind::ToUnsigned)?; - binary_match!(rotate_right(&self, &amt); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128]; rhs: U32) + let amt = other.convert(ValueConversionKind::Exact(types::I32))?; + binary_match!(rotate_right(&self, &amt); [I8, I16, I32, I64, I128]; [i8, i16, i32, i64, i128]; rhs: I32,u32) } fn and(self, other: Self) -> ValueResult { @@ -749,26 +786,26 @@ impl DataValueExt for DataValue { } fn count_ones(self) -> ValueResult { - 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 { - 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 { - 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 { - 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 { - 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 { - unary_match!(swap_bytes(&self); [I16, I32, I64, I128, U16, U32, U64, U128]) + unary_match!(swap_bytes(&self); [I16, I32, I64, I128]) } }