Skip to content

Commit baab4fd

Browse files
committed
Conversion from a wider to a narrower IEEE-754 floating-point type
Adds generic conversion from a wider to a narrower IEEE-754 floating-point type. Implement `__truncdfsf2` and `__truncdfsf2vfp` and associated test-cases.
1 parent a50c848 commit baab4fd

File tree

5 files changed

+137
-3
lines changed

5 files changed

+137
-3
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ features = ["c"]
129129
- [x] arm/softfloat-alias.list
130130
- [x] arm/subdf3vfp.S
131131
- [x] arm/subsf3vfp.S
132-
- [ ] arm/truncdfsf2vfp.S
132+
- [x] arm/truncdfsf2vfp.S
133133
- [ ] arm/udivmodsi4.S (generic version is done)
134134
- [ ] arm/udivsi3.S (generic version is done)
135135
- [ ] arm/umodsi3.S (generic version is done)
@@ -186,7 +186,7 @@ features = ["c"]
186186
- [x] subdf3.c
187187
- [x] subsf3.c
188188
- [ ] truncdfhf2.c
189-
- [ ] truncdfsf2.c
189+
- [x] truncdfsf2.c
190190
- [ ] truncsfhf2.c
191191
- [x] udivdi3.c
192192
- [x] udivmoddi4.c

build.rs

-1
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ mod c {
174174
"subvdi3.c",
175175
"subvsi3.c",
176176
"truncdfhf2.c",
177-
"truncdfsf2.c",
178177
"truncsfhf2.c",
179178
"ucmpdi2.c",
180179
],

src/float/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ pub mod sub;
1111
pub mod mul;
1212
pub mod div;
1313
pub mod extend;
14+
pub mod truncate;
1415

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

src/float/truncate.rs

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
use float::Float;
2+
use int::{CastInto, Int};
3+
4+
/// Generic conversion from a wider to a narrower IEEE-754 floating-point type
5+
fn truncate<F: Float, R: Float>(a: F) -> R
6+
where
7+
F::Int: CastInto<u64>,
8+
u64: CastInto<F::Int>,
9+
F::Int: CastInto<u32>,
10+
u32: CastInto<F::Int>,
11+
u32: CastInto<R::Int>,
12+
R::Int: CastInto<u32>,
13+
F::Int: CastInto<R::Int>,
14+
{
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+
31+
let dst_zero = R::Int::ZERO;
32+
let dst_one = R::Int::ONE;
33+
let dst_qnan = R::SIGNIFICAND_MASK;
34+
let dst_nan_code = dst_qnan - dst_one;
35+
36+
let round_mask = (src_one << src_sign_bits - dst_sign_bits) - src_one;
37+
let half = src_one << src_sign_bits - dst_sign_bits - 1;
38+
let underflow_exp = src_exp_bias + 1 - dst_exp_bias;
39+
let overflow_exp = src_exp_bias + dst_inf_exp - dst_exp_bias;
40+
let underflow: F::Int = underflow_exp.cast(); // << src_sign_bits;
41+
let overflow: F::Int = overflow_exp.cast(); //<< src_sign_bits;
42+
43+
let a_abs = a.repr() & src_abs_mask;
44+
let sign = a.repr() & src_sign_mask;
45+
let mut abs_result: R::Int;
46+
47+
let src_underflow = underflow << src_sign_bits;
48+
let src_overflow = overflow << src_sign_bits;
49+
50+
if a_abs.wrapping_sub(src_underflow) < a_abs.wrapping_sub(src_overflow) {
51+
// The exponent of a is within the range of normal numbers
52+
let bias_delta: R::Int = (src_exp_bias - dst_exp_bias).cast();
53+
abs_result = a_abs.cast();
54+
abs_result = abs_result >> src_sign_bits - dst_sign_bits;
55+
abs_result = abs_result - bias_delta.wrapping_shl(dst_sign_bits);
56+
let round_bits: F::Int = a_abs & round_mask;
57+
abs_result += if round_bits > half {
58+
dst_one
59+
} else {
60+
abs_result & dst_one
61+
};
62+
} else if a_abs > src_infinity {
63+
// a is NaN.
64+
// Conjure the result by beginning with infinity, setting the qNaN
65+
// bit and inserting the (truncated) trailing NaN field
66+
let nan_result: R::Int = (a_abs & src_nan_code).cast();
67+
abs_result = dst_inf_exp.cast();
68+
abs_result = abs_result.wrapping_shl(dst_sign_bits);
69+
abs_result |= dst_qnan;
70+
abs_result |= (nan_result >> (src_sign_bits - dst_sign_bits)) & dst_nan_code;
71+
} else if a_abs >= src_overflow {
72+
// a overflows to infinity.
73+
abs_result = dst_inf_exp.cast();
74+
abs_result = abs_result.wrapping_shl(dst_sign_bits);
75+
} else {
76+
// a underflows on conversion to the destination type or is an exact
77+
// zero. The result may be a denormal or zero. Extract the exponent
78+
// to get the shift amount for the denormalization.
79+
let a_exp = a_abs >> src_sign_bits;
80+
let mut shift: u32 = a_exp.cast();
81+
shift = src_exp_bias - dst_exp_bias - shift + 1;
82+
83+
let significand = (a.repr() & src_sign_mask) | src_min_normal;
84+
if shift > src_sign_bits {
85+
abs_result = dst_zero;
86+
} else {
87+
let sticky = significand << src_bits - shift;
88+
let mut denormalized_significand: R::Int = significand.cast();
89+
let sticky_shift: u32 = sticky.cast();
90+
denormalized_significand = denormalized_significand >> (shift | sticky_shift);
91+
abs_result = denormalized_significand >> src_sign_bits - dst_sign_bits;
92+
let round_bits = denormalized_significand & round_mask.cast();
93+
if round_bits > half.cast() {
94+
abs_result += dst_one; // Round to nearest
95+
} else if round_bits == half.cast() {
96+
abs_result += abs_result & dst_one; // Ties to even
97+
}
98+
}
99+
}
100+
// Finally apply the sign bit
101+
let s = sign >> src_bits - dst_bits;
102+
R::from_repr(abs_result | s.cast())
103+
}
104+
105+
intrinsics! {
106+
#[aapcs_on_arm]
107+
#[arm_aeabi_alias = __aeabi_d2f]
108+
pub extern "C" fn __truncdfsf2(a: f64) -> f32 {
109+
truncate(a)
110+
}
111+
112+
#[cfg(target_arch = "arm")]
113+
pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 {
114+
a as f32
115+
}
116+
}

testcrate/build.rs

+18
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,24 @@ fn main() {
348348
"builtins::float::extend::__extendsfdf2vfp(a)");
349349
}
350350

351+
// float/truncate.rs
352+
gen(|a: MyF64| {
353+
if a.0.is_nan() {
354+
return None;
355+
}
356+
Some(a.0 as f32)
357+
},
358+
"builtins::float::truncate::__truncdfsf2(a)");
359+
if target_arch_arm {
360+
gen(|a: LargeF64| {
361+
if a.0.is_nan() {
362+
return None;
363+
}
364+
Some(a.0 as f32)
365+
},
366+
"builtins::float::truncate::__truncdfsf2vfp(a)");
367+
}
368+
351369
// float/conv.rs
352370
gen(|a: MyF64| i64(a.0).ok(),
353371
"builtins::float::conv::__fixdfdi(a)");

0 commit comments

Comments
 (0)