Skip to content

Commit 8dd28c9

Browse files
committed
implement floor and ceil with inline assembly on i586
1 parent ffe715a commit 8dd28c9

File tree

1 file changed

+52
-50
lines changed

1 file changed

+52
-50
lines changed

libm/src/math/arch/i586.rs

Lines changed: 52 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -6,31 +6,32 @@
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(); 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
3435
}
3536

3637
/// Use an alternative implementation on x86, because the
@@ -39,29 +40,30 @@ pub extern "C" fn ceil(_: f64) -> f64 {
3940
///
4041
/// Based on https://github.com/NetBSD/src/blob/trunk/lib/libm/arch/i387/s_floor.S
4142
/// (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
6769
}

0 commit comments

Comments
 (0)