@@ -60,3 +60,56 @@ pub fn floor(mut x: f64) -> f64 {
6060 }
6161 x
6262}
63+
64+ macro_rules! x87exp {
65+ ( $float_ty: ident, $word_size: literal, $fn_name: ident, $load_op: literal) => {
66+ pub fn $fn_name( mut x: $float_ty) -> $float_ty { unsafe {
67+ core:: arch:: asm!(
68+ // Prepare the register stack as
69+ // ```
70+ // st(0) = y = x*log2(base)
71+ // st(1) = 1.0
72+ // st(2) = round(y)
73+ // ```
74+ concat!( $load_op, " " , $word_size, " ptr [{x}]" ) ,
75+ "fld1" ,
76+ "fld st(1)" ,
77+ "frndint" ,
78+ "fxch st(2)" ,
79+
80+ // Compare y with round(y) to determine if y is finite and
81+ // not an integer. If so, compute `exp2(y - round(y))` into
82+ // st(1). Otherwise skip ahead with `st(1) = 1.0`
83+ "fucom st(2)" ,
84+ "fstsw ax" ,
85+ "test ax, 0x4000" ,
86+ "jnz 2f" ,
87+ "fsub st(0), st(2)" , // st(0) = y - round(y)
88+ "f2xm1" , // st(0) = 2^st(0) - 1.0
89+ "fadd st(1), st(0)" , // st(1) = 1 + st(0) = exp2(y - round(y))
90+ "2:" ,
91+
92+ // Finally, scale by `exp2(round(y))` and clear the stack.
93+ "fstp st(0)" ,
94+ "fscale" ,
95+ concat!( "fstp " , $word_size, " ptr [{x}]" ) ,
96+ "fstp st(0)" ,
97+ x = in( reg) & mut x,
98+ out( "ax" ) _,
99+ out( "st(0)" ) _, out( "st(1)" ) _,
100+ out( "st(2)" ) _, out( "st(3)" ) _,
101+ out( "st(4)" ) _, out( "st(5)" ) _,
102+ out( "st(6)" ) _, out( "st(7)" ) _,
103+ options( nostack) ,
104+ ) ;
105+ x
106+ } }
107+ } ;
108+ }
109+
110+ x87exp ! ( f32 , "dword" , x87_exp2f, "fld" ) ;
111+ x87exp ! ( f64 , "qword" , x87_exp2, "fld" ) ;
112+ x87exp ! ( f32 , "dword" , x87_exp10f, "fldl2t\n fmul" ) ;
113+ x87exp ! ( f64 , "qword" , x87_exp10, "fldl2t\n fmul" ) ;
114+ x87exp ! ( f32 , "dword" , x87_expf, "fldl2e\n fmul" ) ;
115+ x87exp ! ( f64 , "qword" , x87_exp, "fldl2e\n fmul" ) ;
0 commit comments