Skip to content

Fix nm #84

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Oct 1, 2016
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -46,6 +46,8 @@ install:
script:
- cargo generate-lockfile
- if [[ $TRAVIS_OS_NAME = "linux" ]]; then
sudo apt-get remove -y qemu-user-static &&
sudo apt-get install -y qemu-user-static &&
sh ci/run-docker.sh $TARGET;
else
cargo test --target $TARGET &&
2 changes: 2 additions & 0 deletions ci/docker/thumbv6m-none-eabi/Dockerfile
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@ FROM ubuntu:16.04
RUN apt-get update
RUN apt-get install -y --no-install-recommends \
ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev
RUN curl -sf "https://github.com/raw/japaric/rust-everywhere/master/install.sh" | \
bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10
ENV AR_thumbv6m_none_eabi=arm-none-eabi-ar \
CARGO_TARGET_THUMBV6M_NONE_EABI_LINKER=arm-none-eabi-gcc \
CC_thumbv6m_none_eabi=arm-none-eabi-gcc \
2 changes: 2 additions & 0 deletions ci/docker/thumbv7em-none-eabi/Dockerfile
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@ FROM ubuntu:16.04
RUN apt-get update
RUN apt-get install -y --no-install-recommends \
ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev
RUN curl -sf "https://github.com/raw/japaric/rust-everywhere/master/install.sh" | \
bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10
ENV AR_thumbv7em_none_eabi=arm-none-eabi-ar \
CARGO_TARGET_THUMBV7EM_NONE_EABI_LINKER=arm-none-eabi-gcc \
CC_thumbv7em_none_eabi=arm-none-eabi-gcc \
2 changes: 2 additions & 0 deletions ci/docker/thumbv7em-none-eabihf/Dockerfile
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@ FROM ubuntu:16.04
RUN apt-get update
RUN apt-get install -y --no-install-recommends \
ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev
RUN curl -sf "https://github.com/raw/japaric/rust-everywhere/master/install.sh" | \
bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10
ENV AR_thumbv7em_none_eabihf=arm-none-eabi-ar \
CARGO_TARGET_THUMBV7EM_NONE_EABIHF_LINKER=arm-none-eabi-gcc \
CC_thumbv7em_none_eabihf=arm-none-eabi-gcc \
2 changes: 2 additions & 0 deletions ci/docker/thumbv7m-none-eabi/Dockerfile
Original file line number Diff line number Diff line change
@@ -2,6 +2,8 @@ FROM ubuntu:16.04
RUN apt-get update
RUN apt-get install -y --no-install-recommends \
ca-certificates curl gcc gcc-arm-none-eabi libc6-dev libcurl4-openssl-dev libssh2-1 libnewlib-dev
RUN curl -sf "https://github.com/raw/japaric/rust-everywhere/master/install.sh" | \
bash -s -- --at /usr/bin --from japaric/xargo --for x86_64-unknown-linux-gnu --tag v0.1.10
ENV AR_thumbv7m_none_eabi=arm-none-eabi-ar \
CARGO_TARGET_THUMBV7M_NONE_EABI_LINKER=arm-none-eabi-gcc \
CC_thumbv7m_none_eabi=arm-none-eabi-gcc \
2 changes: 1 addition & 1 deletion ci/run-docker.sh
Original file line number Diff line number Diff line change
@@ -24,7 +24,7 @@ run() {
-v `rustc --print sysroot`:/rust:ro \
-w /checkout \
-it $target \
sh -c "PATH=\$PATH:/rust/bin ci/run.sh $target"
sh -c "HOME=/tmp PATH=\$PATH:/rust/bin ci/run.sh $target"
}

if [ -z "$1" ]; then
12 changes: 7 additions & 5 deletions ci/run.sh
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
set -e

# Test our implementation
case $1 in
thumb*)
curl -sf "https://github.com/raw/japaric/rust-everywhere/master/install.sh" | \
bash -s -- --at /usr/bin --from japaric/xargo --tag v0.1.10
xargo build --target $1
xargo build --target $1 --release
;;
@@ -29,7 +29,7 @@ case $1 in
esac

# Look out for duplicated symbols when we include the compiler-rt (C) implementation
PREFIX=$(echo $1 | sed -e 's/unknown-//')
PREFIX=$(echo $1 | sed -e 's/unknown-//')-
case $1 in
armv7-*)
PREFIX=arm-linux-gnueabihf-
@@ -55,8 +55,10 @@ case $TRAVIS_OS_NAME in
esac

