-
Notifications
You must be signed in to change notification settings - Fork 232
WIP: Implement signed/unsigned Integer convertion to single/double precision float #121
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
Closed
Closed
Changes from all commits
Commits
Show all changes
6 commits
Select commit
Hold shift + click to select a range
7569005
add implementation for (u)int to float and double conversion.
ithinuel 6b93746
Merge remote-tracking branch 'upstream/master'
ithinuel 5fac4a0
include __aeabi_ui2d only if we're not building features "c".
ithinuel e416382
Same issue as #90 except this is limited to gnueabihf (hard float)
ithinuel 6cd0eac
rename the module float::convert to float::conv to prepare for upcomi…
ithinuel 435d5c9
Add comments on int::Int::{UnsignedInt, init_float}.
ithinuel File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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))) | ||
} | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,30 +6,78 @@ pub mod udiv; | |
|
||
/// Trait for some basic operations on integers | ||
pub trait Int { | ||
/// Unsigned version of Self | ||
type UnsignedInt; | ||
/// Returns the bitwidth of the int type | ||
fn bits() -> u32; | ||
|
||
/// Extracts the sign from self and returns a tuple. | ||
/// | ||
/// This is used by the module float to prepare conversions. | ||
/// This is needed by the generic code supporting signed and unsigned conversions. | ||
/// | ||
/// # Examples | ||
/// | ||
/// ```rust,ignore | ||
/// let i = -25; | ||
/// let (sign, u) = i.init_float(); | ||
/// assert_eq!(sign, true); | ||
/// assert_eq!(u, 25); | ||
/// ``` | ||
fn init_float(self) -> (bool, Self::UnsignedInt); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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