Thank you Paul, On Wed, Nov 10, 2010 at 12:08 AM, Paul D. DeRocco <pdero...@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:pdero...@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