about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-06-25 15:33:42 -0700
committerAlex Crichton <alex@alexcrichton.com>2015-06-27 13:02:18 -0700
commit87909582374be91bc5affdd2e74e265077a6e571 (patch)
tree3a2ce54e6683a4c38fb85008e1cf909a59252d9e
parent5de665e8b31fc0459839c6377157b9559e4679cc (diff)
downloadrust-87909582374be91bc5affdd2e74e265077a6e571.tar.gz
rust-87909582374be91bc5affdd2e74e265077a6e571.zip
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.
-rw-r--r--src/libcore/num/f32.rs60
-rw-r--r--src/libcore/ops.rs44
-rw-r--r--src/libstd/num/f32.rs95
3 files changed, 157 insertions, 42 deletions
diff --git a/src/libcore/num/f32.rs b/src/libcore/num/f32.rs
index aade9061657..c8f95a3672d 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 48b1cbeef4f..9a22fe3a493 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 0c40f6c1fc8..c2fb2fa4175 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).