# NOTE On i586, It's normal that the get_pc_thunk symbol appears several times so ignore it
$PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib | \
sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __'
stdout=$($PREFIX$NM -g --defined-only /target/${1}/debug/librustc_builtins.rlib)

set +e
echo $stdout | sort | uniq -d | grep -v __x86.get_pc_thunk | grep 'T __'

if test $? = 0; then
exit 1
145 changes: 117 additions & 28 deletions src/float/add.rs
Original file line number Diff line number Diff line change
@@ -9,27 +9,27 @@ macro_rules! add {
#[allow(unused_parens)]
#[cfg_attr(not(test), no_mangle)]
pub extern fn $intrinsic(a: $ty, b: $ty) -> $ty {
let one = Wrapping(1 as <$ty as Float>::Int);
let zero = Wrapping(0 as <$ty as Float>::Int);

let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int);
let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int);
let exponent_bits = Wrapping(<$ty>::exponent_bits() as <$ty as Float>::Int);
let max_exponent = (one << exponent_bits.0 as usize) - one;

let implicit_bit = one << significand_bits.0 as usize;
let significand_mask = implicit_bit - one;
let sign_bit = one << (significand_bits + exponent_bits).0 as usize;
let abs_mask = sign_bit - one;
let exponent_mask = abs_mask ^ significand_mask;
let inf_rep = exponent_mask;
let quiet_bit = implicit_bit >> 1;
let qnan_rep = exponent_mask | quiet_bit;

let mut a_rep = Wrapping(a.repr());
let mut b_rep = Wrapping(b.repr());
let a_abs = a_rep & abs_mask;
let b_abs = b_rep & abs_mask;
let one = Wrapping(1 as <$ty as Float>::Int);
let zero = Wrapping(0 as <$ty as Float>::Int);

let bits = Wrapping(<$ty>::bits() as <$ty as Float>::Int);
let significand_bits = Wrapping(<$ty>::significand_bits() as <$ty as Float>::Int);
let exponent_bits = bits - significand_bits - one;
let max_exponent = (one << exponent_bits.0 as usize) - one;

let implicit_bit = one << significand_bits.0 as usize;
let significand_mask = implicit_bit - one;
let sign_bit = one << (significand_bits + exponent_bits).0 as usize;
let abs_mask = sign_bit - one;
let exponent_mask = abs_mask ^ significand_mask;
let inf_rep = exponent_mask;
let quiet_bit = implicit_bit >> 1;
let qnan_rep = exponent_mask | quiet_bit;

let mut a_rep = Wrapping(a.repr());
let mut b_rep = Wrapping(b.repr());
let a_abs = a_rep & abs_mask;
let b_abs = b_rep & abs_mask;

// Detect if a or b is zero, infinity, or NaN.
if a_abs - one >= inf_rep - one ||
@@ -188,7 +188,7 @@ mod tests {
use core::{f32, f64};

use float::Float;
use qc::{F32, F64};
use qc::{U32, U64};

// NOTE The tests below have special handing for NaN values.
// Because NaN != NaN, the floating-point representations must be used
@@ -212,18 +212,107 @@ mod tests {
}
}

// TODO: Add F32/F64 to qc so that they print the right values (at the very least)
check! {
fn __addsf3(f: extern fn(f32, f32) -> f32,
a: F32,
b: F32)
a: U32,
b: U32)
-> Option<FRepr<f32> > {
Some(FRepr(f(a.0, b.0)))
let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0));
Some(FRepr(f(a, b)))
}

fn __adddf3(f: extern fn(f64, f64) -> f64,
a: F64,
b: F64) -> Option<FRepr<f64> > {
Some(FRepr(f(a.0, b.0)))
a: U64,
b: U64) -> Option<FRepr<f64> > {
let (a, b) = (f64::from_repr(a.0), f64::from_repr(b.0));
Some(FRepr(f(a, b)))
}
}

// More tests for special float values

#[test]
fn test_float_tiny_plus_tiny() {
let tiny = f32::from_repr(1);
let r = super::__addsf3(tiny, tiny);
assert!(r.eq_repr(tiny + tiny));
}

#[test]
fn test_double_tiny_plus_tiny() {
let tiny = f64::from_repr(1);
let r = super::__adddf3(tiny, tiny);
assert!(r.eq_repr(tiny + tiny));
}

