Skip to content

Commit ce02130

Browse files
committed
omit bounds check in release mode
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 rust-lang#129
1 parent 861720b commit ce02130

File tree

7 files changed

+233
-52
lines changed

7 files changed

+233
-52
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,9 @@ name = "libm"
99
repository = "https://github.com/japaric/libm"
1010
version = "0.1.2"
1111

12+
[features]
13+
# only used to run our test suite
14+
checked = []
15+
1216
[workspace]
1317
members = ["cb", "test-generator"]

ci/script.sh

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,21 @@ main() {
1212
# check that we can source import libm into compiler-builtins
1313
cargo check --package cb
1414

15+
# test that the functions don't contain invocations of `panic!`
16+
case $TARGET in
17+
armv7-unknown-linux-gnueabihf)
18+
cross build --release --target $TARGET --example no-panic
19+
;;
20+
esac
21+
22+
# run unit tests
23+
cross test --lib --features checked --target $TARGET --release
24+
1525
# generate tests
1626
cargo run --package test-generator --target x86_64-unknown-linux-musl
1727

18-
# run tests
19-
cross test --target $TARGET --release
28+
# run generated tests
29+
cross test --tests --features checked --target $TARGET --release
2030

2131
# TODO need to fix overflow issues (cf. issue #4)
2232
# cross test --target $TARGET

examples/no-panic.rs

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
#![feature(lang_items)]
2+
#![feature(panic_implementation)]
3+
#![no_main]
4+
#![no_std]
5+
6+
extern crate libm;
7+
8+
use core::panic::PanicInfo;
9+
use core::ptr;
10+
11+
macro_rules! force_eval {
12+
($e:expr) => {
13+
unsafe {
14+
core::ptr::read_volatile(&$e);
15+
}
16+
};
17+
}
18+
19+
#[no_mangle]
20+
pub fn main() {
21+
force_eval!(libm::acos(random()));
22+
force_eval!(libm::acosf(random()));
23+
force_eval!(libm::asin(random()));
24+
force_eval!(libm::asinf(random()));
25+
force_eval!(libm::atan(random()));
26+
force_eval!(libm::atan2(random(), random()));
27+
force_eval!(libm::atan2f(random(), random()));
28+
force_eval!(libm::atanf(random()));
29+
force_eval!(libm::cbrt(random()));
30+
force_eval!(libm::cbrtf(random()));
31+
force_eval!(libm::ceil(random()));
32+
force_eval!(libm::ceilf(random()));
33+
force_eval!(libm::cos(random()));
34+
force_eval!(libm::cosf(random()));
35+
force_eval!(libm::cosh(random()));
36+
force_eval!(libm::coshf(random()));
37+
force_eval!(libm::exp(random()));
38+
force_eval!(libm::exp2(random()));
39+
force_eval!(libm::exp2f(random()));
40+
force_eval!(libm::expf(random()));
41+
force_eval!(libm::expm1(random()));
42+
force_eval!(libm::expm1f(random()));
43+
force_eval!(libm::fabs(random()));
44+
force_eval!(libm::fabsf(random()));
45+
force_eval!(libm::fdim(random(), random()));
46+
force_eval!(libm::fdimf(random(), random()));
47+
force_eval!(libm::floor(random()));
48+
force_eval!(libm::floorf(random()));
49+
force_eval!(libm::fma(random(), random(), random()));
50+
force_eval!(libm::fmaf(random(), random(), random()));
51+
force_eval!(libm::fmod(random(), random()));
52+
force_eval!(libm::fmodf(random(), random()));
53+
force_eval!(libm::hypot(random(), random()));
54+
force_eval!(libm::hypotf(random(), random()));
55+
force_eval!(libm::log(random()));
56+
force_eval!(libm::log2(random()));
57+
force_eval!(libm::log10(random()));
58+
force_eval!(libm::log10f(random()));
59+
force_eval!(libm::log1p(random()));
60+
force_eval!(libm::log1pf(random()));
61+
force_eval!(libm::log2f(random()));
62+
force_eval!(libm::logf(random()));
63+
force_eval!(libm::pow(random(), random()));
64+
force_eval!(libm::powf(random(), random()));
65+
force_eval!(libm::round(random()));
66+
force_eval!(libm::roundf(random()));
67+
force_eval!(libm::scalbn(random(), random()));
68+
force_eval!(libm::scalbnf(random(), random()));
69+
force_eval!(libm::sin(random()));
70+
force_eval!(libm::sinf(random()));
71+
force_eval!(libm::sinh(random()));
72+
force_eval!(libm::sinhf(random()));
73+
force_eval!(libm::sqrt(random()));
74+
force_eval!(libm::sqrtf(random()));
75+
force_eval!(libm::tan(random()));
76+
force_eval!(libm::tanf(random()));
77+
force_eval!(libm::tanh(random()));
78+
force_eval!(libm::tanhf(random()));
79+
force_eval!(libm::trunc(random()));
80+
force_eval!(libm::truncf(random()));
81+
}
82+
83+
fn random<T>() -> T
84+
where
85+
T: Copy,
86+
{
87+
unsafe {
88+
static mut X: usize = 0;
89+
X += 8;
90+
ptr::read_volatile(X as *const T)
91+
}
92+
}
93+
94+
#[panic_implementation]
95+
#[no_mangle]
96+
pub fn panic(_info: &PanicInfo) -> ! {
97+
// loop {}
98+
extern "C" {
99+
fn thou_shalt_not_panic() -> !;
100+
}
101+
102+
unsafe { thou_shalt_not_panic() }
103+
}
104+
105+
#[link(name = "c")]
106+
extern "C" {}
107+
108+
#[lang = "eh_personality"]
109+
fn eh() {}
110+
111+
#[no_mangle]
112+
pub extern "C" fn __aeabi_unwind_cpp_pr0() {}
113+
114+
#[no_mangle]
115+
pub extern "C" fn __aeabi_unwind_cpp_pr1() {}

