cranelift: Fix shifts and implement rotates in interpreter (#4519)
* cranelift: Fix shifts and implement rotates in interpreter * x64: Implement `rotl`/`rotr` for some small type combinations
This commit is contained in:
@@ -153,6 +153,20 @@ where
|
||||
right: V|
|
||||
-> ValueResult<ControlFlow<V>> { Ok(assign(op(left, right)?)) };
|
||||
|
||||
// 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(V, V) -> ValueResult<V>, left: V, right: V| -> ValueResult<ControlFlow<V>> {
|
||||
Ok(assign(
|
||||
op(
|
||||
left.convert(ValueConversionKind::ToUnsigned)?,
|
||||
right.convert(ValueConversionKind::ToUnsigned)?,
|
||||
)
|
||||
.and_then(|v| v.convert(ValueConversionKind::ToSigned))?,
|
||||
))
|
||||
};
|
||||
|
||||
// Similar to `binary` but converts select `ValueError`'s into trap `ControlFlow`'s
|
||||
let binary_can_trap = |op: fn(V, V) -> ValueResult<V>,
|
||||
left: V,
|
||||
@@ -690,10 +704,10 @@ where
|
||||
Opcode::RotlImm => binary(Value::rotl, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::RotrImm => binary(Value::rotr, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::Ishl => binary(Value::shl, arg(0)?, arg(1)?)?,
|
||||
Opcode::Ushr => binary(Value::ushr, arg(0)?, arg(1)?)?,
|
||||
Opcode::Ushr => binary_unsigned(Value::ushr, arg(0)?, arg(1)?)?,
|
||||
Opcode::Sshr => binary(Value::ishr, arg(0)?, arg(1)?)?,
|
||||
Opcode::IshlImm => binary(Value::shl, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::UshrImm => binary(Value::ushr, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::UshrImm => binary_unsigned(Value::ushr, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::SshrImm => binary(Value::ishr, arg(0)?, imm_as_ctrl_ty()?)?,
|
||||
Opcode::Bitrev => assign(Value::reverse_bits(arg(0)?)?),
|
||||
Opcode::Clz => assign(arg(0)?.leading_zeros()?),
|
||||
|
||||
@@ -191,12 +191,19 @@ macro_rules! binary_match {
|
||||
_ => unimplemented!()
|
||||
}
|
||||
};
|
||||
( $op:tt($arg1:expr, $arg2:expr); unsigned integers ) => {
|
||||
( $op:tt($arg1:expr, $arg2:expr); [ $( $data_value_ty:ident ),* ]; rhs: $rhs:tt ) => {
|
||||
match ($arg1, $arg2) {
|
||||
(DataValue::I8(a), DataValue::I8(b)) => { Ok(DataValue::I8((u8::try_from(*a)? $op u8::try_from(*b)?) as i8)) }
|
||||
(DataValue::I16(a), DataValue::I16(b)) => { Ok(DataValue::I16((u16::try_from(*a)? $op u16::try_from(*b)?) as i16)) }
|
||||
(DataValue::I32(a), DataValue::I32(b)) => { Ok(DataValue::I32((u32::try_from(*a)? $op u32::try_from(*b)?) as i32)) }
|
||||
(DataValue::I64(a), DataValue::I64(b)) => { Ok(DataValue::I64((u64::try_from(*a)? $op u64::try_from(*b)?) as i64)) }
|
||||
$( (DataValue::$data_value_ty(a), DataValue::$rhs(b)) => { Ok(DataValue::$data_value_ty(a.$op(*b))) } )*
|
||||
_ => unimplemented!()
|
||||
}
|
||||
};
|
||||
( $op:ident($arg1:expr, $arg2:expr); unsigned integers ) => {
|
||||
match ($arg1, $arg2) {
|
||||
(DataValue::I8(a), DataValue::I8(b)) => { Ok(DataValue::I8((u8::try_from(*a)?.$op(u8::try_from(*b)?) as i8))) }
|
||||
(DataValue::I16(a), DataValue::I16(b)) => { Ok(DataValue::I16((u16::try_from(*a)?.$op(u16::try_from(*b)?) as i16))) }
|
||||
(DataValue::I32(a), DataValue::I32(b)) => { Ok(DataValue::I32((u32::try_from(*a)?.$op(u32::try_from(*b)?) as i32))) }
|
||||
(DataValue::I64(a), DataValue::I64(b)) => { Ok(DataValue::I64((u64::try_from(*a)?.$op(u64::try_from(*b)?) as i64))) }
|
||||
(DataValue::I128(a), DataValue::I128(b)) => { Ok(DataValue::I128((u128::try_from(*a)?.$op(u128::try_from(*b)?) as i64))) }
|
||||
_ => { Err(ValueError::InvalidType(ValueTypeClass::Integer, if !($arg1).ty().is_int() { ($arg1).ty() } else { ($arg2).ty() })) }
|
||||
}
|
||||
};
|
||||
@@ -306,7 +313,9 @@ impl Value for DataValue {
|
||||
Ok(match kind {
|
||||
ValueConversionKind::Exact(ty) => match (self, ty) {
|
||||
// TODO a lot to do here: from bmask to ireduce to raw_bitcast...
|
||||
(DataValue::I64(n), ty) if ty.is_int() => DataValue::from_integer(n as i128, ty)?,
|
||||
(val, ty) if val.ty().is_int() && ty.is_int() => {
|
||||
DataValue::from_integer(val.into_int()?, ty)?
|
||||
}
|
||||
(DataValue::F32(n), types::I32) => DataValue::I32(n.bits() as i32),
|
||||
(DataValue::F64(n), types::I64) => DataValue::I64(n.bits() as i64),
|
||||
(DataValue::B(b), t) if t.is_bool() => DataValue::B(b),
|
||||
@@ -623,23 +632,38 @@ impl Value for DataValue {
|
||||
}
|
||||
|
||||
fn shl(self, other: Self) -> ValueResult<Self> {
|
||||
binary_match!(<<(&self, &other); [I8, I16, I32, I64])
|
||||
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)
|
||||
}
|
||||
|
||||
fn ushr(self, other: Self) -> ValueResult<Self> {
|
||||
binary_match!(>>(&self, &other); unsigned integers)
|
||||
let amt = other
|
||||
.convert(ValueConversionKind::Exact(types::I32))?
|
||||
.convert(ValueConversionKind::ToUnsigned)?;
|
||||
binary_match!(wrapping_shr(&self, &amt); [U8, U16, U32, U64, U128]; rhs: U32)
|
||||
}
|
||||
|
||||
fn ishr(self, other: Self) -> ValueResult<Self> {
|
||||
binary_match!(>>(&self, &other); [I8, I16, I32, I64])
|
||||
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 rotl(self, _other: Self) -> ValueResult<Self> {
|
||||
unimplemented!()
|
||||
fn rotl(self, other: Self) -> ValueResult<Self> {
|
||||
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)
|
||||
}
|
||||
|
||||
fn rotr(self, _other: Self) -> ValueResult<Self> {
|
||||
unimplemented!()
|
||||
fn rotr(self, other: Self) -> ValueResult<Self> {
|
||||
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)
|
||||
}
|
||||
|
||||
fn and(self, other: Self) -> ValueResult<Self> {
|
||||
|
||||
Reference in New Issue
Block a user