Skip to content

Commit

Permalink
std: Avoid missing fns on i686-pc-windows-msvc
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
alexcrichton committed Jun 27, 2015
1 parent 5de665e commit 8790958
Show file tree
Hide file tree
Showing 3 changed files with 157 additions and 42 deletions.
60 changes: 54 additions & 6 deletions src/libcore/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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]
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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.
Expand Down
44 changes: 29 additions & 15 deletions src/libcore/ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 `-`.
///
Expand Down
95 changes: 74 additions & 21 deletions src/libstd/num/f32.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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;
Expand All @@ -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
}
}
}

Expand Down Expand Up @@ -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).
Expand All @@ -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).
Expand Down

0 comments on commit 8790958

Please sign in to comment.