Bin Xin

2008-03-18 22:26:40 UTC

Dear all,

I would appreciate any help in spotting what might be wrong in the

code snippet (attached at the end). A little bit of background: for

reasons not particularly relevant here, I cannot use C math library as

it is, so I have to supply my own implementation of a few math

functions that are used in my code. I searched around and eventually

enclose the following code in my C program (taken from the dietlibc

code base, with some change). The goal is to replace calls to 'log/

pow' with my version 'my_log/my_pow'.

It's working to some extent. For example the following code:

printf("%.3f\n", my_pow(2.0, 35.3));

//... some other code

printf("%.3f\n", my_pow(2.0, 35.3));

<<<

outputs:

42301799935.756

2.000

In other words, the first invocation get the right results, but not

the second one. My intuition is that both log and pow are pure

function, so this should not happen. But then again, I have limited

experience in FP coding at assembly level, so there might be some

thing I overlooked. Like maybe the special ways the FP registers or

FP status register have to be manipulated.

Thanks ahead for any comments.

-bx

Begin code snippet:

======================

double my_log(double);

double my_pow(double x, double y);

asm(".text\n"

".global my_log,my_pow,__finexp\n"

".type my_log,@function\n"

".type my_pow,@function\n"

".type __finexp,@function\n"

"my_log:\n"

"fldln2\n"

"fldl 4(%esp)\n"

"fyl2x\n"

"ret\n"

#ifndef __DYN_LIB

"__finexp:\n"

#endif

".Lfinexp:\n"

"fst %st(1)\n"

"frndint\n"

"fst %st(2)\n"

"fsubrp\n"

"f2xm1\n"

"fld1\n"

"faddp\n"

"fscale\n"

"ret\n"

#ifdef __DYN_LIB

"__finexp:\n"

"PIC_RESTORE\n"

"jmp .Lfinexp\n"

#endif

"my_pow:\n"

"fldl 4(%esp)\n"

"fldl 12(%esp)\n"

".L__pow:\n"

"ftst\n"

"fstsw %ax\n"

"fld1\n"

"sahf\n"

"jz 1f\n"

"fcomp %st(1)\n"

"fstsw %ax\n"

"fxch\n"

"sahf\n"

"jz 1f\n"

"ftst\n"

"fstsw %ax\n"

"sahf\n"

"jz 1f\n"

"jnc .Lfinpow\n"

"fxch\n"

"fld %st(0)\n"

"frndint\n"

"fcomp %st(1)\n"

"fstsw %ax\n"

"fxch\n"

"sahf\n"

"jnz .Lfinpow\n"

"fld1\n"

"fadd %st(0)\n"

"fdivr %st(2),%st(0)\n"

"frndint\n"

"fadd %st(0),%st(0)\n"

"fcomp %st(2)\n"

"fstsw %ax\n"

"fchs\n"

"sahf\n"

"jz .Lfinpow\n"

"call .Lfinpow\n"

"fchs\n"

"1: ret\n"

".Lfinpow:\n"

"fyl2x\n"

#ifdef __DYN_LIB

"PIC_SAVE\n"

"PIC_INIT\n"

"jmp ***@PLT\n"

#else

"jmp __finexp\n"

#endif

".Lende:\n"

".size my_log,.Lende-my_log\n"

".size my_pow,.Lende-my_pow\n"

".size __finexp,.Lende-__finexp\n"

);

======================

End code snippet.

I would appreciate any help in spotting what might be wrong in the

code snippet (attached at the end). A little bit of background: for

reasons not particularly relevant here, I cannot use C math library as

it is, so I have to supply my own implementation of a few math

functions that are used in my code. I searched around and eventually

enclose the following code in my C program (taken from the dietlibc

code base, with some change). The goal is to replace calls to 'log/

pow' with my version 'my_log/my_pow'.

It's working to some extent. For example the following code:

printf("%.3f\n", my_pow(2.0, 35.3));

//... some other code

printf("%.3f\n", my_pow(2.0, 35.3));

<<<

outputs:

42301799935.756

2.000

In other words, the first invocation get the right results, but not

the second one. My intuition is that both log and pow are pure

function, so this should not happen. But then again, I have limited

experience in FP coding at assembly level, so there might be some

thing I overlooked. Like maybe the special ways the FP registers or

FP status register have to be manipulated.

Thanks ahead for any comments.

-bx

Begin code snippet:

======================

double my_log(double);

double my_pow(double x, double y);

asm(".text\n"

".global my_log,my_pow,__finexp\n"

".type my_log,@function\n"

".type my_pow,@function\n"

".type __finexp,@function\n"

"my_log:\n"

"fldln2\n"

"fldl 4(%esp)\n"

"fyl2x\n"

"ret\n"

#ifndef __DYN_LIB

"__finexp:\n"

#endif

".Lfinexp:\n"

"fst %st(1)\n"

"frndint\n"

"fst %st(2)\n"

"fsubrp\n"

"f2xm1\n"

"fld1\n"

"faddp\n"

"fscale\n"

"ret\n"

#ifdef __DYN_LIB

"__finexp:\n"

"PIC_RESTORE\n"

"jmp .Lfinexp\n"

#endif

"my_pow:\n"

"fldl 4(%esp)\n"

"fldl 12(%esp)\n"

".L__pow:\n"

"ftst\n"

"fstsw %ax\n"

"fld1\n"

"sahf\n"

"jz 1f\n"

"fcomp %st(1)\n"

"fstsw %ax\n"

"fxch\n"

"sahf\n"

"jz 1f\n"

"ftst\n"

"fstsw %ax\n"

"sahf\n"

"jz 1f\n"

"jnc .Lfinpow\n"

"fxch\n"

"fld %st(0)\n"

"frndint\n"

"fcomp %st(1)\n"

"fstsw %ax\n"

"fxch\n"

"sahf\n"

"jnz .Lfinpow\n"

"fld1\n"

"fadd %st(0)\n"

"fdivr %st(2),%st(0)\n"

"frndint\n"

"fadd %st(0),%st(0)\n"

"fcomp %st(2)\n"

"fstsw %ax\n"

"fchs\n"

"sahf\n"

"jz .Lfinpow\n"

"call .Lfinpow\n"

"fchs\n"

"1: ret\n"

".Lfinpow:\n"

"fyl2x\n"

#ifdef __DYN_LIB

"PIC_SAVE\n"

"PIC_INIT\n"

"jmp ***@PLT\n"

#else

"jmp __finexp\n"

#endif

".Lende:\n"

".size my_log,.Lende-my_log\n"

".size my_pow,.Lende-my_pow\n"

".size __finexp,.Lende-__finexp\n"

);

======================

End code snippet.