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