@@ -65,6 +65,7 @@ use trans::cleanup::{self, CleanupMethods, DropHintMethods};
65
65
use trans:: common:: * ;
66
66
use trans:: datum:: * ;
67
67
use trans:: debuginfo:: { self , DebugLoc , ToDebugLoc } ;
68
+ use trans:: declare;
68
69
use trans:: glue;
69
70
use trans:: machine;
70
71
use trans:: meth;
@@ -1767,7 +1768,43 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
1767
1768
}
1768
1769
ast:: BiRem => {
1769
1770
if is_float {
1770
- FRem ( bcx, lhs, rhs, binop_debug_loc)
1771
+ // LLVM currently always lowers the `frem` instructions appropriate
1772
+ // library calls typically found in libm. Notably f64 gets wired up
1773
+ // to `fmod` and f32 gets wired up to `fmodf`. Inconveniently for
1774
+ // us, 32-bit MSVC does not actually have a `fmodf` symbol, it's
1775
+ // instead just an inline function in a header that goes up to a
1776
+ // f64, uses `fmod`, and then comes back down to a f32.
1777
+ //
1778
+ // Although LLVM knows that `fmodf` doesn't exist on MSVC, it will
1779
+ // still unconditionally lower frem instructions over 32-bit floats
1780
+ // to a call to `fmodf`. To work around this we special case MSVC
1781
+ // 32-bit float rem instructions and instead do the call out to
1782
+ // `fmod` ourselves.
1783
+ //
1784
+ // Note that this is currently duplicated with src/libcore/ops.rs
1785
+ // which does the same thing, and it would be nice to perhaps unify
1786
+ // these two implementations on day! Also note that we call `fmod`
1787
+ // for both 32 and 64-bit floats because if we emit any FRem
1788
+ // instruction at all then LLVM is capable of optimizing it into a
1789
+ // 32-bit FRem (which we're trying to avoid).
1790
+ let use_fmod = tcx. sess . target . target . options . is_like_msvc &&
1791
+ tcx. sess . target . target . arch == "x86" ;
1792
+ if use_fmod {
1793
+ let f64t = Type :: f64 ( bcx. ccx ( ) ) ;
1794
+ let fty = Type :: func ( & [ f64t, f64t] , & f64t) ;
1795
+ let llfn = declare:: declare_cfn ( bcx. ccx ( ) , "fmod" , fty,
1796
+ tcx. types . f64 ) ;
1797
+ if lhs_t == tcx. types . f32 {
1798
+ let lhs = FPExt ( bcx, lhs, f64t) ;
1799
+ let rhs = FPExt ( bcx, rhs, f64t) ;
1800
+ let res = Call ( bcx, llfn, & [ lhs, rhs] , None , binop_debug_loc) ;
1801
+ FPTrunc ( bcx, res, Type :: f32 ( bcx. ccx ( ) ) )
1802
+ } else {
1803
+ Call ( bcx, llfn, & [ lhs, rhs] , None , binop_debug_loc)
1804
+ }
1805
+ } else {
1806
+ FRem ( bcx, lhs, rhs, binop_debug_loc)
1807
+ }
1771
1808
} else {
1772
1809
// Only zero-check integers; fp %0 is NaN
1773
1810
bcx = base:: fail_if_zero_or_overflows ( bcx,
0 commit comments