Skip to content
Closed
Show file tree
Hide file tree
Changes from 4 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
7 changes: 7 additions & 0 deletions compiler-rt/compiler-rt-cdylib/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,13 @@ fn main() {
"addsf3.c",
"powidf2.c",
"powisf2.c",
"fixsfsi.c",
"floatsisf.c",
"floatsidf.c",
"floatdidf.c",
"floatunsisf.c",
"floatunsidf.c",
"floatundidf.c",
]);

for src in sources.files.iter() {
Expand Down
12 changes: 12 additions & 0 deletions compiler-rt/compiler-rt-cdylib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ extern {
fn __adddf3();
fn __powisf2();
fn __powidf2();
fn __floatsisf();
fn __floatsidf();
fn __floatdidf();
fn __floatunsisf();
fn __floatunsidf();
fn __floatundidf();
}

macro_rules! declare {
Expand Down Expand Up @@ -57,6 +63,12 @@ declare!(___addsf3, __addsf3);
declare!(___adddf3, __adddf3);
declare!(___powisf2, __powisf2);
declare!(___powidf2, __powidf2);
declare!(___floatsisf, __floatsisf);
declare!(___floatsidf, __floatsidf);
declare!(___floatdidf, __floatdidf);
declare!(___floatunsisf, __floatunsisf);
declare!(___floatunsidf, __floatunsidf);
declare!(___floatundidf, __floatundidf);

#[lang = "eh_personality"]
fn eh_personality() {}
Expand Down
7 changes: 6 additions & 1 deletion src/arm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,12 @@ pub extern "C" fn __aeabi_uidiv(a: u32, b: u32) -> u32 {
::int::udiv::__udivsi3(a, b)
}

#[cfg(not(feature = "c"))]
#[cfg_attr(not(test), no_mangle)]
pub extern "C" fn __aeabi_ui2d(a: u32) -> f64 {
::float::convert::__floatunsidf(a)
}

extern "C" {
fn memcpy(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
fn memmove(dest: *mut u8, src: *const u8, n: usize) -> *mut u8;
Expand Down Expand Up @@ -161,7 +167,6 @@ pub unsafe extern "C" fn __aeabi_memclr8(dest: *mut u8, n: usize) {
memset(dest, 0, n);
}


#[cfg(test)]
mod tests {
use quickcheck::TestResult;
Expand Down
126 changes: 126 additions & 0 deletions src/float/convert.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
use float::Float;
use int::Int;

macro_rules! fp_overflow {
(infinity, $fty:ty, $sign: expr) => {
return {
<$fty as Float>::from_parts(
$sign,
<$fty as Float>::exponent_max() as <$fty as Float>::Int,
0 as <$fty as Float>::Int)
}
}
}

macro_rules! fp_convert {
($intrinsic:ident: $ity:ty, $fty:ty) => {

pub extern "C" fn $intrinsic(i: $ity) -> $fty {
let work_bits = 3;
let work_round = 1 << (work_bits - 1);
let work_mask = (1 << (work_bits + 1)) - 1;
let exponent_bias = <$fty>::exponent_bias();
let exponent_max = <$fty>::exponent_max();
let significand_bits = <$fty>::significand_bits();
let significand_wbits = significand_bits + work_bits + 1;
let integer_bits = <$fty>::bits();

if i == 0 {
return <$fty>::from_parts(false,0,0)
}

// work register.
let (sign, i) = i.init_float();
let mut wr = i as <$fty as Float>::Int;

let payload_len = integer_bits - wr.leading_zeros();
let mut exp = exponent_bias + payload_len - 1;

if exp >= exponent_max {
// overflow to infinity
fp_overflow!(infinity, $fty, sign);
}

if payload_len < significand_wbits {
let left_shift = significand_wbits - payload_len;
wr = wr.wrapping_shl(left_shift);
} else {
let right_shift = payload_len - significand_wbits; // this is also the number of unused bits from the i
let has_spare_bits = (if right_shift == 0 {
0
} else {
wr.wrapping_shl(integer_bits - right_shift)
} != 0) as <$fty as Float>::Int;
// shift and if there is any dropped bit to 1, raise the least significant bit.
wr = (wr >> right_shift) | has_spare_bits;
}

wr &= (<$fty>::significand_mask() << work_bits) | work_mask;

if (wr & work_mask) > work_round {
wr += work_round;
}

if wr >= (1<< (significand_wbits - 1)) {
exp += 1;

if exp >= exponent_max {
fp_overflow!(infinity, $fty, sign);
}
}

let frac = wr >> work_bits;
<$fty>::from_parts(sign, exp as <$fty as Float>::Int, frac)
}
}
}

fp_convert!(__floatsisf: i32, f32);
fp_convert!(__floatsidf: i32, f64);
fp_convert!(__floatdidf: i64, f64);
fp_convert!(__floatunsisf: u32, f32);
fp_convert!(__floatunsidf: u32, f64);
fp_convert!(__floatundidf: u64, f64);

// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't
// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll
// just avoid testing against them on those targets. Do note that our implementation gives the
// correct answer; gcc_s and compiler-rt are incorrect in this case.
//
#[cfg(all(test, not(arm_linux)))]
mod tests {
use qc::{I32, U32, I64, U64, F32, F64};

check! {
fn __floatsisf(f: extern fn(i32) -> f32,
a: I32)
-> Option<F32> {
Some(F32(f(a.0)))
}
fn __floatsidf(f: extern fn(i32) -> f64,
a: I32)
-> Option<F64> {
Some(F64(f(a.0)))
}
fn __floatdidf(f: extern fn(i64) -> f64,
a: I64)
-> Option<F64> {
Some(F64(f(a.0)))
}
fn __floatunsisf(f: extern fn(u32) -> f32,
a: U32)
-> Option<F32> {
Some(F32(f(a.0)))
}
fn __floatunsidf(f: extern fn(u32) -> f64,
a: U32)
-> Option<F64> {
Some(F64(f(a.0)))
}
fn __floatundidf(f: extern fn(u64) -> f64,
a: U64)
-> Option<F64> {
Some(F64(f(a.0)))
}
}
}
11 changes: 11 additions & 0 deletions src/float/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use core::mem;

pub mod add;
pub mod pow;
pub mod convert;

/// Trait for some basic operations on floats
pub trait Float: Sized + Copy {
Expand All @@ -19,6 +20,16 @@ pub trait Float: Sized + Copy {
Self::bits() - Self::significand_bits() - 1
}

/// Returns the maximum value of the exponent
fn exponent_max() -> u32 {
(1 << Self::exponent_bits()) - 1
}

/// Returns the exponent bias value
fn exponent_bias() -> u32 {
Self::exponent_max() >> 1
}

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

Expand Down
33 changes: 33 additions & 0 deletions src/int/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,30 +6,63 @@ pub mod udiv;

/// Trait for some basic operations on integers
pub trait Int {
type UnsignedInt;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment here? "Unsigned version of Self" or something

/// Returns the bitwidth of the int type
fn bits() -> u32;
fn init_float(self) -> (bool, Self::UnsignedInt);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a comment here as well? What does this do and where it's used.

}

// TODO: Once i128/u128 support lands, we'll want to add impls for those as well
impl Int for u32 {
type UnsignedInt = u32;
fn bits() -> u32 {
32
}

fn init_float(self) -> (bool, u32) {
(false, self)
}
}
impl Int for i32 {
type UnsignedInt = u32;

fn bits() -> u32 {
32
}

fn init_float(self) -> (bool, u32) {
if self < 0 {
(true, !(self as u32) + 1)
} else {
(false, self as u32)
}
}
}
impl Int for u64 {
type UnsignedInt = u64;

fn bits() -> u32 {
64
}

fn init_float(self) -> (bool, u64) {
(false, self)
}
}
impl Int for i64 {
type UnsignedInt = u64;

fn bits() -> u32 {
64
}

fn init_float(self) -> (bool, u64) {
if self < 0 {
(true, !(self as u64) + 1)
} else {
(false, self as u64)
}
}
}

/// Trait to convert an integer to/from smaller parts
Expand Down