11use std:: { collections:: BTreeMap , env, path:: PathBuf , sync:: atomic:: Ordering } ;
22
3+ #[ allow( dead_code) ]
4+ struct Target {
5+ triple : String ,
6+ os : String ,
7+ arch : String ,
8+ vendor : String ,
9+ env : String ,
10+ pointer_width : u8 ,
11+ little_endian : bool ,
12+ features : Vec < String > ,
13+ }
14+
15+ impl Target {
16+ fn from_env ( ) -> Self {
17+ let little_endian = match env:: var ( "CARGO_CFG_TARGET_ENDIAN" ) . unwrap ( ) . as_str ( ) {
18+ "little" => true ,
19+ "big" => false ,
20+ x => panic ! ( "unknown endian {x}" ) ,
21+ } ;
22+
23+ Self {
24+ triple : env:: var ( "TARGET" ) . unwrap ( ) ,
25+ os : env:: var ( "CARGO_CFG_TARGET_OS" ) . unwrap ( ) ,
26+ arch : env:: var ( "CARGO_CFG_TARGET_ARCH" ) . unwrap ( ) ,
27+ vendor : env:: var ( "CARGO_CFG_TARGET_VENDOR" ) . unwrap ( ) ,
28+ env : env:: var ( "CARGO_CFG_TARGET_ENV" ) . unwrap ( ) ,
29+ pointer_width : env:: var ( "CARGO_CFG_TARGET_POINTER_WIDTH" )
30+ . unwrap ( )
31+ . parse ( )
32+ . unwrap ( ) ,
33+ little_endian,
34+ features : env:: var ( "CARGO_CFG_TARGET_FEATURE" )
35+ . unwrap_or_default ( )
36+ . split ( "," )
37+ . map ( ToOwned :: to_owned)
38+ . collect ( ) ,
39+ }
40+ }
41+ }
42+
343fn main ( ) {
444 println ! ( "cargo:rerun-if-changed=build.rs" ) ;
5- configure_check_cfg ( ) ;
6-
7- let target = env:: var ( "TARGET" ) . unwrap ( ) ;
45+ let target = Target :: from_env ( ) ;
846 let cwd = env:: current_dir ( ) . unwrap ( ) ;
947
48+ configure_check_cfg ( ) ;
49+ configure_f16_f128 ( & target) ;
50+
1051 println ! ( "cargo:compiler-rt={}" , cwd. join( "compiler-rt" ) . display( ) ) ;
1152
1253 // Activate libm's unstable features to make full use of Nightly.
1354 println ! ( "cargo::rustc-check-cfg=cfg(feature, values(\" unstable\" ))" ) ;
1455 println ! ( "cargo:rustc-cfg=feature=\" unstable\" " ) ;
1556
1657 // Emscripten's runtime includes all the builtins
17- if target. contains ( "emscripten" ) {
58+ if target. env == "emscripten" {
1859 return ;
1960 }
2061
2162 // OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source
22- if target. contains ( "openbsd" ) {
63+ if target. os == "openbsd" {
2364 println ! ( "cargo:rustc-link-search=native=/usr/lib" ) ;
2465 println ! ( "cargo:rustc-link-lib=compiler_rt" ) ;
2566 return ;
2667 }
2768
2869 // Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to
2970 // provide them.
30- if ( target. contains ( "wasm" ) && !target. contains ( "wasi" ) )
31- || ( target. contains ( "sgx" ) && target. contains ( "fortanix" ) )
32- || target. contains ( "-none" )
33- || target. contains ( "nvptx" )
34- || target. contains ( "uefi" )
35- || target. contains ( "xous" )
71+ if ( target. triple . contains ( "wasm" ) && !target. triple . contains ( "wasi" ) )
72+ || ( target. triple . contains ( "sgx" ) && target. triple . contains ( "fortanix" ) )
73+ || target. triple . contains ( "-none" )
74+ || target. triple . contains ( "nvptx" )
75+ || target. triple . contains ( "uefi" )
76+ || target. triple . contains ( "xous" )
3677 {
3778 println ! ( "cargo:rustc-cfg=feature=\" mem\" " ) ;
3879 }
3980
4081 // These targets have hardware unaligned access support.
4182 println ! ( "cargo::rustc-check-cfg=cfg(feature, values(\" mem-unaligned\" ))" ) ;
42- if target. contains ( "x86_64" )
43- || target. contains ( "i686" )
44- || target. contains ( "aarch64" )
45- || target. contains ( "bpf" )
83+ if target. arch . contains ( "x86_64" )
84+ || target. arch . contains ( "i686" )
85+ || target. arch . contains ( "aarch64" )
86+ || target. arch . contains ( "bpf" )
4687 {
4788 println ! ( "cargo:rustc-cfg=feature=\" mem-unaligned\" " ) ;
4889 }
4990
5091 // NOTE we are going to assume that llvm-target, what determines our codegen option, matches the
5192 // target triple. This is usually correct for our built-in targets but can break in presence of
5293 // custom targets, which can have arbitrary names.
53- let llvm_target = target. split ( '-' ) . collect :: < Vec < _ > > ( ) ;
94+ let llvm_target = target. triple . split ( '-' ) . collect :: < Vec < _ > > ( ) ;
5495
5596 // Build missing intrinsics from compiler-rt C source code. If we're
5697 // mangling names though we assume that we're also in test mode so we don't
@@ -60,7 +101,7 @@ fn main() {
60101 // Don't use a C compiler for these targets:
61102 //
62103 // * nvptx - everything is bitcode, not compatible with mixed C/Rust
63- if !target. contains ( "nvptx" ) {
104+ if !target. arch . contains ( "nvptx" ) {
64105 #[ cfg( feature = "c" ) ]
65106 c:: compile ( & llvm_target, & target) ;
66107 }
@@ -86,7 +127,7 @@ fn main() {
86127 println ! ( "cargo::rustc-check-cfg=cfg(kernel_user_helpers)" ) ;
87128 if llvm_target[ 0 ] == "armv4t"
88129 || llvm_target[ 0 ] == "armv5te"
89- || target == "arm-linux-androideabi"
130+ || target. triple == "arm-linux-androideabi"
90131 {
91132 println ! ( "cargo:rustc-cfg=kernel_user_helpers" )
92133 }
@@ -219,6 +260,47 @@ fn configure_check_cfg() {
219260 println ! ( "cargo::rustc-check-cfg=cfg(assert_no_panic)" ) ;
220261}
221262
263+ /// Configure whether or not `f16` and `f128` support should be enabled.
264+ fn configure_f16_f128 ( target : & Target ) {
265+ // Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means
266+ // that the backend will not crash when using these types. This does not mean that the
267+ // backend does the right thing, or that the platform doesn't have ABI bugs.
268+ //
269+ // We do this here rather than in `rust-lang/rust` because configuring via cargo features is
270+ // not straightforward.
271+ //
272+ // Original source of this list:
273+ // <https://github.com/rust-lang/compiler-builtins/pull/652#issuecomment-2266151350>
274+ let ( f16_ok, f128_ok) = match target. arch . as_str ( ) {
275+ // `f16` and `f128` both crash <https://github.com/llvm/llvm-project/issues/94434>
276+ "arm64ec" => ( false , false ) ,
277+ // `f16` crashes <https://github.com/llvm/llvm-project/issues/50374>
278+ "s390x" => ( false , true ) ,
279+ // `f128` crashes <https://github.com/llvm/llvm-project/issues/96432>
280+ "mips64" | "mips64r6" => ( true , false ) ,
281+ // `f128` crashes <https://github.com/llvm/llvm-project/issues/101545>
282+ "powerpc64" if & target. os == "aix" => ( true , false ) ,
283+ // `f128` crashes <https://github.com/llvm/llvm-project/issues/41838>
284+ "sparc" | "sparcv9" => ( true , false ) ,
285+ // Most everything else works as of LLVM 19
286+ _ => ( true , true ) ,
287+ } ;
288+
289+ // If the feature is set, disable these types.
290+ let disable_both = env:: var_os ( "CARGO_FEATURE_NO_F16_F128" ) . is_some ( ) ;
291+
292+ println ! ( "cargo::rustc-check-cfg=cfg(f16_enabled)" ) ;
293+ println ! ( "cargo::rustc-check-cfg=cfg(f128_enabled)" ) ;
294+
295+ if f16_ok && !disable_both {
296+ println ! ( "cargo::rustc-cfg=f16_enabled" ) ;
297+ }
298+
299+ if f128_ok && !disable_both {
300+ println ! ( "cargo::rustc-cfg=f128_enabled" ) ;
301+ }
302+ }
303+
222304#[ cfg( feature = "c" ) ]
223305mod c {
224306 use std:: collections:: { BTreeMap , HashSet } ;
@@ -227,6 +309,8 @@ mod c {
227309 use std:: io:: Write ;
228310 use std:: path:: { Path , PathBuf } ;
229311
312+ use super :: Target ;
313+
230314 struct Sources {
231315 // SYMBOL -> PATH TO SOURCE
232316 map : BTreeMap < & ' static str , & ' static str > ,
@@ -267,11 +351,7 @@ mod c {
267351 }
268352
269353 /// Compile intrinsics from the compiler-rt C source code
270- pub fn compile ( llvm_target : & [ & str ] , target : & String ) {
271- let target_arch = env:: var ( "CARGO_CFG_TARGET_ARCH" ) . unwrap ( ) ;
272- let target_env = env:: var ( "CARGO_CFG_TARGET_ENV" ) . unwrap ( ) ;
273- let target_os = env:: var ( "CARGO_CFG_TARGET_OS" ) . unwrap ( ) ;
274- let target_vendor = env:: var ( "CARGO_CFG_TARGET_VENDOR" ) . unwrap ( ) ;
354+ pub fn compile ( llvm_target : & [ & str ] , target : & Target ) {
275355 let mut consider_float_intrinsics = true ;
276356 let cfg = & mut cc:: Build :: new ( ) ;
277357
@@ -280,8 +360,8 @@ mod c {
280360 //
281361 // Therefore, evaluate if those flags are present and set a boolean that causes any
282362 // compiler-rt intrinsics that contain floating point source to be excluded for this target.
283- if target_arch == "aarch64" {
284- let cflags_key = String :: from ( "CFLAGS_" ) + & ( target. to_owned ( ) . replace ( "-" , "_" ) ) ;
363+ if target . arch == "aarch64" {
364+ let cflags_key = String :: from ( "CFLAGS_" ) + & ( target. triple . replace ( "-" , "_" ) ) ;
285365 if let Ok ( cflags_value) = env:: var ( cflags_key) {
286366 if cflags_value. contains ( "+nofp" ) || cflags_value. contains ( "+nosimd" ) {
287367 consider_float_intrinsics = false ;
@@ -299,7 +379,7 @@ mod c {
299379
300380 cfg. warnings ( false ) ;
301381
302- if target_env == "msvc" {
382+ if target . env == "msvc" {
303383 // Don't pull in extra libraries on MSVC
304384 cfg. flag ( "/Zl" ) ;
305385
@@ -328,7 +408,7 @@ mod c {
328408 // at odds with compiling with `-ffreestanding`, as the header
329409 // may be incompatible or not present. Create a minimal stub
330410 // header to use instead.
331- if target_os == "uefi" {
411+ if target . os == "uefi" {
332412 let out_dir = PathBuf :: from ( env:: var ( "OUT_DIR" ) . unwrap ( ) ) ;
333413 let include_dir = out_dir. join ( "include" ) ;
334414 if !include_dir. exists ( ) {
@@ -373,7 +453,7 @@ mod c {
373453
374454 // On iOS and 32-bit OSX these are all just empty intrinsics, no need to
375455 // include them.
376- if target_vendor != "apple" || target_arch != "x86" {
456+ if target . vendor != "apple" || target . arch != "x86" {
377457 sources. extend ( & [
378458 ( "__absvti2" , "absvti2.c" ) ,
379459 ( "__addvti3" , "addvti3.c" ) ,
@@ -392,7 +472,7 @@ mod c {
392472 }
393473 }
394474
395- if target_vendor == "apple" {
475+ if target . vendor == "apple" {
396476 sources. extend ( & [
397477 ( "atomic_flag_clear" , "atomic_flag_clear.c" ) ,
398478 ( "atomic_flag_clear_explicit" , "atomic_flag_clear_explicit.c" ) ,
@@ -406,8 +486,8 @@ mod c {
406486 ] ) ;
407487 }
408488
409- if target_env != "msvc" {
410- if target_arch == "x86" {
489+ if target . env != "msvc" {
490+ if target . arch == "x86" {
411491 sources. extend ( & [
412492 ( "__ashldi3" , "i386/ashldi3.S" ) ,
413493 ( "__ashrdi3" , "i386/ashrdi3.S" ) ,
@@ -421,7 +501,7 @@ mod c {
421501 }
422502 }
423503
424- if target_arch == "arm" && target_vendor != "apple" && target_env != "msvc" {
504+ if target . arch == "arm" && target . vendor != "apple" && target . env != "msvc" {
425505 sources. extend ( & [
426506 ( "__aeabi_div0" , "arm/aeabi_div0.c" ) ,
427507 ( "__aeabi_drsub" , "arm/aeabi_drsub.c" ) ,
@@ -441,7 +521,7 @@ mod c {
441521 ( "__umodsi3" , "arm/umodsi3.S" ) ,
442522 ] ) ;
443523
444- if target_os == "freebsd" {
524+ if target . os == "freebsd" {
445525 sources. extend ( & [ ( "__clear_cache" , "clear_cache.c" ) ] ) ;
446526 }
447527
@@ -513,7 +593,7 @@ mod c {
513593 ] ) ;
514594 }
515595
516- if ( target_arch == "aarch64" || target_arch == "arm64ec" ) && consider_float_intrinsics {
596+ if ( target . arch == "aarch64" || target . arch == "arm64ec" ) && consider_float_intrinsics {
517597 sources. extend ( & [
518598 ( "__comparetf2" , "comparetf2.c" ) ,
519599 ( "__floatditf" , "floatditf.c" ) ,
@@ -526,16 +606,16 @@ mod c {
526606 ( "__fe_raise_inexact" , "fp_mode.c" ) ,
527607 ] ) ;
528608
529- if target_os != "windows" {
609+ if target . os != "windows" {
530610 sources. extend ( & [ ( "__multc3" , "multc3.c" ) ] ) ;
531611 }
532612 }
533613
534- if target_arch == "mips" || target_arch == "riscv32" || target_arch == "riscv64" {
614+ if target . arch == "mips" || target . arch == "riscv32" || target . arch == "riscv64" {
535615 sources. extend ( & [ ( "__bswapsi2" , "bswapsi2.c" ) ] ) ;
536616 }
537617
538- if target_arch == "mips64" {
618+ if target . arch == "mips64" {
539619 sources. extend ( & [
540620 ( "__netf2" , "comparetf2.c" ) ,
541621 ( "__floatsitf" , "floatsitf.c" ) ,
@@ -544,7 +624,7 @@ mod c {
544624 ] ) ;
545625 }
546626
547- if target_arch == "loongarch64" {
627+ if target . arch == "loongarch64" {
548628 sources. extend ( & [
549629 ( "__netf2" , "comparetf2.c" ) ,
550630 ( "__floatsitf" , "floatsitf.c" ) ,
@@ -554,7 +634,7 @@ mod c {
554634 }
555635
556636 // Remove the assembly implementations that won't compile for the target
557- if llvm_target[ 0 ] == "thumbv6m" || llvm_target[ 0 ] == "thumbv8m.base" || target_os == "uefi"
637+ if llvm_target[ 0 ] == "thumbv6m" || llvm_target[ 0 ] == "thumbv8m.base" || target . os == "uefi"
558638 {
559639 let mut to_remove = Vec :: new ( ) ;
560640 for ( k, v) in sources. map . iter ( ) {
@@ -570,7 +650,7 @@ mod c {
570650 }
571651
572652 // Android uses emulated TLS so we need a runtime support function.
573- if target_os == "android" {
653+ if target . os == "android" {
574654 sources. extend ( & [ ( "__emutls_get_address" , "emutls.c" ) ] ) ;
575655
576656 // Work around a bug in the NDK headers (fixed in
@@ -580,7 +660,7 @@ mod c {
580660 }
581661
582662 // OpenHarmony also uses emulated TLS.
583- if target_env == "ohos" {
663+ if target . env == "ohos" {
584664 sources. extend ( & [ ( "__emutls_get_address" , "emutls.c" ) ] ) ;
585665 }
586666
@@ -607,7 +687,7 @@ mod c {
607687 // sets of flags to the same source file.
608688 // Note: Out-of-line aarch64 atomics are not supported by the msvc toolchain (#430).
609689 let src_dir = root. join ( "lib/builtins" ) ;
610- if target_arch == "aarch64" && target_env != "msvc" {
690+ if target . arch == "aarch64" && target . env != "msvc" {
611691 // See below for why we're building these as separate libraries.
612692 build_aarch64_out_of_line_atomics_libraries ( & src_dir, cfg) ;
613693
0 commit comments