Merge pull request #646 from bjorn3/wip_checked_binops2

Implement checked add and sub
This commit is contained in:
bjorn3 2019-07-26 11:37:21 +02:00 committed by GitHub
commit bba11f6172
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 119 additions and 11 deletions

View file

@ -128,6 +128,14 @@ impl Add for u8 {
}
}
impl Add for i8 {
type Output = Self;
fn add(self, rhs: Self) -> Self {
self + rhs
}
}
impl Add for usize {
type Output = Self;
@ -151,6 +159,30 @@ impl Sub for usize {
}
}
impl Sub for u8 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for i8 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
impl Sub for i16 {
type Output = Self;
fn sub(self, rhs: Self) -> Self {
self - rhs
}
}
#[lang = "bitor"]
pub trait BitOr<RHS = Self> {
type Output;
@ -270,6 +302,22 @@ pub trait Neg {
fn neg(self) -> Self::Output;
}
impl Neg for i8 {
type Output = i8;
fn neg(self) -> i8 {
-self
}
}
impl Neg for i16 {
type Output = i16;
fn neg(self) -> i16 {
-self
}
}
impl Neg for isize {
type Output = isize;

View file

@ -236,4 +236,21 @@ fn main() {
unsafe { assert_eq!(ABC as usize, 0); }
&mut (|| Some(0 as *const ())) as &mut FnMut() -> Option<*const ()>;
// checked binops
let zeroi8 = 0i8;
let oneu8 = 1u8;
let onei8 = 1i8;
zeroi8 - 1;
oneu8 - 1;
zeroi8 - -2i8;
#[allow(unreachable_code)]
{
if false {
let minustwoi8 = -2i8;
oneu8 + 255;
onei8 + 127;
minustwoi8 - 127;
}
}
}

View file

@ -241,7 +241,7 @@ fn codegen_fn_content<'a, 'tcx: 'a>(fx: &mut FunctionCx<'a, 'tcx, impl Backend>)
} else {
fx.bcx.ins().brz(cond, target, &[]);
};
trap_panic(fx, format!("[panic] Assert {:?} failed.", msg));
trap_panic(fx, format!("[panic] Assert {:?} failed at {:?}.", msg, bb_data.terminator().source_info.span));
}
TerminatorKind::SwitchInt {
@ -948,17 +948,62 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
let lhs = in_lhs.load_scalar(fx);
let rhs = in_rhs.load_scalar(fx);
let res = match bin_op {
BinOp::Add => fx.bcx.ins().iadd(lhs, rhs),
BinOp::Sub => fx.bcx.ins().isub(lhs, rhs),
BinOp::Mul => fx.bcx.ins().imul(lhs, rhs),
BinOp::Shl => fx.bcx.ins().ishl(lhs, rhs),
let (res, has_overflow) = match bin_op {
BinOp::Add => {
/*let (val, c_out) = fx.bcx.ins().iadd_cout(lhs, rhs);
(val, c_out)*/
// FIXME(CraneStation/cranelift#849) legalize iadd_cout for i8 and i16
let val = fx.bcx.ins().iadd(lhs, rhs);
let has_overflow = if !signed {
fx.bcx.ins().icmp(IntCC::UnsignedLessThan, val, lhs)
} else {
let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
let slt = fx.bcx.ins().icmp(IntCC::SignedLessThan, val, lhs);
fx.bcx.ins().bxor(rhs_is_negative, slt)
};
(val, has_overflow)
}
BinOp::Sub => {
/*let (val, b_out) = fx.bcx.ins().isub_bout(lhs, rhs);
(val, b_out)*/
// FIXME(CraneStation/cranelift#849) legalize isub_bout for i8 and i16
let val = fx.bcx.ins().isub(lhs, rhs);
let has_overflow = if !signed {
fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, val, lhs)
} else {
let rhs_is_negative = fx.bcx.ins().icmp_imm(IntCC::SignedLessThan, rhs, 0);
let sgt = fx.bcx.ins().icmp(IntCC::SignedGreaterThan, val, lhs);
fx.bcx.ins().bxor(rhs_is_negative, sgt)
};
(val, has_overflow)
}
BinOp::Mul => {
let val = fx.bcx.ins().imul(lhs, rhs);
/*let val_hi = if !signed {
fx.bcx.ins().umulhi(lhs, rhs)
} else {
fx.bcx.ins().smulhi(lhs, rhs)
};
let has_overflow = fx.bcx.ins().icmp_imm(IntCC::NotEqual, val_hi, 0);*/
// TODO: check for overflow
let has_overflow = fx.bcx.ins().bconst(types::B1, false);
(val, has_overflow)
}
BinOp::Shl => {
let val = fx.bcx.ins().ishl(lhs, rhs);
// TODO: check for overflow
let has_overflow = fx.bcx.ins().bconst(types::B1, false);
(val, has_overflow)
}
BinOp::Shr => {
if !signed {
let val = if !signed {
fx.bcx.ins().ushr(lhs, rhs)
} else {
fx.bcx.ins().sshr(lhs, rhs)
}
};
// TODO: check for overflow
let has_overflow = fx.bcx.ins().bconst(types::B1, false);
(val, has_overflow)
}
_ => bug!(
"binop {:?} on checked int/uint lhs: {:?} rhs: {:?}",
@ -968,9 +1013,7 @@ pub fn trans_checked_int_binop<'a, 'tcx: 'a>(
),
};
// TODO: check for overflow
let has_overflow = fx.bcx.ins().iconst(types::I8, 0);
let has_overflow = fx.bcx.ins().bint(types::I8, has_overflow);
let out_place = CPlace::new_stack_slot(fx, out_ty);
let out_layout = out_place.layout();
out_place.write_cvalue(fx, CValue::by_val_pair(res, has_overflow, out_layout));