Skip to content

Commit

Permalink
omit bounds check in release mode
Browse files Browse the repository at this point in the history
this eliminates panicking branches in the optimized version of the functions. We keep the bounds
checks when running the test suite to check that we never do an out of bounds access.

This commit also adds a "must link" test that ensures that future changes in our implementation
won't add panicking branches.

closes #129
  • Loading branch information
japaric committed Jul 25, 2018
1 parent 861720b commit ce02130
Show file tree
Hide file tree
Showing 7 changed files with 233 additions and 52 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ name = "libm"
repository = "https://github.com/japaric/libm"
version = "0.1.2"

[features]
# only used to run our test suite
checked = []

[workspace]
members = ["cb", "test-generator"]
14 changes: 12 additions & 2 deletions ci/script.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,21 @@ main() {
# check that we can source import libm into compiler-builtins
cargo check --package cb

# test that the functions don't contain invocations of `panic!`
case $TARGET in
armv7-unknown-linux-gnueabihf)
cross build --release --target $TARGET --example no-panic
;;
esac

# run unit tests
cross test --lib --features checked --target $TARGET --release

# generate tests
cargo run --package test-generator --target x86_64-unknown-linux-musl

# run tests
cross test --target $TARGET --release
# run generated tests
cross test --tests --features checked --target $TARGET --release

# TODO need to fix overflow issues (cf. issue #4)
# cross test --target $TARGET
Expand Down
115 changes: 115 additions & 0 deletions examples/no-panic.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#![feature(lang_items)]
#![feature(panic_implementation)]
#![no_main]
#![no_std]

extern crate libm;

use core::panic::PanicInfo;
use core::ptr;

macro_rules! force_eval {
($e:expr) => {
unsafe {
core::ptr::read_volatile(&$e);
}
};
}

#[no_mangle]
pub fn main() {
force_eval!(libm::acos(random()));
force_eval!(libm::acosf(random()));
force_eval!(libm::asin(random()));
force_eval!(libm::asinf(random()));
force_eval!(libm::atan(random()));
force_eval!(libm::atan2(random(), random()));
force_eval!(libm::atan2f(random(), random()));
force_eval!(libm::atanf(random()));
force_eval!(libm::cbrt(random()));
force_eval!(libm::cbrtf(random()));
force_eval!(libm::ceil(random()));
force_eval!(libm::ceilf(random()));
force_eval!(libm::cos(random()));
force_eval!(libm::cosf(random()));
force_eval!(libm::cosh(random()));
force_eval!(libm::coshf(random()));
force_eval!(libm::exp(random()));
force_eval!(libm::exp2(random()));
force_eval!(libm::exp2f(random()));
force_eval!(libm::expf(random()));
force_eval!(libm::expm1(random()));
force_eval!(libm::expm1f(random()));
force_eval!(libm::fabs(random()));
force_eval!(libm::fabsf(random()));
force_eval!(libm::fdim(random(), random()));
force_eval!(libm::fdimf(random(), random()));
force_eval!(libm::floor(random()));
force_eval!(libm::floorf(random()));
force_eval!(libm::fma(random(), random(), random()));
force_eval!(libm::fmaf(random(), random(), random()));
force_eval!(libm::fmod(random(), random()));
force_eval!(libm::fmodf(random(), random()));
force_eval!(libm::hypot(random(), random()));
force_eval!(libm::hypotf(random(), random()));
force_eval!(libm::log(random()));
force_eval!(libm::log2(random()));
force_eval!(libm::log10(random()));
force_eval!(libm::log10f(random()));
force_eval!(libm::log1p(random()));
force_eval!(libm::log1pf(random()));
force_eval!(libm::log2f(random()));
force_eval!(libm::logf(random()));
force_eval!(libm::pow(random(), random()));
force_eval!(libm::powf(random(), random()));
force_eval!(libm::round(random()));
force_eval!(libm::roundf(random()));
force_eval!(libm::scalbn(random(), random()));
force_eval!(libm::scalbnf(random(), random()));
force_eval!(libm::sin(random()));
force_eval!(libm::sinf(random()));
force_eval!(libm::sinh(random()));
force_eval!(libm::sinhf(random()));
force_eval!(libm::sqrt(random()));
force_eval!(libm::sqrtf(random()));
force_eval!(libm::tan(random()));
force_eval!(libm::tanf(random()));
force_eval!(libm::tanh(random()));
force_eval!(libm::tanhf(random()));
force_eval!(libm::trunc(random()));
force_eval!(libm::truncf(random()));
}

