[ECOS] issue with floor()

David Brennan david@brennanhome.com
Wed Nov 10 14:34:00 GMT 2010


Thank you Paul,

On Wed, Nov 10, 2010 at 12:08 AM, Paul D. DeRocco
<pderocco@ix.netcom.com> wrote:
>> From: David Brennan
>>
>> I am using a relatively recent CVS of eCos on an x86 VME
>> target. I am trying to get an existing application working,
>> and I stumbled across an unusual result.
>>
>> The code called floor() with a value of 0.048000000000000001.
>> the correct return value should have been 0.0.
>>
>> Single stepping through the "bit twiddling" looked like it
>> was pursuing the correct code path, but at this point,
>> somthing went wrong.
>>
>> 97                    if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
>> (gdb) s
>> 98                        if(i0>=0) {i0=i1=0;}
>> (gdb) p i0
>> $4 = 8
>> (gdb) s
>> 131   }
>> (gdb) info locals
>> i0 = 8
>> j0 = -5
>> i = 1067989024
>> x = 0.048000000000000001
>> (gdb) li
>> 126               }
>> 127           }
>> 128           CYG_LIBM_HI(x) = i0;
>> 129           CYG_LIBM_LO(x) = i1;
>> 130           return x;
>> 131   }
>> 132
>> 133   #endif // ifdef CYGPKG_LIBM
>> 134
>> 135   // EOF s_floor.c
>>
>> It appears that the code did not run line 98 correctly.
>
> <snip>
>
>> I am using a compiler that I built (so that is most likely
>> the problem). I am using OS X for my host, and there are not
>> pre-built binaries for that.
>
> I would think examining the assembly language would clear up the mystery,
> especially if you find the problem persists with optimization turned off.
> For instance, it could be that the arithmetic doesn't work because
> something's busted in the FP support, but the sign test works correctly
> because it doesn't use an FP instruction to test the sign.
>
> --
>
> Ciao,               Paul D. DeRocco
> Paul                mailto:pderocco@ix.netcom.com
>

Here is the disassemlby of floor.o

clifford:eCosHighRam david$ i386-elf-objdump -d -S
language/c/libm/current/src/double/portable-api/language_c_libm_s_floor.o

language/c/libm/current/src/double/portable-api/language_c_libm_s_floor.o:
    file format elf32-i386


Disassembly of section .text.floor:

