Skip to content

Commit efd5d7d

Browse files
committed
Add builtins for f16/f128 float conversions
1 parent 2705081 commit efd5d7d

File tree

11 files changed

+283
-115
lines changed

11 files changed

+283
-115
lines changed

Cargo.toml

+4
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,10 @@ c = ["cc"]
4949
# which use inline assembly and fall back to pure Rust versions (if avalible).
5050
no-asm = []
5151

52+
# Workaround for codegen backends which haven't yet implemented `f16` and
53+
# `f128` support. Disabled any intrinsics which use those types.
54+
no-f16-f128 = []
55+
5256
# Flag this library as the unstable compiler-builtins lib
5357
compiler-builtins = []
5458

README.md

+33-28
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,6 @@ rely on CI.
162162
- [x] divmodsi4.c
163163
- [x] divsf3.c
164164
- [x] divsi3.c
165-
- [ ] extendhfsf2.c
166165
- [x] extendsfdf2.c
167166
- [x] fixdfdi.c
168167
- [x] fixdfsi.c
@@ -201,9 +200,7 @@ rely on CI.
201200
- [x] powisf2.c
202201
- [x] subdf3.c
203202
- [x] subsf3.c
204-
- [ ] truncdfhf2.c
205203
- [x] truncdfsf2.c
206-
- [ ] truncsfhf2.c
207204
- [x] udivdi3.c
208205
- [x] udivmoddi4.c
209206
- [x] udivmodsi4.c
@@ -233,60 +230,68 @@ These builtins are needed to support 128-bit integers, which are in the process
233230
- [x] udivti3.c
234231
- [x] umodti3.c
235232

233+
These builtins are needed to support `f16` and `f128`, which are in the process of being added to Rust.
234+
235+
- [ ] addtf3.c
236+
- [ ] comparetf2.c
237+
- [ ] divtf3.c
238+
- [x] extenddftf2.c
239+
- [x] extendhfsf2.c
240+
- [x] extendhftf2.c
241+
- [x] extendsftf2.c
242+
- [ ] fixtfdi.c
243+
- [ ] fixtfsi.c
244+
- [ ] fixtfti.c
245+
- [ ] fixunstfdi.c
246+
- [ ] fixunstfsi.c
247+
- [ ] fixunstfti.c
248+
- [ ] floatditf.c
249+
- [ ] floatsitf.c
250+
- [ ] floatunditf.c
251+
- [ ] floatunsitf.c
252+
- [ ] multf3.c
253+
- [ ] powitf2.c
254+
- [ ] ppc/fixtfdi.c
255+
- [ ] ppc/fixunstfdi.c
256+
- [ ] ppc/floatditf.c
257+
- [ ] ppc/floatunditf.c
258+
- [ ] subtf3.c
259+
- [x] truncdfhf2.c
260+
- [x] truncsfhf2.c
261+
- [x] trunctfdf2.c
262+
- [x] trunctfhf2.c
263+
- [x] trunctfsf2.c
264+
236265
## Unimplemented functions
237266

238-
These builtins involve floating-point types ("`f128`", "`f80`" and complex numbers) that are not supported by Rust.
267+
These builtins involve floating-point types ("`f80`" and complex numbers) that are not supported by Rust.
239268

