Skip site navigation (1)Skip section navigation (2)
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>