Skip to content

Commit 1deeef4

Browse files
authored
Merge pull request #448 from ayrtonm/truncdfsf2
2 parents 4111890 + f654edb commit 1deeef4

File tree

6 files changed

+163
-12
lines changed

6 files changed

+163
-12
lines changed

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ features = ["c"]
126126
- [x] arm/softfloat-alias.list
127127
- [x] arm/subdf3vfp.S
128128
- [x] arm/subsf3vfp.S
129-
- [ ] arm/truncdfsf2vfp.S
129+
- [x] arm/truncdfsf2vfp.S
130130
- [ ] arm/udivmodsi4.S (generic version is done)
131131
- [ ] arm/udivsi3.S (generic version is done)
132132
- [ ] arm/umodsi3.S (generic version is done)
@@ -183,7 +183,7 @@ features = ["c"]
183183
- [x] subdf3.c
184184
- [x] subsf3.c
185185
- [ ] truncdfhf2.c
186-
- [ ] truncdfsf2.c
186+
- [x] truncdfsf2.c
187187
- [ ] truncsfhf2.c
188188
- [x] udivdi3.c
189189
- [x] udivmoddi4.c

build.rs

-1
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,6 @@ mod c {
227227
("__negsf2", "negsf2.c"),
228228
("__powixf2", "powixf2.c"),
229229
("__truncdfhf2", "truncdfhf2.c"),
230-
("__truncdfsf2", "truncdfsf2.c"),
231230
("__truncsfhf2", "truncsfhf2.c"),
232231
]);
233232
}

examples/intrinsics.rs

