}
}
+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> {
// FIXME use a reference to `CodegenCx` instead of `tcx`, `module` and `constants` and `caches`
pub tcx: TyCtxt<'tcx>,
"mul_with_overflow" => BinOp::Mul,
_ => unimplemented!("intrinsic {}", intrinsic),
};
- let res = match T.sty {
- ty::Uint(_) => crate::base::trans_checked_int_binop(
- fx,
- bin_op,
- x,
- y,
- ret.layout().ty,
- false,
- ),
- ty::Int(_) => crate::base::trans_checked_int_binop(
- fx,
- bin_op,
- x,
- y,
- ret.layout().ty,
- true,
- ),
- _ => panic!(),
+
+ let signed = match T.sty {
+ ty::Uint(_) => false,
+ ty::Int(_) => true,
+ _ => unimplemented!("{} for {:?}", intrinsic, T),
};
+
+ let res = crate::base::trans_checked_int_binop(
+ fx,
+ bin_op,
+ x,
+ y,
+ ret.layout().ty,
+ signed,
+ );
ret.write_cvalue(fx, res);
};
_ if intrinsic.starts_with("overflowing_"), <T> (c x, c y) {
let bin_op = match intrinsic {
"saturating_add" => BinOp::Add,
"saturating_sub" => BinOp::Sub,
- "saturating_mul" => BinOp::Mul,
_ => unimplemented!("intrinsic {}", intrinsic),
};
- let res = match T.sty {
- ty::Uint(_) => crate::base::trans_int_binop(
- fx,
- bin_op,
- x,
- y,
- ret.layout().ty,
- false,
- ),
- ty::Int(_) => crate::base::trans_int_binop(
- fx,
- bin_op,
- x,
- y,
- ret.layout().ty,
- true,
- ),
- _ => panic!(),
+
+ let signed = match T.sty {
+ ty::Uint(_) => false,
+ ty::Int(_) => true,
+ _ => unimplemented!("{} for {:?}", intrinsic, T),
};
+
+ 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);
};
rotate_left, <T>(v x, v y) {