pub fn ceil(mut x: f64) -> f64 {
unsafe {
core::arch::asm!(
"fld qword ptr [{x}]",
"fstcw [{x}]",
"mov word ptr [{x} + 2], 0x0b7f",
"fldcw [{x} + 2]",
"frndint",
"fldcw [{x}]",
"fstp qword ptr [{x}]",
x = in(reg) &mut x,
out("st(0)") _, out("st(1)") _,
out("st(2)") _, out("st(3)") _,
out("st(4)") _, out("st(5)") _,
out("st(6)") _, out("st(7)") _,
options(nostack),
);
}
x
}
pub fn floor(mut x: f64) -> f64 {
unsafe {
core::arch::asm!(
"fld qword ptr [{x}]",
"fstcw [{x}]",
"mov word ptr [{x} + 2], 0x077f",
"fldcw [{x} + 2]",
"frndint",
"fldcw [{x}]",
"fstp qword ptr [{x}]",
x = in(reg) &mut x,
out("st(0)") _, out("st(1)") _,
out("st(2)") _, out("st(3)") _,
out("st(4)") _, out("st(5)") _,
out("st(6)") _, out("st(7)") _,
options(nostack),
);
}
x
}
macro_rules! x87exp {
($float_ty:ident, $word_size:literal, $fn_name:ident, $load_op:literal) => {
pub fn $fn_name(mut x: $float_ty) -> $float_ty { unsafe {
core::arch::asm!(
concat!($load_op, " ", $word_size, " ptr [{x}]"),
"fld1",
"fld st(1)",
"frndint",
"fxch st(2)",
"fucom st(2)",
"fstsw ax",
"test ax, 0x4000",
"jnz 2f",
"fsub st(0), st(2)", "f2xm1", "fadd st(1), st(0)", "2:",
"fstp st(0)",
"fscale",
concat!("fstp ", $word_size, " ptr [{x}]"),
"fstp st(0)",
x = in(reg) &mut x,
out("ax") _,
out("st(0)") _, out("st(1)") _,
out("st(2)") _, out("st(3)") _,
out("st(4)") _, out("st(5)") _,
out("st(6)") _, out("st(7)") _,
options(nostack),
);
x
}}
};
}
x87exp!(f32, "dword", x87_exp2f, "fld");
x87exp!(f64, "qword", x87_exp2, "fld");
x87exp!(f32, "dword", x87_exp10f, "fldl2t\nfmul");
x87exp!(f64, "qword", x87_exp10, "fldl2t\nfmul");
x87exp!(f32, "dword", x87_expf, "fldl2e\nfmul");
x87exp!(f64, "qword", x87_exp, "fldl2e\nfmul");