Skip to content

Commit d96102d

Browse files
ithinuelJorge Aparicio
authored and
Jorge Aparicio
committed
implement float/double to (u)int conversion.
1 parent 293fef5 commit d96102d

File tree

5 files changed

+145
-2
lines changed

5 files changed

+145
-2
lines changed

compiler-rt/compiler-rt-cdylib/build.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,14 @@ fn main() {
6868
"floatunsisf.c",
6969
"floatunsidf.c",
7070
"floatundidf.c",
71+
"fixsfsi.c",
72+
"fixsfdi.c",
73+
"fixdfsi.c",
74+
"fixdfdi.c",
75+
"fixunssfsi.c",
76+
"fixunssfdi.c",
77+
"fixunsdfsi.c",
78+
"fixunsdfdi.c",
7179
// 128 bit integers
7280
"lshrti3.c",
7381
"modti3.c",

compiler-rt/compiler-rt-cdylib/src/lib.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ extern {
3232
fn __floatunsisf();
3333
fn __floatunsidf();
3434
fn __floatundidf();
35+
fn __fixsfsi();
36+
fn __fixsfdi();
37+
fn __fixdfsi();
38+
fn __fixdfdi();
39+
fn __fixunssfsi();
40+
fn __fixunssfdi();
41+
fn __fixunsdfsi();
42+
fn __fixunsdfdi();
3543
}
3644

3745
macro_rules! declare {
@@ -73,6 +81,14 @@ declare!(___floatdidf, __floatdidf);
7381
declare!(___floatunsisf, __floatunsisf);
7482
declare!(___floatunsidf, __floatunsidf);
7583
declare!(___floatundidf, __floatundidf);
84+
declare!(___fixsfsi, __fixsfsi);
85+
declare!(___fixsfdi, __fixsfdi);
86+
declare!(___fixdfsi, __fixdfsi);
87+
declare!(___fixdfdi, __fixdfdi);
88+
declare!(___fixunssfsi, __fixunssfsi);
89+
declare!(___fixunssfdi, __fixunssfdi);
90+
declare!(___fixunsdfsi, __fixunsdfsi);
91+
declare!(___fixunsdfdi, __fixunsdfdi);
7692

7793
#[cfg(all(not(windows),
7894
not(target_arch = "mips64"),

src/float/conv.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,73 @@ fp_convert!(__floatunsisf: u32, f32);
8989
fp_convert!(__floatunsidf: u32, f64);
9090
fp_convert!(__floatundidf: u64, f64);
9191

92+
#[derive(PartialEq, Debug)]
93+
enum Sign {
94+
Positive,
95+
Negative
96+
}
97+
macro_rules! fp_fix {
98+
($intrinsic:ident: $fty:ty, $ity:ty) => {
99+
pub extern "C" fn $intrinsic(f: $fty) -> $ity {
100+
let fixint_min = <$ity>::min_value();
101+
let fixint_max = <$ity>::max_value();
102+
let fixint_bits = <$ity>::bits() as usize;
103+
let fixint_unsigned = fixint_min == 0;
104+
105+
let sign_bit = <$fty>::sign_mask();
106+
let significand_bits = <$fty>::significand_bits() as usize;
107+
let exponent_bias = <$fty>::exponent_bias() as usize;
108+
//let exponent_max = <$fty>::exponent_max() as usize;
109+
110+
// Break a into sign, exponent, significand
111+
let a_rep = <$fty>::repr(f);
112+
let a_abs = a_rep & !sign_bit;
113+
114+
// this is used to work around -1 not being available for unsigned
115+
let sign = if (a_rep & sign_bit) == 0 { Sign::Positive } else { Sign::Negative };
116+
let mut exponent = (a_abs >> significand_bits) as usize;
117+
let significand = (a_abs & <$fty>::significand_mask()) | <$fty>::implicit_bit();
118+
119+
// if < 1 or unsigned & negative
120+
if exponent < exponent_bias ||
121+
fixint_unsigned && sign == Sign::Negative {
122+
return 0
123+
}
124+
exponent -= exponent_bias;
125+
126+
// If the value is infinity, saturate.
127+
// If the value is too large for the integer type, 0.
128+
if exponent >= (if fixint_unsigned {fixint_bits} else {fixint_bits -1}) {
129+
return if sign == Sign::Positive {fixint_max} else {fixint_min}
130+
}
131+
// If 0 <= exponent < significand_bits, right shift to get the result.
132+
// Otherwise, shift left.
133+
// (sign - 1) will never overflow as negative signs are already returned as 0 for unsigned
134+
let r = if exponent < significand_bits {
135+
(significand >> (significand_bits - exponent)) as $ity
136+
} else {
137+
(significand as $ity) << (exponent - significand_bits)
138+
};
139+
140+
if sign == Sign::Negative {
141+
(!r).wrapping_add(1)
142+
} else {
143+
r
144+
}
145+
}
146+
}
147+
}
148+
149+
fp_fix!(__fixsfsi: f32, i32);
150+
fp_fix!(__fixsfdi: f32, i64);
151+
fp_fix!(__fixdfsi: f64, i32);
152+
fp_fix!(__fixdfdi: f64, i64);
153+
154+
fp_fix!(__fixunssfsi: f32, u32);
155+
fp_fix!(__fixunssfdi: f32, u64);
156+
fp_fix!(__fixunsdfsi: f64, u32);
157+
fp_fix!(__fixunsdfdi: f64, u64);
158+
92159
// NOTE(cfg) for some reason, on arm*-unknown-linux-gnueabihf, our implementation doesn't
93160
// match the output of its gcc_s or compiler-rt counterpart. Until we investigate further, we'll
94161
// just avoid testing against them on those targets. Do note that our implementation gives the
@@ -129,5 +196,47 @@ mod tests {
129196
-> Option<F64> {
130197
Some(F64(f(a.0)))
131198
}
199+
200+
fn __fixsfsi(f: extern fn(f32) -> i32,
201+
a: F32)
202+
-> Option<I32> {
203+
Some(I32(f(a.0)))
204+
}
205+
fn __fixsfdi(f: extern fn(f32) -> i64,
206+
a: F32)
207+
-> Option<I64> {
208+
Some(I64(f(a.0)))
209+
}
210+
fn __fixdfsi(f: extern fn(f64) -> i32,
211+
a: F64)
212+
-> Option<I32> {
213+
Some(I32(f(a.0)))
214+
}
215+
fn __fixdfdi(f: extern fn(f64) -> i64,
216+
a: F64)
217+
-> Option<I64> {
218+
Some(I64(f(a.0)))
219+
}
220+
221+
fn __fixunssfsi(f: extern fn(f32) -> u32,
222+
a: F32)
223+
-> Option<U32> {
224+
Some(U32(f(a.0)))
225+
}
226+
fn __fixunssfdi(f: extern fn(f32) -> u64,
227+
a: F32)
228+
-> Option<U64> {
229+
Some(U64(f(a.0)))
230+
}
231+
fn __fixunsdfsi(f: extern fn(f64) -> u32,
232+
a: F64)
233+
-> Option<U32> {
234+
Some(U32(f(a.0)))
235+
}
236+
fn __fixunsdfdi(f: extern fn(f64) -> u64,
237+
a: F64)
238+
-> Option<U64> {
239+
Some(U64(f(a.0)))
240+
}
132241
}
133242
}

src/float/mod.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ pub trait Float: Sized + Copy {
3636
/// Returns a mask for the significand
3737
fn significand_mask() -> Self::Int;
3838

39+
// Returns the implicit bit of the float format
40+
fn implicit_bit() -> Self::Int;
41+
3942
/// Returns a mask for the exponent
4043
fn exponent_mask() -> Self::Int;
4144

@@ -68,6 +71,9 @@ impl Float for f32 {
6871
fn significand_bits() -> u32 {
6972
23
7073
}
74+
fn implicit_bit() -> Self::Int {
75+
1 << Self::significand_bits()
76+
}
7177
fn sign_mask() -> Self::Int {
7278
1 << (Self::bits() - 1)
7379
}
@@ -110,6 +116,10 @@ impl Float for f64 {
110116
fn significand_bits() -> u32 {
111117
52
112118
}
119+
// Returns the implicit bit of the float format
120+
fn implicit_bit() -> Self::Int {
121+
1 << Self::significand_bits()
122+
}
113123
fn sign_mask() -> Self::Int {
114124
1 << (Self::bits() - 1)
115125
}

src/qc.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use float::Float;
1515
// Generates values in the full range of the integer type
1616
macro_rules! arbitrary {
1717
($TY:ident : $ty:ident) => {
18-
#[derive(Clone, Copy)]
18+
#[derive(Clone, Copy, PartialEq)]
1919
pub struct $TY(pub $ty);
2020

2121
impl Arbitrary for $TY {
@@ -82,7 +82,7 @@ arbitrary!(U32: u32);
8282
// intrinsics.
8383
macro_rules! arbitrary_large {
8484
($TY:ident : $ty:ident) => {
85-
#[derive(Clone, Copy)]
85+
#[derive(Clone, Copy, PartialEq)]
8686
pub struct $TY(pub $ty);
8787

8888
impl Arbitrary for $TY {

0 commit comments

Comments
 (0)