240-
- ~~addtf3.c~~
241-
- ~~comparetf2.c~~
242269
- ~~divdc3.c~~
243270
- ~~divsc3.c~~
244271
- ~~divtc3.c~~
245-
- ~~divtf3.c~~
246272
- ~~divxc3.c~~
247-
- ~~extenddftf2.c~~
248-
- ~~extendsftf2.c~~
249-
- ~~fixtfdi.c~~
250-
- ~~fixtfsi.c~~
251-
- ~~fixtfti.c~~
252-
- ~~fixunstfdi.c~~
253-
- ~~fixunstfsi.c~~
254-
- ~~fixunstfti.c~~
255273
- ~~fixunsxfdi.c~~
256274
- ~~fixunsxfsi.c~~
257275
- ~~fixunsxfti.c~~
258276
- ~~fixxfdi.c~~
259277
- ~~fixxfti.c~~
260-
- ~~floatditf.c~~
261278
- ~~floatdixf.c~~
262-
- ~~floatsitf.c~~
263279
- ~~floattixf.c~~
264-
- ~~floatunditf.c~~
265280
- ~~floatundixf.c~~
266-
- ~~floatunsitf.c~~
267281
- ~~floatuntixf.c~~
268282
- ~~i386/floatdixf.S~~
269283
- ~~i386/floatundixf.S~~
270284
- ~~muldc3.c~~
271285
- ~~mulsc3.c~~
272286
- ~~multc3.c~~
273-
- ~~multf3.c~~
274287
- ~~mulxc3.c~~
275-
- ~~powitf2.c~~
276288
- ~~powixf2.c~~
277289
- ~~ppc/divtc3.c~~
278-
- ~~ppc/fixtfdi.c~~
279-
- ~~ppc/fixunstfdi.c~~
280-
- ~~ppc/floatditf.c~~
281-
- ~~ppc/floatunditf.c~~
282290
- ~~ppc/gcc_qadd.c~~
283291
- ~~ppc/gcc_qdiv.c~~
284292
- ~~ppc/gcc_qmul.c~~
285293
- ~~ppc/gcc_qsub.c~~
286294
- ~~ppc/multc3.c~~
287-
- ~~subtf3.c~~
288-
- ~~trunctfdf2.c~~
289-
- ~~trunctfsf2.c~~
290295
- ~~x86_64/floatdixf.c~~
291296
- ~~x86_64/floatundixf.S~~
292297

build.rs

+8-13
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,14 @@ mod c {
217217
}
218218
}
219219

220+
// `compiler-rt` requires `COMPILER_RT_HAS_FLOAT16` to be defined to make it use the
221+
// `_Float16` type for `f16` intrinsics. This shouldn't matter as all existing `f16`
222+
// intrinsics have been ported to Rust in `compiler-builtins` as C compilers don't
223+
// support `_Float16` on all targets (whereas Rust does). However, define the macro
224+
// anyway to prevent issues like rust#118813 and rust#123885 silently reoccuring if more
225+
// `f16` intrinsics get accidentally added here in the future.
226+
cfg.define("COMPILER_RT_HAS_FLOAT16", None);
227+
220228
cfg.warnings(false);
221229

