Fix saturated_* intrinsics for 128bit ints

Fixes #968
This commit is contained in:
bjorn3 2020-04-17 14:14:18 +02:00
parent 9a378c3f3f
commit cd684e39e0
3 changed files with 36 additions and 7 deletions

View File

@ -159,7 +159,13 @@ pub(crate) fn clif_int_or_float_cast(
} else {
fx.bcx.ins().fcvt_to_uint_sat(types::I32, from)
};
let (min, max) = type_min_max_value(to_ty, to_signed);
let (min, max) = match (to_ty, to_signed) {
(types::I8, false) => (0, u8::MAX as i64),
(types::I16, false) => (0, u16::MAX as i64),
(types::I8, true) => (i8::MIN as i64, i8::MAX as i64),
(types::I16, true) => (i16::MIN as i64, i16::MAX as i64),
_ => unreachable!(),
};
let min_val = fx.bcx.ins().iconst(types::I32, min);
let max_val = fx.bcx.ins().iconst(types::I32, max);

View File

@ -215,8 +215,33 @@ pub(crate) fn resolve_value_imm(func: &Function, val: Value) -> Option<u128> {
}
}
pub(crate) fn type_min_max_value(ty: Type, signed: bool) -> (i64, i64) {
pub(crate) fn type_min_max_value(bcx: &mut FunctionBuilder<'_>, ty: Type, signed: bool) -> (Value, Value) {
assert!(ty.is_int());
if ty == types::I128 {
if signed {
let min = i128::MIN as u128;
let min_lsb = bcx.ins().iconst(types::I64, min as u64 as i64);
let min_msb = bcx.ins().iconst(types::I64, (min >> 64) as u64 as i64);
let min = bcx.ins().iconcat(min_lsb, min_msb);
let max = i128::MIN as u128;
let max_lsb = bcx.ins().iconst(types::I64, max as u64 as i64);
let max_msb = bcx.ins().iconst(types::I64, (max >> 64) as u64 as i64);
let max = bcx.ins().iconcat(max_lsb, max_msb);
return (min, max);
} else {
let min_half = bcx.ins().iconst(types::I64, 0);
let min = bcx.ins().iconcat(min_half, min_half);
let max_half = bcx.ins().iconst(types::I64, u64::MAX as i64);
let max = bcx.ins().iconcat(max_half, max_half);
return (min, max);
}
}
let min = match (ty, signed) {
(types::I8, false) | (types::I16, false) | (types::I32, false) | (types::I64, false) => {
0i64
@ -225,7 +250,6 @@ pub(crate) fn type_min_max_value(ty: Type, signed: bool) -> (i64, i64) {
(types::I16, true) => i16::MIN as i64,
(types::I32, true) => i32::MIN as i64,
(types::I64, true) => i64::MIN,
(types::I128, _) => unimplemented!(),
_ => unreachable!(),
};
@ -238,10 +262,11 @@ pub(crate) fn type_min_max_value(ty: Type, signed: bool) -> (i64, i64) {
(types::I16, true) => i16::MAX as i64,
(types::I32, true) => i32::MAX as i64,
(types::I64, true) => i64::MAX,
(types::I128, _) => unimplemented!(),
_ => unreachable!(),
};
let (min, max) = (bcx.ins().iconst(ty, min), bcx.ins().iconst(ty, max));
(min, max)
}

View File

@ -583,9 +583,7 @@ pub(crate) fn codegen_intrinsic_call<'tcx>(
// `select.i8` is not implemented by Cranelift.
let has_overflow = fx.bcx.ins().uextend(types::I32, has_overflow);
let (min, max) = type_min_max_value(clif_ty, signed);
let min = fx.bcx.ins().iconst(clif_ty, min);
let max = fx.bcx.ins().iconst(clif_ty, max);
let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed);
let val = match (intrinsic, signed) {
("saturating_add", false) => fx.bcx.ins().select(has_overflow, max, val),