mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-25 08:13:41 +00:00
Auto merge of #128768 - tgross35:rollup-aaq1ny7, r=tgross35
Rollup of 7 pull requests Successful merges: - #128107 (Migrate `raw-dylib-alt-calling-convention`, `raw-dylib-c` and `redundant-libs` `run-make` tests to rmake) - #128362 (add test for symbol visibility of `#[naked]` functions) - #128417 (Add `f16` and `f128` math functions) - #128638 (run-make: enable msvc for `link-dedup`) - #128647 (Enable msvc for link-args-order) - #128649 (run-make: Enable msvc for `no-duplicate-libs` and `zero-extend-abi-param-passing`) - #128766 (Trivial grammar fix in const keyword docs) r? `@ghost` `@rustbot` modify labels: rollup
This commit is contained in:
commit
6a2cd0d50c
@ -775,10 +775,10 @@ impl<'ll> CodegenCx<'ll, '_> {
|
||||
ifn!("llvm.debugtrap", fn() -> void);
|
||||
ifn!("llvm.frameaddress", fn(t_i32) -> ptr);
|
||||
|
||||
ifn!("llvm.powi.f16", fn(t_f16, t_i32) -> t_f16);
|
||||
ifn!("llvm.powi.f32", fn(t_f32, t_i32) -> t_f32);
|
||||
ifn!("llvm.powi.f64", fn(t_f64, t_i32) -> t_f64);
|
||||
ifn!("llvm.powi.f128", fn(t_f128, t_i32) -> t_f128);
|
||||
ifn!("llvm.powi.f16.i32", fn(t_f16, t_i32) -> t_f16);
|
||||
ifn!("llvm.powi.f32.i32", fn(t_f32, t_i32) -> t_f32);
|
||||
ifn!("llvm.powi.f64.i32", fn(t_f64, t_i32) -> t_f64);
|
||||
ifn!("llvm.powi.f128.i32", fn(t_f128, t_i32) -> t_f128);
|
||||
|
||||
ifn!("llvm.pow.f16", fn(t_f16, t_f16) -> t_f16);
|
||||
ifn!("llvm.pow.f32", fn(t_f32, t_f32) -> t_f32);
|
||||
|
@ -35,10 +35,10 @@ fn get_simple_intrinsic<'ll>(
|
||||
sym::sqrtf64 => "llvm.sqrt.f64",
|
||||
sym::sqrtf128 => "llvm.sqrt.f128",
|
||||
|
||||
sym::powif16 => "llvm.powi.f16",
|
||||
sym::powif32 => "llvm.powi.f32",
|
||||
sym::powif64 => "llvm.powi.f64",
|
||||
sym::powif128 => "llvm.powi.f128",
|
||||
sym::powif16 => "llvm.powi.f16.i32",
|
||||
sym::powif32 => "llvm.powi.f32.i32",
|
||||
sym::powif64 => "llvm.powi.f64.i32",
|
||||
sym::powif128 => "llvm.powi.f128.i32",
|
||||
|
||||
sym::sinf16 => "llvm.sin.f16",
|
||||
sym::sinf32 => "llvm.sin.f32",
|
||||
|
@ -1528,6 +1528,12 @@ extern "rust-intrinsic" {
|
||||
#[rustc_diagnostic_item = "intrinsics_unaligned_volatile_store"]
|
||||
pub fn unaligned_volatile_store<T>(dst: *mut T, val: T);
|
||||
|
||||
/// Returns the square root of an `f16`
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::sqrt`](../../std/primitive.f16.html#method.sqrt)
|
||||
#[rustc_nounwind]
|
||||
pub fn sqrtf16(x: f16) -> f16;
|
||||
/// Returns the square root of an `f32`
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1540,6 +1546,12 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::sqrt`](../../std/primitive.f64.html#method.sqrt)
|
||||
#[rustc_nounwind]
|
||||
pub fn sqrtf64(x: f64) -> f64;
|
||||
/// Returns the square root of an `f128`
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::sqrt`](../../std/primitive.f128.html#method.sqrt)
|
||||
#[rustc_nounwind]
|
||||
pub fn sqrtf128(x: f128) -> f128;
|
||||
|
||||
/// Raises an `f16` to an integer power.
|
||||
///
|
||||
@ -1566,6 +1578,12 @@ extern "rust-intrinsic" {
|
||||
#[rustc_nounwind]
|
||||
pub fn powif128(a: f128, x: i32) -> f128;
|
||||
|
||||
/// Returns the sine of an `f16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::sin`](../../std/primitive.f16.html#method.sin)
|
||||
#[rustc_nounwind]
|
||||
pub fn sinf16(x: f16) -> f16;
|
||||
/// Returns the sine of an `f32`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1578,7 +1596,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::sin`](../../std/primitive.f64.html#method.sin)
|
||||
#[rustc_nounwind]
|
||||
pub fn sinf64(x: f64) -> f64;
|
||||
/// Returns the sine of an `f128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::sin`](../../std/primitive.f128.html#method.sin)
|
||||
#[rustc_nounwind]
|
||||
pub fn sinf128(x: f128) -> f128;
|
||||
|
||||
/// Returns the cosine of an `f16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::cos`](../../std/primitive.f16.html#method.cos)
|
||||
#[rustc_nounwind]
|
||||
pub fn cosf16(x: f16) -> f16;
|
||||
/// Returns the cosine of an `f32`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1591,7 +1621,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::cos`](../../std/primitive.f64.html#method.cos)
|
||||
#[rustc_nounwind]
|
||||
pub fn cosf64(x: f64) -> f64;
|
||||
/// Returns the cosine of an `f128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::cos`](../../std/primitive.f128.html#method.cos)
|
||||
#[rustc_nounwind]
|
||||
pub fn cosf128(x: f128) -> f128;
|
||||
|
||||
/// Raises an `f16` to an `f16` power.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::powf`](../../std/primitive.f16.html#method.powf)
|
||||
#[rustc_nounwind]
|
||||
pub fn powf16(a: f16, x: f16) -> f16;
|
||||
/// Raises an `f32` to an `f32` power.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1604,7 +1646,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::powf`](../../std/primitive.f64.html#method.powf)
|
||||
#[rustc_nounwind]
|
||||
pub fn powf64(a: f64, x: f64) -> f64;
|
||||
/// Raises an `f128` to an `f128` power.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::powf`](../../std/primitive.f128.html#method.powf)
|
||||
#[rustc_nounwind]
|
||||
pub fn powf128(a: f128, x: f128) -> f128;
|
||||
|
||||
/// Returns the exponential of an `f16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::exp`](../../std/primitive.f16.html#method.exp)
|
||||
#[rustc_nounwind]
|
||||
pub fn expf16(x: f16) -> f16;
|
||||
/// Returns the exponential of an `f32`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1617,7 +1671,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::exp`](../../std/primitive.f64.html#method.exp)
|
||||
#[rustc_nounwind]
|
||||
pub fn expf64(x: f64) -> f64;
|
||||
/// Returns the exponential of an `f128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::exp`](../../std/primitive.f128.html#method.exp)
|
||||
#[rustc_nounwind]
|
||||
pub fn expf128(x: f128) -> f128;
|
||||
|
||||
/// Returns 2 raised to the power of an `f16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::exp2`](../../std/primitive.f16.html#method.exp2)
|
||||
#[rustc_nounwind]
|
||||
pub fn exp2f16(x: f16) -> f16;
|
||||
/// Returns 2 raised to the power of an `f32`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1630,7 +1696,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::exp2`](../../std/primitive.f64.html#method.exp2)
|
||||
#[rustc_nounwind]
|
||||
pub fn exp2f64(x: f64) -> f64;
|
||||
/// Returns 2 raised to the power of an `f128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::exp2`](../../std/primitive.f128.html#method.exp2)
|
||||
#[rustc_nounwind]
|
||||
pub fn exp2f128(x: f128) -> f128;
|
||||
|
||||
/// Returns the natural logarithm of an `f16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::ln`](../../std/primitive.f16.html#method.ln)
|
||||
#[rustc_nounwind]
|
||||
pub fn logf16(x: f16) -> f16;
|
||||
/// Returns the natural logarithm of an `f32`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1643,7 +1721,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::ln`](../../std/primitive.f64.html#method.ln)
|
||||
#[rustc_nounwind]
|
||||
pub fn logf64(x: f64) -> f64;
|
||||
/// Returns the natural logarithm of an `f128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::ln`](../../std/primitive.f128.html#method.ln)
|
||||
#[rustc_nounwind]
|
||||
pub fn logf128(x: f128) -> f128;
|
||||
|
||||
/// Returns the base 10 logarithm of an `f16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::log10`](../../std/primitive.f16.html#method.log10)
|
||||
#[rustc_nounwind]
|
||||
pub fn log10f16(x: f16) -> f16;
|
||||
/// Returns the base 10 logarithm of an `f32`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1656,7 +1746,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::log10`](../../std/primitive.f64.html#method.log10)
|
||||
#[rustc_nounwind]
|
||||
pub fn log10f64(x: f64) -> f64;
|
||||
/// Returns the base 10 logarithm of an `f128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::log10`](../../std/primitive.f128.html#method.log10)
|
||||
#[rustc_nounwind]
|
||||
pub fn log10f128(x: f128) -> f128;
|
||||
|
||||
/// Returns the base 2 logarithm of an `f16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::log2`](../../std/primitive.f16.html#method.log2)
|
||||
#[rustc_nounwind]
|
||||
pub fn log2f16(x: f16) -> f16;
|
||||
/// Returns the base 2 logarithm of an `f32`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1669,7 +1771,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::log2`](../../std/primitive.f64.html#method.log2)
|
||||
#[rustc_nounwind]
|
||||
pub fn log2f64(x: f64) -> f64;
|
||||
/// Returns the base 2 logarithm of an `f128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::log2`](../../std/primitive.f128.html#method.log2)
|
||||
#[rustc_nounwind]
|
||||
pub fn log2f128(x: f128) -> f128;
|
||||
|
||||
/// Returns `a * b + c` for `f16` values.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::mul_add`](../../std/primitive.f16.html#method.mul_add)
|
||||
#[rustc_nounwind]
|
||||
pub fn fmaf16(a: f16, b: f16, c: f16) -> f16;
|
||||
/// Returns `a * b + c` for `f32` values.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1682,7 +1796,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::mul_add`](../../std/primitive.f64.html#method.mul_add)
|
||||
#[rustc_nounwind]
|
||||
pub fn fmaf64(a: f64, b: f64, c: f64) -> f64;
|
||||
/// Returns `a * b + c` for `f128` values.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::mul_add`](../../std/primitive.f128.html#method.mul_add)
|
||||
#[rustc_nounwind]
|
||||
pub fn fmaf128(a: f128, b: f128, c: f128) -> f128;
|
||||
|
||||
/// Returns the absolute value of an `f16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::abs`](../../std/primitive.f16.html#method.abs)
|
||||
#[rustc_nounwind]
|
||||
pub fn fabsf16(x: f16) -> f16;
|
||||
/// Returns the absolute value of an `f32`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1695,7 +1821,25 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::abs`](../../std/primitive.f64.html#method.abs)
|
||||
#[rustc_nounwind]
|
||||
pub fn fabsf64(x: f64) -> f64;
|
||||
/// Returns the absolute value of an `f128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::abs`](../../std/primitive.f128.html#method.abs)
|
||||
#[rustc_nounwind]
|
||||
pub fn fabsf128(x: f128) -> f128;
|
||||
|
||||
/// Returns the minimum of two `f16` values.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::min`]
|
||||
#[rustc_safe_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub fn minnumf16(x: f16, y: f16) -> f16;
|
||||
/// Returns the minimum of two `f32` values.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
@ -1720,6 +1864,31 @@ extern "rust-intrinsic" {
|
||||
#[rustc_safe_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub fn minnumf64(x: f64, y: f64) -> f64;
|
||||
/// Returns the minimum of two `f128` values.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::min`]
|
||||
#[rustc_safe_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub fn minnumf128(x: f128, y: f128) -> f128;
|
||||
|
||||
/// Returns the maximum of two `f16` values.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::max`]
|
||||
#[rustc_safe_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub fn maxnumf16(x: f16, y: f16) -> f16;
|
||||
/// Returns the maximum of two `f32` values.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
@ -1744,7 +1913,25 @@ extern "rust-intrinsic" {
|
||||
#[rustc_safe_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub fn maxnumf64(x: f64, y: f64) -> f64;
|
||||
/// Returns the maximum of two `f128` values.
|
||||
///
|
||||
/// Note that, unlike most intrinsics, this is safe to call;
|
||||
/// it does not require an `unsafe` block.
|
||||
/// Therefore, implementations must not require the user to uphold
|
||||
/// any safety invariants.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::max`]
|
||||
#[rustc_safe_intrinsic]
|
||||
#[rustc_nounwind]
|
||||
pub fn maxnumf128(x: f128, y: f128) -> f128;
|
||||
|
||||
/// Copies the sign from `y` to `x` for `f16` values.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::copysign`](../../std/primitive.f16.html#method.copysign)
|
||||
#[rustc_nounwind]
|
||||
pub fn copysignf16(x: f16, y: f16) -> f16;
|
||||
/// Copies the sign from `y` to `x` for `f32` values.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1757,7 +1944,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::copysign`](../../std/primitive.f64.html#method.copysign)
|
||||
#[rustc_nounwind]
|
||||
pub fn copysignf64(x: f64, y: f64) -> f64;
|
||||
/// Copies the sign from `y` to `x` for `f128` values.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::copysign`](../../std/primitive.f128.html#method.copysign)
|
||||
#[rustc_nounwind]
|
||||
pub fn copysignf128(x: f128, y: f128) -> f128;
|
||||
|
||||
/// Returns the largest integer less than or equal to an `f16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::floor`](../../std/primitive.f16.html#method.floor)
|
||||
#[rustc_nounwind]
|
||||
pub fn floorf16(x: f16) -> f16;
|
||||
/// Returns the largest integer less than or equal to an `f32`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1770,7 +1969,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::floor`](../../std/primitive.f64.html#method.floor)
|
||||
#[rustc_nounwind]
|
||||
pub fn floorf64(x: f64) -> f64;
|
||||
/// Returns the largest integer less than or equal to an `f128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::floor`](../../std/primitive.f128.html#method.floor)
|
||||
#[rustc_nounwind]
|
||||
pub fn floorf128(x: f128) -> f128;
|
||||
|
||||
/// Returns the smallest integer greater than or equal to an `f16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::ceil`](../../std/primitive.f16.html#method.ceil)
|
||||
#[rustc_nounwind]
|
||||
pub fn ceilf16(x: f16) -> f16;
|
||||
/// Returns the smallest integer greater than or equal to an `f32`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1783,7 +1994,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::ceil`](../../std/primitive.f64.html#method.ceil)
|
||||
#[rustc_nounwind]
|
||||
pub fn ceilf64(x: f64) -> f64;
|
||||
/// Returns the smallest integer greater than or equal to an `f128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::ceil`](../../std/primitive.f128.html#method.ceil)
|
||||
#[rustc_nounwind]
|
||||
pub fn ceilf128(x: f128) -> f128;
|
||||
|
||||
/// Returns the integer part of an `f16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::trunc`](../../std/primitive.f16.html#method.trunc)
|
||||
#[rustc_nounwind]
|
||||
pub fn truncf16(x: f16) -> f16;
|
||||
/// Returns the integer part of an `f32`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1796,7 +2019,25 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::trunc`](../../std/primitive.f64.html#method.trunc)
|
||||
#[rustc_nounwind]
|
||||
pub fn truncf64(x: f64) -> f64;
|
||||
/// Returns the integer part of an `f128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::trunc`](../../std/primitive.f128.html#method.trunc)
|
||||
#[rustc_nounwind]
|
||||
pub fn truncf128(x: f128) -> f128;
|
||||
|
||||
/// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust,
|
||||
/// so this rounds half-way cases to the number with an even least significant digit.
|
||||
///
|
||||
/// May raise an inexact floating-point exception if the argument is not an integer.
|
||||
/// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions
|
||||
/// cannot actually be utilized from Rust code.
|
||||
/// In other words, this intrinsic is equivalent in behavior to `nearbyintf16` and `roundevenf16`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::round_ties_even`](../../std/primitive.f16.html#method.round_ties_even)
|
||||
#[rustc_nounwind]
|
||||
pub fn rintf16(x: f16) -> f16;
|
||||
/// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust,
|
||||
/// so this rounds half-way cases to the number with an even least significant digit.
|
||||
///
|
||||
@ -1821,7 +2062,25 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::round_ties_even`](../../std/primitive.f64.html#method.round_ties_even)
|
||||
#[rustc_nounwind]
|
||||
pub fn rintf64(x: f64) -> f64;
|
||||
/// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust,
|
||||
/// so this rounds half-way cases to the number with an even least significant digit.
|
||||
///
|
||||
/// May raise an inexact floating-point exception if the argument is not an integer.
|
||||
/// However, Rust assumes floating-point exceptions cannot be observed, so these exceptions
|
||||
/// cannot actually be utilized from Rust code.
|
||||
/// In other words, this intrinsic is equivalent in behavior to `nearbyintf128` and `roundevenf128`.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::round_ties_even`](../../std/primitive.f128.html#method.round_ties_even)
|
||||
#[rustc_nounwind]
|
||||
pub fn rintf128(x: f128) -> f128;
|
||||
|
||||
/// Returns the nearest integer to an `f16`. Changing the rounding mode is not possible in Rust,
|
||||
/// so this rounds half-way cases to the number with an even least significant digit.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_nounwind]
|
||||
pub fn nearbyintf16(x: f16) -> f16;
|
||||
/// Returns the nearest integer to an `f32`. Changing the rounding mode is not possible in Rust,
|
||||
/// so this rounds half-way cases to the number with an even least significant digit.
|
||||
///
|
||||
@ -1834,7 +2093,19 @@ extern "rust-intrinsic" {
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_nounwind]
|
||||
pub fn nearbyintf64(x: f64) -> f64;
|
||||
/// Returns the nearest integer to an `f128`. Changing the rounding mode is not possible in Rust,
|
||||
/// so this rounds half-way cases to the number with an even least significant digit.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_nounwind]
|
||||
pub fn nearbyintf128(x: f128) -> f128;
|
||||
|
||||
/// Returns the nearest integer to an `f16`. Rounds half-way cases away from zero.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f16::round`](../../std/primitive.f16.html#method.round)
|
||||
#[rustc_nounwind]
|
||||
pub fn roundf16(x: f16) -> f16;
|
||||
/// Returns the nearest integer to an `f32`. Rounds half-way cases away from zero.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
@ -1847,7 +2118,19 @@ extern "rust-intrinsic" {
|
||||
/// [`f64::round`](../../std/primitive.f64.html#method.round)
|
||||
#[rustc_nounwind]
|
||||
pub fn roundf64(x: f64) -> f64;
|
||||
/// Returns the nearest integer to an `f128`. Rounds half-way cases away from zero.
|
||||
///
|
||||
/// The stabilized version of this intrinsic is
|
||||
/// [`f128::round`](../../std/primitive.f128.html#method.round)
|
||||
#[rustc_nounwind]
|
||||
pub fn roundf128(x: f128) -> f128;
|
||||
|
||||
/// Returns the nearest integer to an `f16`. Rounds half-way cases to the number
|
||||
/// with an even least significant digit.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_nounwind]
|
||||
pub fn roundevenf16(x: f16) -> f16;
|
||||
/// Returns the nearest integer to an `f32`. Rounds half-way cases to the number
|
||||
/// with an even least significant digit.
|
||||
///
|
||||
@ -1860,6 +2143,12 @@ extern "rust-intrinsic" {
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_nounwind]
|
||||
pub fn roundevenf64(x: f64) -> f64;
|
||||
/// Returns the nearest integer to an `f128`. Rounds half-way cases to the number
|
||||
/// with an even least significant digit.
|
||||
///
|
||||
/// This intrinsic does not have a stable counterpart.
|
||||
#[rustc_nounwind]
|
||||
pub fn roundevenf128(x: f128) -> f128;
|
||||
|
||||
/// Float addition that allows optimizations based on algebraic rules.
|
||||
/// May assume inputs are finite.
|
||||
|
@ -686,6 +686,182 @@ impl f128 {
|
||||
self * RADS_PER_DEG
|
||||
}
|
||||
|
||||
/// Returns the maximum of the two numbers, ignoring NaN.
|
||||
///
|
||||
/// If one of the arguments is NaN, then the other argument is returned.
|
||||
/// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
|
||||
/// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
|
||||
/// This also matches the behavior of libm’s fmax.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f128)]
|
||||
/// # // Using aarch64 because `reliable_f128_math` is needed
|
||||
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
|
||||
///
|
||||
/// let x = 1.0f128;
|
||||
/// let y = 2.0f128;
|
||||
///
|
||||
/// assert_eq!(x.max(y), y);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "f128", issue = "116909")]
|
||||
#[must_use = "this returns the result of the comparison, without modifying either input"]
|
||||
pub fn max(self, other: f128) -> f128 {
|
||||
intrinsics::maxnumf128(self, other)
|
||||
}
|
||||
|
||||
/// Returns the minimum of the two numbers, ignoring NaN.
|
||||
///
|
||||
/// If one of the arguments is NaN, then the other argument is returned.
|
||||
/// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
|
||||
/// this function handles all NaNs the same way and avoids minNum's problems with associativity.
|
||||
/// This also matches the behavior of libm’s fmin.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f128)]
|
||||
/// # // Using aarch64 because `reliable_f128_math` is needed
|
||||
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
|
||||
///
|
||||
/// let x = 1.0f128;
|
||||
/// let y = 2.0f128;
|
||||
///
|
||||
/// assert_eq!(x.min(y), x);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "f128", issue = "116909")]
|
||||
#[must_use = "this returns the result of the comparison, without modifying either input"]
|
||||
pub fn min(self, other: f128) -> f128 {
|
||||
intrinsics::minnumf128(self, other)
|
||||
}
|
||||
|
||||
/// Returns the maximum of the two numbers, propagating NaN.
|
||||
///
|
||||
/// This returns NaN when *either* argument is NaN, as opposed to
|
||||
/// [`f128::max`] which only returns NaN when *both* arguments are NaN.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f128)]
|
||||
/// #![feature(float_minimum_maximum)]
|
||||
/// # // Using aarch64 because `reliable_f128_math` is needed
|
||||
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
|
||||
///
|
||||
/// let x = 1.0f128;
|
||||
/// let y = 2.0f128;
|
||||
///
|
||||
/// assert_eq!(x.maximum(y), y);
|
||||
/// assert!(x.maximum(f128::NAN).is_nan());
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
|
||||
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
|
||||
/// Note that this follows the semantics specified in IEEE 754-2019.
|
||||
///
|
||||
/// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
|
||||
/// operand is conserved; see [explanation of NaN as a special value](f128) for more info.
|
||||
#[inline]
|
||||
#[unstable(feature = "f128", issue = "116909")]
|
||||
// #[unstable(feature = "float_minimum_maximum", issue = "91079")]
|
||||
#[must_use = "this returns the result of the comparison, without modifying either input"]
|
||||
pub fn maximum(self, other: f128) -> f128 {
|
||||
if self > other {
|
||||
self
|
||||
} else if other > self {
|
||||
other
|
||||
} else if self == other {
|
||||
if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
|
||||
} else {
|
||||
self + other
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the minimum of the two numbers, propagating NaN.
|
||||
///
|
||||
/// This returns NaN when *either* argument is NaN, as opposed to
|
||||
/// [`f128::min`] which only returns NaN when *both* arguments are NaN.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f128)]
|
||||
/// #![feature(float_minimum_maximum)]
|
||||
/// # // Using aarch64 because `reliable_f128_math` is needed
|
||||
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
|
||||
///
|
||||
/// let x = 1.0f128;
|
||||
/// let y = 2.0f128;
|
||||
///
|
||||
/// assert_eq!(x.minimum(y), x);
|
||||
/// assert!(x.minimum(f128::NAN).is_nan());
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
|
||||
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
|
||||
/// Note that this follows the semantics specified in IEEE 754-2019.
|
||||
///
|
||||
/// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
|
||||
/// operand is conserved; see [explanation of NaN as a special value](f128) for more info.
|
||||
#[inline]
|
||||
#[unstable(feature = "f128", issue = "116909")]
|
||||
// #[unstable(feature = "float_minimum_maximum", issue = "91079")]
|
||||
#[must_use = "this returns the result of the comparison, without modifying either input"]
|
||||
pub fn minimum(self, other: f128) -> f128 {
|
||||
if self < other {
|
||||
self
|
||||
} else if other < self {
|
||||
other
|
||||
} else if self == other {
|
||||
if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
|
||||
} else {
|
||||
// At least one input is NaN. Use `+` to perform NaN propagation and quieting.
|
||||
self + other
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the middle point of `self` and `rhs`.
|
||||
///
|
||||
/// This returns NaN when *either* argument is NaN or if a combination of
|
||||
/// +inf and -inf is provided as arguments.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f128)]
|
||||
/// #![feature(num_midpoint)]
|
||||
/// # // Using aarch64 because `reliable_f128_math` is needed
|
||||
/// # #[cfg(all(target_arch = "aarch64", target_os = "linux"))] {
|
||||
///
|
||||
/// assert_eq!(1f128.midpoint(4.0), 2.5);
|
||||
/// assert_eq!((-5.5f128).midpoint(8.0), 1.25);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "f128", issue = "116909")]
|
||||
// #[unstable(feature = "num_midpoint", issue = "110840")]
|
||||
pub fn midpoint(self, other: f128) -> f128 {
|
||||
const LO: f128 = f128::MIN_POSITIVE * 2.;
|
||||
const HI: f128 = f128::MAX / 2.;
|
||||
|
||||
let (a, b) = (self, other);
|
||||
let abs_a = a.abs_private();
|
||||
let abs_b = b.abs_private();
|
||||
|
||||
if abs_a <= HI && abs_b <= HI {
|
||||
// Overflow is impossible
|
||||
(a + b) / 2.
|
||||
} else if abs_a < LO {
|
||||
// Not safe to halve `a` (would underflow)
|
||||
a + (b / 2.)
|
||||
} else if abs_b < LO {
|
||||
// Not safe to halve `b` (would underflow)
|
||||
(a / 2.) + b
|
||||
} else {
|
||||
// Safe to halve `a` and `b`
|
||||
(a / 2.) + (b / 2.)
|
||||
}
|
||||
}
|
||||
|
||||
/// Rounds toward zero and converts to any primitive integer type,
|
||||
/// assuming that the value is finite and fits in that type.
|
||||
///
|
||||
|
@ -720,6 +720,177 @@ impl f16 {
|
||||
self * RADS_PER_DEG
|
||||
}
|
||||
|
||||
/// Returns the maximum of the two numbers, ignoring NaN.
|
||||
///
|
||||
/// If one of the arguments is NaN, then the other argument is returned.
|
||||
/// This follows the IEEE 754-2008 semantics for maxNum, except for handling of signaling NaNs;
|
||||
/// this function handles all NaNs the same way and avoids maxNum's problems with associativity.
|
||||
/// This also matches the behavior of libm’s fmax.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f16)]
|
||||
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
|
||||
///
|
||||
/// let x = 1.0f16;
|
||||
/// let y = 2.0f16;
|
||||
///
|
||||
/// assert_eq!(x.max(y), y);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "f16", issue = "116909")]
|
||||
#[must_use = "this returns the result of the comparison, without modifying either input"]
|
||||
pub fn max(self, other: f16) -> f16 {
|
||||
intrinsics::maxnumf16(self, other)
|
||||
}
|
||||
|
||||
/// Returns the minimum of the two numbers, ignoring NaN.
|
||||
///
|
||||
/// If one of the arguments is NaN, then the other argument is returned.
|
||||
/// This follows the IEEE 754-2008 semantics for minNum, except for handling of signaling NaNs;
|
||||
/// this function handles all NaNs the same way and avoids minNum's problems with associativity.
|
||||
/// This also matches the behavior of libm’s fmin.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f16)]
|
||||
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
|
||||
///
|
||||
/// let x = 1.0f16;
|
||||
/// let y = 2.0f16;
|
||||
///
|
||||
/// assert_eq!(x.min(y), x);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "f16", issue = "116909")]
|
||||
#[must_use = "this returns the result of the comparison, without modifying either input"]
|
||||
pub fn min(self, other: f16) -> f16 {
|
||||
intrinsics::minnumf16(self, other)
|
||||
}
|
||||
|
||||
/// Returns the maximum of the two numbers, propagating NaN.
|
||||
///
|
||||
/// This returns NaN when *either* argument is NaN, as opposed to
|
||||
/// [`f16::max`] which only returns NaN when *both* arguments are NaN.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f16)]
|
||||
/// #![feature(float_minimum_maximum)]
|
||||
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
|
||||
///
|
||||
/// let x = 1.0f16;
|
||||
/// let y = 2.0f16;
|
||||
///
|
||||
/// assert_eq!(x.maximum(y), y);
|
||||
/// assert!(x.maximum(f16::NAN).is_nan());
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the greater
|
||||
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
|
||||
/// Note that this follows the semantics specified in IEEE 754-2019.
|
||||
///
|
||||
/// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
|
||||
/// operand is conserved; see [explanation of NaN as a special value](f16) for more info.
|
||||
#[inline]
|
||||
#[unstable(feature = "f16", issue = "116909")]
|
||||
// #[unstable(feature = "float_minimum_maximum", issue = "91079")]
|
||||
#[must_use = "this returns the result of the comparison, without modifying either input"]
|
||||
pub fn maximum(self, other: f16) -> f16 {
|
||||
if self > other {
|
||||
self
|
||||
} else if other > self {
|
||||
other
|
||||
} else if self == other {
|
||||
if self.is_sign_positive() && other.is_sign_negative() { self } else { other }
|
||||
} else {
|
||||
self + other
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the minimum of the two numbers, propagating NaN.
|
||||
///
|
||||
/// This returns NaN when *either* argument is NaN, as opposed to
|
||||
/// [`f16::min`] which only returns NaN when *both* arguments are NaN.
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f16)]
|
||||
/// #![feature(float_minimum_maximum)]
|
||||
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
|
||||
///
|
||||
/// let x = 1.0f16;
|
||||
/// let y = 2.0f16;
|
||||
///
|
||||
/// assert_eq!(x.minimum(y), x);
|
||||
/// assert!(x.minimum(f16::NAN).is_nan());
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// If one of the arguments is NaN, then NaN is returned. Otherwise this returns the lesser
|
||||
/// of the two numbers. For this operation, -0.0 is considered to be less than +0.0.
|
||||
/// Note that this follows the semantics specified in IEEE 754-2019.
|
||||
///
|
||||
/// Also note that "propagation" of NaNs here doesn't necessarily mean that the bitpattern of a NaN
|
||||
/// operand is conserved; see [explanation of NaN as a special value](f16) for more info.
|
||||
#[inline]
|
||||
#[unstable(feature = "f16", issue = "116909")]
|
||||
// #[unstable(feature = "float_minimum_maximum", issue = "91079")]
|
||||
#[must_use = "this returns the result of the comparison, without modifying either input"]
|
||||
pub fn minimum(self, other: f16) -> f16 {
|
||||
if self < other {
|
||||
self
|
||||
} else if other < self {
|
||||
other
|
||||
} else if self == other {
|
||||
if self.is_sign_negative() && other.is_sign_positive() { self } else { other }
|
||||
} else {
|
||||
// At least one input is NaN. Use `+` to perform NaN propagation and quieting.
|
||||
self + other
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculates the middle point of `self` and `rhs`.
|
||||
///
|
||||
/// This returns NaN when *either* argument is NaN or if a combination of
|
||||
/// +inf and -inf is provided as arguments.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// #![feature(f16)]
|
||||
/// #![feature(num_midpoint)]
|
||||
/// # #[cfg(target_arch = "aarch64")] { // FIXME(f16_F128): rust-lang/rust#123885
|
||||
///
|
||||
/// assert_eq!(1f16.midpoint(4.0), 2.5);
|
||||
/// assert_eq!((-5.5f16).midpoint(8.0), 1.25);
|
||||
/// # }
|
||||
/// ```
|
||||
#[inline]
|
||||
#[unstable(feature = "f16", issue = "116909")]
|
||||
// #[unstable(feature = "num_midpoint", issue = "110840")]
|
||||
pub fn midpoint(self, other: f16) -> f16 {
|
||||
const LO: f16 = f16::MIN_POSITIVE * 2.;
|
||||
const HI: f16 = f16::MAX / 2.;
|
||||
|
||||
let (a, b) = (self, other);
|
||||
let abs_a = a.abs_private();
|
||||
let abs_b = b.abs_private();
|
||||
|
||||
if abs_a <= HI && abs_b <= HI {
|
||||
// Overflow is impossible
|
||||
(a + b) / 2.
|
||||
} else if abs_a < LO {
|
||||
// Not safe to halve `a` (would underflow)
|
||||
a + (b / 2.)
|
||||
} else if abs_b < LO {
|
||||
// Not safe to halve `b` (would underflow)
|
||||
(a / 2.) + b
|
||||
} else {
|
||||
// Safe to halve `a` and `b`
|
||||
(a / 2.) + (b / 2.)
|
||||
}
|
||||
}
|
||||
|
||||
/// Rounds toward zero and converts to any primitive integer type,
|
||||
/// assuming that the value is finite and fits in that type.
|
||||
///
|
||||
|
@ -1070,13 +1070,13 @@ impl f32 {
|
||||
// Overflow is impossible
|
||||
(a + b) / 2.
|
||||
} else if abs_a < LO {
|
||||
// Not safe to halve a
|
||||
// Not safe to halve `a` (would underflow)
|
||||
a + (b / 2.)
|
||||
} else if abs_b < LO {
|
||||
// Not safe to halve b
|
||||
// Not safe to halve `b` (would underflow)
|
||||
(a / 2.) + b
|
||||
} else {
|
||||
// Not safe to halve a and b
|
||||
// Safe to halve `a` and `b`
|
||||
(a / 2.) + (b / 2.)
|
||||
}
|
||||
}
|
||||
|
@ -1064,13 +1064,13 @@ impl f64 {
|
||||
// Overflow is impossible
|
||||
(a + b) / 2.
|
||||
} else if abs_a < LO {
|
||||
// Not safe to halve a
|
||||
// Not safe to halve `a` (would underflow)
|
||||
a + (b / 2.)
|
||||
} else if abs_b < LO {
|
||||
// Not safe to halve b
|
||||
// Not safe to halve `b` (would underflow)
|
||||
(a / 2.) + b
|
||||
} else {
|
||||
// Not safe to halve a and b
|
||||
// Safe to halve `a` and `b`
|
||||
(a / 2.) + (b / 2.)
|
||||
}
|
||||
}
|
||||
|
@ -1244,6 +1244,9 @@ mod prim_f64 {}
|
||||
/// actually implement it. For x86-64 and AArch64, ISA support is not even specified,
|
||||
/// so it will always be a software implementation significantly slower than `f64`.
|
||||
///
|
||||
/// _Note: `f128` support is incomplete. Many platforms will not be able to link math functions. On
|
||||
/// x86 in particular, these functions do link but their results are always incorrect._
|
||||
///
|
||||
/// *[See also the `std::f128::consts` module](crate::f128::consts).*
|
||||
///
|
||||
/// [wikipedia]: https://en.wikipedia.org/wiki/Quadruple-precision_floating-point_format
|
||||
|
@ -85,6 +85,11 @@ fn main() {
|
||||
println!("cargo:rustc-check-cfg=cfg(reliable_f16)");
|
||||
println!("cargo:rustc-check-cfg=cfg(reliable_f128)");
|
||||
|
||||
// This is a step beyond only having the types and basic functions available. Math functions
|
||||
// aren't consistently available or correct.
|
||||
println!("cargo:rustc-check-cfg=cfg(reliable_f16_math)");
|
||||
println!("cargo:rustc-check-cfg=cfg(reliable_f128_math)");
|
||||
|
||||
let has_reliable_f16 = match (target_arch.as_str(), target_os.as_str()) {
|
||||
// Selection failure until recent LLVM <https://github.com/llvm/llvm-project/issues/93894>
|
||||
// FIXME(llvm19): can probably be removed at the version bump
|
||||
@ -130,10 +135,42 @@ fn main() {
|
||||
_ => false,
|
||||
};
|
||||
|
||||
// These are currently empty, but will fill up as some platforms move from completely
|
||||
// unreliable to reliable basics but unreliable math.
|
||||
|
||||
// LLVM is currenlty adding missing routines, <https://github.com/llvm/llvm-project/issues/93566>
|
||||
let has_reliable_f16_math = has_reliable_f16
|
||||
&& match (target_arch.as_str(), target_os.as_str()) {
|
||||
// Currently nothing special. Hooray!
|
||||
// This will change as platforms gain better better support for standard ops but math
|
||||
// lags behind.
|
||||
_ => true,
|
||||
};
|
||||
|
||||
let has_reliable_f128_math = has_reliable_f128
|
||||
&& match (target_arch.as_str(), target_os.as_str()) {
|
||||
// LLVM lowers `fp128` math to `long double` symbols even on platforms where
|
||||
// `long double` is not IEEE binary128. See
|
||||
// <https://github.com/llvm/llvm-project/issues/44744>.
|
||||
//
|
||||
// This rules out anything that doesn't have `long double` = `binary128`; <= 32 bits
|
||||
// (ld is `f64`), anything other than Linux (Windows and MacOS use `f64`), and `x86`
|
||||
// (ld is 80-bit extended precision).
|
||||
("x86_64", _) => false,
|
||||
(_, "linux") if target_pointer_width == 64 => true,
|
||||
_ => false,
|
||||
};
|
||||
|
||||
if has_reliable_f16 {
|
||||
println!("cargo:rustc-cfg=reliable_f16");
|
||||
}
|
||||
if has_reliable_f128 {
|
||||
println!("cargo:rustc-cfg=reliable_f128");
|
||||
}
|
||||
if has_reliable_f16_math {
|
||||
println!("cargo:rustc-cfg=reliable_f16_math");
|
||||
}
|
||||
if has_reliable_f128_math {
|
||||
println!("cargo:rustc-cfg=reliable_f128_math");
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,6 +4,21 @@
|
||||
use crate::f128::consts;
|
||||
use crate::num::{FpCategory as Fp, *};
|
||||
|
||||
// Note these tolerances make sense around zero, but not for more extreme exponents.
|
||||
|
||||
/// For operations that are near exact, usually not involving math of different
|
||||
/// signs.
|
||||
const TOL_PRECISE: f128 = 1e-28;
|
||||
|
||||
/// Default tolerances. Works for values that should be near precise but not exact. Roughly
|
||||
/// the precision carried by `100 * 100`.
|
||||
const TOL: f128 = 1e-12;
|
||||
|
||||
/// Tolerances for math that is allowed to be imprecise, usually due to multiple chained
|
||||
/// operations.
|
||||
#[cfg(reliable_f128_math)]
|
||||
const TOL_IMPR: f128 = 1e-10;
|
||||
|
||||
/// Smallest number
|
||||
const TINY_BITS: u128 = 0x1;
|
||||
|
||||
@ -41,7 +56,33 @@ fn test_num_f128() {
|
||||
test_num(10f128, 2f128);
|
||||
}
|
||||
|
||||
// FIXME(f16_f128): add min and max tests when available
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_min_nan() {
|
||||
assert_eq!(f128::NAN.min(2.0), 2.0);
|
||||
assert_eq!(2.0f128.min(f128::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_max_nan() {
|
||||
assert_eq!(f128::NAN.max(2.0), 2.0);
|
||||
assert_eq!(2.0f128.max(f128::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_minimum() {
|
||||
assert!(f128::NAN.minimum(2.0).is_nan());
|
||||
assert!(2.0f128.minimum(f128::NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_maximum() {
|
||||
assert!(f128::NAN.maximum(2.0).is_nan());
|
||||
assert!(2.0f128.maximum(f128::NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nan() {
|
||||
@ -191,9 +232,100 @@ fn test_classify() {
|
||||
assert_eq!(1e-4932f128.classify(), Fp::Subnormal);
|
||||
}
|
||||
|
||||
// FIXME(f16_f128): add missing math functions when available
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_floor() {
|
||||
assert_approx_eq!(1.0f128.floor(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.3f128.floor(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.5f128.floor(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.7f128.floor(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(0.0f128.floor(), 0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-0.0f128).floor(), -0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.0f128).floor(), -1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.3f128).floor(), -2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.5f128).floor(), -2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.7f128).floor(), -2.0f128, TOL_PRECISE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_ceil() {
|
||||
assert_approx_eq!(1.0f128.ceil(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.3f128.ceil(), 2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.5f128.ceil(), 2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.7f128.ceil(), 2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(0.0f128.ceil(), 0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-0.0f128).ceil(), -0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.0f128).ceil(), -1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.3f128).ceil(), -1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.5f128).ceil(), -1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.7f128).ceil(), -1.0f128, TOL_PRECISE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_round() {
|
||||
assert_approx_eq!(2.5f128.round(), 3.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.0f128.round(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.3f128.round(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.5f128.round(), 2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.7f128.round(), 2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(0.0f128.round(), 0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-0.0f128).round(), -0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.0f128).round(), -1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.3f128).round(), -1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.5f128).round(), -2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.7f128).round(), -2.0f128, TOL_PRECISE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_round_ties_even() {
|
||||
assert_approx_eq!(2.5f128.round_ties_even(), 2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.0f128.round_ties_even(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.3f128.round_ties_even(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.5f128.round_ties_even(), 2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.7f128.round_ties_even(), 2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(0.0f128.round_ties_even(), 0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-0.0f128).round_ties_even(), -0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.0f128).round_ties_even(), -1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.3f128).round_ties_even(), -1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.5f128).round_ties_even(), -2.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.7f128).round_ties_even(), -2.0f128, TOL_PRECISE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_trunc() {
|
||||
assert_approx_eq!(1.0f128.trunc(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.3f128.trunc(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.5f128.trunc(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.7f128.trunc(), 1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(0.0f128.trunc(), 0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-0.0f128).trunc(), -0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.0f128).trunc(), -1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.3f128).trunc(), -1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.5f128).trunc(), -1.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.7f128).trunc(), -1.0f128, TOL_PRECISE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_fract() {
|
||||
assert_approx_eq!(1.0f128.fract(), 0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.3f128.fract(), 0.3f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.5f128.fract(), 0.5f128, TOL_PRECISE);
|
||||
assert_approx_eq!(1.7f128.fract(), 0.7f128, TOL_PRECISE);
|
||||
assert_approx_eq!(0.0f128.fract(), 0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-0.0f128).fract(), -0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.0f128).fract(), -0.0f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.3f128).fract(), -0.3f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.5f128).fract(), -0.5f128, TOL_PRECISE);
|
||||
assert_approx_eq!((-1.7f128).fract(), -0.7f128, TOL_PRECISE);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_abs() {
|
||||
assert_eq!(f128::INFINITY.abs(), f128::INFINITY);
|
||||
assert_eq!(1f128.abs(), 1f128);
|
||||
@ -293,6 +425,24 @@ fn test_next_down() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_mul_add() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert_approx_eq!(12.3f128.mul_add(4.5, 6.7), 62.05, TOL_PRECISE);
|
||||
assert_approx_eq!((-12.3f128).mul_add(-4.5, -6.7), 48.65, TOL_PRECISE);
|
||||
assert_approx_eq!(0.0f128.mul_add(8.9, 1.2), 1.2, TOL_PRECISE);
|
||||
assert_approx_eq!(3.4f128.mul_add(-0.0, 5.6), 5.6, TOL_PRECISE);
|
||||
assert!(nan.mul_add(7.8, 9.0).is_nan());
|
||||
assert_eq!(inf.mul_add(7.8, 9.0), inf);
|
||||
assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
|
||||
assert_eq!(8.9f128.mul_add(inf, 3.2), inf);
|
||||
assert_eq!((-3.2f128).mul_add(2.4, neg_inf), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_recip() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
@ -301,11 +451,161 @@ fn test_recip() {
|
||||
assert_eq!(2.0f128.recip(), 0.5);
|
||||
assert_eq!((-0.4f128).recip(), -2.5);
|
||||
assert_eq!(0.0f128.recip(), inf);
|
||||
assert_approx_eq!(
|
||||
f128::MAX.recip(),
|
||||
8.40525785778023376565669454330438228902076605e-4933,
|
||||
1e-4900
|
||||
);
|
||||
assert!(nan.recip().is_nan());
|
||||
assert_eq!(inf.recip(), 0.0);
|
||||
assert_eq!(neg_inf.recip(), 0.0);
|
||||
}
|
||||
|
||||
// Many math functions allow for less accurate results, so the next tolerance up is used
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_powi() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert_eq!(1.0f128.powi(1), 1.0);
|
||||
assert_approx_eq!((-3.1f128).powi(2), 9.6100000000000005506706202140776519387, TOL);
|
||||
assert_approx_eq!(5.9f128.powi(-2), 0.028727377190462507313100483690639638451, TOL);
|
||||
assert_eq!(8.3f128.powi(0), 1.0);
|
||||
assert!(nan.powi(2).is_nan());
|
||||
assert_eq!(inf.powi(3), inf);
|
||||
assert_eq!(neg_inf.powi(2), inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_powf() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert_eq!(1.0f128.powf(1.0), 1.0);
|
||||
assert_approx_eq!(3.4f128.powf(4.5), 246.40818323761892815995637964326426756, TOL_IMPR);
|
||||
assert_approx_eq!(2.7f128.powf(-3.2), 0.041652009108526178281070304373500889273, TOL_IMPR);
|
||||
assert_approx_eq!((-3.1f128).powf(2.0), 9.6100000000000005506706202140776519387, TOL_IMPR);
|
||||
assert_approx_eq!(5.9f128.powf(-2.0), 0.028727377190462507313100483690639638451, TOL_IMPR);
|
||||
assert_eq!(8.3f128.powf(0.0), 1.0);
|
||||
assert!(nan.powf(2.0).is_nan());
|
||||
assert_eq!(inf.powf(2.0), inf);
|
||||
assert_eq!(neg_inf.powf(3.0), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_sqrt_domain() {
|
||||
assert!(f128::NAN.sqrt().is_nan());
|
||||
assert!(f128::NEG_INFINITY.sqrt().is_nan());
|
||||
assert!((-1.0f128).sqrt().is_nan());
|
||||
assert_eq!((-0.0f128).sqrt(), -0.0);
|
||||
assert_eq!(0.0f128.sqrt(), 0.0);
|
||||
assert_eq!(1.0f128.sqrt(), 1.0);
|
||||
assert_eq!(f128::INFINITY.sqrt(), f128::INFINITY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_exp() {
|
||||
assert_eq!(1.0, 0.0f128.exp());
|
||||
assert_approx_eq!(consts::E, 1.0f128.exp(), TOL);
|
||||
assert_approx_eq!(148.41315910257660342111558004055227962348775, 5.0f128.exp(), TOL);
|
||||
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
let nan: f128 = f128::NAN;
|
||||
assert_eq!(inf, inf.exp());
|
||||
assert_eq!(0.0, neg_inf.exp());
|
||||
assert!(nan.exp().is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_exp2() {
|
||||
assert_eq!(32.0, 5.0f128.exp2());
|
||||
assert_eq!(1.0, 0.0f128.exp2());
|
||||
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
let nan: f128 = f128::NAN;
|
||||
assert_eq!(inf, inf.exp2());
|
||||
assert_eq!(0.0, neg_inf.exp2());
|
||||
assert!(nan.exp2().is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_ln() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert_approx_eq!(1.0f128.exp().ln(), 1.0, TOL);
|
||||
assert!(nan.ln().is_nan());
|
||||
assert_eq!(inf.ln(), inf);
|
||||
assert!(neg_inf.ln().is_nan());
|
||||
assert!((-2.3f128).ln().is_nan());
|
||||
assert_eq!((-0.0f128).ln(), neg_inf);
|
||||
assert_eq!(0.0f128.ln(), neg_inf);
|
||||
assert_approx_eq!(4.0f128.ln(), 1.3862943611198906188344642429163531366, TOL);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_log() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert_eq!(10.0f128.log(10.0), 1.0);
|
||||
assert_approx_eq!(2.3f128.log(3.5), 0.66485771361478710036766645911922010272, TOL);
|
||||
assert_eq!(1.0f128.exp().log(1.0f128.exp()), 1.0);
|
||||
assert!(1.0f128.log(1.0).is_nan());
|
||||
assert!(1.0f128.log(-13.9).is_nan());
|
||||
assert!(nan.log(2.3).is_nan());
|
||||
assert_eq!(inf.log(10.0), inf);
|
||||
assert!(neg_inf.log(8.8).is_nan());
|
||||
assert!((-2.3f128).log(0.1).is_nan());
|
||||
assert_eq!((-0.0f128).log(2.0), neg_inf);
|
||||
assert_eq!(0.0f128.log(7.0), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_log2() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert_approx_eq!(10.0f128.log2(), 3.32192809488736234787031942948939017, TOL);
|
||||
assert_approx_eq!(2.3f128.log2(), 1.2016338611696504130002982471978765921, TOL);
|
||||
assert_approx_eq!(1.0f128.exp().log2(), 1.4426950408889634073599246810018921381, TOL);
|
||||
assert!(nan.log2().is_nan());
|
||||
assert_eq!(inf.log2(), inf);
|
||||
assert!(neg_inf.log2().is_nan());
|
||||
assert!((-2.3f128).log2().is_nan());
|
||||
assert_eq!((-0.0f128).log2(), neg_inf);
|
||||
assert_eq!(0.0f128.log2(), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_log10() {
|
||||
let nan: f128 = f128::NAN;
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert_eq!(10.0f128.log10(), 1.0);
|
||||
assert_approx_eq!(2.3f128.log10(), 0.36172783601759284532595218865859309898, TOL);
|
||||
assert_approx_eq!(1.0f128.exp().log10(), 0.43429448190325182765112891891660508222, TOL);
|
||||
assert_eq!(1.0f128.log10(), 0.0);
|
||||
assert!(nan.log10().is_nan());
|
||||
assert_eq!(inf.log10(), inf);
|
||||
assert!(neg_inf.log10().is_nan());
|
||||
assert!((-2.3f128).log10().is_nan());
|
||||
assert_eq!((-0.0f128).log10(), neg_inf);
|
||||
assert_eq!(0.0f128.log10(), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_degrees() {
|
||||
let pi: f128 = consts::PI;
|
||||
@ -313,8 +613,8 @@ fn test_to_degrees() {
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert_eq!(0.0f128.to_degrees(), 0.0);
|
||||
assert_approx_eq!((-5.8f128).to_degrees(), -332.315521);
|
||||
assert_eq!(pi.to_degrees(), 180.0);
|
||||
assert_approx_eq!((-5.8f128).to_degrees(), -332.31552117587745090765431723855668471, TOL);
|
||||
assert_approx_eq!(pi.to_degrees(), 180.0, TOL);
|
||||
assert!(nan.to_degrees().is_nan());
|
||||
assert_eq!(inf.to_degrees(), inf);
|
||||
assert_eq!(neg_inf.to_degrees(), neg_inf);
|
||||
@ -328,19 +628,122 @@ fn test_to_radians() {
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
assert_eq!(0.0f128.to_radians(), 0.0);
|
||||
assert_approx_eq!(154.6f128.to_radians(), 2.698279);
|
||||
assert_approx_eq!((-332.31f128).to_radians(), -5.799903);
|
||||
assert_approx_eq!(154.6f128.to_radians(), 2.6982790235832334267135442069489767804, TOL);
|
||||
assert_approx_eq!((-332.31f128).to_radians(), -5.7999036373023566567593094812182763013, TOL);
|
||||
// check approx rather than exact because round trip for pi doesn't fall on an exactly
|
||||
// representable value (unlike `f32` and `f64`).
|
||||
assert_approx_eq!(180.0f128.to_radians(), pi);
|
||||
assert_approx_eq!(180.0f128.to_radians(), pi, TOL_PRECISE);
|
||||
assert!(nan.to_radians().is_nan());
|
||||
assert_eq!(inf.to_radians(), inf);
|
||||
assert_eq!(neg_inf.to_radians(), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_asinh() {
|
||||
// Lower accuracy results are allowed, use increased tolerances
|
||||
assert_eq!(0.0f128.asinh(), 0.0f128);
|
||||
assert_eq!((-0.0f128).asinh(), -0.0f128);
|
||||
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
let nan: f128 = f128::NAN;
|
||||
assert_eq!(inf.asinh(), inf);
|
||||
assert_eq!(neg_inf.asinh(), neg_inf);
|
||||
assert!(nan.asinh().is_nan());
|
||||
assert!((-0.0f128).asinh().is_sign_negative());
|
||||
|
||||
// issue 63271
|
||||
assert_approx_eq!(2.0f128.asinh(), 1.443635475178810342493276740273105f128, TOL_IMPR);
|
||||
assert_approx_eq!((-2.0f128).asinh(), -1.443635475178810342493276740273105f128, TOL_IMPR);
|
||||
// regression test for the catastrophic cancellation fixed in 72486
|
||||
assert_approx_eq!(
|
||||
(-67452098.07139316f128).asinh(),
|
||||
-18.720075426274544393985484294000831757220,
|
||||
TOL_IMPR
|
||||
);
|
||||
|
||||
// test for low accuracy from issue 104548
|
||||
assert_approx_eq!(60.0f128, 60.0f128.sinh().asinh(), TOL_IMPR);
|
||||
// mul needed for approximate comparison to be meaningful
|
||||
assert_approx_eq!(1.0f128, 1e-15f128.sinh().asinh() * 1e15f128, TOL_IMPR);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_acosh() {
|
||||
assert_eq!(1.0f128.acosh(), 0.0f128);
|
||||
assert!(0.999f128.acosh().is_nan());
|
||||
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
let nan: f128 = f128::NAN;
|
||||
assert_eq!(inf.acosh(), inf);
|
||||
assert!(neg_inf.acosh().is_nan());
|
||||
assert!(nan.acosh().is_nan());
|
||||
assert_approx_eq!(2.0f128.acosh(), 1.31695789692481670862504634730796844f128, TOL_IMPR);
|
||||
assert_approx_eq!(3.0f128.acosh(), 1.76274717403908605046521864995958461f128, TOL_IMPR);
|
||||
|
||||
// test for low accuracy from issue 104548
|
||||
assert_approx_eq!(60.0f128, 60.0f128.cosh().acosh(), TOL_IMPR);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_atanh() {
|
||||
assert_eq!(0.0f128.atanh(), 0.0f128);
|
||||
assert_eq!((-0.0f128).atanh(), -0.0f128);
|
||||
|
||||
let inf: f128 = f128::INFINITY;
|
||||
let neg_inf: f128 = f128::NEG_INFINITY;
|
||||
let nan: f128 = f128::NAN;
|
||||
assert_eq!(1.0f128.atanh(), inf);
|
||||
assert_eq!((-1.0f128).atanh(), neg_inf);
|
||||
assert!(2f128.atanh().atanh().is_nan());
|
||||
assert!((-2f128).atanh().atanh().is_nan());
|
||||
assert!(inf.atanh().is_nan());
|
||||
assert!(neg_inf.atanh().is_nan());
|
||||
assert!(nan.atanh().is_nan());
|
||||
assert_approx_eq!(0.5f128.atanh(), 0.54930614433405484569762261846126285f128, TOL_IMPR);
|
||||
assert_approx_eq!((-0.5f128).atanh(), -0.54930614433405484569762261846126285f128, TOL_IMPR);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_gamma() {
|
||||
// precision can differ among platforms
|
||||
assert_approx_eq!(1.0f128.gamma(), 1.0f128, TOL_IMPR);
|
||||
assert_approx_eq!(2.0f128.gamma(), 1.0f128, TOL_IMPR);
|
||||
assert_approx_eq!(3.0f128.gamma(), 2.0f128, TOL_IMPR);
|
||||
assert_approx_eq!(4.0f128.gamma(), 6.0f128, TOL_IMPR);
|
||||
assert_approx_eq!(5.0f128.gamma(), 24.0f128, TOL_IMPR);
|
||||
assert_approx_eq!(0.5f128.gamma(), consts::PI.sqrt(), TOL_IMPR);
|
||||
assert_approx_eq!((-0.5f128).gamma(), -2.0 * consts::PI.sqrt(), TOL_IMPR);
|
||||
assert_eq!(0.0f128.gamma(), f128::INFINITY);
|
||||
assert_eq!((-0.0f128).gamma(), f128::NEG_INFINITY);
|
||||
assert!((-1.0f128).gamma().is_nan());
|
||||
assert!((-2.0f128).gamma().is_nan());
|
||||
assert!(f128::NAN.gamma().is_nan());
|
||||
assert!(f128::NEG_INFINITY.gamma().is_nan());
|
||||
assert_eq!(f128::INFINITY.gamma(), f128::INFINITY);
|
||||
assert_eq!(1760.9f128.gamma(), f128::INFINITY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f128_math)]
|
||||
fn test_ln_gamma() {
|
||||
assert_approx_eq!(1.0f128.ln_gamma().0, 0.0f128, TOL_IMPR);
|
||||
assert_eq!(1.0f128.ln_gamma().1, 1);
|
||||
assert_approx_eq!(2.0f128.ln_gamma().0, 0.0f128, TOL_IMPR);
|
||||
assert_eq!(2.0f128.ln_gamma().1, 1);
|
||||
assert_approx_eq!(3.0f128.ln_gamma().0, 2.0f128.ln(), TOL_IMPR);
|
||||
assert_eq!(3.0f128.ln_gamma().1, 1);
|
||||
assert_approx_eq!((-0.5f128).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_IMPR);
|
||||
assert_eq!((-0.5f128).ln_gamma().1, -1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_real_consts() {
|
||||
// FIXME(f16_f128): add math tests when available
|
||||
use super::consts;
|
||||
|
||||
let pi: f128 = consts::PI;
|
||||
@ -351,29 +754,34 @@ fn test_real_consts() {
|
||||
let frac_pi_8: f128 = consts::FRAC_PI_8;
|
||||
let frac_1_pi: f128 = consts::FRAC_1_PI;
|
||||
let frac_2_pi: f128 = consts::FRAC_2_PI;
|
||||
// let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI;
|
||||
// let sqrt2: f128 = consts::SQRT_2;
|
||||
// let frac_1_sqrt2: f128 = consts::FRAC_1_SQRT_2;
|
||||
// let e: f128 = consts::E;
|
||||
// let log2_e: f128 = consts::LOG2_E;
|
||||
// let log10_e: f128 = consts::LOG10_E;
|
||||
// let ln_2: f128 = consts::LN_2;
|
||||
// let ln_10: f128 = consts::LN_10;
|
||||
|
||||
assert_approx_eq!(frac_pi_2, pi / 2f128);
|
||||
assert_approx_eq!(frac_pi_3, pi / 3f128);
|
||||
assert_approx_eq!(frac_pi_4, pi / 4f128);
|
||||
assert_approx_eq!(frac_pi_6, pi / 6f128);
|
||||
assert_approx_eq!(frac_pi_8, pi / 8f128);
|
||||
assert_approx_eq!(frac_1_pi, 1f128 / pi);
|
||||
assert_approx_eq!(frac_2_pi, 2f128 / pi);
|
||||
// assert_approx_eq!(frac_2_sqrtpi, 2f128 / pi.sqrt());
|
||||
// assert_approx_eq!(sqrt2, 2f128.sqrt());
|
||||
// assert_approx_eq!(frac_1_sqrt2, 1f128 / 2f128.sqrt());
|
||||
// assert_approx_eq!(log2_e, e.log2());
|
||||
// assert_approx_eq!(log10_e, e.log10());
|
||||
// assert_approx_eq!(ln_2, 2f128.ln());
|
||||
// assert_approx_eq!(ln_10, 10f128.ln());
|
||||
assert_approx_eq!(frac_pi_2, pi / 2f128, TOL_PRECISE);
|
||||
assert_approx_eq!(frac_pi_3, pi / 3f128, TOL_PRECISE);
|
||||
assert_approx_eq!(frac_pi_4, pi / 4f128, TOL_PRECISE);
|
||||
assert_approx_eq!(frac_pi_6, pi / 6f128, TOL_PRECISE);
|
||||
assert_approx_eq!(frac_pi_8, pi / 8f128, TOL_PRECISE);
|
||||
assert_approx_eq!(frac_1_pi, 1f128 / pi, TOL_PRECISE);
|
||||
assert_approx_eq!(frac_2_pi, 2f128 / pi, TOL_PRECISE);
|
||||
|
||||
#[cfg(reliable_f128_math)]
|
||||
{
|
||||
let frac_2_sqrtpi: f128 = consts::FRAC_2_SQRT_PI;
|
||||
let sqrt2: f128 = consts::SQRT_2;
|
||||
let frac_1_sqrt2: f128 = consts::FRAC_1_SQRT_2;
|
||||
let e: f128 = consts::E;
|
||||
let log2_e: f128 = consts::LOG2_E;
|
||||
let log10_e: f128 = consts::LOG10_E;
|
||||
let ln_2: f128 = consts::LN_2;
|
||||
let ln_10: f128 = consts::LN_10;
|
||||
|
||||
assert_approx_eq!(frac_2_sqrtpi, 2f128 / pi.sqrt(), TOL_PRECISE);
|
||||
assert_approx_eq!(sqrt2, 2f128.sqrt(), TOL_PRECISE);
|
||||
assert_approx_eq!(frac_1_sqrt2, 1f128 / 2f128.sqrt(), TOL_PRECISE);
|
||||
assert_approx_eq!(log2_e, e.log2(), TOL_PRECISE);
|
||||
assert_approx_eq!(log10_e, e.log10(), TOL_PRECISE);
|
||||
assert_approx_eq!(ln_2, 2f128.ln(), TOL_PRECISE);
|
||||
assert_approx_eq!(ln_10, 10f128.ln(), TOL_PRECISE);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -382,10 +790,10 @@ fn test_float_bits_conv() {
|
||||
assert_eq!((12.5f128).to_bits(), 0x40029000000000000000000000000000);
|
||||
assert_eq!((1337f128).to_bits(), 0x40094e40000000000000000000000000);
|
||||
assert_eq!((-14.25f128).to_bits(), 0xc002c800000000000000000000000000);
|
||||
assert_approx_eq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0);
|
||||
assert_approx_eq!(f128::from_bits(0x40029000000000000000000000000000), 12.5);
|
||||
assert_approx_eq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0);
|
||||
assert_approx_eq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25);
|
||||
assert_approx_eq!(f128::from_bits(0x3fff0000000000000000000000000000), 1.0, TOL_PRECISE);
|
||||
assert_approx_eq!(f128::from_bits(0x40029000000000000000000000000000), 12.5, TOL_PRECISE);
|
||||
assert_approx_eq!(f128::from_bits(0x40094e40000000000000000000000000), 1337.0, TOL_PRECISE);
|
||||
assert_approx_eq!(f128::from_bits(0xc002c800000000000000000000000000), -14.25, TOL_PRECISE);
|
||||
|
||||
// Check that NaNs roundtrip their bits regardless of signaling-ness
|
||||
// 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -4,11 +4,21 @@
|
||||
use crate::f16::consts;
|
||||
use crate::num::{FpCategory as Fp, *};
|
||||
|
||||
// We run out of precision pretty quickly with f16
|
||||
// const F16_APPROX_L1: f16 = 0.001;
|
||||
const F16_APPROX_L2: f16 = 0.01;
|
||||
// const F16_APPROX_L3: f16 = 0.1;
|
||||
const F16_APPROX_L4: f16 = 0.5;
|
||||
/// Tolerance for results on the order of 10.0e-2;
|
||||
#[cfg(reliable_f16_math)]
|
||||
const TOL_N2: f16 = 0.0001;
|
||||
|
||||
/// Tolerance for results on the order of 10.0e+0
|
||||
#[cfg(reliable_f16_math)]
|
||||
const TOL_0: f16 = 0.01;
|
||||
|
||||
/// Tolerance for results on the order of 10.0e+2
|
||||
#[cfg(reliable_f16_math)]
|
||||
const TOL_P2: f16 = 0.5;
|
||||
|
||||
/// Tolerance for results on the order of 10.0e+4
|
||||
#[cfg(reliable_f16_math)]
|
||||
const TOL_P4: f16 = 10.0;
|
||||
|
||||
/// Smallest number
|
||||
const TINY_BITS: u16 = 0x1;
|
||||
@ -47,7 +57,33 @@ fn test_num_f16() {
|
||||
test_num(10f16, 2f16);
|
||||
}
|
||||
|
||||
// FIXME(f16_f128): add min and max tests when available
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_min_nan() {
|
||||
assert_eq!(f16::NAN.min(2.0), 2.0);
|
||||
assert_eq!(2.0f16.min(f16::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_max_nan() {
|
||||
assert_eq!(f16::NAN.max(2.0), 2.0);
|
||||
assert_eq!(2.0f16.max(f16::NAN), 2.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_minimum() {
|
||||
assert!(f16::NAN.minimum(2.0).is_nan());
|
||||
assert!(2.0f16.minimum(f16::NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_maximum() {
|
||||
assert!(f16::NAN.maximum(2.0).is_nan());
|
||||
assert!(2.0f16.maximum(f16::NAN).is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_nan() {
|
||||
@ -197,9 +233,100 @@ fn test_classify() {
|
||||
assert_eq!(1e-5f16.classify(), Fp::Subnormal);
|
||||
}
|
||||
|
||||
// FIXME(f16_f128): add missing math functions when available
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_floor() {
|
||||
assert_approx_eq!(1.0f16.floor(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(1.3f16.floor(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(1.5f16.floor(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(1.7f16.floor(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(0.0f16.floor(), 0.0f16, TOL_0);
|
||||
assert_approx_eq!((-0.0f16).floor(), -0.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.0f16).floor(), -1.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.3f16).floor(), -2.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.5f16).floor(), -2.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.7f16).floor(), -2.0f16, TOL_0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_ceil() {
|
||||
assert_approx_eq!(1.0f16.ceil(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(1.3f16.ceil(), 2.0f16, TOL_0);
|
||||
assert_approx_eq!(1.5f16.ceil(), 2.0f16, TOL_0);
|
||||
assert_approx_eq!(1.7f16.ceil(), 2.0f16, TOL_0);
|
||||
assert_approx_eq!(0.0f16.ceil(), 0.0f16, TOL_0);
|
||||
assert_approx_eq!((-0.0f16).ceil(), -0.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.0f16).ceil(), -1.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.3f16).ceil(), -1.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.5f16).ceil(), -1.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.7f16).ceil(), -1.0f16, TOL_0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_round() {
|
||||
assert_approx_eq!(2.5f16.round(), 3.0f16, TOL_0);
|
||||
assert_approx_eq!(1.0f16.round(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(1.3f16.round(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(1.5f16.round(), 2.0f16, TOL_0);
|
||||
assert_approx_eq!(1.7f16.round(), 2.0f16, TOL_0);
|
||||
assert_approx_eq!(0.0f16.round(), 0.0f16, TOL_0);
|
||||
assert_approx_eq!((-0.0f16).round(), -0.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.0f16).round(), -1.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.3f16).round(), -1.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.5f16).round(), -2.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.7f16).round(), -2.0f16, TOL_0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_round_ties_even() {
|
||||
assert_approx_eq!(2.5f16.round_ties_even(), 2.0f16, TOL_0);
|
||||
assert_approx_eq!(1.0f16.round_ties_even(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(1.3f16.round_ties_even(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(1.5f16.round_ties_even(), 2.0f16, TOL_0);
|
||||
assert_approx_eq!(1.7f16.round_ties_even(), 2.0f16, TOL_0);
|
||||
assert_approx_eq!(0.0f16.round_ties_even(), 0.0f16, TOL_0);
|
||||
assert_approx_eq!((-0.0f16).round_ties_even(), -0.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.0f16).round_ties_even(), -1.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.3f16).round_ties_even(), -1.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.5f16).round_ties_even(), -2.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.7f16).round_ties_even(), -2.0f16, TOL_0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_trunc() {
|
||||
assert_approx_eq!(1.0f16.trunc(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(1.3f16.trunc(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(1.5f16.trunc(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(1.7f16.trunc(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(0.0f16.trunc(), 0.0f16, TOL_0);
|
||||
assert_approx_eq!((-0.0f16).trunc(), -0.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.0f16).trunc(), -1.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.3f16).trunc(), -1.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.5f16).trunc(), -1.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.7f16).trunc(), -1.0f16, TOL_0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_fract() {
|
||||
assert_approx_eq!(1.0f16.fract(), 0.0f16, TOL_0);
|
||||
assert_approx_eq!(1.3f16.fract(), 0.3f16, TOL_0);
|
||||
assert_approx_eq!(1.5f16.fract(), 0.5f16, TOL_0);
|
||||
assert_approx_eq!(1.7f16.fract(), 0.7f16, TOL_0);
|
||||
assert_approx_eq!(0.0f16.fract(), 0.0f16, TOL_0);
|
||||
assert_approx_eq!((-0.0f16).fract(), -0.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.0f16).fract(), -0.0f16, TOL_0);
|
||||
assert_approx_eq!((-1.3f16).fract(), -0.3f16, TOL_0);
|
||||
assert_approx_eq!((-1.5f16).fract(), -0.5f16, TOL_0);
|
||||
assert_approx_eq!((-1.7f16).fract(), -0.7f16, TOL_0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_abs() {
|
||||
assert_eq!(f16::INFINITY.abs(), f16::INFINITY);
|
||||
assert_eq!(1f16.abs(), 1f16);
|
||||
@ -299,6 +426,24 @@ fn test_next_down() {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_mul_add() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert_approx_eq!(12.3f16.mul_add(4.5, 6.7), 62.05, TOL_P2);
|
||||
assert_approx_eq!((-12.3f16).mul_add(-4.5, -6.7), 48.65, TOL_P2);
|
||||
assert_approx_eq!(0.0f16.mul_add(8.9, 1.2), 1.2, TOL_0);
|
||||
assert_approx_eq!(3.4f16.mul_add(-0.0, 5.6), 5.6, TOL_0);
|
||||
assert!(nan.mul_add(7.8, 9.0).is_nan());
|
||||
assert_eq!(inf.mul_add(7.8, 9.0), inf);
|
||||
assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf);
|
||||
assert_eq!(8.9f16.mul_add(inf, 3.2), inf);
|
||||
assert_eq!((-3.2f16).mul_add(2.4, neg_inf), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_recip() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
@ -307,11 +452,157 @@ fn test_recip() {
|
||||
assert_eq!(2.0f16.recip(), 0.5);
|
||||
assert_eq!((-0.4f16).recip(), -2.5);
|
||||
assert_eq!(0.0f16.recip(), inf);
|
||||
assert_approx_eq!(f16::MAX.recip(), 1.526624e-5f16, 1e-4);
|
||||
assert!(nan.recip().is_nan());
|
||||
assert_eq!(inf.recip(), 0.0);
|
||||
assert_eq!(neg_inf.recip(), 0.0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_powi() {
|
||||
// FIXME(llvm19): LLVM misoptimizes `powi.f16`
|
||||
// <https://github.com/llvm/llvm-project/issues/98665>
|
||||
// let nan: f16 = f16::NAN;
|
||||
// let inf: f16 = f16::INFINITY;
|
||||
// let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
// assert_eq!(1.0f16.powi(1), 1.0);
|
||||
// assert_approx_eq!((-3.1f16).powi(2), 9.61, TOL_0);
|
||||
// assert_approx_eq!(5.9f16.powi(-2), 0.028727, TOL_N2);
|
||||
// assert_eq!(8.3f16.powi(0), 1.0);
|
||||
// assert!(nan.powi(2).is_nan());
|
||||
// assert_eq!(inf.powi(3), inf);
|
||||
// assert_eq!(neg_inf.powi(2), inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_powf() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert_eq!(1.0f16.powf(1.0), 1.0);
|
||||
assert_approx_eq!(3.4f16.powf(4.5), 246.408183, TOL_P2);
|
||||
assert_approx_eq!(2.7f16.powf(-3.2), 0.041652, TOL_N2);
|
||||
assert_approx_eq!((-3.1f16).powf(2.0), 9.61, TOL_P2);
|
||||
assert_approx_eq!(5.9f16.powf(-2.0), 0.028727, TOL_N2);
|
||||
assert_eq!(8.3f16.powf(0.0), 1.0);
|
||||
assert!(nan.powf(2.0).is_nan());
|
||||
assert_eq!(inf.powf(2.0), inf);
|
||||
assert_eq!(neg_inf.powf(3.0), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_sqrt_domain() {
|
||||
assert!(f16::NAN.sqrt().is_nan());
|
||||
assert!(f16::NEG_INFINITY.sqrt().is_nan());
|
||||
assert!((-1.0f16).sqrt().is_nan());
|
||||
assert_eq!((-0.0f16).sqrt(), -0.0);
|
||||
assert_eq!(0.0f16.sqrt(), 0.0);
|
||||
assert_eq!(1.0f16.sqrt(), 1.0);
|
||||
assert_eq!(f16::INFINITY.sqrt(), f16::INFINITY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_exp() {
|
||||
assert_eq!(1.0, 0.0f16.exp());
|
||||
assert_approx_eq!(2.718282, 1.0f16.exp(), TOL_0);
|
||||
assert_approx_eq!(148.413159, 5.0f16.exp(), TOL_0);
|
||||
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
let nan: f16 = f16::NAN;
|
||||
assert_eq!(inf, inf.exp());
|
||||
assert_eq!(0.0, neg_inf.exp());
|
||||
assert!(nan.exp().is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_exp2() {
|
||||
assert_eq!(32.0, 5.0f16.exp2());
|
||||
assert_eq!(1.0, 0.0f16.exp2());
|
||||
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
let nan: f16 = f16::NAN;
|
||||
assert_eq!(inf, inf.exp2());
|
||||
assert_eq!(0.0, neg_inf.exp2());
|
||||
assert!(nan.exp2().is_nan());
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_ln() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert_approx_eq!(1.0f16.exp().ln(), 1.0, TOL_0);
|
||||
assert!(nan.ln().is_nan());
|
||||
assert_eq!(inf.ln(), inf);
|
||||
assert!(neg_inf.ln().is_nan());
|
||||
assert!((-2.3f16).ln().is_nan());
|
||||
assert_eq!((-0.0f16).ln(), neg_inf);
|
||||
assert_eq!(0.0f16.ln(), neg_inf);
|
||||
assert_approx_eq!(4.0f16.ln(), 1.386294, TOL_0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_log() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert_eq!(10.0f16.log(10.0), 1.0);
|
||||
assert_approx_eq!(2.3f16.log(3.5), 0.664858, TOL_0);
|
||||
assert_eq!(1.0f16.exp().log(1.0f16.exp()), 1.0);
|
||||
assert!(1.0f16.log(1.0).is_nan());
|
||||
assert!(1.0f16.log(-13.9).is_nan());
|
||||
assert!(nan.log(2.3).is_nan());
|
||||
assert_eq!(inf.log(10.0), inf);
|
||||
assert!(neg_inf.log(8.8).is_nan());
|
||||
assert!((-2.3f16).log(0.1).is_nan());
|
||||
assert_eq!((-0.0f16).log(2.0), neg_inf);
|
||||
assert_eq!(0.0f16.log(7.0), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_log2() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert_approx_eq!(10.0f16.log2(), 3.321928, TOL_0);
|
||||
assert_approx_eq!(2.3f16.log2(), 1.201634, TOL_0);
|
||||
assert_approx_eq!(1.0f16.exp().log2(), 1.442695, TOL_0);
|
||||
assert!(nan.log2().is_nan());
|
||||
assert_eq!(inf.log2(), inf);
|
||||
assert!(neg_inf.log2().is_nan());
|
||||
assert!((-2.3f16).log2().is_nan());
|
||||
assert_eq!((-0.0f16).log2(), neg_inf);
|
||||
assert_eq!(0.0f16.log2(), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_log10() {
|
||||
let nan: f16 = f16::NAN;
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert_eq!(10.0f16.log10(), 1.0);
|
||||
assert_approx_eq!(2.3f16.log10(), 0.361728, TOL_0);
|
||||
assert_approx_eq!(1.0f16.exp().log10(), 0.434294, TOL_0);
|
||||
assert_eq!(1.0f16.log10(), 0.0);
|
||||
assert!(nan.log10().is_nan());
|
||||
assert_eq!(inf.log10(), inf);
|
||||
assert!(neg_inf.log10().is_nan());
|
||||
assert!((-2.3f16).log10().is_nan());
|
||||
assert_eq!((-0.0f16).log10(), neg_inf);
|
||||
assert_eq!(0.0f16.log10(), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_to_degrees() {
|
||||
let pi: f16 = consts::PI;
|
||||
@ -319,8 +610,8 @@ fn test_to_degrees() {
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert_eq!(0.0f16.to_degrees(), 0.0);
|
||||
assert_approx_eq!((-5.8f16).to_degrees(), -332.315521);
|
||||
assert_approx_eq!(pi.to_degrees(), 180.0, F16_APPROX_L4);
|
||||
assert_approx_eq!((-5.8f16).to_degrees(), -332.315521, TOL_P2);
|
||||
assert_approx_eq!(pi.to_degrees(), 180.0, TOL_P2);
|
||||
assert!(nan.to_degrees().is_nan());
|
||||
assert_eq!(inf.to_degrees(), inf);
|
||||
assert_eq!(neg_inf.to_degrees(), neg_inf);
|
||||
@ -334,14 +625,112 @@ fn test_to_radians() {
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
assert_eq!(0.0f16.to_radians(), 0.0);
|
||||
assert_approx_eq!(154.6f16.to_radians(), 2.698279);
|
||||
assert_approx_eq!((-332.31f16).to_radians(), -5.799903);
|
||||
assert_approx_eq!(180.0f16.to_radians(), pi, F16_APPROX_L2);
|
||||
assert_approx_eq!(154.6f16.to_radians(), 2.698279, TOL_0);
|
||||
assert_approx_eq!((-332.31f16).to_radians(), -5.799903, TOL_0);
|
||||
assert_approx_eq!(180.0f16.to_radians(), pi, TOL_0);
|
||||
assert!(nan.to_radians().is_nan());
|
||||
assert_eq!(inf.to_radians(), inf);
|
||||
assert_eq!(neg_inf.to_radians(), neg_inf);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_asinh() {
|
||||
assert_eq!(0.0f16.asinh(), 0.0f16);
|
||||
assert_eq!((-0.0f16).asinh(), -0.0f16);
|
||||
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
let nan: f16 = f16::NAN;
|
||||
assert_eq!(inf.asinh(), inf);
|
||||
assert_eq!(neg_inf.asinh(), neg_inf);
|
||||
assert!(nan.asinh().is_nan());
|
||||
assert!((-0.0f16).asinh().is_sign_negative());
|
||||
// issue 63271
|
||||
assert_approx_eq!(2.0f16.asinh(), 1.443635475178810342493276740273105f16, TOL_0);
|
||||
assert_approx_eq!((-2.0f16).asinh(), -1.443635475178810342493276740273105f16, TOL_0);
|
||||
// regression test for the catastrophic cancellation fixed in 72486
|
||||
assert_approx_eq!((-200.0f16).asinh(), -5.991470797049389, TOL_0);
|
||||
|
||||
// test for low accuracy from issue 104548
|
||||
assert_approx_eq!(10.0f16, 10.0f16.sinh().asinh(), TOL_0);
|
||||
// mul needed for approximate comparison to be meaningful
|
||||
assert_approx_eq!(1.0f16, 1e-3f16.sinh().asinh() * 1e3f16, TOL_0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_acosh() {
|
||||
assert_eq!(1.0f16.acosh(), 0.0f16);
|
||||
assert!(0.999f16.acosh().is_nan());
|
||||
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
let nan: f16 = f16::NAN;
|
||||
assert_eq!(inf.acosh(), inf);
|
||||
assert!(neg_inf.acosh().is_nan());
|
||||
assert!(nan.acosh().is_nan());
|
||||
assert_approx_eq!(2.0f16.acosh(), 1.31695789692481670862504634730796844f16, TOL_0);
|
||||
assert_approx_eq!(3.0f16.acosh(), 1.76274717403908605046521864995958461f16, TOL_0);
|
||||
|
||||
// test for low accuracy from issue 104548
|
||||
assert_approx_eq!(10.0f16, 10.0f16.cosh().acosh(), TOL_P2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_atanh() {
|
||||
assert_eq!(0.0f16.atanh(), 0.0f16);
|
||||
assert_eq!((-0.0f16).atanh(), -0.0f16);
|
||||
|
||||
let inf: f16 = f16::INFINITY;
|
||||
let neg_inf: f16 = f16::NEG_INFINITY;
|
||||
let nan: f16 = f16::NAN;
|
||||
assert_eq!(1.0f16.atanh(), inf);
|
||||
assert_eq!((-1.0f16).atanh(), neg_inf);
|
||||
assert!(2f16.atanh().atanh().is_nan());
|
||||
assert!((-2f16).atanh().atanh().is_nan());
|
||||
assert!(inf.atanh().is_nan());
|
||||
assert!(neg_inf.atanh().is_nan());
|
||||
assert!(nan.atanh().is_nan());
|
||||
assert_approx_eq!(0.5f16.atanh(), 0.54930614433405484569762261846126285f16, TOL_0);
|
||||
assert_approx_eq!((-0.5f16).atanh(), -0.54930614433405484569762261846126285f16, TOL_0);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_gamma() {
|
||||
// precision can differ among platforms
|
||||
assert_approx_eq!(1.0f16.gamma(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(2.0f16.gamma(), 1.0f16, TOL_0);
|
||||
assert_approx_eq!(3.0f16.gamma(), 2.0f16, TOL_0);
|
||||
assert_approx_eq!(4.0f16.gamma(), 6.0f16, TOL_0);
|
||||
assert_approx_eq!(5.0f16.gamma(), 24.0f16, TOL_0);
|
||||
assert_approx_eq!(0.5f16.gamma(), consts::PI.sqrt(), TOL_0);
|
||||
assert_approx_eq!((-0.5f16).gamma(), -2.0 * consts::PI.sqrt(), TOL_0);
|
||||
assert_eq!(0.0f16.gamma(), f16::INFINITY);
|
||||
assert_eq!((-0.0f16).gamma(), f16::NEG_INFINITY);
|
||||
assert!((-1.0f16).gamma().is_nan());
|
||||
assert!((-2.0f16).gamma().is_nan());
|
||||
assert!(f16::NAN.gamma().is_nan());
|
||||
assert!(f16::NEG_INFINITY.gamma().is_nan());
|
||||
assert_eq!(f16::INFINITY.gamma(), f16::INFINITY);
|
||||
assert_eq!(171.71f16.gamma(), f16::INFINITY);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(reliable_f16_math)]
|
||||
fn test_ln_gamma() {
|
||||
assert_approx_eq!(1.0f16.ln_gamma().0, 0.0f16, TOL_0);
|
||||
assert_eq!(1.0f16.ln_gamma().1, 1);
|
||||
assert_approx_eq!(2.0f16.ln_gamma().0, 0.0f16, TOL_0);
|
||||
assert_eq!(2.0f16.ln_gamma().1, 1);
|
||||
assert_approx_eq!(3.0f16.ln_gamma().0, 2.0f16.ln(), TOL_0);
|
||||
assert_eq!(3.0f16.ln_gamma().1, 1);
|
||||
assert_approx_eq!((-0.5f16).ln_gamma().0, (2.0 * consts::PI.sqrt()).ln(), TOL_0);
|
||||
assert_eq!((-0.5f16).ln_gamma().1, -1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_real_consts() {
|
||||
// FIXME(f16_f128): add math tests when available
|
||||
@ -355,29 +744,34 @@ fn test_real_consts() {
|
||||
let frac_pi_8: f16 = consts::FRAC_PI_8;
|
||||
let frac_1_pi: f16 = consts::FRAC_1_PI;
|
||||
let frac_2_pi: f16 = consts::FRAC_2_PI;
|
||||
// let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI;
|
||||
// let sqrt2: f16 = consts::SQRT_2;
|
||||
// let frac_1_sqrt2: f16 = consts::FRAC_1_SQRT_2;
|
||||
// let e: f16 = consts::E;
|
||||
// let log2_e: f16 = consts::LOG2_E;
|
||||
// let log10_e: f16 = consts::LOG10_E;
|
||||
// let ln_2: f16 = consts::LN_2;
|
||||
// let ln_10: f16 = consts::LN_10;
|
||||
|
||||
assert_approx_eq!(frac_pi_2, pi / 2f16);
|
||||
assert_approx_eq!(frac_pi_3, pi / 3f16);
|
||||
assert_approx_eq!(frac_pi_4, pi / 4f16);
|
||||
assert_approx_eq!(frac_pi_6, pi / 6f16);
|
||||
assert_approx_eq!(frac_pi_8, pi / 8f16);
|
||||
assert_approx_eq!(frac_1_pi, 1f16 / pi);
|
||||
assert_approx_eq!(frac_2_pi, 2f16 / pi);
|
||||
// assert_approx_eq!(frac_2_sqrtpi, 2f16 / pi.sqrt());
|
||||
// assert_approx_eq!(sqrt2, 2f16.sqrt());
|
||||
// assert_approx_eq!(frac_1_sqrt2, 1f16 / 2f16.sqrt());
|
||||
// assert_approx_eq!(log2_e, e.log2());
|
||||
// assert_approx_eq!(log10_e, e.log10());
|
||||
// assert_approx_eq!(ln_2, 2f16.ln());
|
||||
// assert_approx_eq!(ln_10, 10f16.ln());
|
||||
assert_approx_eq!(frac_pi_2, pi / 2f16, TOL_0);
|
||||
assert_approx_eq!(frac_pi_3, pi / 3f16, TOL_0);
|
||||
assert_approx_eq!(frac_pi_4, pi / 4f16, TOL_0);
|
||||
assert_approx_eq!(frac_pi_6, pi / 6f16, TOL_0);
|
||||
assert_approx_eq!(frac_pi_8, pi / 8f16, TOL_0);
|
||||
assert_approx_eq!(frac_1_pi, 1f16 / pi, TOL_0);
|
||||
assert_approx_eq!(frac_2_pi, 2f16 / pi, TOL_0);
|
||||
|
||||
#[cfg(reliable_f16_math)]
|
||||
{
|
||||
let frac_2_sqrtpi: f16 = consts::FRAC_2_SQRT_PI;
|
||||
let sqrt2: f16 = consts::SQRT_2;
|
||||
let frac_1_sqrt2: f16 = consts::FRAC_1_SQRT_2;
|
||||
let e: f16 = consts::E;
|
||||
let log2_e: f16 = consts::LOG2_E;
|
||||
let log10_e: f16 = consts::LOG10_E;
|
||||
let ln_2: f16 = consts::LN_2;
|
||||
let ln_10: f16 = consts::LN_10;
|
||||
|
||||
assert_approx_eq!(frac_2_sqrtpi, 2f16 / pi.sqrt(), TOL_0);
|
||||
assert_approx_eq!(sqrt2, 2f16.sqrt(), TOL_0);
|
||||
assert_approx_eq!(frac_1_sqrt2, 1f16 / 2f16.sqrt(), TOL_0);
|
||||
assert_approx_eq!(log2_e, e.log2(), TOL_0);
|
||||
assert_approx_eq!(log10_e, e.log10(), TOL_0);
|
||||
assert_approx_eq!(ln_2, 2f16.ln(), TOL_0);
|
||||
assert_approx_eq!(ln_10, 10f16.ln(), TOL_0);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -386,10 +780,10 @@ fn test_float_bits_conv() {
|
||||
assert_eq!((12.5f16).to_bits(), 0x4a40);
|
||||
assert_eq!((1337f16).to_bits(), 0x6539);
|
||||
assert_eq!((-14.25f16).to_bits(), 0xcb20);
|
||||
assert_approx_eq!(f16::from_bits(0x3c00), 1.0);
|
||||
assert_approx_eq!(f16::from_bits(0x4a40), 12.5);
|
||||
assert_approx_eq!(f16::from_bits(0x6539), 1337.0);
|
||||
assert_approx_eq!(f16::from_bits(0xcb20), -14.25);
|
||||
assert_approx_eq!(f16::from_bits(0x3c00), 1.0, TOL_0);
|
||||
assert_approx_eq!(f16::from_bits(0x4a40), 12.5, TOL_0);
|
||||
assert_approx_eq!(f16::from_bits(0x6539), 1337.0, TOL_P4);
|
||||
assert_approx_eq!(f16::from_bits(0xcb20), -14.25, TOL_0);
|
||||
|
||||
// Check that NaNs roundtrip their bits regardless of signaling-ness
|
||||
let masked_nan1 = f16::NAN.to_bits() ^ NAN_MASK1;
|
||||
|
@ -155,7 +155,7 @@ mod break_keyword {}
|
||||
/// const WORDS: &str = "hello convenience!";
|
||||
/// ```
|
||||
///
|
||||
/// `const` items looks remarkably similar to `static` items, which introduces some confusion as
|
||||
/// `const` items look remarkably similar to `static` items, which introduces some confusion as
|
||||
/// to which one should be used at which times. To put it simply, constants are inlined wherever
|
||||
/// they're used, making using them identical to simply replacing the name of the `const` with its
|
||||
/// value. Static variables, on the other hand, point to a single location in memory, which all
|
||||
|
@ -382,7 +382,7 @@ macro_rules! assert_approx_eq {
|
||||
let diff = (*a - *b).abs();
|
||||
assert!(
|
||||
diff < $lim,
|
||||
"{a:?} is not approximately equal to {b:?} (threshold {lim:?}, actual {diff:?})",
|
||||
"{a:?} is not approximately equal to {b:?} (threshold {lim:?}, difference {diff:?})",
|
||||
lim = $lim
|
||||
);
|
||||
}};
|
||||
|
@ -28,6 +28,21 @@ extern "C" {
|
||||
pub fn lgamma_r(n: f64, s: &mut i32) -> f64;
|
||||
pub fn lgammaf_r(n: f32, s: &mut i32) -> f32;
|
||||
|
||||
pub fn acosf128(n: f128) -> f128;
|
||||
pub fn asinf128(n: f128) -> f128;
|
||||
pub fn atanf128(n: f128) -> f128;
|
||||
pub fn atan2f128(a: f128, b: f128) -> f128;
|
||||
pub fn cbrtf128(n: f128) -> f128;
|
||||
pub fn coshf128(n: f128) -> f128;
|
||||
pub fn expm1f128(n: f128) -> f128;
|
||||
pub fn hypotf128(x: f128, y: f128) -> f128;
|
||||
pub fn log1pf128(n: f128) -> f128;
|
||||
pub fn sinhf128(n: f128) -> f128;
|
||||
pub fn tanf128(n: f128) -> f128;
|
||||
pub fn tanhf128(n: f128) -> f128;
|
||||
pub fn tgammaf128(n: f128) -> f128;
|
||||
pub fn lgammaf128_r(n: f128, s: &mut i32) -> f128;
|
||||
|
||||
cfg_if::cfg_if! {
|
||||
if #[cfg(not(all(target_os = "windows", target_env = "msvc", target_arch = "x86")))] {
|
||||
pub fn acosf(n: f32) -> f32;
|
||||
|
@ -12,14 +12,31 @@ use crate::targets::{is_darwin, is_msvc, is_windows};
|
||||
/// Built from a C file.
|
||||
#[track_caller]
|
||||
pub fn build_native_static_lib(lib_name: &str) -> PathBuf {
|
||||
build_native_static_lib_internal(lib_name, false)
|
||||
}
|
||||
|
||||
/// Builds an optimized static lib (`.lib` on Windows MSVC and `.a` for the rest) with the given name.
|
||||
/// Built from a C file.
|
||||
#[track_caller]
|
||||
pub fn build_native_static_lib_optimized(lib_name: &str) -> PathBuf {
|
||||
build_native_static_lib_internal(lib_name, true)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn build_native_static_lib_internal(lib_name: &str, optimzed: bool) -> PathBuf {
|
||||
let obj_file = if is_msvc() { format!("{lib_name}") } else { format!("{lib_name}.o") };
|
||||
let src = format!("{lib_name}.c");
|
||||
let lib_path = static_lib_name(lib_name);
|
||||
if is_msvc() {
|
||||
cc().arg("-c").out_exe(&obj_file).input(src).run();
|
||||
} else {
|
||||
cc().arg("-v").arg("-c").out_exe(&obj_file).input(src).run();
|
||||
};
|
||||
|
||||
let mut cc = cc();
|
||||
if !is_msvc() {
|
||||
cc.arg("-v");
|
||||
}
|
||||
if optimzed {
|
||||
cc.optimize();
|
||||
}
|
||||
cc.arg("-c").out_exe(&obj_file).input(src).optimize().run();
|
||||
|
||||
let obj_file = if is_msvc() {
|
||||
PathBuf::from(format!("{lib_name}.obj"))
|
||||
} else {
|
||||
|
@ -115,6 +115,17 @@ impl Cc {
|
||||
self.cmd.arg(path.as_ref());
|
||||
self
|
||||
}
|
||||
|
||||
/// Optimize the output.
|
||||
/// Equivalent to `-O3` for GNU-compatible linkers or `-O2` for MSVC linkers.
|
||||
pub fn optimize(&mut self) -> &mut Self {
|
||||
if is_msvc() {
|
||||
self.cmd.arg("-O2");
|
||||
} else {
|
||||
self.cmd.arg("-O3");
|
||||
}
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// `EXTRACFLAGS`
|
||||
|
@ -45,7 +45,7 @@ pub use external_deps::{c_build, cc, clang, htmldocck, llvm, python, rustc, rust
|
||||
|
||||
// These rely on external dependencies.
|
||||
pub use cc::{cc, cxx, extra_c_flags, extra_cxx_flags, Cc};
|
||||
pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_cxx};
|
||||
pub use c_build::{build_native_dynamic_lib, build_native_static_lib, build_native_static_lib_optimized, build_native_static_lib_cxx};
|
||||
pub use clang::{clang, Clang};
|
||||
pub use htmldocck::htmldocck;
|
||||
pub use llvm::{
|
||||
|
@ -22,9 +22,6 @@ run-make/no-alloc-shim/Makefile
|
||||
run-make/pdb-buildinfo-cl-cmd/Makefile
|
||||
run-make/pgo-gen-lto/Makefile
|
||||
run-make/pgo-indirect-call-promotion/Makefile
|
||||
run-make/raw-dylib-alt-calling-convention/Makefile
|
||||
run-make/raw-dylib-c/Makefile
|
||||
run-make/redundant-libs/Makefile
|
||||
run-make/remap-path-prefix-dwarf/Makefile
|
||||
run-make/reproducible-build/Makefile
|
||||
run-make/rlib-format-packed-bundled-libs/Makefile
|
||||
|
@ -3,15 +3,14 @@
|
||||
// checks that linker arguments remain intact and in the order they were originally passed in.
|
||||
// See https://github.com/rust-lang/rust/pull/70665
|
||||
|
||||
//@ ignore-msvc
|
||||
// Reason: the ld linker does not exist on Windows.
|
||||
|
||||
use run_make_support::rustc;
|
||||
use run_make_support::{is_msvc, rustc};
|
||||
|
||||
fn main() {
|
||||
let linker = if is_msvc() { "msvc" } else { "ld" };
|
||||
|
||||
rustc()
|
||||
.input("empty.rs")
|
||||
.linker_flavor("ld")
|
||||
.linker_flavor(linker)
|
||||
.link_arg("a")
|
||||
.link_args("b c")
|
||||
.link_args("d e")
|
||||
@ -20,7 +19,7 @@ fn main() {
|
||||
.assert_stderr_contains(r#""a" "b" "c" "d" "e" "f""#);
|
||||
rustc()
|
||||
.input("empty.rs")
|
||||
.linker_flavor("ld")
|
||||
.linker_flavor(linker)
|
||||
.arg("-Zpre-link-arg=a")
|
||||
.arg("-Zpre-link-args=b c")
|
||||
.arg("-Zpre-link-args=d e")
|
||||
|
@ -5,20 +5,37 @@
|
||||
// Without the --cfg flag, there should be a single -ltesta, no more, no less.
|
||||
// See https://github.com/rust-lang/rust/pull/84794
|
||||
|
||||
//@ ignore-msvc
|
||||
use std::fmt::Write;
|
||||
|
||||
use run_make_support::rustc;
|
||||
use run_make_support::{is_msvc, rustc};
|
||||
|
||||
fn main() {
|
||||
rustc().input("depa.rs").run();
|
||||
rustc().input("depb.rs").run();
|
||||
rustc().input("depc.rs").run();
|
||||
|
||||
let output = rustc().input("empty.rs").cfg("bar").run_fail();
|
||||
output.assert_stderr_contains(r#""-ltesta" "-ltestb" "-ltesta""#);
|
||||
output.assert_stderr_contains(needle_from_libs(&["testa", "testb", "testa"]));
|
||||
|
||||
let output = rustc().input("empty.rs").run_fail();
|
||||
output.assert_stderr_contains(r#""-ltesta""#);
|
||||
let output = rustc().input("empty.rs").run_fail();
|
||||
output.assert_stderr_not_contains(r#""-ltestb""#);
|
||||
let output = rustc().input("empty.rs").run_fail();
|
||||
output.assert_stderr_not_contains(r#""-ltesta" "-ltesta" "-ltesta""#);
|
||||
output.assert_stderr_contains(needle_from_libs(&["testa"]));
|
||||
output.assert_stderr_not_contains(needle_from_libs(&["testb"]));
|
||||
output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa", "testa"]));
|
||||
// Adjacent identical native libraries are no longer deduplicated if
|
||||
// they come from different crates (https://github.com/rust-lang/rust/pull/103311)
|
||||
// so the following will fail:
|
||||
//output.assert_stderr_not_contains(needle_from_libs(&["testa", "testa"]));
|
||||
}
|
||||
|
||||
fn needle_from_libs(libs: &[&str]) -> String {
|
||||
let mut needle = String::new();
|
||||
for lib in libs {
|
||||
if is_msvc() {
|
||||
let _ = needle.write_fmt(format_args!(r#""{lib}.lib" "#));
|
||||
} else {
|
||||
let _ = needle.write_fmt(format_args!(r#""-l{lib}" "#));
|
||||
}
|
||||
}
|
||||
needle.pop(); // remove trailing space
|
||||
needle
|
||||
}
|
||||
|
89
tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
Normal file
89
tests/run-make/naked-symbol-visibility/a_rust_dylib.rs
Normal file
@ -0,0 +1,89 @@
|
||||
#![feature(naked_functions, asm_const, linkage)]
|
||||
#![crate_type = "dylib"]
|
||||
|
||||
use std::arch::asm;
|
||||
|
||||
pub trait TraitWithConst {
|
||||
const COUNT: u32;
|
||||
}
|
||||
|
||||
struct Test;
|
||||
|
||||
impl TraitWithConst for Test {
|
||||
const COUNT: u32 = 1;
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
fn entry() {
|
||||
private_vanilla();
|
||||
private_naked();
|
||||
|
||||
public_vanilla_generic::<Test>();
|
||||
public_naked_generic::<Test>();
|
||||
}
|
||||
|
||||
extern "C" fn private_vanilla() -> u32 {
|
||||
42
|
||||
}
|
||||
|
||||
#[naked]
|
||||
extern "C" fn private_naked() -> u32 {
|
||||
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn public_vanilla() -> u32 {
|
||||
42
|
||||
}
|
||||
|
||||
#[naked]
|
||||
#[no_mangle]
|
||||
pub extern "C" fn public_naked() -> u32 {
|
||||
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
|
||||
}
|
||||
|
||||
pub extern "C" fn public_vanilla_generic<T: TraitWithConst>() -> u32 {
|
||||
T::COUNT
|
||||
}
|
||||
|
||||
#[naked]
|
||||
pub extern "C" fn public_naked_generic<T: TraitWithConst>() -> u32 {
|
||||
unsafe { asm!("mov rax, {}", "ret", const T::COUNT, options(noreturn)) }
|
||||
}
|
||||
|
||||
#[linkage = "external"]
|
||||
extern "C" fn vanilla_external_linkage() -> u32 {
|
||||
42
|
||||
}
|
||||
|
||||
#[naked]
|
||||
#[linkage = "external"]
|
||||
extern "C" fn naked_external_linkage() -> u32 {
|
||||
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
|
||||
}
|
||||
|
||||
#[cfg(not(windows))]
|
||||
#[linkage = "weak"]
|
||||
extern "C" fn vanilla_weak_linkage() -> u32 {
|
||||
42
|
||||
}
|
||||
|
||||
#[naked]
|
||||
#[cfg(not(windows))]
|
||||
#[linkage = "weak"]
|
||||
extern "C" fn naked_weak_linkage() -> u32 {
|
||||
unsafe { asm!("mov rax, 42", "ret", options(noreturn)) }
|
||||
}
|
||||
|
||||
// functions that are declared in an `extern "C"` block are currently not exported
|
||||
// this maybe should change in the future, this is just tracking the current behavior
|
||||
// reported in https://github.com/rust-lang/rust/issues/128071
|
||||
std::arch::global_asm! {
|
||||
".globl function_defined_in_global_asm",
|
||||
"function_defined_in_global_asm:",
|
||||
"ret",
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
pub fn function_defined_in_global_asm();
|
||||
}
|
98
tests/run-make/naked-symbol-visibility/rmake.rs
Normal file
98
tests/run-make/naked-symbol-visibility/rmake.rs
Normal file
@ -0,0 +1,98 @@
|
||||
//@ ignore-windows
|
||||
//@ only-x86_64
|
||||
use run_make_support::object::read::{File, Object, Symbol};
|
||||
use run_make_support::object::ObjectSymbol;
|
||||
use run_make_support::targets::is_windows;
|
||||
use run_make_support::{dynamic_lib_name, env_var, rfs, rustc};
|
||||
|
||||
fn main() {
|
||||
let rdylib_name = dynamic_lib_name("a_rust_dylib");
|
||||
rustc().arg("-Zshare-generics=no").input("a_rust_dylib.rs").run();
|
||||
|
||||
let binary_data = rfs::read(&rdylib_name);
|
||||
let rdylib = File::parse(&*binary_data).unwrap();
|
||||
|
||||
// naked should mirror vanilla
|
||||
not_exported(&rdylib, "private_vanilla");
|
||||
not_exported(&rdylib, "private_naked");
|
||||
|
||||
global_function(&rdylib, "public_vanilla");
|
||||
global_function(&rdylib, "public_naked");
|
||||
|
||||
not_exported(&rdylib, "public_vanilla_generic");
|
||||
not_exported(&rdylib, "public_naked_generic");
|
||||
|
||||
global_function(&rdylib, "vanilla_external_linkage");
|
||||
global_function(&rdylib, "naked_external_linkage");
|
||||
|
||||
// FIXME: make this work on windows (gnu and msvc). See the PR
|
||||
// https://github.com/rust-lang/rust/pull/128362 for some approaches
|
||||
// that don't work
|
||||
//
|
||||
// #[linkage = "weak"] does not work well on windows, we get
|
||||
//
|
||||
// lib.def : error LNK2001: unresolved external symbol naked_weak_linkage␍
|
||||
// lib.def : error LNK2001: unresolved external symbol vanilla_weak_linkage
|
||||
//
|
||||
// so just skip weak symbols on windows (for now)
|
||||
if !is_windows() {
|
||||
weak_function(&rdylib, "vanilla_weak_linkage");
|
||||
weak_function(&rdylib, "naked_weak_linkage");
|
||||
}
|
||||
|
||||
// functions that are declared in an `extern "C"` block are currently not exported
|
||||
// this maybe should change in the future, this is just tracking the current behavior
|
||||
// reported in https://github.com/rust-lang/rust/issues/128071
|
||||
not_exported(&rdylib, "function_defined_in_global_asm");
|
||||
|
||||
// share generics should expose the generic functions
|
||||
rustc().arg("-Zshare-generics=yes").input("a_rust_dylib.rs").run();
|
||||
let binary_data = rfs::read(&rdylib_name);
|
||||
let rdylib = File::parse(&*binary_data).unwrap();
|
||||
|
||||
global_function(&rdylib, "public_vanilla_generic");
|
||||
global_function(&rdylib, "public_naked_generic");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn global_function(file: &File, symbol_name: &str) {
|
||||
let symbols = find_dynamic_symbol(file, symbol_name);
|
||||
let [symbol] = symbols.as_slice() else {
|
||||
panic!("symbol {symbol_name} occurs {} times", symbols.len())
|
||||
};
|
||||
|
||||
assert!(symbol.is_definition(), "`{symbol_name}` is not a function");
|
||||
assert!(symbol.is_global(), "`{symbol_name}` is not marked as global");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn weak_function(file: &File, symbol_name: &str) {
|
||||
let symbols = find_dynamic_symbol(file, symbol_name);
|
||||
let [symbol] = symbols.as_slice() else {
|
||||
panic!("symbol {symbol_name} occurs {} times", symbols.len())
|
||||
};
|
||||
|
||||
assert!(symbol.is_definition(), "`{symbol_name}` is not a function");
|
||||
assert!(symbol.is_weak(), "`{symbol_name}` is not marked as weak");
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn not_exported(file: &File, symbol_name: &str) {
|
||||
assert_eq!(find_dynamic_symbol(file, symbol_name).len(), 0)
|
||||
}
|
||||
|
||||
fn find_subsequence(haystack: &[u8], needle: &[u8]) -> bool {
|
||||
haystack.windows(needle.len()).any(|window| window == needle)
|
||||
}
|
||||
|
||||
fn find_dynamic_symbol<'file, 'data>(
|
||||
file: &'file File<'data>,
|
||||
expected: &str,
|
||||
) -> Vec<Symbol<'data, 'file>> {
|
||||
file.exports()
|
||||
.unwrap()
|
||||
.into_iter()
|
||||
.filter(|e| find_subsequence(e.name(), expected.as_bytes()))
|
||||
.filter_map(|e| file.symbol_by_name_bytes(e.name()))
|
||||
.collect()
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
#[link(name = "foo")] // linker should drop this library, no symbols used
|
||||
#[link(name = "bar")] // symbol comes from this library
|
||||
#[link(name = "foo")] // now linker picks up `foo` b/c `bar` library needs it
|
||||
#[link(name = "foo", kind = "static")] // linker should drop this library, no symbols used
|
||||
#[link(name = "bar", kind = "static")] // symbol comes from this library
|
||||
#[link(name = "foo", kind = "static")] // now linker picks up `foo` b/c `bar` library needs it
|
||||
extern "C" {
|
||||
fn bar();
|
||||
}
|
||||
|
@ -9,9 +9,6 @@
|
||||
//@ ignore-cross-compile
|
||||
// Reason: the compiled binary is executed
|
||||
|
||||
//@ ignore-msvc
|
||||
// Reason: native compilation results in an unresolved external symbol
|
||||
|
||||
use run_make_support::{build_native_static_lib, run, rustc};
|
||||
|
||||
fn main() {
|
||||
|
@ -1,24 +0,0 @@
|
||||
# Test the behavior of #[link(.., kind = "raw-dylib")] with alternative calling conventions.
|
||||
|
||||
# only-x86
|
||||
# only-windows
|
||||
|
||||
include ../tools.mk
|
||||
|
||||
all:
|
||||
$(RUSTC) --crate-type lib --crate-name raw_dylib_alt_calling_convention_test lib.rs
|
||||
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
|
||||
$(call COMPILE_OBJ,"$(TMPDIR)"/extern.obj,extern.c)
|
||||
ifdef IS_MSVC
|
||||
$(CC) "$(TMPDIR)"/extern.obj -link -dll -out:"$(TMPDIR)"/extern.dll -noimplib
|
||||
else
|
||||
$(CC) "$(TMPDIR)"/extern.obj -shared -o "$(TMPDIR)"/extern.dll
|
||||
endif
|
||||
|
||||
"$(TMPDIR)"/driver > "$(TMPDIR)"/output.txt
|
||||
$(RUSTC_TEST_OP) "$(TMPDIR)"/output.txt output.txt
|
||||
|
||||
ifdef IS_MSVC
|
||||
"$(TMPDIR)"/driver true > "$(TMPDIR)"/output.msvc.txt
|
||||
$(RUSTC_TEST_OP) "$(TMPDIR)"/output.msvc.txt output.msvc.txt
|
||||
endif
|
32
tests/run-make/raw-dylib-alt-calling-convention/rmake.rs
Normal file
32
tests/run-make/raw-dylib-alt-calling-convention/rmake.rs
Normal file
@ -0,0 +1,32 @@
|
||||
// `raw-dylib` is a Windows-specific attribute which emits idata sections for the items in the
|
||||
// attached extern block,
|
||||
// so they may be linked against without linking against an import library.
|
||||
// To learn more, read https://github.com/rust-lang/rfcs/blob/master/text/2627-raw-dylib-kind.md
|
||||
// This test uses this feature alongside alternative calling conventions, checking that both
|
||||
// features are compatible and result in the expected output upon execution of the binary.
|
||||
// See https://github.com/rust-lang/rust/pull/84171
|
||||
|
||||
//@ only-x86
|
||||
//@ only-windows
|
||||
|
||||
use run_make_support::{build_native_dynamic_lib, diff, is_msvc, run, run_with_args, rustc};
|
||||
|
||||
fn main() {
|
||||
rustc()
|
||||
.crate_type("lib")
|
||||
.crate_name("raw_dylib_alt_calling_convention_test")
|
||||
.input("lib.rs")
|
||||
.run();
|
||||
rustc().crate_type("bin").input("driver.rs").run();
|
||||
build_native_dynamic_lib("extern");
|
||||
let out = run("driver").stdout_utf8();
|
||||
diff().expected_file("output.txt").actual_text("actual", out).normalize(r#"\r"#, "").run();
|
||||
if is_msvc() {
|
||||
let out_msvc = run_with_args("driver", &["true"]).stdout_utf8();
|
||||
diff()
|
||||
.expected_file("output.msvc.txt")
|
||||
.actual_text("actual", out_msvc)
|
||||
.normalize(r#"\r"#, "")
|
||||
.run();
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
# Test the behavior of #[link(.., kind = "raw-dylib")] on windows-msvc
|
||||
|
||||
# only-windows
|
||||
|
||||
include ../tools.mk
|
||||
|
||||
all:
|
||||
$(RUSTC) --crate-type lib --crate-name raw_dylib_test lib.rs
|
||||
$(RUSTC) --crate-type bin driver.rs -L "$(TMPDIR)"
|
||||
$(RUSTC) --crate-type bin --crate-name raw_dylib_test_bin lib.rs
|
||||
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_1.obj,extern_1.c)
|
||||
$(call COMPILE_OBJ,"$(TMPDIR)"/extern_2.obj,extern_2.c)
|
||||
ifdef IS_MSVC
|
||||
$(CC) "$(TMPDIR)"/extern_1.obj -link -dll -out:"$(TMPDIR)"/extern_1.dll -noimplib
|
||||
$(CC) "$(TMPDIR)"/extern_2.obj -link -dll -out:"$(TMPDIR)"/extern_2.dll -noimplib
|
||||
else
|
||||
$(CC) "$(TMPDIR)"/extern_1.obj -shared -o "$(TMPDIR)"/extern_1.dll
|
||||
$(CC) "$(TMPDIR)"/extern_2.obj -shared -o "$(TMPDIR)"/extern_2.dll
|
||||
endif
|
||||
"$(TMPDIR)"/driver | tr -d '\r' > "$(TMPDIR)"/output.txt
|
||||
"$(TMPDIR)"/raw_dylib_test_bin > "$(TMPDIR)"/output_bin.txt
|
||||
|
||||
ifdef RUSTC_BLESS_TEST
|
||||
cp "$(TMPDIR)"/output.txt output.txt
|
||||
else
|
||||
$(DIFF) output.txt "$(TMPDIR)"/output.txt
|
||||
$(DIFF) output.txt "$(TMPDIR)"/output_bin.txt
|
||||
endif
|
29
tests/run-make/raw-dylib-c/rmake.rs
Normal file
29
tests/run-make/raw-dylib-c/rmake.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// `raw-dylib` is a Windows-specific attribute which emits idata sections for the items in the
|
||||
// attached extern block,
|
||||
// so they may be linked against without linking against an import library.
|
||||
// To learn more, read https://github.com/rust-lang/rfcs/blob/master/text/2627-raw-dylib-kind.md
|
||||
// This test is the simplest of the raw-dylib tests, simply smoke-testing that the feature
|
||||
// can be used to build an executable binary with an expected output with native C files
|
||||
// compiling into dynamic libraries.
|
||||
// See https://github.com/rust-lang/rust/pull/86419
|
||||
|
||||
//@ only-windows
|
||||
|
||||
use run_make_support::{build_native_dynamic_lib, diff, run, rustc};
|
||||
|
||||
fn main() {
|
||||
rustc().crate_type("lib").crate_name("raw_dylib_test").input("lib.rs").run();
|
||||
rustc().crate_type("bin").input("driver.rs").run();
|
||||
rustc().crate_type("bin").crate_name("raw_dylib_test_bin").input("lib.rs").run();
|
||||
build_native_dynamic_lib("extern_1");
|
||||
build_native_dynamic_lib("extern_2");
|
||||
let out_driver = run("driver").stdout_utf8();
|
||||
let out_raw = run("raw_dylib_test_bin").stdout_utf8();
|
||||
|
||||
diff()
|
||||
.expected_file("output.txt")
|
||||
.actual_text("actual", out_driver)
|
||||
.normalize(r#"\r"#, "")
|
||||
.run();
|
||||
diff().expected_file("output.txt").actual_text("actual", out_raw).normalize(r#"\r"#, "").run();
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
# ignore-cross-compile
|
||||
include ../tools.mk
|
||||
|
||||
# ignore-windows-msvc
|
||||
|
||||
# rustc will remove one of the two redundant references to foo below. Depending
|
||||
# on which one gets removed, we'll get a linker error on SOME platforms (like
|
||||
# Linux). On these platforms, when a library is referenced, the linker will
|
||||
# only pull in the symbols needed _at that point in time_. If a later library
|
||||
# depends on additional symbols from the library, they will not have been pulled
|
||||
# in, and you'll get undefined symbols errors.
|
||||
#
|
||||
# So in this example, we need to ensure that rustc keeps the _later_ reference
|
||||
# to foo, and not the former one.
|
||||
RUSTC_FLAGS = \
|
||||
-l static=bar \
|
||||
-l foo \
|
||||
-l static=baz \
|
||||
-l foo \
|
||||
--print link-args
|
||||
|
||||
all: $(call DYLIB,foo) $(call STATICLIB,bar) $(call STATICLIB,baz)
|
||||
$(RUSTC) $(RUSTC_FLAGS) main.rs
|
||||
$(call RUN,main)
|
34
tests/run-make/redundant-libs/rmake.rs
Normal file
34
tests/run-make/redundant-libs/rmake.rs
Normal file
@ -0,0 +1,34 @@
|
||||
// rustc will remove one of the two redundant references to foo below. Depending
|
||||
// on which one gets removed, we'll get a linker error on SOME platforms (like
|
||||
// Linux). On these platforms, when a library is referenced, the linker will
|
||||
// only pull in the symbols needed _at that point in time_. If a later library
|
||||
// depends on additional symbols from the library, they will not have been pulled
|
||||
// in, and you'll get undefined symbols errors.
|
||||
//
|
||||
// So in this example, we need to ensure that rustc keeps the _later_ reference
|
||||
// to foo, and not the former one.
|
||||
|
||||
//@ ignore-cross-compile
|
||||
// Reason: the compiled binary is executed
|
||||
//@ ignore-windows-msvc
|
||||
// Reason: this test links libraries via link.exe, which only accepts the import library
|
||||
// for the dynamic library, i.e. `foo.dll.lib`. However, build_native_dynamic_lib only
|
||||
// produces `foo.dll` - the dynamic library itself. To make this test work on MSVC, one
|
||||
// would need to derive the import library from the dynamic library.
|
||||
// See https://stackoverflow.com/questions/9360280/
|
||||
|
||||
use run_make_support::{
|
||||
build_native_dynamic_lib, build_native_static_lib, cwd, is_msvc, rfs, run, rustc,
|
||||
};
|
||||
|
||||
fn main() {
|
||||
build_native_dynamic_lib("foo");
|
||||
build_native_static_lib("bar");
|
||||
build_native_static_lib("baz");
|
||||
rustc()
|
||||
.args(&["-lstatic=bar", "-lfoo", "-lstatic=baz", "-lfoo"])
|
||||
.input("main.rs")
|
||||
.print("link-args")
|
||||
.run();
|
||||
run("main");
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
// LLVM optimization choices. See additional note below for an
|
||||
// example.
|
||||
|
||||
#[link(name = "bad")]
|
||||
#[link(name = "bad", kind = "static")]
|
||||
extern "C" {
|
||||
pub fn c_read_value(a: u32, b: u32, c: u32) -> u16;
|
||||
}
|
||||
|
@ -6,20 +6,13 @@
|
||||
// while simultaneously interfacing with a C library and using the -O3 flag.
|
||||
// See https://github.com/rust-lang/rust/issues/97463
|
||||
|
||||
//@ ignore-msvc
|
||||
// Reason: the rustc compilation fails due to an unresolved external symbol
|
||||
|
||||
//@ ignore-cross-compile
|
||||
// Reason: The compiled binary is executed.
|
||||
|
||||
use run_make_support::{cc, is_msvc, llvm_ar, run, rustc, static_lib_name};
|
||||
use run_make_support::{build_native_static_lib_optimized, run, rustc};
|
||||
|
||||
fn main() {
|
||||
// The issue exercised by this test specifically needs needs `-O`
|
||||
// flags (like `-O3`) to reproduce. Thus, we call `cc()` instead of
|
||||
// the nicer `build_native_static_lib`.
|
||||
cc().arg("-c").arg("-O3").out_exe("bad.o").input("bad.c").run();
|
||||
llvm_ar().obj_to_ar().output_input(static_lib_name("bad"), "bad.o").run();
|
||||
rustc().input("param_passing.rs").arg("-lbad").opt_level("3").run();
|
||||
// The issue exercised by this test specifically needs an optimized native static lib.
|
||||
build_native_static_lib_optimized("bad");
|
||||
rustc().input("param_passing.rs").opt_level("3").run();
|
||||
run("param_passing");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user