about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbjorn3 <bjorn3@users.noreply.github.com>2019-07-13 16:55:08 +0200
committerbjorn3 <bjorn3@users.noreply.github.com>2019-07-26 11:19:14 +0200
commitbf3ec3be3e595780d842ac3069bb07f3c50f54b8 (patch)
treef77ff990d44133e29c96ef03f825d9a9e1f46db1
parent92f2b6243d717b6ff711fdf9fe9d579d41669ee1 (diff)
downloadrust-bf3ec3be3e595780d842ac3069bb07f3c50f54b8.tar.gz
rust-bf3ec3be3e595780d842ac3069bb07f3c50f54b8.zip
Implement checked binops
-rw-r--r--example/mini_core.rs48
-rw-r--r--example/mini_core_hello_world.rs17
-rw-r--r--src/base.rs65
3 files changed, 119 insertions, 11 deletions
diff --git a/example/mini_core.rs b/example/mini_core.rs
index d900776c55c..8c372450abd 100644
--- a/example/mini_core.rs
+++ b/example/mini_core.rs
@@ -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;
 
diff --git a/example/mini_core_hello_world.rs b/example/mini_core_hello_world.rs
index e51f257f6b4..15f0442b624 100644
--- a/example/mini_core_hello_world.rs
+++ b/example/mini_core_hello_world.rs
@@ -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;
+        }
+    }
 }
diff --git a/src/base.rs b/src/base.rs
index 1adcec046e0..7b29d15e56b 100644
--- a/src/base.rs
+++ b/src/base.rs
@@ -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));