Implement real saturating behaviour for the saturating_* intrinsics with unsigned ints
This commit is contained in:
parent
6414f03644
commit
e7a507863c
@ -116,6 +116,74 @@ pub fn resolve_value_imm(func: &Function, val: Value) -> Option<u128> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn type_min_max_value<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (i64, i64) {
|
||||||
|
use syntax::ast::UintTy::*;
|
||||||
|
use syntax::ast::IntTy::*;
|
||||||
|
|
||||||
|
let uint_usize_cvt = |uint| {
|
||||||
|
match uint {
|
||||||
|
UintTy::Usize => match pointer_ty(tcx) {
|
||||||
|
types::I16 => UintTy::U16,
|
||||||
|
types::I32 => UintTy::U32,
|
||||||
|
types::I64 => UintTy::U64,
|
||||||
|
ty => unreachable!("{:?}", ty),
|
||||||
|
}
|
||||||
|
_ => uint,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let int_isize_cvt = |int| {
|
||||||
|
match int {
|
||||||
|
IntTy::Isize => match pointer_ty(tcx) {
|
||||||
|
types::I16 => IntTy::I16,
|
||||||
|
types::I32 => IntTy::I32,
|
||||||
|
types::I64 => IntTy::I64,
|
||||||
|
ty => unreachable!("{:?}", ty),
|
||||||
|
}
|
||||||
|
_ => int,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let min = match ty.sty {
|
||||||
|
ty::Uint(uint) => match uint_usize_cvt(uint) {
|
||||||
|
U8 | U16 | U32 | U64 => 0i64,
|
||||||
|
U128 => unimplemented!(),
|
||||||
|
Usize => unreachable!(),
|
||||||
|
}
|
||||||
|
ty::Int(int) => match int_isize_cvt(int) {
|
||||||
|
I8 => i8::min_value() as i64,
|
||||||
|
I16 => i16::min_value() as i64,
|
||||||
|
I32 => i32::min_value() as i64,
|
||||||
|
I64 => i64::min_value(),
|
||||||
|
I128 => unimplemented!(),
|
||||||
|
Isize => unreachable!(),
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let max = match ty.sty {
|
||||||
|
ty::Uint(uint) => match uint_usize_cvt(uint) {
|
||||||
|
U8 => u8::max_value() as i64,
|
||||||
|
U16 => u16::max_value() as i64,
|
||||||
|
U32 => u32::max_value() as i64,
|
||||||
|
U64 => u64::max_value() as i64,
|
||||||
|
U128 => unimplemented!(),
|
||||||
|
Usize => unreachable!(),
|
||||||
|
}
|
||||||
|
ty::Int(int) => match int_isize_cvt(int) {
|
||||||
|
I8 => i8::max_value() as i64,
|
||||||
|
I16 => i16::max_value() as i64,
|
||||||
|
I32 => i32::max_value() as i64,
|
||||||
|
I64 => i64::max_value(),
|
||||||
|
I128 => unimplemented!(),
|
||||||
|
Isize => unreachable!(),
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
(min, max)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct FunctionCx<'a, 'tcx: 'a, B: Backend> {
|
pub struct FunctionCx<'a, 'tcx: 'a, B: Backend> {
|
||||||
// FIXME use a reference to `CodegenCx` instead of `tcx`, `module` and `constants` and `caches`
|
// FIXME use a reference to `CodegenCx` instead of `tcx`, `module` and `constants` and `caches`
|
||||||
pub tcx: TyCtxt<'tcx>,
|
pub tcx: TyCtxt<'tcx>,
|
||||||
|
@ -470,25 +470,21 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
|
|||||||
"mul_with_overflow" => BinOp::Mul,
|
"mul_with_overflow" => BinOp::Mul,
|
||||||
_ => unimplemented!("intrinsic {}", intrinsic),
|
_ => unimplemented!("intrinsic {}", intrinsic),
|
||||||
};
|
};
|
||||||
let res = match T.sty {
|
|
||||||
ty::Uint(_) => crate::base::trans_checked_int_binop(
|
let signed = match T.sty {
|
||||||
fx,
|
ty::Uint(_) => false,
|
||||||
bin_op,
|
ty::Int(_) => true,
|
||||||
x,
|
_ => unimplemented!("{} for {:?}", intrinsic, T),
|
||||||
y,
|
|
||||||
ret.layout().ty,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
ty::Int(_) => crate::base::trans_checked_int_binop(
|
|
||||||
fx,
|
|
||||||
bin_op,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
ret.layout().ty,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
_ => panic!(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let res = crate::base::trans_checked_int_binop(
|
||||||
|
fx,
|
||||||
|
bin_op,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
ret.layout().ty,
|
||||||
|
signed,
|
||||||
|
);
|
||||||
ret.write_cvalue(fx, res);
|
ret.write_cvalue(fx, res);
|
||||||
};
|
};
|
||||||
_ if intrinsic.starts_with("overflowing_"), <T> (c x, c y) {
|
_ if intrinsic.starts_with("overflowing_"), <T> (c x, c y) {
|
||||||
@ -526,28 +522,44 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
|
|||||||
let bin_op = match intrinsic {
|
let bin_op = match intrinsic {
|
||||||
"saturating_add" => BinOp::Add,
|
"saturating_add" => BinOp::Add,
|
||||||
"saturating_sub" => BinOp::Sub,
|
"saturating_sub" => BinOp::Sub,
|
||||||
"saturating_mul" => BinOp::Mul,
|
|
||||||
_ => unimplemented!("intrinsic {}", intrinsic),
|
_ => unimplemented!("intrinsic {}", intrinsic),
|
||||||
};
|
};
|
||||||
let res = match T.sty {
|
|
||||||
ty::Uint(_) => crate::base::trans_int_binop(
|
let signed = match T.sty {
|
||||||
fx,
|
ty::Uint(_) => false,
|
||||||
bin_op,
|
ty::Int(_) => true,
|
||||||
x,
|
_ => unimplemented!("{} for {:?}", intrinsic, T),
|
||||||
y,
|
|
||||||
ret.layout().ty,
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
ty::Int(_) => crate::base::trans_int_binop(
|
|
||||||
fx,
|
|
||||||
bin_op,
|
|
||||||
x,
|
|
||||||
y,
|
|
||||||
ret.layout().ty,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
_ => panic!(),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let checked_res = crate::base::trans_checked_int_binop(
|
||||||
|
fx,
|
||||||
|
bin_op,
|
||||||
|
x,
|
||||||
|
y,
|
||||||
|
fx.tcx.mk_tup([T, fx.tcx.types.bool].into_iter()),
|
||||||
|
signed,
|
||||||
|
);
|
||||||
|
|
||||||
|
let (val, has_overflow) = checked_res.load_scalar_pair(fx);
|
||||||
|
let clif_ty = fx.clif_type(T).unwrap();
|
||||||
|
|
||||||
|
// `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(fx.tcx, T);
|
||||||
|
let min = fx.bcx.ins().iconst(clif_ty, min);
|
||||||
|
let max = fx.bcx.ins().iconst(clif_ty, max);
|
||||||
|
|
||||||
|
let val = match (intrinsic, signed) {
|
||||||
|
("saturating_add", false) => fx.bcx.ins().select(has_overflow, max, val),
|
||||||
|
("saturating_sub", false) => fx.bcx.ins().select(has_overflow, min, val),
|
||||||
|
("saturating_add", true) => unimplemented!(),
|
||||||
|
("saturating_sub", true) => unimplemented!(),
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let res = CValue::by_val(val, fx.layout_of(T));
|
||||||
|
|
||||||
ret.write_cvalue(fx, res);
|
ret.write_cvalue(fx, res);
|
||||||
};
|
};
|
||||||
rotate_left, <T>(v x, v y) {
|
rotate_left, <T>(v x, v y) {
|
||||||
|
Loading…
Reference in New Issue
Block a user