fn random<T>() -> T
where
T: Copy,
{
unsafe {
static mut X: usize = 0;
X += 8;
ptr::read_volatile(X as *const T)
}
}

#[panic_implementation]
#[no_mangle]
pub fn panic(_info: &PanicInfo) -> ! {
// loop {}
extern "C" {
fn thou_shalt_not_panic() -> !;
}

unsafe { thou_shalt_not_panic() }
}

#[link(name = "c")]
extern "C" {}

#[lang = "eh_personality"]
fn eh() {}

#[no_mangle]
pub extern "C" fn __aeabi_unwind_cpp_pr0() {}

#[no_mangle]
pub extern "C" fn __aeabi_unwind_cpp_pr1() {}
2 changes: 1 addition & 1 deletion src/math/atan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ pub fn atan(x: f64) -> f64 {
return x - x * (s1 + s2);
}

let z = ATANHI[id as usize] - (x * (s1 + s2) - ATANLO[id as usize] - x);
let z = i!(ATANHI, id as usize) - (x * (s1 + s2) - i!(ATANLO, id as usize) - x);

if sign != 0 {
-z
Expand Down
44 changes: 44 additions & 0 deletions src/math/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,50 @@ macro_rules! force_eval {
};
}

#[cfg(not(feature = "checked"))]
macro_rules! i {
($array:expr, $index:expr) => {
unsafe { *$array.get_unchecked($index) }
};
($array:expr, $index:expr, =, $rhs:expr) => {
unsafe { *$array.get_unchecked_mut($index) = $rhs; }
};
($array:expr, $index:expr, +=, $rhs:expr) => {
unsafe { *$array.get_unchecked_mut($index) += $rhs; }
};
($array:expr, $index:expr, -=, $rhs:expr) => {
unsafe { *$array.get_unchecked_mut($index) -= $rhs; }
};
($array:expr, $index:expr, &=, $rhs:expr) => {
unsafe { *$array.get_unchecked_mut($index) &= $rhs; }
};
($array:expr, $index:expr, ==, $rhs:expr) => {
unsafe { *$array.get_unchecked_mut($index) == $rhs }
};
}

#[cfg(feature = "checked")]
macro_rules! i {
($array:expr, $index:expr) => {
*$array.get($index).unwrap()
};
($array:expr, $index:expr, =, $rhs:expr) => {
*$array.get_mut($index).unwrap() = $rhs;
};
($array:expr, $index:expr, -=, $rhs:expr) => {
*$array.get_mut($index).unwrap() -= $rhs;
};
($array:expr, $index:expr, +=, $rhs:expr) => {
*$array.get_mut($index).unwrap() += $rhs;
};
($array:expr, $index:expr, &=, $rhs:expr) => {
*$array.get_mut($index).unwrap() &= $rhs;
};
($array:expr, $index:expr, ==, $rhs:expr) => {
*$array.get_mut($index).unwrap() == $rhs
};
}

// Public modules
mod acos;
mod acosf;
Expand Down
2 changes: 1 addition & 1 deletion src/math/rem_pio2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ pub fn rem_pio2(x: f64) -> (i32, f64, f64) {
tx[2] = z;
/* skip zero terms, first term is non-zero */
let mut i = 2;
while tx[i] == 0.0 {
while i != 0 && tx[i] == 0.0 {
i -= 1;
}
let mut ty = [0.0; 3];
Expand Down
Loading

0 comments on commit ce02130

Please sign in to comment.