Skip to content

Commit 8790958

Browse files
committed
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.
1 parent 5de665e commit 8790958

File tree

3 files changed

+157
-42
lines changed

3 files changed

+157
-42
lines changed

src/libcore/num/f32.rs

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,13 +215,37 @@ impl Float for f32 {
215215
/// Rounds towards minus infinity.
216216
#[inline]
217217
fn floor(self) -> f32 {
218-
unsafe { intrinsics::floorf32(self) }
218+
return floorf(self);
219+
220+
// On MSVC LLVM will lower many math intrinsics to a call to the
221+
// corresponding function. On MSVC, however, many of these functions
222+
// aren't actually available as symbols to call, but rather they are all
223+
// `static inline` functions in header files. This means that from a C
224+
// perspective it's "compatible", but not so much from an ABI
225+
// perspective (which we're worried about).
226+
//
227+
// The inline header functions always just cast to a f64 and do their
228+
// operation, so we do that here as well, but only for MSVC targets.
229+
//
230+
// Note that there are many MSVC-specific float operations which
231+
// redirect to this comment, so `floorf` is just one case of a missing
232+
// function on MSVC, but there are many others elsewhere.
233+
#[cfg(target_env = "msvc")]
234+
fn floorf(f: f32) -> f32 { (f as f64).floor() as f32 }
235+
#[cfg(not(target_env = "msvc"))]
236+
fn floorf(f: f32) -> f32 { unsafe { intrinsics::floorf32(f) } }
219237
}
220238

221239
/// Rounds towards plus infinity.
222240
#[inline]
223241
fn ceil(self) -> f32 {
224-
unsafe { intrinsics::ceilf32(self) }
242+
return ceilf(self);
243+
244+
// see notes above in `floor`
245+
#[cfg(target_env = "msvc")]
246+
fn ceilf(f: f32) -> f32 { (f as f64).ceil() as f32 }
247+
#[cfg(not(target_env = "msvc"))]
248+
fn ceilf(f: f32) -> f32 { unsafe { intrinsics::ceilf32(f) } }
225249
}
226250

227251
/// Rounds to nearest integer. Rounds half-way cases away from zero.
@@ -299,7 +323,13 @@ impl Float for f32 {
299323

300324
#[inline]
301325
fn powf(self, n: f32) -> f32 {
302-
unsafe { intrinsics::powf32(self, n) }
326+
return powf(self, n);
327+
328+
// see notes above in `floor`
329+
#[cfg(target_env = "msvc")]
330+
fn powf(f: f32, n: f32) -> f32 { (f as f64).powf(n as f64) as f32 }
331+
#[cfg(not(target_env = "msvc"))]
332+
fn powf(f: f32, n: f32) -> f32 { unsafe { intrinsics::powf32(f, n) } }
303333
}
304334

305335
#[inline]
@@ -317,7 +347,13 @@ impl Float for f32 {
317347
/// Returns the exponential of the number.
318348
#[inline]
319349
fn exp(self) -> f32 {
320-
unsafe { intrinsics::expf32(self) }
350+
return expf(self);
351+
352+
// see notes above in `floor`
353+
#[cfg(target_env = "msvc")]
354+
fn expf(f: f32) -> f32 { (f as f64).exp() as f32 }
355+
#[cfg(not(target_env = "msvc"))]
356+
fn expf(f: f32) -> f32 { unsafe { intrinsics::expf32(f) } }
321357
}
322358

323359
/// Returns 2 raised to the power of the number.
@@ -329,7 +365,13 @@ impl Float for f32 {
329365
/// Returns the natural logarithm of the number.
330366
#[inline]
331367
fn ln(self) -> f32 {
332-
unsafe { intrinsics::logf32(self) }
368+
return logf(self);
369+
370+
// see notes above in `floor`
371+
#[cfg(target_env = "msvc")]
372+
fn logf(f: f32) -> f32 { (f as f64).ln() as f32 }
373+
#[cfg(not(target_env = "msvc"))]
374+
fn logf(f: f32) -> f32 { unsafe { intrinsics::logf32(f) } }
333375
}
334376

335377
/// Returns the logarithm of the number with respect to an arbitrary base.
@@ -345,7 +387,13 @@ impl Float for f32 {
345387
/// Returns the base 10 logarithm of the number.
346388
#[inline]
347389
fn log10(self) -> f32 {
348-
unsafe { intrinsics::log10f32(self) }
390+
return log10f(self);
391+
392+
// see notes above in `floor`
393+
#[cfg(target_env = "msvc")]
394+
fn log10f(f: f32) -> f32 { (f as f64).log10() as f32 }
395+
#[cfg(not(target_env = "msvc"))]
396+
fn log10f(f: f32) -> f32 { unsafe { intrinsics::log10f32(f) } }
349397
}
350398

351399
/// Converts to degrees, assuming the number is in radians.

src/libcore/ops.rs

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -419,26 +419,40 @@ macro_rules! rem_impl {
419419
)*)
420420
}
421421

422-
macro_rules! rem_float_impl {
423-
($t:ty, $fmod:ident) => {
424-
#[stable(feature = "rust1", since = "1.0.0")]
425-
impl Rem for $t {
426-
type Output = $t;
422+
rem_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
427423

428-
#[inline]
429-
fn rem(self, other: $t) -> $t {
430-
extern { fn $fmod(a: $t, b: $t) -> $t; }
431-
unsafe { $fmod(self, other) }
432-
}
433-
}
424+
#[stable(feature = "rust1", since = "1.0.0")]
425+
impl Rem for f32 {
426+
type Output = f32;
427+
428+
// see notes in `core::f32::Float::floor`
429+
#[inline]
430+
#[cfg(target_env = "msvc")]
431+
fn rem(self, other: f32) -> f32 {
432+
(self as f64).rem(other as f64) as f32
433+
}
434434

435-
forward_ref_binop! { impl Rem, rem for $t, $t }
435+
#[inline]
436+
#[cfg(not(target_env = "msvc"))]
437+
fn rem(self, other: f32) -> f32 {
438+
extern { fn fmodf(a: f32, b: f32) -> f32; }
439+
unsafe { fmodf(self, other) }
436440
}
437441
}
438442

439-
rem_impl! { usize u8 u16 u32 u64 isize i8 i16 i32 i64 }
440-
rem_float_impl! { f32, fmodf }
441-
rem_float_impl! { f64, fmod }
443+
#[stable(feature = "rust1", since = "1.0.0")]
444+
impl Rem for f64 {
445+
type Output = f64;
446+
447+
#[inline]
448+
fn rem(self, other: f64) -> f64 {
449+
extern { fn fmod(a: f64, b: f64) -> f64; }
450+
unsafe { fmod(self, other) }
451+
}
452+
}
453+
454+
forward_ref_binop! { impl Rem, rem for f64, f64 }
455+
forward_ref_binop! { impl Rem, rem for f32, f32 }
442456

443457
/// The `Neg` trait is used to specify the functionality of unary `-`.
444458
///

src/libstd/num/f32.rs

Lines changed: 74 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use prelude::v1::*;
1919

2020
use core::num;
21+
#[cfg(not(target_env = "msvc"))]
2122
use intrinsics;
2223
use libc::c_int;
2324
use num::{FpCategory, ParseFloatError};
@@ -33,12 +34,7 @@ mod cmath {
3334
use libc::{c_float, c_int};
3435

3536
extern {
36-
pub fn acosf(n: c_float) -> c_float;
37-
pub fn asinf(n: c_float) -> c_float;
38-
pub fn atanf(n: c_float) -> c_float;
39-
pub fn atan2f(a: c_float, b: c_float) -> c_float;
4037
pub fn cbrtf(n: c_float) -> c_float;
41-
pub fn coshf(n: c_float) -> c_float;
4238
pub fn erff(n: c_float) -> c_float;
4339
pub fn erfcf(n: c_float) -> c_float;
4440
pub fn expm1f(n: c_float) -> c_float;
@@ -51,32 +47,77 @@ mod cmath {
5147
pub fn log1pf(n: c_float) -> c_float;
5248
pub fn ilogbf(n: c_float) -> c_int;
5349
pub fn modff(n: c_float, iptr: &mut c_float) -> c_float;
54-
pub fn sinhf(n: c_float) -> c_float;
55-
pub fn tanf(n: c_float) -> c_float;
56-
pub fn tanhf(n: c_float) -> c_float;
5750
pub fn tgammaf(n: c_float) -> c_float;
5851

5952
#[cfg_attr(all(windows, target_env = "msvc"), link_name = "__lgammaf_r")]
6053
pub fn lgammaf_r(n: c_float, sign: &mut c_int) -> c_float;
6154
#[cfg_attr(all(windows, target_env = "msvc"), link_name = "_hypotf")]
6255
pub fn hypotf(x: c_float, y: c_float) -> c_float;
56+
}
6357

64-
#[cfg(any(unix, all(windows, not(target_env = "msvc"))))]
58+
// See the comments in `core::float::Float::floor` for why MSVC is special
59+
// here.
60+
#[cfg(not(target_env = "msvc"))]
61+
extern {
62+
pub fn acosf(n: c_float) -> c_float;
63+
pub fn asinf(n: c_float) -> c_float;
64+
pub fn atan2f(a: c_float, b: c_float) -> c_float;
65+
pub fn atanf(n: c_float) -> c_float;
66+
pub fn coshf(n: c_float) -> c_float;
6567
pub fn frexpf(n: c_float, value: &mut c_int) -> c_float;
66-
#[cfg(any(unix, all(windows, not(target_env = "msvc"))))]
6768
pub fn ldexpf(x: c_float, n: c_int) -> c_float;
69+
pub fn sinhf(n: c_float) -> c_float;
70+
pub fn tanf(n: c_float) -> c_float;
71+
pub fn tanhf(n: c_float) -> c_float;
6872
}
6973

70-
#[cfg(all(windows, target_env = "msvc"))]
71-
pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float {
72-
f64::ldexp(x as f64, n as isize) as c_float
73-
}
74+
#[cfg(target_env = "msvc")]
75+
pub use self::shims::*;
76+
#[cfg(target_env = "msvc")]
77+
mod shims {
78+
use libc::{c_float, c_int};
79+
80+
pub unsafe fn acosf(n: c_float) -> c_float {
81+
f64::acos(n as f64) as c_float
82+
}
83+
84+
pub unsafe fn asinf(n: c_float) -> c_float {
85+
f64::asin(n as f64) as c_float
86+
}
87+
88+
pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float {
89+
f64::atan2(n as f64, b as f64) as c_float
90+
}
91+
92+
pub unsafe fn atanf(n: c_float) -> c_float {
93+
f64::atan(n as f64) as c_float
94+
}
95+
96+
pub unsafe fn coshf(n: c_float) -> c_float {
97+
f64::cosh(n as f64) as c_float
98+
}
99+
100+
pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float {
101+
let (a, b) = f64::frexp(x as f64);
102+
*value = b as c_int;
103+
a as c_float
104+
}
105+
106+
pub unsafe fn ldexpf(x: c_float, n: c_int) -> c_float {
107+
f64::ldexp(x as f64, n as isize) as c_float
108+
}
109+
110+
pub unsafe fn sinhf(n: c_float) -> c_float {
111+
f64::sinh(n as f64) as c_float
112+
}
74113

75-
#[cfg(all(windows, target_env = "msvc"))]
76-
pub unsafe fn frexpf(x: c_float, value: &mut c_int) -> c_float {
77-
let (a, b) = f64::frexp(x as f64);
78-
*value = b as c_int;
79-
a as c_float
114+
pub unsafe fn tanf(n: c_float) -> c_float {
115+
f64::tan(n as f64) as c_float
116+
}
117+
118+
pub unsafe fn tanhf(n: c_float) -> c_float {
119+
f64::tanh(n as f64) as c_float
120+
}
80121
}
81122
}
82123

@@ -761,7 +802,13 @@ impl f32 {
761802
#[stable(feature = "rust1", since = "1.0.0")]
762803
#[inline]
763804
pub fn sin(self) -> f32 {
764-
unsafe { intrinsics::sinf32(self) }
805+
return sinf(self);
806+
807+
// see notes in `core::f32::Float::floor`
808+
#[cfg(target_env = "msvc")]
809+
fn sinf(f: f32) -> f32 { (f as f64).sin() as f32 }
810+
#[cfg(not(target_env = "msvc"))]
811+
fn sinf(f: f32) -> f32 { unsafe { intrinsics::sinf32(f) } }
765812
}
766813

767814
/// Computes the cosine of a number (in radians).
@@ -778,7 +825,13 @@ impl f32 {
778825
#[stable(feature = "rust1", since = "1.0.0")]
779826
#[inline]
780827
pub fn cos(self) -> f32 {
781-
unsafe { intrinsics::cosf32(self) }
828+
return cosf(self);
829+
830+
// see notes in `core::f32::Float::floor`
831+
#[cfg(target_env = "msvc")]
832+
fn cosf(f: f32) -> f32 { (f as f64).cos() as f32 }
833+
#[cfg(not(target_env = "msvc"))]
834+
fn cosf(f: f32) -> f32 { unsafe { intrinsics::cosf32(f) } }
782835
}
783836

784837
/// Computes the tangent of a number (in radians).

0 commit comments

Comments
 (0)