#[test]
fn test_float_small_plus_small() {
let a = f32::from_repr(327);
let b = f32::from_repr(256);
let r = super::__addsf3(a, b);
assert!(r.eq_repr(a + b));
}

#[test]
fn test_double_small_plus_small() {
let a = f64::from_repr(327);
let b = f64::from_repr(256);
let r = super::__adddf3(a, b);
assert!(r.eq_repr(a + b));
}

#[test]
fn test_float_one_plus_one() {
let r = super::__addsf3(1f32, 1f32);
assert!(r.eq_repr(1f32 + 1f32));
}

#[test]
fn test_double_one_plus_one() {
let r = super::__adddf3(1f64, 1f64);
assert!(r.eq_repr(1f64 + 1f64));
}

#[test]
fn test_float_different_nan() {
let a = f32::from_repr(1);
let b = f32::from_repr(0b11111111100100010001001010101010);
let x = super::__addsf3(a, b);
let y = a + b;
assert!(x.eq_repr(y));
}

#[test]
fn test_double_different_nan() {
let a = f64::from_repr(1);
let b = f64::from_repr(0b1111111111110010001000100101010101001000101010000110100011101011);
let x = super::__adddf3(a, b);
let y = a + b;
assert!(x.eq_repr(y));
}

#[test]
fn test_float_nan() {
let r = super::__addsf3(f32::NAN, 1.23);
assert_eq!(r.repr(), f32::NAN.repr());
}

#[test]
fn test_double_nan() {
let r = super::__adddf3(f64::NAN, 1.23);
assert_eq!(r.repr(), f64::NAN.repr());
}

#[test]
fn test_float_inf() {
let r = super::__addsf3(f32::INFINITY, -123.4);
assert_eq!(r, f32::INFINITY);
}