222230
if target_env == "msvc" {
@@ -288,13 +296,10 @@ mod c {
288296
sources.extend(&[
289297
("__divdc3", "divdc3.c"),
290298
("__divsc3", "divsc3.c"),
291-
("__extendhfsf2", "extendhfsf2.c"),
292299
("__muldc3", "muldc3.c"),
293300
("__mulsc3", "mulsc3.c"),
294301
("__negdf2", "negdf2.c"),
295302
("__negsf2", "negsf2.c"),
296-
("__truncdfhf2", "truncdfhf2.c"),
297-
("__truncsfhf2", "truncsfhf2.c"),
298303
]);
299304
}
300305

@@ -464,8 +469,6 @@ mod c {
464469
if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics {
465470
sources.extend(&[
466471
("__comparetf2", "comparetf2.c"),
467-
("__extenddftf2", "extenddftf2.c"),
468-
("__extendsftf2", "extendsftf2.c"),
469472
("__fixtfdi", "fixtfdi.c"),
470473
("__fixtfsi", "fixtfsi.c"),
471474
("__fixtfti", "fixtfti.c"),
@@ -476,8 +479,6 @@ mod c {
476479
("__floatsitf", "floatsitf.c"),
477480
("__floatunditf", "floatunditf.c"),
478481
("__floatunsitf", "floatunsitf.c"),
479-
("__trunctfdf2", "trunctfdf2.c"),
480-
("__trunctfsf2", "trunctfsf2.c"),
481482
("__addtf3", "addtf3.c"),
482483
("__multf3", "multf3.c"),
483484
("__subtf3", "subtf3.c"),
@@ -498,7 +499,6 @@ mod c {
498499

499500
if target_arch == "mips64" {
500501
sources.extend(&[
501-
("__extenddftf2", "extenddftf2.c"),
502502
("__netf2", "comparetf2.c"),
503503
("__addtf3", "addtf3.c"),
504504
("__multf3", "multf3.c"),
@@ -509,14 +509,11 @@ mod c {
509509
("__floatunsitf", "floatunsitf.c"),
510510
("__fe_getround", "fp_mode.c"),
511511
("__divtf3", "divtf3.c"),
512-
("__trunctfdf2", "trunctfdf2.c"),
513-
("__trunctfsf2", "trunctfsf2.c"),
514512
]);
515513
}
516514

517515
if target_arch == "loongarch64" {
518516
sources.extend(&[
519-
("__extenddftf2", "extenddftf2.c"),
520517
("__netf2", "comparetf2.c"),
521518
("__addtf3", "addtf3.c"),
522519
("__multf3", "multf3.c"),
@@ -527,8 +524,6 @@ mod c {
527524
("__floatunsitf", "floatunsitf.c"),
528525
("__fe_getround", "fp_mode.c"),
529526
("__divtf3", "divtf3.c"),
530-
("__trunctfdf2", "trunctfdf2.c"),
531-
("__trunctfsf2", "trunctfsf2.c"),
532527
]);
533528
}
534529

ci/run.sh

+4
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ else
2828
$run --features c --release
2929
$run --features no-asm
3030
$run --features no-asm --release
31+
$run --features no-f16-f128
32+
$run --features no-f16-f128 --release
3133
fi
3234

3335
if [ -d /builtins-target ]; then
@@ -45,6 +47,8 @@ cargo build --target "$target" --features c
4547
cargo build --target "$target" --release --features c
4648
cargo build --target "$target" --features no-asm
4749
cargo build --target "$target" --release --features no-asm
50+
cargo build --target "$target" --features no-f16-f128
51+
cargo build --target "$target" --release --features no-f16-f128
4852

4953
PREFIX=${target//unknown-/}-
5054
case "$target" in

src/float/extend.rs

+34
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,37 @@ intrinsics! {
8282
a as f64 // LLVM generate 'fcvtds'
8383
}
8484
}
85+
86+
#[cfg(not(feature = "no-f16-f128"))]
87+
intrinsics! {
88+
#[avr_skip]
89+
#[aapcs_on_arm]
90+
#[arm_aeabi_alias = __aeabi_h2f]
91+
pub extern "C" fn __extendhfsf2(a: f16) -> f32 {
92+
extend(a)
93+
}
94+
95+
#[avr_skip]
96+
#[aapcs_on_arm]
97+
pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 {
98+
extend(a)
99+
}
100+
101+
#[avr_skip]
102+
#[aapcs_on_arm]
103+
pub extern "C" fn __extendhftf2(a: f16) -> f128 {
104+
extend(a)
105+
}
106+
107+
#[avr_skip]
108+
#[aapcs_on_arm]
109+
pub extern "C" fn __extendsftf2(a: f32) -> f128 {
110+
extend(a)
111+
}
112+
113+
#[avr_skip]
114+
#[aapcs_on_arm]
115+
pub extern "C" fn __extenddftf2(a: f64) -> f128 {
116+
extend(a)
117+
}
118+
}

src/float/mod.rs

+18-1
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,20 @@ macro_rules! float_impl {
127127
self.to_bits() as Self::SignedInt
128128
}
129129
fn eq_repr(self, rhs: Self) -> bool {
130-
if self.is_nan() && rhs.is_nan() {
130+
#[cfg(feature = "mangled-names")]
131+
fn is_nan(x: $ty) -> bool {
132+
// When using mangled-names, the "real" compiler-builtins might not have the
133+
// necessary builtin (__unordtf2) to test whether `f128` is NaN.
134+
// FIXME(f16_f128): Remove once the nightly toolchain has the __unordtf2 builtin
135+
// x is NaN if all the bits of the exponent are set and the significand is non-0
136+
x.repr() & $ty::EXPONENT_MASK == $ty::EXPONENT_MASK
137+
&& x.repr() & $ty::SIGNIFICAND_MASK != 0
138+
}
139+
#[cfg(not(feature = "mangled-names"))]
140+
fn is_nan(x: $ty) -> bool {
141+
x.is_nan()
142+
}
143+
if is_nan(self) && is_nan(rhs) {
131144
true
132145
} else {
133146
self.repr() == rhs.repr()
@@ -171,5 +184,9 @@ macro_rules! float_impl {
171184
};
172185
}
173186

187+
#[cfg(not(feature = "no-f16-f128"))]
188+
float_impl!(f16, u16, i16, i8, 16, 10);
174189
float_impl!(f32, u32, i32, i16, 32, 23);
175190
float_impl!(f64, u64, i64, i16, 64, 52);
191+
#[cfg(not(feature = "no-f16-f128"))]
192+
float_impl!(f128, u128, i128, i16, 128, 112);

src/float/trunc.rs

+51-4
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,10 @@ where
5252
// destination format. We can convert by simply right-shifting with
5353
// rounding and adjusting the exponent.
5454
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());
55+
// Cast before shifting ro prevent overflow.
56+
let bias_diff: R::Int = src_exp_bias.wrapping_sub(dst_exp_bias).cast();
57+
let tmp = bias_diff << R::SIGNIFICAND_BITS;
58+
abs_result = abs_result.wrapping_sub(tmp);
5759

5860
let round_bits = a_abs & round_mask;
5961
if round_bits > halfway {
@@ -67,13 +69,17 @@ where
6769
// a is NaN.
6870
// Conjure the result by beginning with infinity, setting the qNaN
6971
// bit and inserting the (truncated) trailing NaN field.
70-
abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast();
72+
// Cast before shifting to prevent overflow.
73+
let dst_inf_exp: R::Int = dst_inf_exp.cast();
74+
abs_result = dst_inf_exp << R::SIGNIFICAND_BITS;
7175
abs_result |= dst_qnan;
7276
abs_result |= dst_nan_code
7377
& ((a_abs & src_nan_code) >> (F::SIGNIFICAND_BITS - R::SIGNIFICAND_BITS)).cast();
7478
} else if a_abs >= overflow {
7579
// a overflows to infinity.
76-
abs_result = (dst_inf_exp << R::SIGNIFICAND_BITS).cast();
80+
// Cast before shifting to prevent overflow.
81+
let dst_inf_exp: R::Int = dst_inf_exp.cast();
82+
abs_result = dst_inf_exp << R::SIGNIFICAND_BITS;
7783
} else {
7884
// a underflows on conversion to the destination type or is an exact
7985
// zero. The result may be a denormal or zero. Extract the exponent
@@ -124,3 +130,44 @@ intrinsics! {
124130
a as f32
125131
}
126132
}
133+
134+
#[cfg(not(feature = "no-f16-f128"))]
135+
intrinsics! {
136+
#[avr_skip]
137+
#[aapcs_on_arm]
138+
#[arm_aeabi_alias = __aeabi_f2h]
139+
pub extern "C" fn __truncsfhf2(a: f32) -> f16 {
140+
trunc(a)
141+
}
142+
143+
#[avr_skip]
144+
#[aapcs_on_arm]
145+
pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 {
146+
trunc(a)
147+
}
148+
149+
#[avr_skip]
150+
#[aapcs_on_arm]
151+
#[arm_aeabi_alias = __aeabi_d2h]
152+
pub extern "C" fn __truncdfhf2(a: f64) -> f16 {
153+
trunc(a)
154+
}
155+
156+
#[avr_skip]
157+
#[aapcs_on_arm]
158+
pub extern "C" fn __trunctfhf2(a: f128) -> f16 {
159+
trunc(a)
160+
}
161+
162+
#[avr_skip]
163+
#[aapcs_on_arm]
164+
pub extern "C" fn __trunctfsf2(a: f128) -> f32 {
165+
trunc(a)
166+
}
167+
168+
#[avr_skip]
169+
#[aapcs_on_arm]
170+
pub extern "C" fn __trunctfdf2(a: f128) -> f64 {
171+
trunc(a)
172+
}
173+
}

src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@
1313
#![feature(naked_functions)]
1414
#![feature(repr_simd)]
1515
#![feature(c_unwind)]
16+
#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))]
17+
#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))]
1618
#![no_builtins]
1719
#![no_std]
1820
#![allow(unused_features)]

0 commit comments

Comments
 (0)