Skip to content

Commit d2d4f22

Browse files
committed
Add integer to f16 conversions
These are not present in LLVM's `compiler-rt` but LLVM does emit them in some cases [1]. [1]: rust-lang/rust#132614 (comment)
1 parent e344295 commit d2d4f22

File tree

5 files changed

+153
-26
lines changed

5 files changed

+153
-26
lines changed

README.md

+6
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,17 @@ of being added to Rust.
233233
- [x] fixunstfdi.c
234234
- [x] fixunstfsi.c
235235
- [x] fixunstfti.c
236+
- [x] floatdihf.c (not yet in `compiler-rt` but emitted by LLVM)
236237
- [x] floatditf.c
238+
- [x] floatsihf.c (not yet in `compiler-rt` but emitted by LLVM)
237239
- [x] floatsitf.c
240+
- [x] floattihf.c (not yet in `compiler-rt` but emitted by LLVM)
238241
- [x] floattitf.c
242+
- [x] floatundihf.c (not yet in `compiler-rt` but emitted by LLVM)
239243
- [x] floatunditf.c
244+
- [x] floatunsihf.c (not yet in `compiler-rt` but emitted by LLVM)
240245
- [x] floatunsitf.c
246+
- [x] floatuntihf.c (not yet in `compiler-rt` but emitted by LLVM)
241247
- [x] floatuntitf.c
242248
- [x] multf3.c
243249
- [x] powitf2.c

src/float/conv.rs

+128-24
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,26 @@ mod int_to_float {
7979
F::from_bits(conv(i.unsigned_abs()) | sign_bit)
8080
}
8181

