This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Re: libgcc2.c floatdisf is broken
- From: Richard Henderson <rth at redhat dot com>
- To: gcc at gcc dot gnu dot org, David Edelsohn <dje at watson dot ibm dot com>
- Date: Tue, 17 Sep 2002 10:25:37 -0700
- Subject: Re: libgcc2.c floatdisf is broken
- References: <20020918003603.I14457@bubble.sa.bigpond.net.au>
On Wed, Sep 18, 2002 at 12:36:03AM +0930, Alan Modra wrote:
> The attempted fix in libgcc2.c:__floatdisf for the double rounding
> problem won't work. Case (B) cannot be fixed by setting a bit.
> I think the following patch will cure case (B) as well as (A), but
> haven't properly tested for compliance with IEEE rounding requirements
> yet. ie. I'm not at this point requesting permission to apply the
> patch. It's more a case of inviting comment. Also, can someone
> suggest a test program?
>
> * libgcc2.c (__floatdisf): Mask off bits below REP_BIT.
> * config/rs6000/rs6000.md (floatdisf2): Rename to floatdisf2_int1.
> (floatdisf2): New define_expand.
> (floatdisf2_int2): Likewise.
Alternately, we could avoid DFmode entirely. That doesn't
do you much good in the rs6000 backend though, since its
DFmode operations that are present in hardware.
r~
SFtype
__floatdisf (DWtype u)
{
DWunion uu;
UWtype high, low;
bool neg;
SFtype ret;
if (u == 0)
return 0.0f;
neg = false;
if (u < 0)
{
neg = true;
u = -u;
}
uu.ll = u;
high = uu.s.high;
low = uu.s.low;
if (high == 0)
ret = low;
else
{
unsigned int leading, exp;
count_leading_zeros (leading, high);
if (leading > 0)
{
high = (high << leading) | (low >> (W_TYPE_SIZE - leading));
low = low << leading;
}
exp = W_TYPE_SIZE - leading;
/* The assumption is that UWtype is larger than the significand
of SFtype by at least two bits. That lets us merge all the
least significant bits into one "sticky" bit that is below
the half position such that round-to-even will come out right. */
if (low)
high |= 1;
ret = high;
while (exp >= 32)
{
ret *= 4294967296.0f;
exp -= 32;
}
if (exp >= 16)
{
ret *= 65536.0f;
exp -= 16;
}
if (exp >= 8)
{
ret *= 256.0f;
exp -= 8;
}
if (exp >= 4)
{
ret *= 16.0f;
exp -= 4;
}
if (exp >= 2)
{
ret *= 4.0f;
exp -= 2;
}
if (exp)
ret *= 2.0f;
}
if (neg)
ret = -ret;
return ret;
}