#[test]
fn test_double_inf() {
let r = super::__adddf3(f64::INFINITY, -123.4);
assert_eq!(r, f64::INFINITY);
}
}
79 changes: 1 addition & 78 deletions src/float/mod.rs
Original file line number Diff line number Diff line change
@@ -10,45 +10,21 @@ pub trait Float: Sized + Copy {
/// Returns the bitwidth of the float type
fn bits() -> u32;

/// Returns the bitwidth of the exponent
fn exponent_bits() -> u32;

/// Returns the bitwidth of the significand
fn significand_bits() -> u32;

/// Returns a mask for the sign bit of `self`
fn sign_mask() -> Self::Int;

/// Returns a mask for the exponent portion of `self`
fn exponent_mask() -> Self::Int;

/// Returns a mask for the significand portion of `self`
fn significand_mask() -> Self::Int;

/// Returns the sign bit of `self`
fn sign(self) -> bool;

/// Returns the exponent portion of `self`, shifted to the right
fn exponent(self) -> Self::Int;

/// Returns the significand portion of `self`
fn significand(self) -> Self::Int;

/// Returns `self` transmuted to `Self::Int`
fn repr(self) -> Self::Int;

#[cfg(test)]
/// Checks if two floats have the same bit representation. *Except* for NaNs! NaN can be
/// represented in multiple different ways. This method returns `true` if two NaNs are
/// represented in multiple different ways. This methods returns `true` if two NaNs are
/// compared.
fn eq_repr(self, rhs: Self) -> bool;

/// Returns a `Self::Int` transmuted back to `Self`
fn from_repr(a: Self::Int) -> Self;

/// Constructs a `Self` from its parts
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self;

/// Returns (normalized exponent, normalized significand)
fn normalize(significand: Self::Int) -> (i32, Self::Int);
}
@@ -58,21 +34,9 @@ impl Float for f32 {
fn bits() -> u32 {
32
}
fn exponent_bits() -> u32 {
8
}
fn significand_bits() -> u32 {
23
}
fn sign_mask() -> Self::Int {
1 << (Self::bits() - 1)
}
fn exponent_mask() -> Self::Int {
((1 << Self::exponent_bits()) - 1) << Self::significand_bits()
}
fn significand_mask() -> Self::Int {
(1 << Self::significand_bits()) - 1
}
fn repr(self) -> Self::Int {
unsafe { mem::transmute(self) }
}
@@ -87,21 +51,6 @@ impl Float for f32 {
fn from_repr(a: Self::Int) -> Self {
unsafe { mem::transmute(a) }
}

fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) |
exponent & Self::exponent_mask() |
significand & Self::significand_mask())
}
fn sign(self) -> bool {
(self.repr() & Self::sign_mask()) != 0
}
fn exponent(self) -> Self::Int {
self.repr() >> Self::significand_bits() & Self::exponent_mask()
}
fn significand(self) -> Self::Int {
self.repr() & Self::significand_mask()
}
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
let shift = significand.leading_zeros()
.wrapping_sub((1u32 << Self::significand_bits()).leading_zeros());
@@ -113,21 +62,9 @@ impl Float for f64 {
fn bits() -> u32 {
64
}
fn exponent_bits() -> u32 {
11
}
fn significand_bits() -> u32 {
52
}
fn sign_mask() -> Self::Int {
1 << (Self::bits() - 1)
}
fn exponent_mask() -> Self::Int {
((1 << Self::exponent_bits()) - 1) << Self::significand_bits()
}
fn significand_mask() -> Self::Int {
(1 << Self::significand_bits()) - 1
}
fn repr(self) -> Self::Int {
unsafe { mem::transmute(self) }
}
@@ -142,20 +79,6 @@ impl Float for f64 {
fn from_repr(a: Self::Int) -> Self {
unsafe { mem::transmute(a) }
}
fn from_parts(sign: bool, exponent: Self::Int, significand: Self::Int) -> Self {
Self::from_repr(((sign as Self::Int) << (Self::bits() - 1)) |
exponent & Self::exponent_mask() |
significand & Self::significand_mask())
}
fn sign(self) -> bool {
(self.repr() & Self::sign_mask()) != 0
}
fn exponent(self) -> Self::Int {
self.repr() >> Self::significand_bits() & Self::exponent_mask()
}
fn significand(self) -> Self::Int {
self.repr() & Self::significand_mask()
}
fn normalize(significand: Self::Int) -> (i32, Self::Int) {
let shift = significand.leading_zeros()
.wrapping_sub((1u64 << Self::significand_bits()).leading_zeros());
55 changes: 0 additions & 55 deletions src/qc.rs
Original file line number Diff line number Diff line change
@@ -5,12 +5,10 @@

use std::boxed::Box;
use std::fmt;
use core::{f32, f64};

use quickcheck::{Arbitrary, Gen};

use int::LargeInt;
use float::Float;

// Generates values in the full range of the integer type
macro_rules! arbitrary {
@@ -73,7 +71,6 @@ macro_rules! arbitrary {
arbitrary!(I32: i32);
arbitrary!(U32: u32);


// These integers are "too large". If we generate e.g. `u64` values in the full range then there's
// only `1 / 2^32` chance of seeing a value smaller than `2^32` (i.e. whose higher "word" (32-bits)
// is `0`)! But this is an important group of values to tests because we have special code paths for
@@ -146,57 +143,6 @@ macro_rules! arbitrary_large {
arbitrary_large!(I64: i64);
arbitrary_large!(U64: u64);


macro_rules! arbitrary_float {
($TY:ident : $ty:ident) => {
#[derive(Clone, Copy)]
pub struct $TY(pub $ty);

impl Arbitrary for $TY {
fn arbitrary<G>(g: &mut G) -> $TY
where G: Gen
{
let special = [
-0.0, 0.0, $ty::NAN, $ty::INFINITY, -$ty::INFINITY
];

if g.gen_weighted_bool(10) { // Random special case
$TY(*g.choose(&special).unwrap())
} else if g.gen_weighted_bool(10) { // NaN variants
let sign: bool = g.gen();
let exponent: <$ty as Float>::Int = g.gen();
let significand: <$ty as Float>::Int = 0;
$TY($ty::from_parts(sign, exponent, significand))
} else if g.gen() { // Denormalized
let sign: bool = g.gen();
let exponent: <$ty as Float>::Int = 0;
let significand: <$ty as Float>::Int = g.gen();
$TY($ty::from_parts(sign, exponent, significand))
} else { // Random anything
let sign: bool = g.gen();
let exponent: <$ty as Float>::Int = g.gen();
let significand: <$ty as Float>::Int = g.gen();
$TY($ty::from_parts(sign, exponent, significand))
}
}

fn shrink(&self) -> Box<Iterator<Item=$TY>> {
::quickcheck::empty_shrinker()
}
}

impl fmt::Debug for $TY {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&self.0, f)
}
}
}
}

arbitrary_float!(F32: f32);
arbitrary_float!(F64: f64);


// Convenience macro to test intrinsics against their reference implementations.
//
// Each intrinsic is tested against both the `gcc_s` library as well as
@@ -317,4 +263,3 @@ macro_rules! check {
}
)
}