Merge pull request #652 from tgross35/control-f16-f128-feature
This commit is contained in:
commit
035f1fff6e
17 changed files with 273 additions and 247 deletions
|
|
@ -1,12 +1,53 @@
|
|||
use std::{collections::BTreeMap, env, path::PathBuf, sync::atomic::Ordering};
|
||||
|
||||
#[allow(dead_code)]
|
||||
struct Target {
|
||||
triple: String,
|
||||
os: String,
|
||||
arch: String,
|
||||
vendor: String,
|
||||
env: String,
|
||||
pointer_width: u8,
|
||||
little_endian: bool,
|
||||
features: Vec<String>,
|
||||
}
|
||||
|
||||
impl Target {
|
||||
fn from_env() -> Self {
|
||||
let little_endian = match env::var("CARGO_CFG_TARGET_ENDIAN").unwrap().as_str() {
|
||||
"little" => true,
|
||||
"big" => false,
|
||||
x => panic!("unknown endian {x}"),
|
||||
};
|
||||
|
||||
Self {
|
||||
triple: env::var("TARGET").unwrap(),
|
||||
os: env::var("CARGO_CFG_TARGET_OS").unwrap(),
|
||||
arch: env::var("CARGO_CFG_TARGET_ARCH").unwrap(),
|
||||
vendor: env::var("CARGO_CFG_TARGET_VENDOR").unwrap(),
|
||||
env: env::var("CARGO_CFG_TARGET_ENV").unwrap(),
|
||||
pointer_width: env::var("CARGO_CFG_TARGET_POINTER_WIDTH")
|
||||
.unwrap()
|
||||
.parse()
|
||||
.unwrap(),
|
||||
little_endian,
|
||||
features: env::var("CARGO_CFG_TARGET_FEATURE")
|
||||
.unwrap_or_default()
|
||||
.split(",")
|
||||
.map(ToOwned::to_owned)
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
configure_check_cfg();
|
||||
|
||||
let target = env::var("TARGET").unwrap();
|
||||
let target = Target::from_env();
|
||||
let cwd = env::current_dir().unwrap();
|
||||
|
||||
configure_check_cfg();
|
||||
configure_f16_f128(&target);
|
||||
|
||||
println!("cargo:compiler-rt={}", cwd.join("compiler-rt").display());
|
||||
|
||||
// Activate libm's unstable features to make full use of Nightly.
|
||||
|
|
@ -14,12 +55,12 @@ fn main() {
|
|||
println!("cargo:rustc-cfg=feature=\"unstable\"");
|
||||
|
||||
// Emscripten's runtime includes all the builtins
|
||||
if target.contains("emscripten") {
|
||||
if target.env == "emscripten" {
|
||||
return;
|
||||
}
|
||||
|
||||
// OpenBSD provides compiler_rt by default, use it instead of rebuilding it from source
|
||||
if target.contains("openbsd") {
|
||||
if target.os == "openbsd" {
|
||||
println!("cargo:rustc-link-search=native=/usr/lib");
|
||||
println!("cargo:rustc-link-lib=compiler_rt");
|
||||
return;
|
||||
|
|
@ -27,22 +68,22 @@ fn main() {
|
|||
|
||||
// Forcibly enable memory intrinsics on wasm & SGX as we don't have a libc to
|
||||
// provide them.
|
||||
if (target.contains("wasm") && !target.contains("wasi"))
|
||||
|| (target.contains("sgx") && target.contains("fortanix"))
|
||||
|| target.contains("-none")
|
||||
|| target.contains("nvptx")
|
||||
|| target.contains("uefi")
|
||||
|| target.contains("xous")
|
||||
if (target.triple.contains("wasm") && !target.triple.contains("wasi"))
|
||||
|| (target.triple.contains("sgx") && target.triple.contains("fortanix"))
|
||||
|| target.triple.contains("-none")
|
||||
|| target.triple.contains("nvptx")
|
||||
|| target.triple.contains("uefi")
|
||||
|| target.triple.contains("xous")
|
||||
{
|
||||
println!("cargo:rustc-cfg=feature=\"mem\"");
|
||||
}
|
||||
|
||||
// These targets have hardware unaligned access support.
|
||||
println!("cargo::rustc-check-cfg=cfg(feature, values(\"mem-unaligned\"))");
|
||||
if target.contains("x86_64")
|
||||
|| target.contains("i686")
|
||||
|| target.contains("aarch64")
|
||||
|| target.contains("bpf")
|
||||
if target.arch.contains("x86_64")
|
||||
|| target.arch.contains("i686")
|
||||
|| target.arch.contains("aarch64")
|
||||
|| target.arch.contains("bpf")
|
||||
{
|
||||
println!("cargo:rustc-cfg=feature=\"mem-unaligned\"");
|
||||
}
|
||||
|
|
@ -50,7 +91,7 @@ fn main() {
|
|||
// 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.
|
||||
let llvm_target = target.split('-').collect::<Vec<_>>();
|
||||
let llvm_target = target.triple.split('-').collect::<Vec<_>>();
|
||||
|
||||
// Build missing intrinsics from compiler-rt C source code. If we're
|
||||
// mangling names though we assume that we're also in test mode so we don't
|
||||
|
|
@ -60,7 +101,7 @@ fn main() {
|
|||
// Don't use a C compiler for these targets:
|
||||
//
|
||||
// * nvptx - everything is bitcode, not compatible with mixed C/Rust
|
||||
if !target.contains("nvptx") {
|
||||
if !target.arch.contains("nvptx") {
|
||||
#[cfg(feature = "c")]
|
||||
c::compile(&llvm_target, &target);
|
||||
}
|
||||
|
|
@ -86,7 +127,7 @@ fn main() {
|
|||
println!("cargo::rustc-check-cfg=cfg(kernel_user_helpers)");
|
||||
if llvm_target[0] == "armv4t"
|
||||
|| llvm_target[0] == "armv5te"
|
||||
|| target == "arm-linux-androideabi"
|
||||
|| target.triple == "arm-linux-androideabi"
|
||||
{
|
||||
println!("cargo:rustc-cfg=kernel_user_helpers")
|
||||
}
|
||||
|
|
@ -219,6 +260,47 @@ fn configure_check_cfg() {
|
|||
println!("cargo::rustc-check-cfg=cfg(assert_no_panic)");
|
||||
}
|
||||
|
||||
/// Configure whether or not `f16` and `f128` support should be enabled.
|
||||
fn configure_f16_f128(target: &Target) {
|
||||
// Set whether or not `f16` and `f128` are supported at a basic level by LLVM. This only means
|
||||
// that the backend will not crash when using these types. This does not mean that the
|
||||
// backend does the right thing, or that the platform doesn't have ABI bugs.
|
||||
//
|
||||
// We do this here rather than in `rust-lang/rust` because configuring via cargo features is
|
||||
// not straightforward.
|
||||
//
|
||||
// Original source of this list:
|
||||
// <https://github.com/rust-lang/compiler-builtins/pull/652#issuecomment-2266151350>
|
||||
let (f16_ok, f128_ok) = match target.arch.as_str() {
|
||||
// `f16` and `f128` both crash <https://github.com/llvm/llvm-project/issues/94434>
|
||||
"arm64ec" => (false, false),
|
||||
// `f16` crashes <https://github.com/llvm/llvm-project/issues/50374>
|
||||
"s390x" => (false, true),
|
||||
// `f128` crashes <https://github.com/llvm/llvm-project/issues/96432>
|
||||
"mips64" | "mips64r6" => (true, false),
|
||||
// `f128` crashes <https://github.com/llvm/llvm-project/issues/101545>
|
||||
"powerpc64" if &target.os == "aix" => (true, false),
|
||||
// `f128` crashes <https://github.com/llvm/llvm-project/issues/41838>
|
||||
"sparc" | "sparcv9" => (true, false),
|
||||
// Most everything else works as of LLVM 19
|
||||
_ => (true, true),
|
||||
};
|
||||
|
||||
// If the feature is set, disable these types.
|
||||
let disable_both = env::var_os("CARGO_FEATURE_NO_F16_F128").is_some();
|
||||
|
||||
println!("cargo::rustc-check-cfg=cfg(f16_enabled)");
|
||||
println!("cargo::rustc-check-cfg=cfg(f128_enabled)");
|
||||
|
||||
if f16_ok && !disable_both {
|
||||
println!("cargo::rustc-cfg=f16_enabled");
|
||||
}
|
||||
|
||||
if f128_ok && !disable_both {
|
||||
println!("cargo::rustc-cfg=f128_enabled");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "c")]
|
||||
mod c {
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
|
|
@ -227,6 +309,8 @@ mod c {
|
|||
use std::io::Write;
|
||||
use std::path::{Path, PathBuf};
|
||||
|
||||
use super::Target;
|
||||
|
||||
struct Sources {
|
||||
// SYMBOL -> PATH TO SOURCE
|
||||
map: BTreeMap<&'static str, &'static str>,
|
||||
|
|
@ -267,11 +351,7 @@ mod c {
|
|||
}
|
||||
|
||||
/// Compile intrinsics from the compiler-rt C source code
|
||||
pub fn compile(llvm_target: &[&str], target: &String) {
|
||||
let target_arch = env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
||||
let target_env = env::var("CARGO_CFG_TARGET_ENV").unwrap();
|
||||
let target_os = env::var("CARGO_CFG_TARGET_OS").unwrap();
|
||||
let target_vendor = env::var("CARGO_CFG_TARGET_VENDOR").unwrap();
|
||||
pub fn compile(llvm_target: &[&str], target: &Target) {
|
||||
let mut consider_float_intrinsics = true;
|
||||
let cfg = &mut cc::Build::new();
|
||||
|
||||
|
|
@ -280,8 +360,8 @@ mod c {
|
|||
//
|
||||
// Therefore, evaluate if those flags are present and set a boolean that causes any
|
||||
// compiler-rt intrinsics that contain floating point source to be excluded for this target.
|
||||
if target_arch == "aarch64" {
|
||||
let cflags_key = String::from("CFLAGS_") + &(target.to_owned().replace("-", "_"));
|
||||
if target.arch == "aarch64" {
|
||||
let cflags_key = String::from("CFLAGS_") + &(target.triple.replace("-", "_"));
|
||||
if let Ok(cflags_value) = env::var(cflags_key) {
|
||||
if cflags_value.contains("+nofp") || cflags_value.contains("+nosimd") {
|
||||
consider_float_intrinsics = false;
|
||||
|
|
@ -299,7 +379,7 @@ mod c {
|
|||
|
||||
cfg.warnings(false);
|
||||
|
||||
if target_env == "msvc" {
|
||||
if target.env == "msvc" {
|
||||
// Don't pull in extra libraries on MSVC
|
||||
cfg.flag("/Zl");
|
||||
|
||||
|
|
@ -328,7 +408,7 @@ mod c {
|
|||
// 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" {
|
||||
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() {
|
||||
|
|
@ -373,7 +453,7 @@ mod c {
|
|||
|
||||
// On iOS and 32-bit OSX these are all just empty intrinsics, no need to
|
||||
// include them.
|
||||
if target_vendor != "apple" || target_arch != "x86" {
|
||||
if target.vendor != "apple" || target.arch != "x86" {
|
||||
sources.extend(&[
|
||||
("__absvti2", "absvti2.c"),
|
||||
("__addvti3", "addvti3.c"),
|
||||
|
|
@ -392,7 +472,7 @@ mod c {
|
|||
}
|
||||
}
|
||||
|
||||
if target_vendor == "apple" {
|
||||
if target.vendor == "apple" {
|
||||
sources.extend(&[
|
||||
("atomic_flag_clear", "atomic_flag_clear.c"),
|
||||
("atomic_flag_clear_explicit", "atomic_flag_clear_explicit.c"),
|
||||
|
|
@ -406,8 +486,8 @@ mod c {
|
|||
]);
|
||||
}
|
||||
|
||||
if target_env != "msvc" {
|
||||
if target_arch == "x86" {
|
||||
if target.env != "msvc" {
|
||||
if target.arch == "x86" {
|
||||
sources.extend(&[
|
||||
("__ashldi3", "i386/ashldi3.S"),
|
||||
("__ashrdi3", "i386/ashrdi3.S"),
|
||||
|
|
@ -421,7 +501,7 @@ mod c {
|
|||
}
|
||||
}
|
||||
|
||||
if target_arch == "arm" && target_vendor != "apple" && target_env != "msvc" {
|
||||
if target.arch == "arm" && target.vendor != "apple" && target.env != "msvc" {
|
||||
sources.extend(&[
|
||||
("__aeabi_div0", "arm/aeabi_div0.c"),
|
||||
("__aeabi_drsub", "arm/aeabi_drsub.c"),
|
||||
|
|
@ -441,7 +521,7 @@ mod c {
|
|||
("__umodsi3", "arm/umodsi3.S"),
|
||||
]);
|
||||
|
||||
if target_os == "freebsd" {
|
||||
if target.os == "freebsd" {
|
||||
sources.extend(&[("__clear_cache", "clear_cache.c")]);
|
||||
}
|
||||
|
||||
|
|
@ -513,7 +593,7 @@ mod c {
|
|||
]);
|
||||
}
|
||||
|
||||
if (target_arch == "aarch64" || target_arch == "arm64ec") && consider_float_intrinsics {
|
||||
if (target.arch == "aarch64" || target.arch == "arm64ec") && consider_float_intrinsics {
|
||||
sources.extend(&[
|
||||
("__comparetf2", "comparetf2.c"),
|
||||
("__floatditf", "floatditf.c"),
|
||||
|
|
@ -526,16 +606,16 @@ mod c {
|
|||
("__fe_raise_inexact", "fp_mode.c"),
|
||||
]);
|
||||
|
||||
if target_os != "windows" {
|
||||
if target.os != "windows" {
|
||||
sources.extend(&[("__multc3", "multc3.c")]);
|
||||
}
|
||||
}
|
||||
|
||||
if target_arch == "mips" || target_arch == "riscv32" || target_arch == "riscv64" {
|
||||
if target.arch == "mips" || target.arch == "riscv32" || target.arch == "riscv64" {
|
||||
sources.extend(&[("__bswapsi2", "bswapsi2.c")]);
|
||||
}
|
||||
|
||||
if target_arch == "mips64" {
|
||||
if target.arch == "mips64" {
|
||||
sources.extend(&[
|
||||
("__netf2", "comparetf2.c"),
|
||||
("__floatsitf", "floatsitf.c"),
|
||||
|
|
@ -544,7 +624,7 @@ mod c {
|
|||
]);
|
||||
}
|
||||
|
||||
if target_arch == "loongarch64" {
|
||||
if target.arch == "loongarch64" {
|
||||
sources.extend(&[
|
||||
("__netf2", "comparetf2.c"),
|
||||
("__floatsitf", "floatsitf.c"),
|
||||
|
|
@ -554,7 +634,7 @@ mod c {
|
|||
}
|
||||
|
||||
// Remove the assembly implementations that won't compile for the target
|
||||
if llvm_target[0] == "thumbv6m" || llvm_target[0] == "thumbv8m.base" || target_os == "uefi"
|
||||
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() {
|
||||
|
|
@ -570,7 +650,7 @@ mod c {
|
|||
}
|
||||
|
||||
// Android uses emulated TLS so we need a runtime support function.
|
||||
if target_os == "android" {
|
||||
if target.os == "android" {
|
||||
sources.extend(&[("__emutls_get_address", "emutls.c")]);
|
||||
|
||||
// Work around a bug in the NDK headers (fixed in
|
||||
|
|
@ -580,7 +660,7 @@ mod c {
|
|||
}
|
||||
|
||||
// OpenHarmony also uses emulated TLS.
|
||||
if target_env == "ohos" {
|
||||
if target.env == "ohos" {
|
||||
sources.extend(&[("__emutls_get_address", "emutls.c")]);
|
||||
}
|
||||
|
||||
|
|
@ -607,7 +687,7 @@ mod c {
|
|||
// 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" {
|
||||
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);
|
||||
|
||||
|
|
|
|||
|
|
@ -204,7 +204,7 @@ intrinsics! {
|
|||
}
|
||||
|
||||
#[ppc_alias = __addkf3]
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __addtf3(a: f128, b: f128) -> f128 {
|
||||
add(a, b)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -172,7 +172,7 @@ intrinsics! {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128",))]
|
||||
#[cfg(f128_enabled)]
|
||||
intrinsics! {
|
||||
#[avr_skip]
|
||||
#[ppc_alias = __lekf2]
|
||||
|
|
|
|||
|
|
@ -263,19 +263,19 @@ intrinsics! {
|
|||
}
|
||||
|
||||
#[ppc_alias = __fixunskfsi]
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __fixunstfsi(f: f128) -> u32 {
|
||||
float_to_unsigned_int(f)
|
||||
}
|
||||
|
||||
#[ppc_alias = __fixunskfdi]
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __fixunstfdi(f: f128) -> u64 {
|
||||
float_to_unsigned_int(f)
|
||||
}
|
||||
|
||||
#[ppc_alias = __fixunskfti]
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __fixunstfti(f: f128) -> u128 {
|
||||
float_to_unsigned_int(f)
|
||||
}
|
||||
|
|
@ -314,19 +314,19 @@ intrinsics! {
|
|||
}
|
||||
|
||||
#[ppc_alias = __fixkfsi]
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __fixtfsi(f: f128) -> i32 {
|
||||
float_to_signed_int(f)
|
||||
}
|
||||
|
||||
#[ppc_alias = __fixkfdi]
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __fixtfdi(f: f128) -> i64 {
|
||||
float_to_signed_int(f)
|
||||
}
|
||||
|
||||
#[ppc_alias = __fixkfti]
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __fixtfti(f: f128) -> i128 {
|
||||
float_to_signed_int(f)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -83,17 +83,18 @@ intrinsics! {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
intrinsics! {
|
||||
#[avr_skip]
|
||||
#[aapcs_on_arm]
|
||||
#[arm_aeabi_alias = __aeabi_h2f]
|
||||
#[cfg(f16_enabled)]
|
||||
pub extern "C" fn __extendhfsf2(a: f16) -> f32 {
|
||||
extend(a)
|
||||
}
|
||||
|
||||
#[avr_skip]
|
||||
#[aapcs_on_arm]
|
||||
#[cfg(f16_enabled)]
|
||||
pub extern "C" fn __gnu_h2f_ieee(a: f16) -> f32 {
|
||||
extend(a)
|
||||
}
|
||||
|
|
@ -101,6 +102,7 @@ intrinsics! {
|
|||
#[avr_skip]
|
||||
#[aapcs_on_arm]
|
||||
#[ppc_alias = __extendhfkf2]
|
||||
#[cfg(all(f16_enabled, f128_enabled))]
|
||||
pub extern "C" fn __extendhftf2(a: f16) -> f128 {
|
||||
extend(a)
|
||||
}
|
||||
|
|
@ -108,6 +110,7 @@ intrinsics! {
|
|||
#[avr_skip]
|
||||
#[aapcs_on_arm]
|
||||
#[ppc_alias = __extendsfkf2]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __extendsftf2(a: f32) -> f128 {
|
||||
extend(a)
|
||||
}
|
||||
|
|
@ -115,6 +118,7 @@ intrinsics! {
|
|||
#[avr_skip]
|
||||
#[aapcs_on_arm]
|
||||
#[ppc_alias = __extenddfkf2]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __extenddftf2(a: f64) -> f128 {
|
||||
extend(a)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -188,9 +188,9 @@ macro_rules! float_impl {
|
|||
};
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(f16_enabled)]
|
||||
float_impl!(f16, u16, i16, i8, 16, 10);
|
||||
float_impl!(f32, u32, i32, i16, 32, 23);
|
||||
float_impl!(f64, u64, i64, i16, 64, 52);
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(f128_enabled)]
|
||||
float_impl!(f128, u128, i128, i16, 128, 112);
|
||||
|
|
|
|||
|
|
@ -195,7 +195,7 @@ intrinsics! {
|
|||
}
|
||||
|
||||
#[ppc_alias = __mulkf3]
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __multf3(a: f128, b: f128) -> f128 {
|
||||
mul(a, b)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ intrinsics! {
|
|||
}
|
||||
|
||||
#[ppc_alias = __subkf3]
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __subtf3(a: f128, b: f128) -> f128 {
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
use crate::float::add::__addkf3 as __addtf3;
|
||||
|
|
|
|||
|
|
@ -131,17 +131,18 @@ intrinsics! {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
intrinsics! {
|
||||
#[avr_skip]
|
||||
#[aapcs_on_arm]
|
||||
#[arm_aeabi_alias = __aeabi_f2h]
|
||||
#[cfg(f16_enabled)]
|
||||
pub extern "C" fn __truncsfhf2(a: f32) -> f16 {
|
||||
trunc(a)
|
||||
}
|
||||
|
||||
#[avr_skip]
|
||||
#[aapcs_on_arm]
|
||||
#[cfg(f16_enabled)]
|
||||
pub extern "C" fn __gnu_f2h_ieee(a: f32) -> f16 {
|
||||
trunc(a)
|
||||
}
|
||||
|
|
@ -149,6 +150,7 @@ intrinsics! {
|
|||
#[avr_skip]
|
||||
#[aapcs_on_arm]
|
||||
#[arm_aeabi_alias = __aeabi_d2h]
|
||||
#[cfg(f16_enabled)]
|
||||
pub extern "C" fn __truncdfhf2(a: f64) -> f16 {
|
||||
trunc(a)
|
||||
}
|
||||
|
|
@ -156,6 +158,7 @@ intrinsics! {
|
|||
#[avr_skip]
|
||||
#[aapcs_on_arm]
|
||||
#[ppc_alias = __trunckfhf2]
|
||||
#[cfg(all(f16_enabled, f128_enabled))]
|
||||
pub extern "C" fn __trunctfhf2(a: f128) -> f16 {
|
||||
trunc(a)
|
||||
}
|
||||
|
|
@ -163,6 +166,7 @@ intrinsics! {
|
|||
#[avr_skip]
|
||||
#[aapcs_on_arm]
|
||||
#[ppc_alias = __trunckfsf2]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __trunctfsf2(a: f128) -> f32 {
|
||||
trunc(a)
|
||||
}
|
||||
|
|
@ -170,6 +174,7 @@ intrinsics! {
|
|||
#[avr_skip]
|
||||
#[aapcs_on_arm]
|
||||
#[ppc_alias = __trunckfdf2]
|
||||
#[cfg(f128_enabled)]
|
||||
pub extern "C" fn __trunctfdf2(a: f128) -> f64 {
|
||||
trunc(a)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,8 @@
|
|||
#![feature(naked_functions)]
|
||||
#![feature(repr_simd)]
|
||||
#![feature(c_unwind)]
|
||||
#![cfg_attr(not(feature = "no-f16-f128"), feature(f16))]
|
||||
#![cfg_attr(not(feature = "no-f16-f128"), feature(f128))]
|
||||
#![cfg_attr(f16_enabled, feature(f16))]
|
||||
#![cfg_attr(f128_enabled, feature(f128))]
|
||||
#![no_builtins]
|
||||
#![no_std]
|
||||
#![allow(unused_features)]
|
||||
|
|
|
|||
|
|
@ -290,6 +290,7 @@ macro_rules! intrinsics {
|
|||
$($rest:tt)*
|
||||
) => (
|
||||
#[cfg(target_arch = "arm")]
|
||||
$(#[$($attr)*])*
|
||||
pub extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
|
||||
$($body)*
|
||||
}
|
||||
|
|
@ -298,6 +299,7 @@ macro_rules! intrinsics {
|
|||
mod $name {
|
||||
#[no_mangle]
|
||||
#[cfg_attr(all(not(windows), not(target_vendor = "apple")), linkage = "weak")]
|
||||
$(#[$($attr)*])*
|
||||
extern $abi fn $name( $($argname: $ty),* ) $(-> $ret)? {
|
||||
super::$name($($argname),*)
|
||||
}
|
||||
|
|
@ -307,6 +309,7 @@ macro_rules! intrinsics {
|
|||
mod $alias {
|
||||
#[no_mangle]
|
||||
#[cfg_attr(all(not(windows), not(target_vendor="apple")), linkage = "weak")]
|
||||
$(#[$($attr)*])*
|
||||
extern "aapcs" fn $alias( $($argname: $ty),* ) $(-> $ret)? {
|
||||
super::$name($($argname),*)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ doctest = false
|
|||
# `xoshiro128**` is used for its quality, size, and speed at generating `u32` shift amounts.
|
||||
rand_xoshiro = "0.6"
|
||||
# To compare float builtins against
|
||||
rustc_apfloat = "0.2.0"
|
||||
rustc_apfloat = "0.2.1"
|
||||
|
||||
[dependencies.compiler_builtins]
|
||||
path = ".."
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ float_bench! {
|
|||
asm: [],
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
criterion_group!(
|
||||
float_extend,
|
||||
extend_f16_f32,
|
||||
|
|
@ -90,4 +91,14 @@ criterion_group!(
|
|||
extend_f32_f128,
|
||||
extend_f64_f128,
|
||||
);
|
||||
|
||||
// FIXME(#655): `f16` tests disabled until we can bootstrap symbols
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
criterion_group!(
|
||||
float_extend,
|
||||
extend_f32_f64,
|
||||
extend_f32_f128,
|
||||
extend_f64_f128,
|
||||
);
|
||||
|
||||
criterion_main!(float_extend);
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ float_bench! {
|
|||
sig: (a: f64) -> f16,
|
||||
crate_fn: trunc::__truncdfhf2,
|
||||
sys_fn: __truncdfhf2,
|
||||
sys_available: not(feature = "no-sys-f128"),
|
||||
sys_available: not(feature = "no-sys-f16"),
|
||||
asm: [
|
||||
#[cfg(target_arch = "aarch64")] {
|
||||
// FIXME(f16_f128): remove `from_bits()` after f16 asm support (rust-lang/rust/#116909)
|
||||
|
|
@ -115,6 +115,7 @@ float_bench! {
|
|||
asm: [],
|
||||
}
|
||||
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
criterion_group!(
|
||||
float_trunc,
|
||||
trunc_f32_f16,
|
||||
|
|
@ -124,4 +125,9 @@ criterion_group!(
|
|||
trunc_f128_f32,
|
||||
trunc_f128_f64,
|
||||
);
|
||||
|
||||
// FIXME(#655): `f16` tests disabled until we can bootstrap symbols
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
criterion_group!(float_trunc, trunc_f64_f32, trunc_f128_f32, trunc_f128_f64,);
|
||||
|
||||
criterion_main!(float_trunc);
|
||||
|
|
|
|||
|
|
@ -44,10 +44,21 @@ fn main() {
|
|||
features.insert(Feature::NoSysF16F128Convert);
|
||||
}
|
||||
|
||||
if target.starts_with("wasm32-") {
|
||||
// These platforms do not have f16 symbols available in their system libraries, so
|
||||
// skip related tests. Most of these are missing `f16 <-> f32` conversion routines.
|
||||
if (target.starts_with("aarch64-") && target.contains("linux"))
|
||||
|| target.starts_with("arm")
|
||||
|| target.starts_with("powerpc-")
|
||||
|| target.starts_with("powerpc64-")
|
||||
|| target.starts_with("powerpc64le-")
|
||||
|| target.starts_with("i586-")
|
||||
|| target.contains("windows-")
|
||||
// Linking says "error: function signature mismatch: __extendhfsf2" and seems to
|
||||
// think the signature is either `(i32) -> f32` or `(f32) -> f32`
|
||||
|| target.starts_with("wasm32-")
|
||||
{
|
||||
features.insert(Feature::NoSysF16);
|
||||
features.insert(Feature::NoSysF16F128Convert);
|
||||
}
|
||||
|
||||
for feature in features {
|
||||
|
|
|
|||
|
|
@ -282,6 +282,8 @@ macro_rules! apfloat_fallback {
|
|||
// The expression to run. This expression may use `FloatTy` for its signature.
|
||||
// Optionally, the final conversion back to a float can be suppressed using
|
||||
// `=> no_convert` (for e.g. operations that return a bool).
|
||||
//
|
||||
// If the apfloat needs a different operation, it can be provided here.
|
||||
$op:expr $(=> $convert:ident)? $(; $apfloat_op:expr)?,
|
||||
// Arguments that get passed to `$op` after converting to a float
|
||||
$($arg:expr),+
|
||||
|
|
@ -318,7 +320,7 @@ macro_rules! apfloat_fallback {
|
|||
|
||||
// Some apfloat operations return a `StatusAnd` that we need to extract the value from. This
|
||||
// is the default.
|
||||
(@inner fty: $float_ty:ty, op_res: $val:expr, args: $($_arg:expr),+) => {{
|
||||
(@inner fty: $float_ty:ty, op_res: $val:expr, args: $($_arg:expr),+) => {{
|
||||
// ignore the status, just get the value
|
||||
let unwrapped = $val.value;
|
||||
|
||||
|
|
@ -326,7 +328,7 @@ macro_rules! apfloat_fallback {
|
|||
}};
|
||||
|
||||
// This is the case where we can't use the same expression for the default builtin and
|
||||
// nonstandard apfloat fallbac (e.g. `as` casts in std are normal functions in apfloat, so
|
||||
// nonstandard apfloat fallback (e.g. `as` casts in std are normal functions in apfloat, so
|
||||
// two separate expressions must be specified.
|
||||
(@inner
|
||||
fty: $float_ty:ty, op_res: $_val:expr,
|
||||
|
|
|
|||
|
|
@ -206,212 +206,116 @@ mod f_to_i {
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! conv {
|
||||
($fX:ident, $fD:ident, $fn:ident, $apfloatX:ident, $apfloatD:ident) => {
|
||||
fuzz_float(N, |x: $fX| {
|
||||
let tmp0: $apfloatD = $apfloatX::from_bits(x.to_bits().into())
|
||||
.convert(&mut false)
|
||||
.value;
|
||||
let tmp0 = $fD::from_bits(tmp0.to_bits().try_into().unwrap());
|
||||
let tmp1: $fD = $fn(x);
|
||||
if !Float::eq_repr(tmp0, tmp1) {
|
||||
panic!(
|
||||
"{}({x:?}): apfloat: {tmp0:?}, builtins: {tmp1:?}",
|
||||
stringify!($fn)
|
||||
macro_rules! f_to_f {
|
||||
(
|
||||
$mod:ident,
|
||||
$(
|
||||
$from_ty:ty => $to_ty:ty,
|
||||
$from_ap_ty:ident => $to_ap_ty:ident,
|
||||
$fn:ident, $sys_available:meta
|
||||
);+;
|
||||
) => {$(
|
||||
#[test]
|
||||
fn $fn() {
|
||||
use compiler_builtins::float::{$mod::$fn, Float};
|
||||
use rustc_apfloat::ieee::{$from_ap_ty, $to_ap_ty};
|
||||
|
||||
fuzz_float(N, |x: $from_ty| {
|
||||
let tmp0: $to_ty = apfloat_fallback!(
|
||||
$from_ty,
|
||||
$from_ap_ty,
|
||||
$sys_available,
|
||||
|x: $from_ty| x as $to_ty;
|
||||
|x: $from_ty| {
|
||||
let from_apf = FloatTy::from_bits(x.to_bits().into());
|
||||
// Get `value` directly to ignore INVALID_OP
|
||||
let to_apf: $to_ap_ty = from_apf.convert(&mut false).value;
|
||||
<$to_ty>::from_bits(to_apf.to_bits().try_into().unwrap())
|
||||
},
|
||||
x
|
||||
);
|
||||
}
|
||||
})
|
||||
};
|
||||
}
|
||||
let tmp1: $to_ty = $fn(x);
|
||||
|
||||
macro_rules! extend {
|
||||
($fX:ident, $fD:ident, $fn:ident) => {
|
||||
#[test]
|
||||
fn $fn() {
|
||||
use compiler_builtins::float::extend::$fn;
|
||||
|
||||
fuzz_float(N, |x: $fX| {
|
||||
let tmp0 = x as $fD;
|
||||
let tmp1: $fD = $fn(x);
|
||||
if !Float::eq_repr(tmp0, tmp1) {
|
||||
panic!(
|
||||
"{}({}): std: {}, builtins: {}",
|
||||
"{}({:?}): std: {:?}, builtins: {:?}",
|
||||
stringify!($fn),
|
||||
x,
|
||||
tmp0,
|
||||
tmp1
|
||||
);
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
};
|
||||
)+};
|
||||
}
|
||||
|
||||
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
|
||||
#[cfg(not(target_arch = "powerpc64"))]
|
||||
mod float_extend {
|
||||
mod extend {
|
||||
use super::*;
|
||||
|
||||
extend!(f32, f64, __extendsfdf2);
|
||||
f_to_f! {
|
||||
extend,
|
||||
f32 => f64, Single => Double, __extendsfdf2, all();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::extend::__extendsfdf2;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
#[cfg(target_arch = "arm")]
|
||||
f_to_f! {
|
||||
extend,
|
||||
f32 => f64, Single => Double, __extendsfdf2vfp, all();
|
||||
}
|
||||
|
||||
conv!(f32, f64, __extendsfdf2, Single, Double);
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
f_to_f! {
|
||||
extend,
|
||||
f16 => f32, Half => Single, __extendhfsf2, not(feature = "no-sys-f16");
|
||||
f16 => f32, Half => Single, __gnu_h2f_ieee, not(feature = "no-sys-f16");
|
||||
f16 => f128, Half => Quad, __extendhftf2, not(feature = "no-sys-f16-f128-convert");
|
||||
f32 => f128, Single => Quad, __extendsftf2, not(feature = "no-sys-f128");
|
||||
f64 => f128, Double => Quad, __extenddftf2, not(feature = "no-sys-f128");
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
f_to_f! {
|
||||
extend,
|
||||
// FIXME(#655): `f16` tests disabled until we can bootstrap symbols
|
||||
f32 => f128, Single => Quad, __extendsfkf2, not(feature = "no-sys-f128");
|
||||
f64 => f128, Double => Quad, __extenddfkf2, not(feature = "no-sys-f128");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
mod float_extend_f128 {
|
||||
mod trunc {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::extend::{
|
||||
__extenddftf2, __extendhfsf2, __extendhftf2, __extendsftf2, __gnu_h2f_ieee,
|
||||
};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
f_to_f! {
|
||||
trunc,
|
||||
f64 => f32, Double => Single, __truncdfsf2, all();
|
||||
}
|
||||
|
||||
// FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly
|
||||
conv!(f16, f32, __extendhfsf2, Half, Single);
|
||||
conv!(f16, f32, __gnu_h2f_ieee, Half, Single);
|
||||
conv!(f16, f128, __extendhftf2, Half, Quad);
|
||||
conv!(f32, f128, __extendsftf2, Single, Quad);
|
||||
conv!(f64, f128, __extenddftf2, Double, Quad);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
mod float_extend_f128_ppc {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::extend::{
|
||||
__extenddfkf2, __extendhfkf2, __extendhfsf2, __extendsfkf2, __gnu_h2f_ieee,
|
||||
};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
|
||||
// FIXME(f16_f128): Also do extend!() for `f16` and `f128` when builtins are in nightly
|
||||
conv!(f16, f32, __extendhfsf2, Half, Single);
|
||||
conv!(f16, f32, __gnu_h2f_ieee, Half, Single);
|
||||
conv!(f16, f128, __extendhfkf2, Half, Quad);
|
||||
conv!(f32, f128, __extendsfkf2, Single, Quad);
|
||||
conv!(f64, f128, __extenddfkf2, Double, Quad);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
mod float_extend_arm {
|
||||
use super::*;
|
||||
|
||||
extend!(f32, f64, __extendsfdf2vfp);
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::extend::__extendsfdf2vfp;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
|
||||
conv!(f32, f64, __extendsfdf2vfp, Single, Double);
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! trunc {
|
||||
($fX:ident, $fD:ident, $fn:ident) => {
|
||||
#[test]
|
||||
fn $fn() {
|
||||
use compiler_builtins::float::trunc::$fn;
|
||||
|
||||
fuzz_float(N, |x: $fX| {
|
||||
let tmp0 = x as $fD;
|
||||
let tmp1: $fD = $fn(x);
|
||||
if !Float::eq_repr(tmp0, tmp1) {
|
||||
panic!(
|
||||
"{}({}): std: {}, builtins: {}",
|
||||
stringify!($fn),
|
||||
x,
|
||||
tmp0,
|
||||
tmp1
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// PowerPC tests are failing on LLVM 13: https://github.com/rust-lang/rust/issues/88520
|
||||
#[cfg(not(target_arch = "powerpc64"))]
|
||||
mod float_trunc {
|
||||
use super::*;
|
||||
|
||||
trunc!(f64, f32, __truncdfsf2);
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::trunc::__truncdfsf2;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
|
||||
conv!(f64, f32, __truncdfsf2, Double, Single);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
mod float_trunc_f128 {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2};
|
||||
use compiler_builtins::float::trunc::{__trunctfdf2, __trunctfhf2, __trunctfsf2};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
|
||||
// FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly
|
||||
conv!(f32, f16, __truncsfhf2, Single, Half);
|
||||
conv!(f32, f16, __gnu_f2h_ieee, Single, Half);
|
||||
conv!(f64, f16, __truncdfhf2, Double, Half);
|
||||
conv!(f128, f16, __trunctfhf2, Quad, Half);
|
||||
conv!(f128, f32, __trunctfsf2, Quad, Single);
|
||||
conv!(f128, f64, __trunctfdf2, Quad, Double);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
mod float_trunc_f128_ppc {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::trunc::{__gnu_f2h_ieee, __truncdfhf2, __truncsfhf2};
|
||||
use compiler_builtins::float::trunc::{__trunckfdf2, __trunckfhf2, __trunckfsf2};
|
||||
use rustc_apfloat::ieee::{Double, Half, Quad, Single};
|
||||
|
||||
// FIXME(f16_f128): Also do trunc!() for `f16` and `f128` when builtins are in nightly
|
||||
conv!(f32, f16, __truncsfhf2, Single, Half);
|
||||
conv!(f32, f16, __gnu_f2h_ieee, Single, Half);
|
||||
conv!(f64, f16, __truncdfhf2, Double, Half);
|
||||
conv!(f128, f16, __trunckfhf2, Quad, Half);
|
||||
conv!(f128, f32, __trunckfsf2, Quad, Single);
|
||||
conv!(f128, f64, __trunckfdf2, Quad, Double);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "arm")]
|
||||
mod float_trunc_arm {
|
||||
use super::*;
|
||||
|
||||
trunc!(f64, f32, __truncdfsf2vfp);
|
||||
|
||||
#[test]
|
||||
fn conv() {
|
||||
use compiler_builtins::float::trunc::__truncdfsf2vfp;
|
||||
use rustc_apfloat::ieee::{Double, Single};
|
||||
|
||||
conv!(f64, f32, __truncdfsf2vfp, Double, Single)
|
||||
#[cfg(target_arch = "arm")]
|
||||
f_to_f! {
|
||||
trunc,
|
||||
f64 => f32, Double => Single, __truncdfsf2vfp, all();
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(not(any(target_arch = "powerpc", target_arch = "powerpc64")))]
|
||||
f_to_f! {
|
||||
trunc,
|
||||
f32 => f16, Single => Half, __truncsfhf2, not(feature = "no-sys-f16");
|
||||
f32 => f16, Single => Half, __gnu_f2h_ieee, not(feature = "no-sys-f16");
|
||||
f128 => f16, Quad => Half, __trunctfhf2, not(feature = "no-sys-f16-f128-convert");
|
||||
f128 => f32, Quad => Single, __trunctfsf2, not(feature = "no-sys-f128");
|
||||
f128 => f64, Quad => Double, __trunctfdf2, not(feature = "no-sys-f128");
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no-f16-f128"))]
|
||||
#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))]
|
||||
f_to_f! {
|
||||
trunc,
|
||||
// FIXME(#655): `f16` tests disabled until we can bootstrap symbols
|
||||
f128 => f32, Quad => Single, __trunckfsf2, not(feature = "no-sys-f128");
|
||||
f128 => f64, Quad => Double, __trunckfdf2, not(feature = "no-sys-f128");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue