66///
77/// Based on https://github.com/NetBSD/src/blob/trunk/lib/libm/arch/i387/s_ceil.S
88/// (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
3436}
3537
3638/// Use an alternative implementation on x86, because the
@@ -39,29 +41,31 @@ pub extern "C" fn ceil(_: f64) -> f64 {
3941///
4042/// Based on https://github.com/NetBSD/src/blob/trunk/lib/libm/arch/i387/s_floor.S
4143/// (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
6771}
0 commit comments