82+
#[cfg(f16_enabled)]
83+
pub fn u32_to_f16_bits(i: u32) -> u16 {
84+
let n = i.leading_zeros();
85+
let i_m = i.wrapping_shl(n);
86+
// Mantissa with implicit bit set
87+
let m_base: u16 = (i_m >> shift_f_lt_i::<u32, f16>()) as u16;
88+
// The entire lower half of `i` will be truncated (masked portion), plus the
89+
// next `EXPONENT_BITS` bits.
90+
let adj = (i_m >> f16::EXPONENT_BITS | i_m & 0xFF) as u16;
91+
let m = m_adj::<f16>(m_base, adj);
92+
let e = if i == 0 { 0 } else { exp::<u32, f16>(n) - 1 };
93+
// Any int can have an exponent out of range for `f16`, unlike other float types.
94+
// Clamp this.
95+
if e >= f16::EXPONENT_MAX as u16 - 1 {
96+
f16::INFINITY.to_bits()
97+
} else {
98+
repr::<f16>(e, m)
99+
}
100+
}
101+
82102
pub fn u32_to_f32_bits(i: u32) -> u32 {
83103
if i == 0 {
84104
return 0;
@@ -122,6 +142,33 @@ mod int_to_float {
122142
(h as u128) << 64
123143
}
124144

145+
#[cfg(f16_enabled)]
146+
pub fn u64_to_f16_bits(i: u64) -> u16 {
147+
let n = i.leading_zeros();
148+
let i_m = i.wrapping_shl(n); // Mantissa, shifted so the first bit is nonzero
149+
let m_base: u16 = (i_m >> shift_f_lt_i::<u64, f16>()) as u16;
150+
151+
// Within the upper `F::BITS`, everything except for the signifcand
152+
// gets truncated
153+
let d1: u16 = (i_m >> (u64::BITS - f16::BITS - f16::SIGNIFICAND_BITS - 1)).cast();
154+
155+
// The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just
156+
// check if it is nonzero.
157+
let d2: u16 = (i_m << f16::BITS >> f16::BITS != 0).into();
158+
let adj = d1 | d2;
159+
160+
// Mantissa with implicit bit set
161+
let m = m_adj::<f16>(m_base, adj);
162+
let e = if i == 0 { 0 } else { exp::<u64, f16>(n) - 1 };
163+
164+
// Clamp to infinity if the exponent is out of range
165+
if e >= f16::EXPONENT_MAX as u16 - 1 {
166+
f16::INFINITY.to_bits()
167+
} else {
168+
repr::<f16>(e, m)
169+
}
170+
}
171+
125172
pub fn u64_to_f32_bits(i: u64) -> u32 {
126173
let n = i.leading_zeros();
127174
let i_m = i.wrapping_shl(n);
@@ -160,6 +207,33 @@ mod int_to_float {
160207
repr::<f128>(e, m)
161208
}
162209

210+
#[cfg(f16_enabled)]
211+
pub fn u128_to_f16_bits(i: u128) -> u16 {
212+
let n = i.leading_zeros();
213+
let i_m = i.wrapping_shl(n); // Mantissa, shifted so the first bit is nonzero
214+
let m_base: u16 = (i_m >> shift_f_lt_i::<u128, f16>()) as u16;
215+
216+
// Within the upper `F::BITS`, everything except for the signifcand
217+
// gets truncated
218+
let d1: u16 = (i_m >> (u128::BITS - f16::BITS - f16::SIGNIFICAND_BITS - 1)).cast();
219+
220+
// The entire rest of `i_m` gets truncated. Zero the upper `F::BITS` then just
221+
// check if it is nonzero.
222+
let d2: u16 = (i_m << f16::BITS >> f16::BITS != 0).into();
223+
let adj = d1 | d2;
224+
225+
// Mantissa with implicit bit set
226+
let m = m_adj::<f16>(m_base, adj);
227+
let e = if i == 0 { 0 } else { exp::<u128, f16>(n) - 1 };
228+
229+
// Clamp to infinity if the exponent is out of range
230+
if e >= f16::EXPONENT_MAX as u16 - 1 {
231+
f16::INFINITY.to_bits()
232+
} else {
233+
repr::<f16>(e, m)
234+
}
235+
}
236+
163237
pub fn u128_to_f32_bits(i: u128) -> u32 {
164238
let n = i.leading_zeros();
165239
let i_m = i.wrapping_shl(n); // Mantissa, shifted so the first bit is nonzero
@@ -210,6 +284,11 @@ mod int_to_float {
210284

211285
// Conversions from unsigned integers to floats.
212286
intrinsics! {
287+
#[cfg(f16_enabled)]
288+
pub extern "C" fn __floatunsihf(i: u32) -> f16 {
289+
f16::from_bits(int_to_float::u32_to_f16_bits(i))
290+
}
291+
213292
#[arm_aeabi_alias = __aeabi_ui2f]
214293
pub extern "C" fn __floatunsisf(i: u32) -> f32 {
215294
f32::from_bits(int_to_float::u32_to_f32_bits(i))
@@ -220,6 +299,17 @@ intrinsics! {
220299
f64::from_bits(int_to_float::u32_to_f64_bits(i))
221300
}
222301

302+
#[ppc_alias = __floatunsikf]
303+
#[cfg(f128_enabled)]
304+
pub extern "C" fn __floatunsitf(i: u32) -> f128 {
305+
f128::from_bits(int_to_float::u32_to_f128_bits(i))
306+
}
307+
308+
#[cfg(f16_enabled)]
309+
pub extern "C" fn __floatundihf(i: u64) -> f16 {
310+
f16::from_bits(int_to_float::u64_to_f16_bits(i))
311+
}
312+
223313
#[arm_aeabi_alias = __aeabi_ul2f]
224314
pub extern "C" fn __floatundisf(i: u64) -> f32 {
225315
f32::from_bits(int_to_float::u64_to_f32_bits(i))
@@ -230,6 +320,17 @@ intrinsics! {
230320
f64::from_bits(int_to_float::u64_to_f64_bits(i))
231321
}
232322

323+
#[ppc_alias = __floatundikf]
324+
#[cfg(f128_enabled)]
325+
pub extern "C" fn __floatunditf(i: u64) -> f128 {
326+
f128::from_bits(int_to_float::u64_to_f128_bits(i))
327+
}
328+
329+
#[cfg(f16_enabled)]
330+
pub extern "C" fn __floatuntihf(i: u128) -> f16 {
331+
f16::from_bits(int_to_float::u128_to_f16_bits(i))
332+
}
333+
233334
#[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
234335
pub extern "C" fn __floatuntisf(i: u128) -> f32 {
235336
f32::from_bits(int_to_float::u128_to_f32_bits(i))
@@ -240,18 +341,6 @@ intrinsics! {
240341
f64::from_bits(int_to_float::u128_to_f64_bits(i))
241342
}
242343

243-
#[ppc_alias = __floatunsikf]
244-
#[cfg(f128_enabled)]
245-
pub extern "C" fn __floatunsitf(i: u32) -> f128 {
246-
f128::from_bits(int_to_float::u32_to_f128_bits(i))
247-
}
248-
249-
#[ppc_alias = __floatundikf]
250-
#[cfg(f128_enabled)]
251-
pub extern "C" fn __floatunditf(i: u64) -> f128 {
252-
f128::from_bits(int_to_float::u64_to_f128_bits(i))
253-
}
254-
255344
#[ppc_alias = __floatuntikf]
256345
#[cfg(f128_enabled)]
257346
pub extern "C" fn __floatuntitf(i: u128) -> f128 {
@@ -261,6 +350,11 @@ intrinsics! {
261350

262351
// Conversions from signed integers to floats.
263352
intrinsics! {
353+
#[cfg(f16_enabled)]
354+
pub extern "C" fn __floatsihf(i: i32) -> f16 {
355+
int_to_float::signed(i, int_to_float::u32_to_f16_bits)
356+
}
357+
264358
#[arm_aeabi_alias = __aeabi_i2f]
265359
pub extern "C" fn __floatsisf(i: i32) -> f32 {
266360
int_to_float::signed(i, int_to_float::u32_to_f32_bits)
@@ -271,6 +365,17 @@ intrinsics! {
271365
int_to_float::signed(i, int_to_float::u32_to_f64_bits)
272366
}
273367

368+
#[ppc_alias = __floatsikf]
369+
#[cfg(f128_enabled)]
370+
pub extern "C" fn __floatsitf(i: i32) -> f128 {
371+
int_to_float::signed(i, int_to_float::u32_to_f128_bits)
372+
}
373+
374+
#[cfg(f16_enabled)]
375+
pub extern "C" fn __floatdihf(i: i64) -> f16 {
376+
int_to_float::signed(i, int_to_float::u64_to_f16_bits)
377+
}
378+
274379
#[arm_aeabi_alias = __aeabi_l2f]
275380
pub extern "C" fn __floatdisf(i: i64) -> f32 {
276381
int_to_float::signed(i, int_to_float::u64_to_f32_bits)
@@ -281,6 +386,17 @@ intrinsics! {
281386
int_to_float::signed(i, int_to_float::u64_to_f64_bits)
282387
}
283388

389+
#[ppc_alias = __floatdikf]
390+
#[cfg(f128_enabled)]
391+
pub extern "C" fn __floatditf(i: i64) -> f128 {
392+
int_to_float::signed(i, int_to_float::u64_to_f128_bits)
393+
}
394+
395+
#[cfg(f16_enabled)]
396+
pub extern "C" fn __floattihf(i: i128) -> f16 {
397+
int_to_float::signed(i, int_to_float::u128_to_f16_bits)
398+
}
399+
284400
#[cfg_attr(target_os = "uefi", unadjusted_on_win64)]
285401
pub extern "C" fn __floattisf(i: i128) -> f32 {
286402
int_to_float::signed(i, int_to_float::u128_to_f32_bits)
@@ -291,18 +407,6 @@ intrinsics! {
291407
int_to_float::signed(i, int_to_float::u128_to_f64_bits)
292408
}
293409

294-
#[ppc_alias = __floatsikf]
295-
#[cfg(f128_enabled)]
296-
pub extern "C" fn __floatsitf(i: i32) -> f128 {
297-
int_to_float::signed(i, int_to_float::u32_to_f128_bits)
298-
}
299-
300-
#[ppc_alias = __floatdikf]
301-
#[cfg(f128_enabled)]
302-
pub extern "C" fn __floatditf(i: i64) -> f128 {
303-
int_to_float::signed(i, int_to_float::u64_to_f128_bits)
304-
}
305-
306410
#[ppc_alias = __floattikf]
307411
#[cfg(f128_enabled)]
308412
pub extern "C" fn __floattitf(i: i128) -> f128 {

testcrate/Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,10 @@ no-f16-f128 = ["compiler_builtins/no-f16-f128"]
3939
mem = ["compiler_builtins/mem"]
4040
mangled-names = ["compiler_builtins/mangled-names"]
4141
# Skip tests that rely on f128 symbols being available on the system
42-
no-sys-f128 = ["no-sys-f128-int-convert", "no-sys-f16-f128-convert"]
42+
no-sys-f128 = ["no-sys-f16-int-convert", "no-sys-f128-int-convert", "no-sys-f16-f128-convert"]
4343
# Some platforms have some f128 functions but everything except integer conversions
4444
no-sys-f128-int-convert = []
45+
no-sys-f16-int-convert = []
4546
no-sys-f16-f128-convert = []
4647
# Skip tests that rely on f16 symbols being available on the system
4748
no-sys-f16 = []

testcrate/build.rs

+6
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ enum Feature {
66
NoSysF128,
77
NoSysF128IntConvert,
88
NoSysF16,
9+
NoSysF16IntConvert,
910
NoSysF16F128Convert,
1011
}
1112

@@ -40,6 +41,7 @@ fn main() {
4041
{
4142
features.insert(Feature::NoSysF128);
4243
features.insert(Feature::NoSysF128IntConvert);
44+
features.insert(Feature::NoSysF16IntConvert);
4345
features.insert(Feature::NoSysF16F128Convert);
4446
}
4547

@@ -76,6 +78,10 @@ fn main() {
7678
"no-sys-f128-int-convert",
7779
"using apfloat fallback for f128 <-> int conversions",
7880
),
81+
Feature::NoSysF16IntConvert => (
82+
"no-sys-f16-int-convert",
83+
"using apfloat fallback for f16 <-> int conversions",
84+
),
7985
Feature::NoSysF16F128Convert => (
8086
"no-sys-f16-f128-convert",
8187
"using apfloat fallback for f16 <-> f128 conversions",

testcrate/tests/conv.rs

+11-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ mod i_to_f {
3434
FloatTy::from_u128(x.try_into().unwrap()).value
3535
};
3636

37-
<$f_ty>::from_bits(apf.to_bits())
37+
<$f_ty>::from_bits(apf.to_bits().try_into().unwrap())
3838
},
3939
x
4040
);
@@ -100,6 +100,16 @@ mod i_to_f {
100100
};
101101
}
102102

103+
#[cfg(f16_enabled)]
104+
i_to_f! { f16, Half, not(feature = "no-sys-f16-int-convert"),
105+
u32, __floatunsihf;
106+
i32, __floatsihf;
107+
u64, __floatundihf;
108+
i64, __floatdihf;
109+
u128, __floatuntihf;
110+
i128, __floattihf;
111+
}
112+
103113
i_to_f! { f32, Single, all(),
104114
u32, __floatunsisf;
105115
i32, __floatsisf;

0 commit comments

Comments
 (0)