Browse Source

Merge pull request #80 from japaric/abort

panic! -> abort
Jorge Aparicio 8 years ago
parent
commit
c56faf22ab
7 changed files with 149 additions and 57 deletions
  1. 13 0
      ci/run.sh
  2. 52 45
      src/bin/intrinsics.rs
  3. 1 0
      src/float/mod.rs
  4. 2 3
      src/float/pow.rs
  5. 4 2
      src/int/sdiv.rs
  6. 16 7
      src/int/udiv.rs
  7. 61 0
      src/lib.rs

+ 13 - 0
ci/run.sh

@@ -28,6 +28,19 @@ case $1 in
         ;;
 esac
 
+# Verify that there are no undefined symbols to `panic` within our implementations
+# TODO(#79) fix the undefined references problem for debug-assertions+lto
+case $1 in
+    thumb*)
+        RUSTFLAGS="-C debug-assertions=no -C link-arg=-nostartfiles" xargo rustc --features c --target $1 --bin intrinsics -- -C lto
+        xargo rustc --features c --target $1 --bin intrinsics --release -- -C lto
+        ;;
+    *)
+        RUSTFLAGS="-C debug-assertions=no" cargo rustc --features c --target $1 --bin intrinsics -- -C lto
+        cargo rustc --features c --target $1 --bin intrinsics --release -- -C lto
+        ;;
+esac
+
 # Look out for duplicated symbols when we include the compiler-rt (C) implementation
 PREFIX=$(echo $1 | sed -e 's/unknown-//')-
 case $1 in

+ 52 - 45
src/bin/intrinsics.rs

@@ -4,13 +4,14 @@
 // to link due to the missing intrinsic (symbol).
 
 #![allow(unused_features)]
+#![cfg_attr(thumb, no_main)]
 #![deny(dead_code)]
+#![feature(asm)]
 #![feature(core_float)]
 #![feature(lang_items)]
 #![feature(libc)]
 #![feature(start)]
 #![no_std]
-#![cfg_attr(thumb, no_main)]
 
 #[cfg(not(thumb))]
 extern crate libc;
