@@ -65,6 +65,7 @@ use trans::cleanup::{self, CleanupMethods, DropHintMethods};
6565use trans:: common:: * ;
6666use trans:: datum:: * ;
6767use trans:: debuginfo:: { self , DebugLoc , ToDebugLoc } ;
68+ use trans:: declare;
6869use trans:: glue;
6970use trans:: machine;
7071use trans:: meth;
@@ -1767,7 +1768,43 @@ fn trans_eager_binop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
17671768 }
17681769 ast:: BiRem => {
17691770 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+ }
17711808 } else {
17721809 // Only zero-check integers; fp %0 is NaN
17731810 bcx = base:: fail_if_zero_or_overflows ( bcx,
0 commit comments