Skip to content

Commit 45f924e

Browse files
committed
Add generic conversion from a narrower to a wider FP type
Add `extend` module to implement conversion from a narrower to a wider floating-point type. This implementation is only intended to support *widening* operations. Module to convert a *narrower* floating-point will be added in the future.
1 parent 3e7fba7 commit 45f924e

File tree

5 files changed

+88
-2
lines changed

5 files changed

+88
-2
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ features = ["c"]
146146
- [x] divsf3.c
147147
- [x] divsi3.c
148148
- [ ] extendhfsf2.c
149-
- [ ] extendsfdf2.c
149+
- [x] extendsfdf2.c
150150
- [x] fixdfdi.c
151151
- [x] fixdfsi.c
152152
- [x] fixsfdi.c

build.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,6 @@ mod c {
171171
"divdc3.c",
172172
"divsc3.c",
173173
"divxc3.c",
174-
"extendsfdf2.c",
175174
"extendhfsf2.c",
176175
"floatdisf.c",
177176
"floatundisf.c",

src/float/extend.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
use int::{CastInto, Int};
2+
use float::Float;
3+
4+
/// Generic conversion from a narrower to a wider IEEE-754 floating-point type
5+
fn extend<F: Float, R: Float>(a: F) -> R where
6+
F::Int: CastInto<u64>,
7+
u64: CastInto<F::Int>,
8+
u32: CastInto<R::Int>,
9+
R::Int: CastInto<u32>,
10+
R::Int: CastInto<u64>,
11+
u64: CastInto<R::Int>,
12+
F::Int: CastInto<R::Int>,
13+
{
14+
let src_zero = F::Int::ZERO;
15+
let src_one = F::Int::ONE;
16+
let src_bits = F::BITS;
17+
let src_sign_bits = F::SIGNIFICAND_BITS;
18+
let src_exp_bias = F::EXPONENT_BIAS;
19+
let src_min_normal = F::IMPLICIT_BIT;
20+
let src_infinity = F::EXPONENT_MASK;
21+
let src_sign_mask = F::SIGN_MASK as F::Int;
22+
let src_abs_mask = src_sign_mask - src_one;
23+
let src_qnan = F::SIGNIFICAND_MASK;
24+
let src_nan_code = src_qnan - src_one;
25+
26+
let dst_bits = R::BITS;
27+
let dst_sign_bits = R::SIGNIFICAND_BITS;
28+
let dst_inf_exp = R::EXPONENT_MAX;
29+
let dst_exp_bias = R::EXPONENT_BIAS;
30+
let dst_min_normal = R::IMPLICIT_BIT;
31+
32+
let sign_bits_delta = dst_sign_bits - src_sign_bits;
33+
let exp_bias_delta = dst_exp_bias - src_exp_bias;
34+
let a_abs = a.repr() & src_abs_mask;
35+
let mut abs_result = R::Int::ZERO;
36+
37+
if a_abs.wrapping_sub(src_min_normal) < src_infinity.wrapping_sub(src_min_normal) {
38+
// a is a normal number.
39+
// Extend to the destination type by shifting the significand and
40+
// exponent into the proper position and rebiasing the exponent.
41+
let abs_dst: R::Int = a_abs.cast();
42+
let bias_dst: R::Int = exp_bias_delta.cast();
43+
abs_result = abs_dst.wrapping_shl(sign_bits_delta);
44+
abs_result |= bias_dst.wrapping_shl(dst_sign_bits);
45+
} else if a_abs >= src_infinity {
46+
// a is NaN or infinity.
47+
// Conjure the result by beginning with infinity, then setting the qNaN
48+
// bit (if needed) and right-aligning the rest of the trailing NaN
49+
// payload field.
50+
let qnan_dst: R::Int = (a_abs & src_qnan).cast();
51+
let nan_code_dst: R::Int = (a_abs & src_nan_code).cast();
52+
let inf_exp_dst: R::Int = dst_inf_exp.cast();
53+
abs_result = inf_exp_dst.wrapping_shl(dst_sign_bits);
54+
abs_result |= qnan_dst.wrapping_shl(sign_bits_delta);
55+
abs_result |= nan_code_dst.wrapping_shl(sign_bits_delta);
56+
} else if a_abs != src_zero {
57+
// a is denormal.
58+
// Renormalize the significand and clear the leading bit, then insert
59+
// the correct adjusted exponent in the destination type.
60+
let scale = a_abs.leading_zeros() - src_min_normal.leading_zeros();
61+
let abs_dst: R::Int = a_abs.cast();
62+
let bias_dst: R::Int = (exp_bias_delta - scale + 1).cast();
63+
abs_result = abs_dst.wrapping_shl(sign_bits_delta + scale);
64+
abs_result = (abs_result ^ dst_min_normal) | (bias_dst.wrapping_shl(dst_sign_bits));
65+
}
66+
67+
let sign_result: R::Int = (a.repr() & src_sign_mask).cast();
68+
R::from_repr(abs_result | (sign_result.wrapping_shl(dst_bits - src_bits)))
69+
}
70+
71+
intrinsics! {
72+
#[aapcs_on_arm]
73+
#[arm_aeabi_alias = __aeabi_f2d]
74+
pub extern "C" fn __extendsfdf2(a: f32) -> f64 {
75+
extend(a)
76+
}
77+
}

src/float/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub mod pow;
1010
pub mod sub;
1111
pub mod mul;
1212
pub mod div;
13+
pub mod extend;
1314

1415
/// Trait for some basic operations on floats
1516
pub trait Float:

testcrate/build.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,15 @@ fn main() {
235235
"compiler_builtins::float::cmp::__aeabi_dcmpgt(a, b)");
236236
}
237237

238+
// float/extend.rs
239+
gen(|a: MyF32| {
240+
if a.0.is_nan() {
241+
return None;
242+
}
243+
Some(f64(a.0))
244+
},
245+
"compiler_builtins::float::extend::__extendsfdf2(a)");
246+
238247
// float/conv.rs
239248
gen(|a: MyF64| i64(a.0).ok(),
240249
"compiler_builtins::float::conv::__fixdfdi(a)");

0 commit comments

Comments
 (0)