std: Avoid missing fns on i686-pc-windows-msvc
It turns out that the 32-bit toolchain for MSVC has many of these functions as `static inline` functions in header files so there's not actually a symbol for Rust to call. All of the implementations just cast floats to their 64-bit variants and then cast back to 32-bit at the end, so the standard library now takes this strategy.
This commit is contained in:
parent
5de665e8b3
commit
8790958237
@ -215,13 +215,37 @@ impl Float for f32 {
|
||||
/// Rounds towards minus infinity.
|
||||
#[inline]
|
||||
fn floor(self) -> f32 {
|
||||
unsafe { intrinsics::floorf32(self) }
|
||||
return floorf(self);
|
||||
|
||||
// On MSVC LLVM will lower many math intrinsics to a call to the
|
||||
// corresponding function. On MSVC, however, many of these functions
|
||||
// aren't actually available as symbols to call, but rather they are all
|
||||
// `static inline` functions in header files. This means that from a C
|
||||
// perspective it's "compatible", but not so much from an ABI
|
||||
// perspective (which we're worried about).
|
||||
//
|
||||
// The inline header functions always just cast to a f64 and do their
|
||||
// operation, so we do that here as well, but only for MSVC targets.
|
||||
//
|
||||
// Note that there are many MSVC-specific float operations which
|
||||
// redirect to this comment, so `floorf` is just one case of a missing
|
||||
// function on MSVC, but there are many others elsewhere.
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn floorf(f: f32) -> f32 { (f as f64).floor() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } }
|
||||
}
|
||||
|
||||
/// Rounds towards plus infinity.
|
||||
#[inline]
|
||||
fn ceil(self) -> f32 {
|
||||
unsafe { intrinsics::ceilf32(self) }
|
||||
return ceilf(self);
|
||||
|
||||
// see notes above in `floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn ceilf(f: f32) -> f32 { (f as f64).ceil() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceilf32(f) } }
|
||||
}
|
||||
|
||||
/// Rounds to nearest integer. Rounds half-way cases away from zero.
|
||||
@ -299,7 +323,13 @@ impl Float for f32 {
|
||||
|
||||
#[inline]
|
||||
fn powf(self, n: f32) -> f32 {
|
||||
unsafe { intrinsics::powf32(self, n) }
|
||||
return powf(self, n);
|
||||
|
||||
// see notes above in `floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn powf(f: f32, n: f32) -> f32 { (f as f64).powf(n as f64) as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::powf32(f, n) } }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@ -317,7 +347,13 @@ impl Float for f32 {
|
||||
/// Returns the exponential of the number.
|
||||
#[inline]
|
||||
fn exp(self) -> f32 {
|
||||
unsafe { intrinsics::expf32(self) }
|
||||
return expf(self);
|
||||
|
||||
// see notes above in `floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn expf(f: f32) -> f32 { (f as f64).exp() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn expf(f: f32) -> f32 { unsafe { intrinsics::expf32(f) } }
|
||||
}
|
||||
|
||||
/// Returns 2 raised to the power of the number.
|
||||
@ -329,7 +365,13 @@ impl Float for f32 {
|
||||
/// Returns the natural logarithm of the number.
|
||||
#[inline]
|
||||
fn ln(self) -> f32 {
|
||||
unsafe { intrinsics::logf32(self) }
|
||||
return logf(self);
|
||||
|
||||
// see notes above in `floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn logf(f: f32) -> f32 { (f as f64).ln() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn logf(f: f32) -> f32 { unsafe { intrinsics::logf32(f) } }
|
||||
}
|
||||
|
||||
/// Returns the logarithm of the number with respect to an arbitrary base.
|
||||
@ -345,7 +387,13 @@ impl Float for f32 {
|
||||
/// Returns the base 10 logarithm of the number.
|
||||
#[inline]
|
||||
fn log10(self) -> f32 {
|
||||
unsafe { intrinsics::log10f32(self) }
|
||||
return log10f(self);
|
||||
|
||||
// see notes above in `floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn log10f(f: f32) -> f32 { (f as f64).log10() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10f32(f) } }
|
||||
}
|
||||
|
||||
/// Converts to degrees, assuming the number is in radians.
|
||||
|
@ -419,26 +419,40 @@ macro_rules! rem_impl {
|
||||
)*)
|
||||
}
|
||||
|
||||
macro_rules! rem_float_impl {
|
||||
($t:ty, $fmod:ident) => {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Rem for $t {
|
||||
type Output = $t;
|
||||
rem_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
|
||||
|
||||
#[inline]
|
||||
fn rem(self, other: $t) -> $t {
|
||||
extern { fn $fmod(a: $t, b: $t) -> $t; }
|
||||
unsafe { $fmod(self, other) }
|
||||
}
|
||||
}
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Rem for f32 {
|
||||
type Output = f32;
|
||||
|
||||
forward_ref_binop! { impl Rem, rem for $t, $t }
|
||||
// see notes in `core::f32::Float::floor`
|
||||
#[inline]
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn rem(self, other: f32) -> f32 {
|
||||
(self as f64).rem(other as f64) as f32
|
||||
}
|
||||
|
||||
#[inline]
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn rem(self, other: f32) -> f32 {
|
||||
extern { fn fmodf(a: f32, b: f32) -> f32; }
|
||||
unsafe { fmodf(self, other) }
|
||||
}
|
||||
}
|
||||
|
||||
rem_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
|
||||
rem_float_impl! { f32, fmodf }
|
||||
rem_float_impl! { f64, fmod }
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
impl Rem for f64 {
|
||||
type Output = f64;
|
||||
|
||||
#[inline]
|
||||
fn rem(self, other: f64) -> f64 {
|
||||
extern { fn fmod(a: f64, b: f64) -> f64; }
|
||||
unsafe { fmod(self, other) }
|
||||
}
|
||||
}
|
||||
|
||||
forward_ref_binop! { impl Rem, rem for f64, f64 }
|
||||
forward_ref_binop! { impl Rem, rem for f32, f32 }
|
||||
|
||||
/// The `Neg` trait is used to specify the functionality of unary `-`.
|
||||
///
|
||||
|
@ -18,6 +18,7 @@
|
||||
use prelude::v1::*;
|
||||
|
||||
use core::num;
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
use intrinsics;
|
||||
use libc::c_int;
|
||||
use num::{FpCategory, ParseFloatError};
|
||||
@ -33,12 +34,7 @@ mod cmath {
|
||||
use libc::{c_float, c_int};
|
||||
|
||||
extern {
|
||||
pub fn acosf(n: c_float) -> c_float;
|
||||
pub fn asinf(n: c_float) -> c_float;
|
||||
pub fn atanf(n: c_float) -> c_float;
|
||||
pub fn atan2f(a: c_float, b: c_float) -> c_float;
|
||||
pub fn cbrtf(n: c_float) -> c_float;
|
||||
pub fn coshf(n: c_float) -> c_float;
|
||||
pub fn erff(n: c_float) -> c_float;
|
||||
pub fn erfcf(n: c_float) -> c_float;
|
||||
pub fn expm1f(n: c_float) -> c_float;
|
||||
@ -51,32 +47,77 @@ mod cmath {
|
||||
pub fn log1pf(n: c_float) -> c_float;
|
||||
pub fn ilogbf(n: c_float) -> c_int;
|
||||
pub fn modff(n: c_float, iptr: &mut c_float) -> c_float;
|
||||
pub fn sinhf(n: c_float) -> c_float;
|
||||
pub fn tanf(n: c_float) -> c_float;
|
||||
pub fn tanhf(n: c_float) -> c_float;
|
||||
pub fn tgammaf(n: c_float) -> c_float;
|
||||
|
||||
#[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgammaf_r")]
|
||||
pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float;
|
||||
#[cfg_attr(all(windows, target_env = "msvc"), link_name = "_hypotf")]
|
||||
pub fn hypotf(x: c_float, y: c_float) -> c_float;
|
||||
}
|
||||
|
||||
#[cfg(any(unix, all(windows, not(target_env = "msvc"))))]
|
||||
// See the comments in `core::float::Float::floor` for why MSVC is special
|
||||
// here.
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
extern {
|
||||
pub fn acosf(n: c_float) -> c_float;
|
||||
pub fn asinf(n: c_float) -> c_float;
|
||||
pub fn atan2f(a: c_float, b: c_float) -> c_float;
|
||||
pub fn atanf(n: c_float) -> c_float;
|
||||
pub fn coshf(n: c_float) -> c_float;
|
||||
pub fn frexpf(n: c_float, value: &mut c_int) -> c_float;
|
||||
#[cfg(any(unix, all(windows, not(target_env = "msvc"))))]
|
||||
pub fn ldexpf(x: c_float, n: c_int) -> c_float;
|
||||
pub fn sinhf(n: c_float) -> c_float;
|
||||
pub fn tanf(n: c_float) -> c_float;
|
||||
pub fn tanhf(n: c_float) -> c_float;
|
||||
}
|
||||
|
||||
#[cfg(all(windows, target_env = "msvc"))]
|
||||
pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float {
|
||||
f64::ldexp(x as f64, n as isize) as c_float
|
||||
}
|
||||
#[cfg(target_env = "msvc")]
|
||||
pub use self::shims::*;
|
||||
#[cfg(target_env = "msvc")]
|
||||
mod shims {
|
||||
use libc::{c_float, c_int};
|
||||
|
||||
#[cfg(all(windows, target_env = "msvc"))]
|
||||
pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float {
|
||||
let (a, b) = f64::frexp(x as f64);
|
||||
*value = b as c_int;
|
||||
a as c_float
|
||||
pub unsafe fn acosf(n: c_float) -> c_float {
|
||||
f64::acos(n as f64) as c_float
|
||||
}
|
||||
|
||||
pub unsafe fn asinf(n: c_float) -> c_float {
|
||||
f64::asin(n as f64) as c_float
|
||||
}
|
||||
|
||||
pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float {
|
||||
f64::atan2(n as f64, b as f64) as c_float
|
||||
}
|
||||
|
||||
pub unsafe fn atanf(n: c_float) -> c_float {
|
||||
f64::atan(n as f64) as c_float
|
||||
}
|
||||
|
||||
pub unsafe fn coshf(n: c_float) -> c_float {
|
||||
f64::cosh(n as f64) as c_float
|
||||
}
|
||||
|
||||
pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float {
|
||||
let (a, b) = f64::frexp(x as f64);
|
||||
*value = b as c_int;
|
||||
a as c_float
|
||||
}
|
||||
|
||||
pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float {
|
||||
f64::ldexp(x as f64, n as isize) as c_float
|
||||
}
|
||||
|
||||
pub unsafe fn sinhf(n: c_float) -> c_float {
|
||||
f64::sinh(n as f64) as c_float
|
||||
}
|
||||
|
||||
pub unsafe fn tanf(n: c_float) -> c_float {
|
||||
f64::tan(n as f64) as c_float
|
||||
}
|
||||
|
||||
pub unsafe fn tanhf(n: c_float) -> c_float {
|
||||
f64::tanh(n as f64) as c_float
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -761,7 +802,13 @@ impl f32 {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn sin(self) -> f32 {
|
||||
unsafe { intrinsics::sinf32(self) }
|
||||
return sinf(self);
|
||||
|
||||
// see notes in `core::f32::Float::floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn sinf(f: f32) -> f32 { (f as f64).sin() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn sinf(f: f32) -> f32 { unsafe { intrinsics::sinf32(f) } }
|
||||
}
|
||||
|
||||
/// Computes the cosine of a number (in radians).
|
||||
@ -778,7 +825,13 @@ impl f32 {
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
#[inline]
|
||||
pub fn cos(self) -> f32 {
|
||||
unsafe { intrinsics::cosf32(self) }
|
||||
return cosf(self);
|
||||
|
||||
// see notes in `core::f32::Float::floor`
|
||||
#[cfg(target_env = "msvc")]
|
||||
fn cosf(f: f32) -> f32 { (f as f64).cos() as f32 }
|
||||
#[cfg(not(target_env = "msvc"))]
|
||||
fn cosf(f: f32) -> f32 { unsafe { intrinsics::cosf32(f) } }
|
||||
}
|
||||
|
||||
/// Computes the tangent of a number (in radians).
|
||||
|
Loading…
x
Reference in New Issue
Block a user