00000000 <floor>:

        double floor(double x)
{
        int i0,i1,j0;
        unsigned i,j;
        i0 =  CYG_LIBM_HI(x);
   0:	55                   	push   %ebp
   1:	89 e5                	mov    %esp,%ebp
   3:	57                   	push   %edi
   4:	56                   	push   %esi
   5:	53                   	push   %ebx
   6:	83 ec 0c             	sub    $0xc,%esp
   9:	8b 75 08             	mov    0x8(%ebp),%esi
   c:	89 75 e8             	mov    %esi,-0x18(%ebp)
   f:	8b 55 0c             	mov    0xc(%ebp),%edx
  12:	89 55 ec             	mov    %edx,-0x14(%ebp)
        i1 =  CYG_LIBM_LO(x);
        j0 = ((i0>>20)&0x7ff)-0x3ff;
  15:	89 d1                	mov    %edx,%ecx
  17:	c1 f9 14             	sar    $0x14,%ecx
  1a:	81 e1 ff 07 00 00    	and    $0x7ff,%ecx
  20:	8d 99 01 fc ff ff    	lea    -0x3ff(%ecx),%ebx
        if(j0<20) {
  26:	83 fb 13             	cmp    $0x13,%ebx
  29:	7f 1d                	jg     48 <floor+0x48>
            if(j0<0) {  /* raise inexact if x != 0 */
  2b:	85 db                	test   %ebx,%ebx
  2d:	78 61                	js     90 <floor+0x90>
                    if(i0>=0) {i0=i1=0;}
                    else if(((i0&0x7fffffff)|i1)!=0)
                        { i0=0xbff00000;i1=0;}
                }
            } else {
                i = (0x000fffff)>>j0;
  2f:	b8 ff ff 0f 00       	mov    $0xfffff,%eax
  34:	88 d9                	mov    %bl,%cl
  36:	d3 f8                	sar    %cl,%eax
                if(((i0&i)|i1)==0) return x; /* x is integral */
  38:	85 d0                	test   %edx,%eax
  3a:	74 78                	je     b4 <floor+0xb4>
                if(huge+x>0.0) {        /* raise inexact flag */
  3c:	dd 45 e8             	fldl   -0x18(%ebp)
            }
        }
        CYG_LIBM_HI(x) = i0;
        CYG_LIBM_LO(x) = i1;
        return x;
}
  3f:	83 c4 0c             	add    $0xc,%esp
  42:	5b                   	pop    %ebx
  43:	5e                   	pop    %esi
  44:	5f                   	pop    %edi
  45:	c9                   	leave
  46:	c3                   	ret
  47:	90                   	nop
                if(huge+x>0.0) {        /* raise inexact flag */
                    if(i0<0) i0 += (0x00100000)>>j0;
                    i0 &= (~i); i1=0;
                }
            }
        } else if (j0>51) {
  48:	83 fb 33             	cmp    $0x33,%ebx
  4b:	7e 13                	jle    60 <floor+0x60>
            if(j0==0x400) return x+x;   /* inf or NaN */
  4d:	81 fb 00 04 00 00    	cmp    $0x400,%ebx
  53:	74 57                	je     ac <floor+0xac>
            else return x;              /* x is integral */
        } else {
            i = ((unsigned)(0xffffffff))>>(j0-20);
            if((i1&i)==0) return x;     /* x is integral */
  55:	dd 45 e8             	fldl   -0x18(%ebp)
            }
        }
        CYG_LIBM_HI(x) = i0;
        CYG_LIBM_LO(x) = i1;
        return x;
}
  58:	83 c4 0c             	add    $0xc,%esp
  5b:	5b                   	pop    %ebx
  5c:	5e                   	pop    %esi
  5d:	5f                   	pop    %edi
  5e:	c9                   	leave
  5f:	c3                   	ret
            }
        } else if (j0>51) {
            if(j0==0x400) return x+x;   /* inf or NaN */
            else return x;              /* x is integral */
        } else {
            i = ((unsigned)(0xffffffff))>>(j0-20);
  60:	81 e9 13 04 00 00    	sub    $0x413,%ecx
  66:	b8 ff ff ff ff       	mov    $0xffffffff,%eax
  6b:	d3 e8                	shr    %cl,%eax
            if((i1&i)==0) return x;     /* x is integral */
  6d:	85 f0                	test   %esi,%eax
  6f:	74 e4                	je     55 <floor+0x55>
            if(huge+x>0.0) {            /* raise inexact flag */
  71:	dd 45 e8             	fldl   -0x18(%ebp)
  74:	dd 05 00 00 00 00    	fldl   0x0
  7a:	d8 c1                	fadd   %st(1),%st
  7c:	d9 ee                	fldz
  7e:	d9 c9                	fxch   %st(1)
  80:	da e9                	fucompp
  82:	df e0                	fnstsw %ax
  84:	f6 c4 45             	test   $0x45,%ah
  87:	75 b6                	jne    3f <floor+0x3f>
                if(i0<0) {
  89:	85 d2                	test   %edx,%edx
  8b:	eb b2                	jmp    3f <floor+0x3f>
  8d:	8d 76 00             	lea    0x0(%esi),%esi
        i0 =  CYG_LIBM_HI(x);
        i1 =  CYG_LIBM_LO(x);
        j0 = ((i0>>20)&0x7ff)-0x3ff;
        if(j0<20) {
            if(j0<0) {  /* raise inexact if x != 0 */
                if(huge+x>0.0) {/* return 0*sign(x) if |x|<1 */
  90:	dd 45 e8             	fldl   -0x18(%ebp)
  93:	dd 05 00 00 00 00    	fldl   0x0
  99:	d8 c1                	fadd   %st(1),%st
  9b:	d9 ee                	fldz
  9d:	d9 c9                	fxch   %st(1)
  9f:	da e9                	fucompp
  a1:	df e0                	fnstsw %ax
  a3:	f6 c4 45             	test   $0x45,%ah
  a6:	75 97                	jne    3f <floor+0x3f>
                    if(i0>=0) {i0=i1=0;}
  a8:	85 d2                	test   %edx,%edx
  aa:	eb 93                	jmp    3f <floor+0x3f>
                    if(i0<0) i0 += (0x00100000)>>j0;
                    i0 &= (~i); i1=0;
                }
            }
        } else if (j0>51) {
            if(j0==0x400) return x+x;   /* inf or NaN */
  ac:	dd 45 e8             	fldl   -0x18(%ebp)
  af:	d8 c0                	fadd   %st(0),%st
  b1:	eb 8c                	jmp    3f <floor+0x3f>
  b3:	90                   	nop
                    else if(((i0&0x7fffffff)|i1)!=0)
                        { i0=0xbff00000;i1=0;}
                }
            } else {
                i = (0x000fffff)>>j0;
                if(((i0&i)|i1)==0) return x; /* x is integral */
  b4:	85 f6                	test   %esi,%esi
  b6:	75 84                	jne    3c <floor+0x3c>
  b8:	eb 9b                	jmp    55 <floor+0x55>

Unfornately in its optimized state, (and my very meager x86 assembly
skills), I can't really follow if it is correct.

But it does seem that this instruction is wrong:
aa:	eb 93                	jmp    3f <floor+0x3f>
Because at this point it does not look like i0 and i1 have been set to
0, which is exactly the problem that I saw single stepping in C.

I will re-run the floor test later today without optimization. But if
that solves the problem, then what? Is this a gcc bug? Or a gcc
configuration error?

Thanks again for your help
David Brennan

--
Before posting, please read the FAQ: http://ecos.sourceware.org/fom/ecos
and search the list archive: http://ecos.sourceware.org/ml/ecos-discuss



More information about the Ecos-discuss mailing list