-
Notifications
You must be signed in to change notification settings - Fork 214
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
Add soft float addition builtins #43
Conversation
You can use |
*significand <<= shift as T; | ||
T::one() - shift as T | ||
} | ||
} |
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.
I would suggest a simpler version of this trait:
trait Float {
type Int: Sized + Copy + Clone + Sub<Output=T> + ShlAssign<T> + Shl<T, Output=T> + One;
fn bits() -> u32; // Always use u32 for bit widths
fn significand_bits() -> u32;
fn repr(self) -> Self::Int;
fn from_repr(Self::Int) -> self;
fn normalize(Self::Int) -> Self::Int;
}
I think we should move all int related stuff into an int/ subdirectory and all the float related stuff into float/. The source tree will then look like this: |
fn rep_clz(a: u32) -> u32 { | ||
#[cfg(not(msvc))] | ||
extern "C" { | ||
fn __builtin_clz(a: u32) -> u32; |
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.
Where does this symbol come from? And is this even necessary? Couldn't this just use u32::leading_zeros
? That method (and the u64 variant) already lower to an LLVM intrinsic: llvm.ctlz.i*
in LLVM IR.
@Amanieu I don't think you can use leading_zeroes when compiling with
I agree with your other comments. |
It's |
@Amanieu facepalm |
let exponent_mask = (abs_mask ^ significand_mask) as <$ty as Float>::Int; | ||
let inf_rep = (exponent_mask) as <$ty as Float>::Int; | ||
let quiet_bit = (implicit_bit >> 1) as <$ty as Float>::Int; | ||
let qnan_rep = (exponent_mask | quiet_bit) as <$ty as Float>::Int; |
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.
You can probably get rid of all the as <$ty as Float>::Int
casts here. Type inference will figure it out.
Can you move the transmutes into the fn repr(self) -> Self::Int;
fn from_repr(Self::Int) -> Self; And generally anything that might be reused by the other soft-float implementations should go into that trait. |
@Amanieu that makes a lot of sense, I'll do that. |
__adddf3(a, b) | ||
} | ||
|
||
#[cfg(arm)] |
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.
#[cfg(target_arch = "arm")]
For now tests with plain |
@Amanieu yeah, I started writing the tests earlier, using quickcheck and some regular ones for the special cases. Doing this has identified a few issues:
I'll probably figure this out tomorrow. |
Yeah, we can add
This is good enough for this PR. 👍 |
bcdbb7e
to
4eed0fe
Compare
Rebased on master, I'll cleanup the history once this works. |
quickcheck! { | ||
fn addsf3(a: U32, b: U32) -> bool { | ||
let (a, b) = (a.0, b.0); | ||
let r = super::__addsf3(<f32 as Float>::from_repr(a), <f32 as Float>::from_repr(b)); |
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.
I think this can simply be f32::from_repr
. Same in the f64
case.
Another thing that might cause an issue is constant folding, which might give different results than actual runtime addition. |
I'm starting to think the use of This last commit fixed the common qc test failure case of |
df90297
to
1d83529
Compare
1d83529
to
005ca06
Compare
005ca06
to
ef16de3
Compare
let (a, b) = (f32::from_repr(a.0), f32::from_repr(b.0)); | ||
let x = super::__addsf3(a, b); | ||
let y = a + b; | ||
if !(x.is_nan() && y.is_nan()) { |
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.
I personally find this easier to read as:
if x.is_nan() && y.is_nan() {
true
} else {
x.repr() == y.repr()
}
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.
I also think this if-else block should be written as an utility function because it repeats in several places.
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.
I that utility function should be used everywhere we need to test for float "equality" -- i.e. in all these tests.
@mattico Thanks for working on this! Looks great to me. I left some comments about nits. I'd personally like to see tests that involve |
Thanks for the review! I'll keep these comments in mind when writing the I do handle +-0 in the follow up PR, although I'm not sure about the method On Sat, Aug 20, 2016, 9:46 PM Jorge Aparicio [email protected]
|
I'm going to merge this as is. We can add the utility function in a follow up PR. Thanks again @mattico! |
TODO:
Moverep_clz
toint
module?from_repr(1) + from_repr(1) == INFINITY