Subject: Re: casting double to unsigned long will round values
To: Martin Husemann <firstname.lastname@example.org>
From: Andrey Petrov <email@example.com>
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.