|  | 
| 1 | 1 | //! Architecture-specific support for x86-32 without SSE2 | 
| 2 | 2 | 
 | 
| 3 |  | -use super::super::fabs; | 
| 4 |  | - | 
| 5 | 3 | /// Use an alternative implementation on x86, because the | 
| 6 | 4 | /// main implementation fails with the x87 FPU used by | 
| 7 | 5 | /// 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; | 
| 19 |  | -    } | 
|  | 6 | +/// Based on https://github.com/NetBSD/src/blob/trunk/lib/libm/arch/i387/s_ceil.S | 
|  | 7 | +#[unsafe(naked)] | 
|  | 8 | +extern "C" fn ceil(_: f64) -> f64 { | 
|  | 9 | +    core::arch::naked_asm!( | 
|  | 10 | +        "pushl  %ebp", | 
|  | 11 | +        "movl   %esp,%ebp", | 
|  | 12 | +        "subl   $8,%esp", | 
|  | 13 | +        // Store fpu control word. | 
|  | 14 | +        "fstcw   -4(%ebp)", | 
|  | 15 | +        "movw    -4(%ebp),%dx", | 
|  | 16 | +        // Round towards +oo. | 
|  | 17 | +        "orw $0x0800,%dx", | 
|  | 18 | +        "andw    $0xfbff,%dx", | 
|  | 19 | +        "movw    %dx,-8(%ebp)", | 
|  | 20 | +        // Load modified control word | 
|  | 21 | +        "fldcw   -8(%ebp)", | 
|  | 22 | +        // Round. | 
|  | 23 | +        "fldl    8(%ebp)", | 
|  | 24 | +        "frndint", | 
|  | 25 | +        // Restore original control word. | 
|  | 26 | +        "fldcw   -4(%ebp)", | 
|  | 27 | +        // | 
|  | 28 | +        "leave", | 
|  | 29 | +        "ret", | 
|  | 30 | +        options(att_syntax) | 
|  | 31 | +    ) | 
| 20 | 32 | } | 
| 21 | 33 | 
 | 
| 22 | 34 | /// Use an alternative implementation on x86, because the | 
| 23 | 35 | /// main implementation fails with the x87 FPU used by | 
| 24 | 36 | /// 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; | 
| 36 |  | -    } | 
|  | 37 | +/// Based on https://github.com/NetBSD/src/blob/trunk/lib/libm/arch/i387/s_floor.S | 
|  | 38 | +#[unsafe(naked)] | 
|  | 39 | +extern "C" fn floor(_: f64) -> f64 { | 
|  | 40 | +    core::arch::naked_asm!( | 
|  | 41 | +        "pushl  %ebp", | 
|  | 42 | +        "movl   %esp,%ebp", | 
|  | 43 | +        "subl   $8,%esp", | 
|  | 44 | +        // Store fpu control word. | 
|  | 45 | +        "fstcw   -4(%ebp)", | 
|  | 46 | +        "movw    -4(%ebp),%dx", | 
|  | 47 | +        // Round towards -oo. | 
|  | 48 | +        "orw	$0x0400,%dx", | 
|  | 49 | +        "andw	$0xf7ff,%dx", | 
|  | 50 | +        "movw   %dx,-8(%ebp)", | 
|  | 51 | +        // Load modified control word | 
|  | 52 | +        "fldcw   -8(%ebp)", | 
|  | 53 | +        // Round. | 
|  | 54 | +        "fldl    8(%ebp)", | 
|  | 55 | +        "frndint", | 
|  | 56 | +        // Restore original control word. | 
|  | 57 | +        "fldcw   -4(%ebp)", | 
|  | 58 | +        // | 
|  | 59 | +        "leave", | 
|  | 60 | +        "ret", | 
|  | 61 | +        options(att_syntax) | 
|  | 62 | +    ) | 
| 37 | 63 | } | 
0 commit comments