@@ -304,50 +305,56 @@ mod intrinsics {
 fn run() {
     use intrinsics::*;
 
-    aeabi_d2f(2.);
-    aeabi_d2i(2.);
-    aeabi_d2l(2.);
-    aeabi_d2uiz(2.);
-    aeabi_d2ulz(2.);
-    aeabi_dadd(2., 3.);
-    aeabi_dcmpeq(2., 3.);
-    aeabi_dcmpgt(2., 3.);
-    aeabi_dcmplt(2., 3.);
-    aeabi_ddiv(2., 3.);
-    aeabi_dmul(2., 3.);
-    aeabi_dsub(2., 3.);
-    aeabi_f2d(2.);
-    aeabi_f2iz(2.);
-    aeabi_f2lz(2.);
-    aeabi_f2uiz(2.);
-    aeabi_f2ulz(2.);
-    aeabi_fadd(2., 3.);
-    aeabi_fcmpeq(2., 3.);
-    aeabi_fcmpgt(2., 3.);
-    aeabi_fcmplt(2., 3.);
-    aeabi_fdiv(2., 3.);
-    aeabi_fmul(2., 3.);
-    aeabi_fsub(2., 3.);
-    aeabi_i2d(2);
-    aeabi_i2f(2);
-    aeabi_idiv(2, 3);
-    aeabi_idivmod(2, 3);
-    aeabi_l2d(2);
-    aeabi_l2f(2);
-    aeabi_ldivmod(2, 3);
-    aeabi_lmul(2, 3);
-    aeabi_ui2d(2);
-    aeabi_ui2f(2);
-    aeabi_uidiv(2, 3);
-    aeabi_uidivmod(2, 3);
-    aeabi_ul2d(2);
-    aeabi_ul2f(2);
-    aeabi_uldivmod(2, 3);
-    moddi3(2, 3);
-    mulodi4(2, 3);
-    powidf2(2., 3);
-    powisf2(2., 3);
-    umoddi3(2, 3);
+    // A copy of "test::black_box". Used to prevent LLVM from optimizing away the intrinsics during LTO
+    fn bb<T>(dummy: T) -> T {
+        unsafe { asm!("" : : "r"(&dummy)) }
+        dummy
+    }
+
+    bb(aeabi_d2f(bb(2.)));
+    bb(aeabi_d2i(bb(2.)));
+    bb(aeabi_d2l(bb(2.)));
+    bb(aeabi_d2uiz(bb(2.)));
+    bb(aeabi_d2ulz(bb(2.)));
+    bb(aeabi_dadd(bb(2.), bb(3.)));
+    bb(aeabi_dcmpeq(bb(2.), bb(3.)));
+    bb(aeabi_dcmpgt(bb(2.), bb(3.)));
+    bb(aeabi_dcmplt(bb(2.), bb(3.)));
+    bb(aeabi_ddiv(bb(2.), bb(3.)));
+    bb(aeabi_dmul(bb(2.), bb(3.)));
+    bb(aeabi_dsub(bb(2.), bb(3.)));
+    bb(aeabi_f2d(bb(2.)));
+    bb(aeabi_f2iz(bb(2.)));
+    bb(aeabi_f2lz(bb(2.)));
+    bb(aeabi_f2uiz(bb(2.)));
+    bb(aeabi_f2ulz(bb(2.)));
+    bb(aeabi_fadd(bb(2.), bb(3.)));
+    bb(aeabi_fcmpeq(bb(2.), bb(3.)));
+    bb(aeabi_fcmpgt(bb(2.), bb(3.)));
+    bb(aeabi_fcmplt(bb(2.), bb(3.)));
+    bb(aeabi_fdiv(bb(2.), bb(3.)));
+    bb(aeabi_fmul(bb(2.), bb(3.)));
+    bb(aeabi_fsub(bb(2.), bb(3.)));
+    bb(aeabi_i2d(bb(2)));
+    bb(aeabi_i2f(bb(2)));
+    bb(aeabi_idiv(bb(2), bb(3)));
+    bb(aeabi_idivmod(bb(2), bb(3)));
+    bb(aeabi_l2d(bb(2)));
+    bb(aeabi_l2f(bb(2)));
+    bb(aeabi_ldivmod(bb(2), bb(3)));
+    bb(aeabi_lmul(bb(2), bb(3)));
+    bb(aeabi_ui2d(bb(2)));
+    bb(aeabi_ui2f(bb(2)));
+    bb(aeabi_uidiv(bb(2), bb(3)));
+    bb(aeabi_uidivmod(bb(2), bb(3)));
+    bb(aeabi_ul2d(bb(2)));
+    bb(aeabi_ul2f(bb(2)));
+    bb(aeabi_uldivmod(bb(2), bb(3)));
+    bb(moddi3(bb(2), bb(3)));
+    bb(mulodi4(bb(2), bb(3)));
+    bb(powidf2(bb(2.), bb(3)));
+    bb(powisf2(bb(2.), bb(3)));
+    bb(umoddi3(bb(2), bb(3)));
 }
 
 #[cfg(all(feature = "c", not(thumb)))]

+ 1 - 0
src/float/mod.rs

@@ -1,4 +1,5 @@
 use core::mem;
+#[cfg(test)]
 use core::fmt;
 
 pub mod add;

+ 2 - 3
src/float/pow.rs

@@ -1,6 +1,5 @@
-
 macro_rules! pow {
-    ($intrinsic:ident: $fty:ty, $ity:ty) => {
+    ($intrinsic:ident: $fty:ty, $ity:ident) => {
         /// Returns `a` raised to the power `b`
         #[cfg_attr(not(test), no_mangle)]
         pub extern "C" fn $intrinsic(a: $fty, b: $ity) -> $fty {
@@ -11,7 +10,7 @@ macro_rules! pow {
                 if (b & 1) != 0 {
                     r *= a;
                 }
-                b /= 2;
+                b = sdiv!($ity, b, 2);
                 if b == 0 {
                     break;
                 }

+ 4 - 2
src/int/sdiv.rs

@@ -10,7 +10,8 @@ macro_rules! div {
             let a = (a ^ s_a) - s_a;
             let b = (b ^ s_b) - s_b;
             let s = s_a ^ s_b;
-            let r = (a as $uty) / (b as $uty);
+
+            let r = udiv!(a as $uty, b as $uty);
             (r as $ty ^ s) - s
         }
     }
@@ -25,7 +26,8 @@ macro_rules! mod_ {
             let b = (b ^ s) - s;
             let s = a >> (<$ty>::bits() - 1);
             let a = (a ^ s) - s;
-            let r = (a as $uty) % (b as $uty);
+
+            let r = urem!(a as $uty, b as $uty);
             (r as $ty ^ s) - s
         }
     }

+ 16 - 7
src/int/udiv.rs

@@ -1,4 +1,4 @@
-use core::mem;
+use core::{intrinsics, mem};
 use int::{Int, LargeInt};
 
 /// Returns `n / d`
@@ -7,7 +7,11 @@ use int::{Int, LargeInt};
 pub extern "C" fn __udivsi3(n: u32, d: u32) -> u32 {
     // Special cases
     if d == 0 {
-        panic!("Division by zero");
+        // NOTE This should be unreachable in safe Rust because the program will panic before
+        // this intrinsic is called
+        unsafe {
+            intrinsics::abort()
+        }
     }
 
     if n == 0 {
@@ -105,10 +109,11 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
             // 0 X
             // ---
             // 0 X
+
             if let Some(rem) = rem {
-                *rem = u64::from(n.low() % d.low());
+                *rem = u64::from(urem!(n.low(), d.low()));
             }
-            return u64::from(n.low() / d.low());
+            return u64::from(udiv!(n.low(), d.low()));
         } else {
             // 0 X
             // ---
@@ -129,7 +134,11 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
             // K X
             // ---
             // 0 0
-            panic!("Division by zero");
+            // NOTE This should be unreachable in safe Rust because the program will panic before
+            // this intrinsic is called
+            unsafe {
+                intrinsics::abort()
+            }
         }
 
         if n.low() == 0 {
@@ -137,9 +146,9 @@ pub extern "C" fn __udivmoddi4(n: u64, d: u64, rem: Option<&mut u64>) -> u64 {
             // ---
             // K 0
             if let Some(rem) = rem {
-                *rem = u64::from_parts(0, n.high() % d.high());
+                *rem = u64::from_parts(0, urem!(n.high(), d.high()));
             }
-            return u64::from(n.high() / d.high());
+            return u64::from(udiv!(n.high(), d.high()));
         }
 
         // K K

+ 61 - 0
src/lib.rs

@@ -13,6 +13,67 @@
 // NOTE cfg(all(feature = "c", ..)) indicate that compiler-rt provides an arch optimized
 // implementation of that intrinsic and we'll prefer to use that
 
+// TODO(rust-lang/rust#37029) use e.g. checked_div(_).unwrap_or_else(|| abort())
+macro_rules! udiv {
+    ($a:expr, $b:expr) => {
+        unsafe {
+            let a = $a;
+            let b = $b;
+
+            if b == 0 {
+                ::core::intrinsics::abort()
+            } else {
+                ::core::intrinsics::unchecked_div(a, b)
+            }
+        }
+    }
+}
+
+macro_rules! sdiv {
+    ($sty:ident, $a:expr, $b:expr) => {
+        unsafe {
+            let a = $a;
+            let b = $b;
+
+            if b == 0 || (b == -1 && a == $sty::min_value()) {
+                ::core::intrinsics::abort()
+            } else {
+                ::core::intrinsics::unchecked_div(a, b)
+            }
+        }
+    }
+}
+
+macro_rules! urem {
+    ($a:expr, $b:expr) => {
+        unsafe {
+            let a = $a;
+            let b = $b;
+
+            if b == 0 {
+                ::core::intrinsics::abort()
+            } else {
+                ::core::intrinsics::unchecked_rem(a, b)
+            }
+        }
+    }
+}
+
+macro_rules! srem {
+    ($sty:ty, $a:expr, $b:expr) => {
+        unsafe {
+            let a = $a;
+            let b = $b;
+
+            if b == 0 || (b == -1 && a == $sty::min_value()) {
+                ::core::intrinsics::abort()
+            } else {
+                ::core::intrinsics::unchecked_rem(a, b)
+            }
+        }
+    }
+}
+
 #[cfg(test)]
 #[macro_use]
 extern crate quickcheck;