+2-9
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,9 @@ extern "C" {}
2424
// have an additional comment: the function name is the ARM name for the intrinsic and the comment
2525
// in the non-ARM name for the intrinsic.
2626
mod intrinsics {
27-
// trunccdfsf2
27+
// truncdfsf2
2828
pub fn aeabi_d2f(x: f64) -> f32 {
29-
// This is only implemented in C currently, so only test it there.
30-
#[cfg(feature = "c")]
31-
return x as f32;
32-
#[cfg(not(feature = "c"))]
33-
{
34-
drop(x);
35-
0.0
36-
}
29+
x as f32
3730
}
3831

3932
// fixdfsi

src/float/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub mod extend;
1010
pub mod mul;
1111
pub mod pow;
1212
pub mod sub;
13+
pub mod trunc;
1314

1415
public_test_dep! {
1516
/// Trait for some basic operations on floats

src/float/trunc.rs

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
use float::Float;
2+
use int::{CastInto, Int};
3+
4+
fn trunc<F: Float, R: Float>(a: F) -> R
5+
where
6+
F::Int: CastInto<u64>,
7+
F::Int: CastInto<u32>,
8+
u64: CastInto<F::Int>,
9+
u32: CastInto<F::Int>,
10+
11+
R::Int: CastInto<u32>,
12+
u32: CastInto<R::Int>,
13+
F::Int: CastInto<R::Int>,
14+
{
15+
let src_zero = F::Int::ZERO;
16+
let src_one = F::Int::ONE;
17+
let src_bits = F::BITS;
18+
let src_exp_bias = F::EXPONENT_BIAS;
19+
20+
let src_min_normal = F::IMPLICIT_BIT;
21+
let src_significand_mask = F::SIGNIFICAND_MASK;
22+
let src_infinity = F::EXPONENT_MASK;
23+
let src_sign_mask = F::SIGN_MASK;
24+
let src_abs_mask = src_sign_mask - src_one;
25+
let round_mask = (src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)) - src_one;
26+
let halfway = src_one << (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS - 1);
27+
let src_qnan = src_one << (F::SIGNIFICAND_BITS - 1);
28+
let src_nan_code = src_qnan - src_one;
29+
30+
let dst_zero = R::Int::ZERO;
31+
let dst_one = R::Int::ONE;
32+
let dst_bits = R::BITS;
33+
let dst_inf_exp = R::EXPONENT_MAX;
34+
let dst_exp_bias = R::EXPONENT_BIAS;
35+
36+
let underflow_exponent: F::Int = (src_exp_bias + 1 - dst_exp_bias).cast();
37+
let overflow_exponent: F::Int = (src_exp_bias + dst_inf_exp - dst_exp_bias).cast();
38+
let underflow: F::Int = underflow_exponent << F::SIGNIFICAND_BITS;
39+
let overflow: F::Int = overflow_exponent << F::SIGNIFICAND_BITS;
40+
41+
let dst_qnan = R::Int::ONE << (R::SIGNIFICAND_BITS - 1);
42+
let dst_nan_code = dst_qnan - dst_one;
43+
44+
let sign_bits_delta = F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS;
45+
// Break a into a sign and representation of the absolute value.
46+
let a_abs = a.repr() & src_abs_mask;
47+
let sign = a.repr() & src_sign_mask;
48+
let mut abs_result: R::Int;
49+
50+
if a_abs.wrapping_sub(underflow) < a_abs.wrapping_sub(overflow) {
51+
// The exponent of a is within the range of normal numbers in the
52+
// destination format. We can convert by simply right-shifting with
53+
// rounding and adjusting the exponent.
54+
abs_result = (a_abs >> sign_bits_delta).cast();
55+
let tmp = src_exp_bias.wrapping_sub(dst_exp_bias) << R::SIGNIFICAND_BITS;
56+
abs_result = abs_result.wrapping_sub(tmp.cast());
57+
58+
let round_bits = a_abs & round_mask;
59+
if round_bits > halfway {
60+
// Round to nearest.
61+
abs_result += dst_one;
62+
} else if round_bits == halfway {
63+
// Tie to even.
64+
abs_result += abs_result & dst_one;
65+
};
66+
} else if a_abs > src_infinity {
67+
// a is NaN.
68+
// Conjure the result by beginning with infinity, setting the qNaN
69+
// bit and inserting the (truncated) trailing NaN field.
70+
abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast();
71+
abs_result |= dst_qnan;
72+
abs_result |= dst_nan_code
73+
& ((a_abs & src_nan_code) >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast();
74+
} else if a_abs >= overflow {
75+
// a overflows to infinity.
76+
abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast();
77+
} else {
78+
// a underflows on conversion to the destination type or is an exact
79+
// zero. The result may be a denormal or zero. Extract the exponent
80+
// to get the shift amount for the denormalization.
81+
let a_exp: u32 = (a_abs >> F::SIGNIFICAND_BITS).cast();
82+
let shift = src_exp_bias - dst_exp_bias - a_exp + 1;
83+
84+
let significand = (a.repr() & src_significand_mask) | src_min_normal;
85+
86+
// Right shift by the denormalization amount with sticky.
87+
if shift > F::SIGNIFICAND_BITS {
88+
abs_result = dst_zero;
89+
} else {
90+
let sticky = if (significand << (src_bits - shift)) != src_zero {
91+
src_one
92+
} else {
93+
src_zero
94+
};
95+
let denormalized_significand: F::Int = significand >> shift | sticky;
96+
abs_result =
97+
(denormalized_significand >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast();
98+
let round_bits = denormalized_significand & round_mask;
99+
// Round to nearest
100+
if round_bits > halfway {
101+
abs_result += dst_one;
102+
}
103+
// Ties to even
104+
else if round_bits == halfway {
105+
abs_result += abs_result & dst_one;
106+
};
107+
}
108+
}
109+
110+
// Apply the signbit to the absolute value.
111+
R::from_repr(abs_result | sign.wrapping_shr(src_bits - dst_bits).cast())
112+
}
113+
114+
intrinsics! {
115+
#[aapcs_on_arm]
116+
#[arm_aeabi_alias = __aeabi_d2f]
117+
pub extern "C" fn __truncdfsf2(a: f64) -> f32 {
118+
trunc(a)
119+
}
120+
121+
#[cfg(target_arch = "arm")]
122+
pub extern "C" fn __truncdfsf2vfp(a: f64) -> f32 {
123+
a as f32
124+
}
125+
}

testcrate/tests/misc.rs

+33
Original file line numberDiff line numberDiff line change
@@ -179,3 +179,36 @@ fn float_pow() {
179179
f64, 1e-12, __powidf2;
180180
);
181181
}
182+
183+
macro_rules! trunc {
184+
($fX:ident, $fD:ident, $fn:ident) => {
185+
fuzz_float(N, |x: $fX| {
186+
let tmp0 = x as $fD;
187+
let tmp1: $fD = $fn(x);
188+
if !Float::eq_repr(tmp0, tmp1) {
189+
panic!(
190+
"{}({}): std: {}, builtins: {}",
191+
stringify!($fn),
192+
x,
193+
tmp0,
194+
tmp1
195+
);
196+
}
197+
});
198+
};
199+
}
200+
201+
#[test]
202+
fn float_trunc() {
203+
use compiler_builtins::float::trunc::__truncdfsf2;
204+
205+
trunc!(f64, f32, __truncdfsf2);
206+
}
207+
208+
#[cfg(target_arch = "arm")]
209+
#[test]
210+
fn float_trunc_arm() {
211+
use compiler_builtins::float::trunc::__truncdfsf2vfp;
212+
213+
trunc!(f64, f32, __truncdfsf2vfp);
214+
}

0 commit comments

Comments
 (0)