diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs index aade9061657b7..c8f95a3672d4a 100644 --- a/src/libcore/num/f32.rs +++ b/src/libcore/num/f32.rs @@ -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. diff --git a/src/libcore/ops.rs b/src/libcore/ops.rs index 48b1cbeef4fdd..9a22fe3a493f1 100644 --- a/src/libcore/ops.rs +++ b/src/libcore/ops.rs @@ -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; + + // 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 + } - forward_ref_binop! { impl Rem, rem for $t, $t } + #[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 `-`. /// diff --git a/src/libstd/num/f32.rs b/src/libstd/num/f32.rs index 0c40f6c1fc8a8..c2fb2fa417598 100644 --- a/src/libstd/num/f32.rs +++ b/src/libstd/num/f32.rs @@ -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}; + + 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 + } - #[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 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).