Add {u,s}{add,sub,mul}_overflow instructions (#5784)

* add `{u,s}{add,sub,mul}_overflow` with interpreter

* add `{u,s}{add,sub,mul}_overflow` for x64

* add `{u,s}{add,sub,mul}_overflow` for aarch64

* 128bit filetests for `{u,s}{add,sub,mul}_overflow`

* `{u,s}{add,sub,mul}_overflow` emit tests for x64

* `{u,s}{add,sub,mul}_overflow` emit tests for aarch64

* Initial review changes

* add `with_flags_extended` helper

* add `with_flags_chained` helper
This commit is contained in:
T0b1-iOS
2023-04-11 22:16:04 +02:00
committed by GitHub
parent 4c32dd7786
commit 569089e473
27 changed files with 2195 additions and 99 deletions

View File

@@ -752,6 +752,48 @@ where
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::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)?;
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)?;
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)?;
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)?;
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)?;
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)?;
assign_multiple(&[sum, DataValueExt::bool(carry, false, types::I8)?])
}
Opcode::IaddCin => choose(
DataValueExt::into_bool(arg(2))?,
DataValueExt::add(

View File

@@ -44,6 +44,9 @@ pub trait DataValueExt: Sized {
fn fma(self, a: Self, b: Self) -> ValueResult<Self>;
fn abs(self) -> ValueResult<Self>;
fn checked_add(self, other: Self) -> ValueResult<Option<Self>>;
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)>;
// Float operations
fn neg(self) -> ValueResult<Self>;
@@ -181,6 +184,15 @@ macro_rules! binary_match {
_ => unimplemented!()
}
};
( pair $op:ident($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ] ) => {
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))
} )*
_ => unimplemented!()
}
};
( $op:tt($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ] ) => {
match ($arg1, $arg2) {
$( (DataValue::$data_value_ty(a), DataValue::$data_value_ty(b)) => { Ok(DataValue::$data_value_ty(a $op b)) } )*
@@ -439,6 +451,11 @@ impl DataValueExt for DataValue {
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 {
@@ -447,6 +464,11 @@ impl DataValueExt for DataValue {
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) {
@@ -615,6 +637,18 @@ impl DataValueExt for DataValue {
binary_match!(option checked_add(&self, &other); [I8, I16, I32, I64, I128, U8, U16, U32, U64, U128])
}
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 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 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 neg(self) -> ValueResult<Self> {
unary_match!(neg(&self); [F32, F64])
}