src/math/atan.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ pub fn atan(x: f64) -> f64 {
124124
return x - x * (s1 + s2);
125125
}
126126

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

129129
if sign != 0 {
130130
-z

src/math/mod.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,50 @@ macro_rules! force_eval {
66
};
77
}
88

9+
#[cfg(not(feature = "checked"))]
10+
macro_rules! i {
11+
($array:expr, $index:expr) => {
12+
unsafe { *$array.get_unchecked($index) }
13+
};
14+
($array:expr, $index:expr, =, $rhs:expr) => {
15+
unsafe { *$array.get_unchecked_mut($index) = $rhs; }
16+
};
17+
($array:expr, $index:expr, +=, $rhs:expr) => {
18+
unsafe { *$array.get_unchecked_mut($index) += $rhs; }
19+
};
20+
($array:expr, $index:expr, -=, $rhs:expr) => {
21+
unsafe { *$array.get_unchecked_mut($index) -= $rhs; }
22+
};
23+
($array:expr, $index:expr, &=, $rhs:expr) => {
24+
unsafe { *$array.get_unchecked_mut($index) &= $rhs; }
25+
};
26+
($array:expr, $index:expr, ==, $rhs:expr) => {
27+
unsafe { *$array.get_unchecked_mut($index) == $rhs }
28+
};
29+
}
30+
31+
#[cfg(feature = "checked")]
32+
macro_rules! i {
33+
($array:expr, $index:expr) => {
34+
*$array.get($index).unwrap()
35+
};
36+
($array:expr, $index:expr, =, $rhs:expr) => {
37+
*$array.get_mut($index).unwrap() = $rhs;
38+
};
39+
($array:expr, $index:expr, -=, $rhs:expr) => {
40+
*$array.get_mut($index).unwrap() -= $rhs;
41+
};
42+
($array:expr, $index:expr, +=, $rhs:expr) => {
43+
*$array.get_mut($index).unwrap() += $rhs;
44+
};
45+
($array:expr, $index:expr, &=, $rhs:expr) => {
46+
*$array.get_mut($index).unwrap() &= $rhs;
47+
};
48+
($array:expr, $index:expr, ==, $rhs:expr) => {
49+
*$array.get_mut($index).unwrap() == $rhs
50+
};
51+
}
52+
953
// Public modules
1054
mod acos;
1155
mod acosf;

src/math/rem_pio2.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ pub fn rem_pio2(x: f64) -> (i32, f64, f64) {
177177
tx[2] = z;
178178
/* skip zero terms, first term is non-zero */
179179
let mut i = 2;
180-
while tx[i] == 0.0 {
180+
while i != 0 && tx[i] == 0.0 {
181181
i -= 1;
182182
}
183183
let mut ty = [0.0; 3];

0 commit comments

Comments
 (0)