Subject: Re: casting double to unsigned long will round values
To: Martin Husemann <martin@duskware.de>
From: Andrey Petrov <petrov@netbsd.org>
List: tech-toolchain
Date: 05/01/2004 12:20:06
On Sat, May 01, 2004 at 09:02:17PM +0200, Martin Husemann wrote:
> I found a stupid bug, that manifests in breaking perl 5.8.x big time, in
> gcc on sparc64. If you do
> 
> 	double v = 5.6;
> 	unsigned long u = (unsigned long)v;
> 
> the u will be 6.
> 
> I think it happens because the only conversion pattern that could match is
> this (from gcc/config/sparc/sparc.md):
> 
> (define_expand "fixuns_trunctfdi2"
>   [(set (match_operand:DI 0 "register_operand" "")
>         (unsigned_fix:DI (match_operand:TF 1 "general_operand" "")))]
>   "TARGET_FPU && TARGET_ARCH64 && ! TARGET_HARD_QUAD"
>   "emit_tfmode_cvt (UNSIGNED_FIX, operands); DONE;")
> 
> This forces it's operand into TF (128 bit float) mode, so the emitted code
> basically is  _Qp_qtoux(_Qp_dtoq(v))
> 
> Now, since _Qp_qtoux always rounds, the result is always rounded. Which, of
> course, is wrong.
> 
> If you use "long" instead of "unsigned long", the result is OK, probably
> because there are more conversion patterns for fix:DI target modes and the
> complex version via 128 bit floats is not selected, but the fix_truncdfdi2
> pattern, that just emits a "fdtox" instruction.
> 
> So the eays way to fix this is to add equivalents of all fix:DI conversion
> patterns as unsigned_fix:DI too.
> 
> But: to me this looks like it works in that case by pure luck. The bogus
> conversion via TF is still there, and if it ever is chosen, the result
> will be bogus.
> 
> What I'd like to know is:
> 
>  - why other OSes apparently don't have this problem (the Perl bug report
>    that triggered this got a response from a sparc64 64bit linux user
>    stating that it works on his machine)
>  - if this are bugs in sparc.md or if our _Qp_* functions are broken
> 
> If our _Qp_* functions are OK (and to me it looks like this), we probably
> should bounce this to the gcc people.
> 

I think it's fixed in more recent (than 3.3) gcc versions.

	Andrey