This is the mail archive of the gcc@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: libgcc2.c floatdisf is broken


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;
}


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]