Date: Sun, 10 Mar 2002 00:38:54 -0500 (EST) From: Garrett Wollman <wollman@lcs.mit.edu> To: sparc@freebsd.org Subject: Details of float->unsigned long conversion bug Message-ID: <200203100538.g2A5csD04413@khavrinen.lcs.mit.edu>
next in thread | raw e-mail | index | archive | help
Posted by request of David O'Brien. ------- start of forwarded message (RFC 934 encapsulation) ------- In-Reply-To: <20020309185700.C75152@dragon.nuxi.com> References: <200203092111.g29LB1O61538@freefall.freebsd.org> <200203092114.g29LEIk00987@khavrinen.lcs.mit.edu> <20020309142222.A75252@dragon.nuxi.com> <200203100031.g2A0Vjr02401@khavrinen.lcs.mit.edu> <20020309185700.C75152@dragon.nuxi.com> To: obrien@FreeBSD.org Cc: tmm@freebsd.org, jake@freebsd.org Subject: Re: serious sparc64 toolchain bug <<On Sat, 9 Mar 2002 18:57:00 -0800, "David O'Brien" <obrien@FreeBSD.org> said: > I am trying to build a new toolchain for tomarrow's ISO. > I'll play with this on the newer compiler. Actually, having spent some time looking at the code which is generated, I'm convinced that it is (at least logically) correct. Do we emulate quad-length floating-point? If so, then it may be a bug in the emulator. Here's the code GCC generates for my test program, with comments: .file "foo.c" .section .rodata.str1.8,"aMS",@progbits,1 .align 8 .LLC0: .asciz "as int: %d\n" .align 8 .LLC1: .asciz "as unsigned int: %u\n" .align 8 .LLC2: .asciz "as long: %ld\n" .align 8 .LLC3: .asciz "as unsigned long: %lu\n" .section ".rodata" .align 16 ! ! The following constant is 2**63 as a long double, verified by ! printing it from another program. ! .LLC4: .long 1077805056 .long 0 .long 0 .long 0 .section ".text" .align 4 .global main .type main,#function .proc 04 main: !#PROLOGUE# 0 save %sp, -208, %sp !#PROLOGUE# 1 ldx [%i1+8], %o0 ! %o0 <= argv[1] call strtod, 0 ! %f0 <= strtod(argv[1]) mov 0, %o1 ! %o1 <= 0 (delay slot) fdtos %f0, %f0 ! %f0 <= (float)%f0 st %f0, [%fp+2027] ! save %f0 in f fstoi %f0, %f2 ! %f2 <= trunc(%f0) st %f2, [%fp+2031] ! save result in temp ld [%fp+2031], %o1 ! get it into integer register sra %o1, 0, %o1 ! sign-extend to 64 bits sethi %h44(.LLC0), %o0 ! load address of format string or %o0, %m44(.LLC0), %o0 ! ...into %o0 sllx %o0, 12, %o0 ! ...still loading address... call printf, 0 ! print it! or %o0, %l44(.LLC0), %o0 ! ...finish address (delay slot) ld [%fp+2027], %f3 ! get original float back fstox %f3, %f2 ! convert to 64-bit int std %f2, [%fp+2031] ! save to temp ldx [%fp+2031], %l0 ! load it to %l0 srl %l0, 0, %o1 ! put low half to %o1 and zero sethi %h44(.LLC1), %o0 ! compute address of format or %o0, %m44(.LLC1), %o0 sllx %o0, 12, %o0 call printf, 0 ! ...and print or %o0, %l44(.LLC1), %o0 sethi %h44(.LLC2), %o0 ! compute address of format or %o0, %m44(.LLC2), %o0 sllx %o0, 12, %o0 or %o0, %l44(.LLC2), %o0 call printf, 0 ! ...and print mov %l0, %o1 ! put 64-bit value into %o1 ! (delay slot) ! Here is where the bizarre parts begin, as we use a 23-instruction ! sequence to convert a float to an unsigned long. (This must be ! what Chris Torek meant by complaining about machines with very ! slow unsigned arithmetic!) ! ! .LLC4 is the label for a floating-point constant against which ! we compare the number we are trying to convert. ld [%fp+2027], %f4 ! get original float to %f4 fstoq %f4, %f0 ! %f0 = (long double)%f4 sethi %h44(.LLC4), %o0 ! load address of .LLC4 into or %o0, %m44(.LLC4), %o0 ! %o0... sllx %o0, 12, %o0 or %o0, %l44(.LLC4), %o0 ! ...done ldd [%o0], %f4 ! load constant at that addr ldd [%o0+8], %f6 ! into quad %f4 fcmpeq %fcc0, %f0, %f4 ! compare f0 and f4 as ! quad fp; raise exception ! if the comparison is ! unordered ! ! I added this NOP just in case the ! assertion in the manual about not ! requiring an intervening ILU instruction ! was false. ! nop ! ! This instruction was generated by GCC as ! fbge,a,pt, and the branch is always taken. ! I changed it to fbe,a,pt and the branch was ! still always taken. (See below for how I know.) ! With fbg,a,pt, the branch is *never* taken, not ! even when it should be. ! fbg,a,pt %fcc0, .LL2 ! if %f0 >= %f4 (which we ! predict that it is), ! retire the instruction ! in the delay slot and ! jump to .LL2. If, OTOH, ! %f0 < %f4, then cancel ! the instruction in the ! delay slot and do not jump. sethi %h44(.LLC4), %o0 ! see .LL2 fqtox %f0, %f0 ! %f0 = (long)%f0 ! ! When the branch above is erroneously not taken, ! and the value being converted is one which should ! overflow, the wrong result is generated. SPARCv9 ! ARM says that, if integer overflow is masked, ! the result should be 0x7fffffffffffffff. The ! value I see is 0xffffffff00000000. ! std %f0, [%fp+2031] ! store (long)%f0 to temp ba,pt %xcc, .LL3 ! jump to .LLC, after... ldx [%fp+2031], %o1 ! ...loading (long)%f0 to %o1 .LL2: ! ! We die here if the branch for overflow is ever taken. ! call abort, 0 or %o0, %m44(.LLC4), %o0 ! finish computing address sllx %o0, 12, %o0 ! of .LLC4 (again), from delay or %o0, %l44(.LLC4), %o0 ! slot of branch ldd [%o0], %f4 ! whee! reload the constant ldd [%o0+8], %f6 ! into long double %f4 again! fsubq %f0, %f4, %f4 ! %f4 = %f0 - %f4 fqtox %f4, %f4 ! convert to long std %f4, [%fp+2031] ! store long to temp ldx [%fp+2031], %o1 ! load into %o1 mov -1, %o0 sllx %o0, 63, %o0 ! %o0 = (1 << 63) xor %o1, %o0, %o1 ! %o1 ^= (1 << 63) .LL3: sethi %h44(.LLC3), %o0 ! get the message EA or %o0, %m44(.LLC3), %o0 sllx %o0, 12, %o0 call printf, 0 ! PRINT! or %o0, %l44(.LLC3), %o0 return %i7+8 mov 0, %o0 .LLfe1: .size main,.LLfe1-main .ident "GCC: (GNU) 3.1 20020224 (experimental)" - -GAWollman ------- end ------- [no save] To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-sparc" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200203100538.g2A5csD04413>
