6
6
///
7
7
/// Based on https://github.com/NetBSD/src/blob/trunk/lib/libm/arch/i387/s_ceil.S
8
8
/// (written by J.T. Conklin <[email protected] >).
9
- #[ unsafe( naked) ]
10
- pub extern "C" fn ceil ( _: f64 ) -> f64 {
11
- core:: arch:: naked_asm!(
12
- "pushl %ebp" ,
13
- "movl %esp,%ebp" ,
14
- "subl $8,%esp" ,
15
- // Store fpu control word.
16
- "fstcw -4(%ebp)" ,
17
- "movw -4(%ebp),%dx" ,
18
- // Round towards +oo.
19
- "orw $0x0800,%dx" ,
20
- "andw $0xfbff,%dx" ,
21
- "movw %dx,-8(%ebp)" ,
22
- // Load modified control word
23
- "fldcw -8(%ebp)" ,
24
- // Round.
25
- "fldl 8(%ebp)" ,
26
- "frndint" ,
27
- // Restore original control word.
28
- "fldcw -4(%ebp)" ,
29
- // Restore esp and ebp and return
30
- "leave" ,
31
- "ret" ,
32
- options( att_syntax)
33
- )
9
+ pub fn ceil ( mut x : f64 ) -> f64 {
10
+ // We save and later restore the FPU control word.
11
+ let mut cw_stash = [ core:: mem:: MaybeUninit :: < u16 > :: uninit ( ) ; 2 ] ;
12
+ unsafe {
13
+ core:: arch:: asm!(
14
+ "fstcw ({stash_ptr})" , // Save the cw
15
+ "movw ({stash_ptr}), %dx" , // ...
16
+ "orw $0x0800, %dx" , // Set rounding control to 0b10 (+∞),
17
+ "andw $0xfbff, %dx" , // preserving other controls
18
+ "movw %dx, ({cw_ptr})" , // Apply cw
19
+ "fldcw ({cw_ptr})" , // ...
20
+ "fldl ({x_ptr})" , // Push x to the stack
21
+ "frndint" , // Round
22
+ "fldcw ({stash_ptr})" , // Restore cw
23
+ "fstpl ({x_ptr})" , // Save rounded x to mem
24
+ cw_ptr = in( reg) cw_stash[ 0 ] . as_mut_ptr( ) ,
25
+ stash_ptr = in( reg) cw_stash[ 1 ] . as_mut_ptr( ) ,
26
+ x_ptr = in( reg) & mut x,
27
+ out( "dx" ) _, // Cw scratch
28
+ // All the x87 FPU stack is used, all registers must be clobbered
29
+ out( "st(0)" ) _, out( "st(1)" ) _, out( "st(2)" ) _, out( "st(3)" ) _,
30
+ out( "st(4)" ) _, out( "st(5)" ) _, out( "st(6)" ) _, out( "st(7)" ) _,
31
+ options( att_syntax)
32
+ )
33
+ }
34
+ x
34
35
}
35
36
36
37
/// Use an alternative implementation on x86, because the
@@ -39,29 +40,30 @@ pub extern "C" fn ceil(_: f64) -> f64 {
39
40
///
40
41
/// Based on https://github.com/NetBSD/src/blob/trunk/lib/libm/arch/i387/s_floor.S
41
42
/// (written by J.T. Conklin <[email protected] >).
42
- #[ unsafe( naked) ]
43
- pub extern "C" fn floor ( _: f64 ) -> f64 {
44
- core:: arch:: naked_asm!(
45
- "pushl %ebp" ,
46
- "movl %esp,%ebp" ,
47
- "subl $8,%esp" ,
48
- // Store fpu control word.
49
- "fstcw -4(%ebp)" ,
50
- "movw -4(%ebp),%dx" ,
51
- // Round towards -oo.
52
- "orw $0x0400,%dx" ,
53
- "andw $0xf7ff,%dx" ,
54
- "movw %dx,-8(%ebp)" ,
55
- // Load modified control word
56
- "fldcw -8(%ebp)" ,
57
- // Round.
58
- "fldl 8(%ebp)" ,
59
- "frndint" ,
60
- // Restore original control word.
61
- "fldcw -4(%ebp)" ,
62
- // Restore esp and ebp and return
63
- "leave" ,
64
- "ret" ,
65
- options( att_syntax)
66
- )
43
+ pub fn floor ( mut x : f64 ) -> f64 {
44
+ // We save and later restore the FPU control word.
45
+ let mut cw_stash = [ core:: mem:: MaybeUninit :: < u16 > :: uninit ( ) ; 2 ] ;
46
+ unsafe {
47
+ core:: arch:: asm!(
48
+ "fstcw ({stash_ptr})" , // Save the cw
49
+ "movw ({stash_ptr}), %dx" , // ...
50
+ "orw $0x0400, %dx" , // Set rounding control to 0b01 (-∞),
51
+ "andw $0xf7ff, %dx" , // preserving other controls
52
+ "movw %dx, ({cw_ptr})" , // Apply cw
53
+ "fldcw ({cw_ptr})" , // ...
54
+ "fldl ({x_ptr})" , // Push x to the stack
55
+ "frndint" , // Round
56
+ "fldcw ({stash_ptr})" , // Restore cw
57
+ "fstpl ({x_ptr})" , // Save rounded x to mem
58
+ cw_ptr = in( reg) cw_stash[ 0 ] . as_mut_ptr( ) ,
59
+ stash_ptr = in( reg) cw_stash[ 1 ] . as_mut_ptr( ) ,
60
+ x_ptr = in( reg) & mut x,
61
+ out( "dx" ) _, // Cw scratch
62
+ // All the x87 FPU stack is used, all registers must be clobbered
63
+ out( "st(0)" ) _, out( "st(1)" ) _, out( "st(2)" ) _, out( "st(3)" ) _,
64
+ out( "st(4)" ) _, out( "st(5)" ) _, out( "st(6)" ) _, out( "st(7)" ) _,
65
+ options( att_syntax)
66
+ )
67
+ }
68
+ x
67
69
}
0 commit comments