return;
}
- // Forcibly enable memory intrinsics on wasm32 & SGX as we don't have a libc to
+ // Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to
// provide them.
- if (target.contains("wasm32") && !target.contains("wasi"))
+ if (target.contains("wasm") && !target.contains("wasi"))
|| (target.contains("sgx") && target.contains("fortanix"))
+ || target.contains("-none")
+ || target.contains("nvptx")
+ || target.contains("uefi")
{
println!("cargo:rustc-cfg=feature=\"mem\"");
}
+ // These targets have hardware unaligned access support.
+ if target.contains("x86_64")
+ || target.contains("i686")
+ || target.contains("aarch64")
+ || target.contains("bpf")
+ {
+ println!("cargo:rustc-cfg=feature=\"mem-unaligned\"");
+ }
+
// NOTE we are going to assume that llvm-target, what determines our codegen option, matches the
// target triple. This is usually correct for our built-in targets but can break in presence of
// custom targets, which can have arbitrary names.
if !cfg!(feature = "mangled-names") && cfg!(feature = "c") {
// Don't use a C compiler for these targets:
//
- // * wasm32 - clang 8 for wasm is somewhat hard to come by and it's
+ // * wasm - clang for wasm is somewhat hard to come by and it's
// unlikely that the C is really that much better than our own Rust.
// * nvptx - everything is bitcode, not compatible with mixed C/Rust
// * riscv - the rust-lang/rust distribution container doesn't have a C
- // compiler nor is cc-rs ready for compilation to riscv (at this
- // time). This can probably be removed in the future
- if !target.contains("wasm32") && !target.contains("nvptx") && !target.starts_with("riscv") {
+ // compiler.
+ if !target.contains("wasm")
+ && !target.contains("nvptx")
+ && (!target.starts_with("riscv") || target.contains("xous"))
+ {
#[cfg(feature = "c")]
c::compile(&llvm_target, &target);
}
println!("cargo:rustc-cfg=thumb_1")
}
- // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures.
- if llvm_target[0] == "armv4t" || llvm_target[0] == "armv5te" {
+ // Only emit the ARM Linux atomic emulation on pre-ARMv6 architectures. This
+ // includes the old androideabi. It is deprecated but it is available as a
+ // rustc target (arm-linux-androideabi).
+ if llvm_target[0] == "armv4t"
+ || llvm_target[0] == "armv5te"
+ || target == "arm-linux-androideabi"
+ {
println!("cargo:rustc-cfg=kernel_user_helpers")
}
}
mod c {
extern crate cc;
- use std::collections::BTreeMap;
+ use std::collections::{BTreeMap, HashSet};
use std::env;
- use std::path::PathBuf;
+ use std::fs::{self, File};
+ use std::io::Write;
+ use std::path::{Path, PathBuf};
struct Sources {
// SYMBOL -> PATH TO SOURCE
cfg.define("VISIBILITY_HIDDEN", None);
}
+ // int_util.c tries to include stdlib.h if `_WIN32` is defined,
+ // which it is when compiling UEFI targets with clang. This is
+ // at odds with compiling with `-ffreestanding`, as the header
+ // may be incompatible or not present. Create a minimal stub
+ // header to use instead.
+ if target_os == "uefi" {
+ let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
+ let include_dir = out_dir.join("include");
+ if !include_dir.exists() {
+ fs::create_dir(&include_dir).unwrap();
+ }
+ fs::write(include_dir.join("stdlib.h"), "#include <stddef.h>").unwrap();
+ cfg.flag(&format!("-I{}", include_dir.to_str().unwrap()));
+ }
+
let mut sources = Sources::new();
sources.extend(&[
("__absvdi2", "absvdi2.c"),
("__absvsi2", "absvsi2.c"),
("__addvdi3", "addvdi3.c"),
("__addvsi3", "addvsi3.c"),
- ("apple_versioning", "apple_versioning.c"),
("__clzdi2", "clzdi2.c"),
("__clzsi2", "clzsi2.c"),
("__cmpdi2", "cmpdi2.c"),
("__negsf2", "negsf2.c"),
("__powixf2", "powixf2.c"),
("__truncdfhf2", "truncdfhf2.c"),
- ("__truncdfsf2", "truncdfsf2.c"),
("__truncsfhf2", "truncsfhf2.c"),
]);
}
// On iOS and 32-bit OSX these are all just empty intrinsics, no need to
// include them.
- if target_os != "ios" && (target_vendor != "apple" || target_arch != "x86") {
+ if target_os != "ios"
+ && target_os != "watchos"
+ && (target_vendor != "apple" || target_arch != "x86")
+ {
sources.extend(&[
("__absvti2", "absvti2.c"),
("__addvti3", "addvti3.c"),
if target_env == "msvc" {
if target_arch == "x86_64" {
- sources.extend(&[
- ("__floatdisf", "x86_64/floatdisf.c"),
- ("__floatdixf", "x86_64/floatdixf.c"),
- ]);
+ sources.extend(&[("__floatdixf", "x86_64/floatdixf.c")]);
}
} else {
// None of these seem to be used on x86_64 windows, and they've all
if target_os != "windows" {
if target_arch == "x86_64" {
sources.extend(&[
- ("__floatdisf", "x86_64/floatdisf.c"),
("__floatdixf", "x86_64/floatdixf.c"),
- ("__floatundidf", "x86_64/floatundidf.S"),
- ("__floatundisf", "x86_64/floatundisf.S"),
("__floatundixf", "x86_64/floatundixf.S"),
]);
}
("__ashldi3", "i386/ashldi3.S"),
("__ashrdi3", "i386/ashrdi3.S"),
("__divdi3", "i386/divdi3.S"),
- ("__floatdidf", "i386/floatdidf.S"),
- ("__floatdisf", "i386/floatdisf.S"),
("__floatdixf", "i386/floatdixf.S"),
- ("__floatundidf", "i386/floatundidf.S"),
- ("__floatundisf", "i386/floatundisf.S"),
("__floatundixf", "i386/floatundixf.S"),
("__lshrdi3", "i386/lshrdi3.S"),
("__moddi3", "i386/moddi3.S"),
}
}
- if target_arch == "arm" && target_os != "ios" && target_env != "msvc" {
+ if target_arch == "arm"
+ && target_os != "ios"
+ && target_os != "watchos"
+ && target_env != "msvc"
+ {
sources.extend(&[
("__aeabi_div0", "arm/aeabi_div0.c"),
("__aeabi_drsub", "arm/aeabi_drsub.c"),
("__floatunsitf", "floatunsitf.c"),
("__trunctfdf2", "trunctfdf2.c"),
("__trunctfsf2", "trunctfsf2.c"),
+ ("__addtf3", "addtf3.c"),
+ ("__multf3", "multf3.c"),
+ ("__subtf3", "subtf3.c"),
+ ("__divtf3", "divtf3.c"),
+ ("__powitf2", "powitf2.c"),
+ ("__fe_getround", "fp_mode.c"),
+ ("__fe_raise_inexact", "fp_mode.c"),
]);
if target_os != "windows" {
}
}
+ if target_arch == "mips" {
+ sources.extend(&[("__bswapsi2", "bswapsi2.c")]);
+ }
+
+ if target_arch == "mips64" {
+ sources.extend(&[
+ ("__extenddftf2", "extenddftf2.c"),
+ ("__netf2", "comparetf2.c"),
+ ("__addtf3", "addtf3.c"),
+ ("__multf3", "multf3.c"),
+ ("__subtf3", "subtf3.c"),
+ ("__fixtfsi", "fixtfsi.c"),
+ ("__floatsitf", "floatsitf.c"),
+ ("__fixunstfsi", "fixunstfsi.c"),
+ ("__floatunsitf", "floatunsitf.c"),
+ ("__fe_getround", "fp_mode.c"),
+ ("__divtf3", "divtf3.c"),
+ ("__trunctfdf2", "trunctfdf2.c"),
+ ("__trunctfsf2", "trunctfsf2.c"),
+ ]);
+ }
+
// Remove the assembly implementations that won't compile for the target
- if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" {
+ if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" || target_os == "uefi"
+ {
let mut to_remove = Vec::new();
for (k, v) in sources.map.iter() {
if v.ends_with(".S") {
sources.remove(&["__aeabi_cdcmp", "__aeabi_cfcmp"]);
}
+ // Android uses emulated TLS so we need a runtime support function.
+ if target_os == "android" {
+ sources.extend(&[("__emutls_get_address", "emutls.c")]);
+
+ // Work around a bug in the NDK headers (fixed in
+ // https://r.android.com/2038949 which will be released in a future
+ // NDK version) by providing a definition of LONG_BIT.
+ cfg.define("LONG_BIT", "(8 * sizeof(long))");
+ }
+
+ // OpenHarmony also uses emulated TLS.
+ if target_env == "ohos" {
+ sources.extend(&[("__emutls_get_address", "emutls.c")]);
+ }
+
// When compiling the C code we require the user to tell us where the
// source code is, and this is largely done so when we're compiling as
// part of rust-lang/rust we can use the same llvm-project repository as
// use of that macro in lib/builtins/int_util.h in compiler-rt.
cfg.flag_if_supported(&format!("-ffile-prefix-map={}=.", root.display()));
+ // Include out-of-line atomics for aarch64, which are all generated by supplying different
+ // sets of flags to the same source file.
+ // Note: Out-of-line aarch64 atomics are not supported by the msvc toolchain (#430).
let src_dir = root.join("lib/builtins");
+ if target_arch == "aarch64" && target_env != "msvc" {
+ // See below for why we're building these as separate libraries.
+ build_aarch64_out_of_line_atomics_libraries(&src_dir, cfg);
+
+ // Some run-time CPU feature detection is necessary, as well.
+ sources.extend(&[("__aarch64_have_lse_atomics", "cpu_model.c")]);
+ }
+
+ let mut added_sources = HashSet::new();
for (sym, src) in sources.map.iter() {
let src = src_dir.join(src);
- cfg.file(&src);
- println!("cargo:rerun-if-changed={}", src.display());
+ if added_sources.insert(src.clone()) {
+ cfg.file(&src);
+ println!("cargo:rerun-if-changed={}", src.display());
+ }
println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);
}
cfg.compile("libcompiler-rt.a");
}
+
+ fn build_aarch64_out_of_line_atomics_libraries(builtins_dir: &Path, cfg: &mut cc::Build) {
+ let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
+ let outlined_atomics_file = builtins_dir.join("aarch64/lse.S");
+ println!("cargo:rerun-if-changed={}", outlined_atomics_file.display());
+
+ cfg.include(&builtins_dir);
+
+ for instruction_type in &["cas", "swp", "ldadd", "ldclr", "ldeor", "ldset"] {
+ for size in &[1, 2, 4, 8, 16] {
+ if *size == 16 && *instruction_type != "cas" {
+ continue;
+ }
+
+ for (model_number, model_name) in
+ &[(1, "relax"), (2, "acq"), (3, "rel"), (4, "acq_rel")]
+ {
+ // The original compiler-rt build system compiles the same
+ // source file multiple times with different compiler
+ // options. Here we do something slightly different: we
+ // create multiple .S files with the proper #defines and
+ // then include the original file.
+ //
+ // This is needed because the cc crate doesn't allow us to
+ // override the name of object files and libtool requires
+ // all objects in an archive to have unique names.
+ let path =
+ out_dir.join(format!("lse_{}{}_{}.S", instruction_type, size, model_name));
+ let mut file = File::create(&path).unwrap();
+ writeln!(file, "#define L_{}", instruction_type).unwrap();
+ writeln!(file, "#define SIZE {}", size).unwrap();
+ writeln!(file, "#define MODEL {}", model_number).unwrap();
+ writeln!(
+ file,
+ "#include \"{}\"",
+ outlined_atomics_file.canonicalize().unwrap().display()
+ )
+ .unwrap();
+ drop(file);
+ cfg.file(path);
+
+ let sym = format!("__aarch64_{}{}_{}", instruction_type, size, model_name);
+ println!("cargo:rustc-cfg={}=\"optimized-c\"", sym);
+ }
+ }
+ }
+ }
}