|  | 
| 1 | 1 | //! Architecture-specific support for x86-32 without SSE2 | 
|  | 2 | +//! | 
|  | 3 | +//! We use an alternative implementation on x86, because the | 
|  | 4 | +//! main implementation fails with the x87 FPU used by | 
|  | 5 | +//! debian i386, probably due to excess precision issues. | 
|  | 6 | +//! | 
|  | 7 | +//! See https://github.com/rust-lang/compiler-builtins/pull/976 for discussion on why these | 
|  | 8 | +//! functions are implemented in this way. | 
| 2 | 9 | 
 | 
| 3 |  | -use super::super::fabs; | 
| 4 |  | - | 
| 5 |  | -/// Use an alternative implementation on x86, because the | 
| 6 |  | -/// main implementation fails with the x87 FPU used by | 
| 7 |  | -/// debian i386, probably due to excess precision issues. | 
| 8 |  | -/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. | 
| 9 |  | -pub fn ceil(x: f64) -> f64 { | 
| 10 |  | -    if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { | 
| 11 |  | -        let truncated = x as i64 as f64; | 
| 12 |  | -        if truncated < x { | 
| 13 |  | -            return truncated + 1.0; | 
| 14 |  | -        } else { | 
| 15 |  | -            return truncated; | 
| 16 |  | -        } | 
| 17 |  | -    } else { | 
| 18 |  | -        return x; | 
|  | 10 | +pub fn ceil(mut x: f64) -> f64 { | 
|  | 11 | +    unsafe { | 
|  | 12 | +        core::arch::asm!( | 
|  | 13 | +            "fld qword ptr [{x}]", | 
|  | 14 | +            // Save the FPU control word, using `x` as scratch space. | 
|  | 15 | +            "fstcw [{x}]", | 
|  | 16 | +            // Set rounding control to 0b10 (+∞). | 
|  | 17 | +            "mov word ptr [{x} + 2], 0x0b7f", | 
|  | 18 | +            "fldcw [{x} + 2]", | 
|  | 19 | +            // Round. | 
|  | 20 | +            "frndint", | 
|  | 21 | +            // Restore FPU control word. | 
|  | 22 | +            "fldcw [{x}]", | 
|  | 23 | +            // Save rounded value to memory. | 
|  | 24 | +            "fstp qword ptr [{x}]", | 
|  | 25 | +            x = in(reg) &mut x, | 
|  | 26 | +            // All the x87 FPU stack is used, all registers must be clobbered | 
|  | 27 | +            out("st(0)") _, out("st(1)") _, | 
|  | 28 | +            out("st(2)") _, out("st(3)") _, | 
|  | 29 | +            out("st(4)") _, out("st(5)") _, | 
|  | 30 | +            out("st(6)") _, out("st(7)") _, | 
|  | 31 | +            options(nostack), | 
|  | 32 | +        ); | 
| 19 | 33 |     } | 
|  | 34 | +    x | 
| 20 | 35 | } | 
| 21 | 36 | 
 | 
| 22 |  | -/// Use an alternative implementation on x86, because the | 
| 23 |  | -/// main implementation fails with the x87 FPU used by | 
| 24 |  | -/// debian i386, probably due to excess precision issues. | 
| 25 |  | -/// Basic implementation taken from https://github.com/rust-lang/libm/issues/219. | 
| 26 |  | -pub fn floor(x: f64) -> f64 { | 
| 27 |  | -    if fabs(x).to_bits() < 4503599627370496.0_f64.to_bits() { | 
| 28 |  | -        let truncated = x as i64 as f64; | 
| 29 |  | -        if truncated > x { | 
| 30 |  | -            return truncated - 1.0; | 
| 31 |  | -        } else { | 
| 32 |  | -            return truncated; | 
| 33 |  | -        } | 
| 34 |  | -    } else { | 
| 35 |  | -        return x; | 
|  | 37 | +pub fn floor(mut x: f64) -> f64 { | 
|  | 38 | +    unsafe { | 
|  | 39 | +        core::arch::asm!( | 
|  | 40 | +            "fld qword ptr [{x}]", | 
|  | 41 | +            // Save the FPU control word, using `x` as scratch space. | 
|  | 42 | +            "fstcw [{x}]", | 
|  | 43 | +            // Set rounding control to 0b01 (-∞). | 
|  | 44 | +            "mov word ptr [{x} + 2], 0x077f", | 
|  | 45 | +            "fldcw [{x} + 2]", | 
|  | 46 | +            // Round. | 
|  | 47 | +            "frndint", | 
|  | 48 | +            // Restore FPU control word. | 
|  | 49 | +            "fldcw [{x}]", | 
|  | 50 | +            // Save rounded value to memory. | 
|  | 51 | +            "fstp qword ptr [{x}]", | 
|  | 52 | +            x = in(reg) &mut x, | 
|  | 53 | +            // All the x87 FPU stack is used, all registers must be clobbered | 
|  | 54 | +            out("st(0)") _, out("st(1)") _, | 
|  | 55 | +            out("st(2)") _, out("st(3)") _, | 
|  | 56 | +            out("st(4)") _, out("st(5)") _, | 
|  | 57 | +            out("st(6)") _, out("st(7)") _, | 
|  | 58 | +            options(nostack), | 
|  | 59 | +        ); | 
| 36 | 60 |     } | 
|  | 61 | +    x | 
| 37 | 62 | } | 
0 commit comments