This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB 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: RFA fix conversion of little-byte big-word floats to doublest


On Sat, 04 Dec 2004 12:32:57 EST, Daniel Jacobowitz <drow@false.org>  
wrote:
> On Sat, Dec 04, 2004 at 05:25:21PM +0000, Richard Earnshaw wrote:
> > I've just been thinking.
> > 
> > The current code (for both conversions to and from doublest) tries to work 
> > by normalizing the word order to match the byte order.  This clearly makes 
> > things quite difficult when the number of words involved is variable.
> > 
> > I think it would be a more tractable problem to change all this around so 
> > that the byte order is normalized to match the word order.  This can be 
> > done by simply repeating a word-normalization step for each word in the 
> > value.
> > 
> > Thoughts?
> 
> That sounds good to me - much simpler.

I withdraw my previous patch and substitute this one.  This should also 
fix handling of mixed endian formats that are larger than 64 bits.

Unlike the previous patch this one also correctly handles NaNs; though it 
appears that nothing in the testsuite currently tests this.

	* doublest.c (FLOATFORMAT_LARGEST_BYTES): New define.
	(get_field, put_field): Assert that the format is one we can handle.
	Simplify logic accordingly.
	(floatformat_normalize_byteorder): New function.
	(convert_floatformat_to_doublest): Use floatformat_normalize_byteorder to
	normalize and select modified byte order. Pass modified byte order to
	get_field.
	(floatformat_is_negative, floatformat_is_nan, floatformat_mantissa): 
	Likewise.
	(convert_doublest_to_floatformat): Select an appropriate intermediate
	byte order if necessary.  Always convert to the final format before
	returning.

OK?

R.

Index: doublest.c
===================================================================
RCS file: /cvs/src/src/gdb/doublest.c,v
retrieving revision 1.22
diff -p -p -r1.22 doublest.c
*** doublest.c	24 Aug 2004 22:49:27 -0000	1.22
--- doublest.c	4 Dec 2004 23:42:51 -0000
***************
*** 40,45 ****
--- 40,49 ----
     a system header, what we do if not, etc.  */
  #define FLOATFORMAT_CHAR_BIT 8
  
+ /* The number of bytes that the largest floating-point type that we
+    can convert to doublest will need.  */
+ #define FLOATFORMAT_LARGEST_BYTES 16
+ 
  static unsigned long get_field (unsigned char *,
  				enum floatformat_byteorders,
  				unsigned int, unsigned int, unsigned int);
*************** get_field (unsigned char *data, enum flo
*** 54,61 ****
    unsigned int cur_byte;
    int cur_bitshift;
  
    /* Start at the least significant part of the field.  */
!   if (order == floatformat_little || order == floatformat_littlebyte_bigword)
      {
        /* We start counting from the other end (i.e, from the high bytes
  	 rather than the low bytes).  As such, we need to be concerned
--- 58,68 ----
    unsigned int cur_byte;
    int cur_bitshift;
  
+   /* Caller must byte-swap words before calling this routine.  */
+   gdb_assert (order == floatformat_little || order == floatformat_big);
+ 
    /* Start at the least significant part of the field.  */
!   if (order == floatformat_little)
      {
        /* We start counting from the other end (i.e, from the high bytes
  	 rather than the low bytes).  As such, we need to be concerned
*************** get_field (unsigned char *data, enum flo
*** 81,87 ****
    else
      result = 0;
    cur_bitshift += FLOATFORMAT_CHAR_BIT;
!   if (order == floatformat_little || order == floatformat_littlebyte_bigword)
      ++cur_byte;
    else
      --cur_byte;
--- 88,94 ----
    else
      result = 0;
    cur_bitshift += FLOATFORMAT_CHAR_BIT;
!   if (order == floatformat_little)
      ++cur_byte;
    else
      --cur_byte;
*************** get_field (unsigned char *data, enum flo
*** 99,106 ****
  	case floatformat_big:
  	  --cur_byte;
  	  break;
- 	case floatformat_littlebyte_bigword:
- 	  break;
  	}
      }
    if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT)
--- 106,111 ----
*************** get_field (unsigned char *data, enum flo
*** 109,114 ****
--- 114,153 ----
    return result;
  }
  
+ /* Normalize the byte order of FROM into TO.  If no normalization is needed
+    then FMT->byteorder is returned and TO is not changed; otherwise the format
+    of the normalized form in TO is returned.  */
+ static enum floatformat_byteorders
+ floatformat_normalize_byteorder (const struct floatformat *fmt,
+ 				 const void *from, void *to)
+ {
+   const unsigned char *swapin;
+   unsigned char *swapout;
+   int words;
+   
+   if (fmt->byteorder == floatformat_little
+       || fmt->byteorder == floatformat_big)
+     return fmt->byteorder;
+ 
+   gdb_assert (fmt->byteorder == floatformat_littlebyte_bigword);
+ 
+   words = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
+   words >>= 2;
+ 
+   swapout = (unsigned char *)to;
+   swapin = (const unsigned char *)from;
+ 
+   while (words-- > 0)
+     {
+       *swapout++ = swapin[3];
+       *swapout++ = swapin[2];
+       *swapout++ = swapin[1];
+       *swapout++ = swapin[0];
+       swapin += 4;
+     }
+   return floatformat_big;
+ }
+   
  /* Convert from FMT to a DOUBLEST.
     FROM is the address of the extended float.
     Store the DOUBLEST in *TO.  */
*************** convert_floatformat_to_doublest (const s
*** 125,175 ****
    unsigned int mant_bits, mant_off;
    int mant_bits_left;
    int special_exponent;		/* It's a NaN, denorm or zero */
  
!   /* If the mantissa bits are not contiguous from one end of the
!      mantissa to the other, we need to make a private copy of the
!      source bytes that is in the right order since the unpacking
!      algorithm assumes that the bits are contiguous.
! 
!      Swap the bytes individually rather than accessing them through
!      "long *" since we have no guarantee that they start on a long
!      alignment, and also sizeof(long) for the host could be different
!      than sizeof(long) for the target.  FIXME: Assumes sizeof(long)
!      for the target is 4. */
! 
!   if (fmt->byteorder == floatformat_littlebyte_bigword)
!     {
!       static unsigned char *newfrom;
!       unsigned char *swapin, *swapout;
!       int longswaps;
! 
!       longswaps = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
!       longswaps >>= 3;
  
!       if (newfrom == NULL)
! 	{
! 	  newfrom = (unsigned char *) xmalloc (fmt->totalsize);
! 	}
!       swapout = newfrom;
!       swapin = ufrom;
!       ufrom = newfrom;
!       while (longswaps-- > 0)
! 	{
! 	  /* This is ugly, but efficient */
! 	  *swapout++ = swapin[4];
! 	  *swapout++ = swapin[5];
! 	  *swapout++ = swapin[6];
! 	  *swapout++ = swapin[7];
! 	  *swapout++ = swapin[0];
! 	  *swapout++ = swapin[1];
! 	  *swapout++ = swapin[2];
! 	  *swapout++ = swapin[3];
! 	  swapin += 8;
! 	}
!     }
  
!   exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
! 			fmt->exp_start, fmt->exp_len);
    /* Note that if exponent indicates a NaN, we can't really do anything useful
       (not knowing if the host has NaN's, or how to build one).  So it will
       end up as an infinity or something close; that is OK.  */
--- 164,182 ----
    unsigned int mant_bits, mant_off;
    int mant_bits_left;
    int special_exponent;		/* It's a NaN, denorm or zero */
+   enum floatformat_byteorders order;
+   unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+   
+   gdb_assert (fmt->totalsize
+ 	      <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
  
!   order = floatformat_normalize_byteorder (fmt, ufrom, newfrom);
  
!   if (order != fmt->byteorder)
!     ufrom = newfrom;
  
!   exponent = get_field (ufrom, order, fmt->totalsize, fmt->exp_start,
! 			fmt->exp_len);
    /* Note that if exponent indicates a NaN, we can't really do anything useful
       (not knowing if the host has NaN's, or how to build one).  So it will
       end up as an infinity or something close; that is OK.  */
*************** convert_floatformat_to_doublest (const s
*** 207,214 ****
      {
        mant_bits = min (mant_bits_left, 32);
  
!       mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
! 			mant_off, mant_bits);
  
        dto += ldexp ((double) mant, exponent - mant_bits);
        exponent -= mant_bits;
--- 214,220 ----
      {
        mant_bits = min (mant_bits_left, 32);
  
!       mant = get_field (ufrom, order, fmt->totalsize, mant_off, mant_bits);
  
        dto += ldexp ((double) mant, exponent - mant_bits);
        exponent -= mant_bits;
*************** convert_floatformat_to_doublest (const s
*** 217,223 ****
      }
  
    /* Negate it if negative.  */
!   if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
      dto = -dto;
    *to = dto;
  }
--- 223,229 ----
      }
  
    /* Negate it if negative.  */
!   if (get_field (ufrom, order, fmt->totalsize, fmt->sign_start, 1))
      dto = -dto;
    *to = dto;
  }
*************** put_field (unsigned char *data, enum flo
*** 236,243 ****
    unsigned int cur_byte;
    int cur_bitshift;
  
    /* Start at the least significant part of the field.  */
!   if (order == floatformat_little || order == floatformat_littlebyte_bigword)
      {
        int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
        cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) 
--- 242,252 ----
    unsigned int cur_byte;
    int cur_bitshift;
  
+   /* Caller must byte-swap words before calling this routine.  */
+   gdb_assert (order == floatformat_little || order == floatformat_big);
+ 
    /* Start at the least significant part of the field.  */
!   if (order == floatformat_little)
      {
        int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
        cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) 
*************** put_field (unsigned char *data, enum flo
*** 260,266 ****
  	(stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
      }
    cur_bitshift += FLOATFORMAT_CHAR_BIT;
!   if (order == floatformat_little || order == floatformat_littlebyte_bigword)
      ++cur_byte;
    else
      --cur_byte;
--- 269,275 ----
  	(stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
      }
    cur_bitshift += FLOATFORMAT_CHAR_BIT;
!   if (order == floatformat_little)
      ++cur_byte;
    else
      --cur_byte;
*************** put_field (unsigned char *data, enum flo
*** 279,285 ****
  	*(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
  			      & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
        cur_bitshift += FLOATFORMAT_CHAR_BIT;
!       if (order == floatformat_little || order == floatformat_littlebyte_bigword)
  	++cur_byte;
        else
  	--cur_byte;
--- 288,294 ----
  	*(data + cur_byte) = ((stuff_to_put >> cur_bitshift)
  			      & ((1 << FLOATFORMAT_CHAR_BIT) - 1));
        cur_bitshift += FLOATFORMAT_CHAR_BIT;
!       if (order == floatformat_little)
  	++cur_byte;
        else
  	--cur_byte;
*************** convert_doublest_to_floatformat (CONST s
*** 347,352 ****
--- 356,365 ----
    unsigned int mant_bits, mant_off;
    int mant_bits_left;
    unsigned char *uto = (unsigned char *) to;
+   enum floatformat_byteorders order = fmt->byteorder;
+ 
+   if (order == floatformat_littlebyte_bigword)
+     order = floatformat_big;
  
    memcpy (&dfrom, from, sizeof (dfrom));
    memset (uto, 0, (fmt->totalsize + FLOATFORMAT_CHAR_BIT - 1) 
*************** convert_doublest_to_floatformat (CONST s
*** 356,385 ****
    if (dfrom != dfrom)		/* Result is NaN */
      {
        /* From is NaN */
!       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
  		 fmt->exp_len, fmt->exp_nan);
        /* Be sure it's not infinity, but NaN value is irrel */
!       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
  		 32, 1);
!       return;
      }
  
    /* If negative, set the sign bit.  */
    if (dfrom < 0)
      {
!       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
        dfrom = -dfrom;
      }
  
    if (dfrom + dfrom == dfrom && dfrom != 0.0)	/* Result is Infinity */
      {
        /* Infinity exponent is same as NaN's.  */
!       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
  		 fmt->exp_len, fmt->exp_nan);
        /* Infinity mantissa is all zeroes.  */
!       put_field (uto, fmt->byteorder, fmt->totalsize, fmt->man_start,
  		 fmt->man_len, 0);
!       return;
      }
  
  #ifdef HAVE_LONG_DOUBLE
--- 369,398 ----
    if (dfrom != dfrom)		/* Result is NaN */
      {
        /* From is NaN */
!       put_field (uto, order, fmt->totalsize, fmt->exp_start,
  		 fmt->exp_len, fmt->exp_nan);
        /* Be sure it's not infinity, but NaN value is irrel */
!       put_field (uto, order, fmt->totalsize, fmt->man_start,
  		 32, 1);
!       goto finalize_byteorder;
      }
  
    /* If negative, set the sign bit.  */
    if (dfrom < 0)
      {
!       put_field (uto, order, fmt->totalsize, fmt->sign_start, 1, 1);
        dfrom = -dfrom;
      }
  
    if (dfrom + dfrom == dfrom && dfrom != 0.0)	/* Result is Infinity */
      {
        /* Infinity exponent is same as NaN's.  */
!       put_field (uto, order, fmt->totalsize, fmt->exp_start,
  		 fmt->exp_len, fmt->exp_nan);
        /* Infinity mantissa is all zeroes.  */
!       put_field (uto, order, fmt->totalsize, fmt->man_start,
  		 fmt->man_len, 0);
!       goto finalize_byteorder;
      }
  
  #ifdef HAVE_LONG_DOUBLE
*************** convert_doublest_to_floatformat (CONST s
*** 388,394 ****
    mant = frexp (dfrom, &exponent);
  #endif
  
!   put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len,
  	     exponent + fmt->exp_bias - 1);
  
    mant_bits_left = fmt->man_len;
--- 401,407 ----
    mant = frexp (dfrom, &exponent);
  #endif
  
!   put_field (uto, order, fmt->totalsize, fmt->exp_start, fmt->exp_len,
  	     exponent + fmt->exp_bias - 1);
  
    mant_bits_left = fmt->man_len;
*************** convert_doublest_to_floatformat (CONST s
*** 429,451 ****
  	  mant_long >>= 32 - mant_bits;
  	}
  
!       put_field (uto, fmt->byteorder, fmt->totalsize,
  		 mant_off, mant_bits, mant_long);
        mant_off += mant_bits;
        mant_bits_left -= mant_bits;
      }
!   if (fmt->byteorder == floatformat_littlebyte_bigword)
      {
!       int count;
!       unsigned char *swaplow = uto;
!       unsigned char *swaphigh = uto + 4;
        unsigned char tmp;
  
!       for (count = 0; count < 4; count++)
  	{
! 	  tmp = *swaplow;
! 	  *swaplow++ = *swaphigh;
! 	  *swaphigh++ = tmp;
  	}
      }
  }
--- 442,472 ----
  	  mant_long >>= 32 - mant_bits;
  	}
  
!       put_field (uto, order, fmt->totalsize,
  		 mant_off, mant_bits, mant_long);
        mant_off += mant_bits;
        mant_bits_left -= mant_bits;
      }
! 
!  finalize_byteorder:
!   /* Do we need to byte-swap the words in the result?  */
!   if (order != fmt->byteorder)
      {
!       int words;
!       unsigned char *curword = uto;
        unsigned char tmp;
  
!       words = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
!       words >>= 2;
!       while (words-- > 0)
  	{
! 	  tmp = curword[0];
! 	  curword[0] = curword[3];
! 	  curword[3] = tmp;
! 	  tmp = curword[1];
! 	  curword[1] = curword[2];
! 	  curword[2] = tmp;
! 	  curword += 4;
  	}
      }
  }
*************** int
*** 457,464 ****
  floatformat_is_negative (const struct floatformat *fmt, char *val)
  {
    unsigned char *uval = (unsigned char *) val;
    gdb_assert (fmt != NULL);
!   return get_field (uval, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1);
  }
  
  /* Check if VAL is "not a number" (NaN) for FMT.  */
--- 478,496 ----
  floatformat_is_negative (const struct floatformat *fmt, char *val)
  {
    unsigned char *uval = (unsigned char *) val;
+   enum floatformat_byteorders order;
+   unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+   
    gdb_assert (fmt != NULL);
!   gdb_assert (fmt->totalsize
! 	      <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
! 
!   order = floatformat_normalize_byteorder (fmt, uval, newfrom);
! 
!   if (order != fmt->byteorder)
!     uval = newfrom;
! 
!   return get_field (uval, order, fmt->totalsize, fmt->sign_start, 1);
  }
  
  /* Check if VAL is "not a number" (NaN) for FMT.  */
*************** floatformat_is_nan (const struct floatfo
*** 471,484 ****
    unsigned long mant;
    unsigned int mant_bits, mant_off;
    int mant_bits_left;
! 
    gdb_assert (fmt != NULL);
  
    if (! fmt->exp_nan)
      return 0;
  
!   exponent = get_field (uval, fmt->byteorder, fmt->totalsize,
! 			fmt->exp_start, fmt->exp_len);
  
    if (exponent != fmt->exp_nan)
      return 0;
--- 503,525 ----
    unsigned long mant;
    unsigned int mant_bits, mant_off;
    int mant_bits_left;
!   enum floatformat_byteorders order;
!   unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
!   
    gdb_assert (fmt != NULL);
+   gdb_assert (fmt->totalsize
+ 	      <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+ 
+   order = floatformat_normalize_byteorder (fmt, uval, newfrom);
+ 
+   if (order != fmt->byteorder)
+     uval = newfrom;
  
    if (! fmt->exp_nan)
      return 0;
  
!   exponent = get_field (uval, order, fmt->totalsize, fmt->exp_start,
! 			fmt->exp_len);
  
    if (exponent != fmt->exp_nan)
      return 0;
*************** floatformat_is_nan (const struct floatfo
*** 490,497 ****
      {
        mant_bits = min (mant_bits_left, 32);
  
!       mant = get_field (uval, fmt->byteorder, fmt->totalsize,
! 			mant_off, mant_bits);
  
        /* If there is an explicit integer bit, mask it off.  */
        if (mant_off == fmt->man_start
--- 531,537 ----
      {
        mant_bits = min (mant_bits_left, 32);
  
!       mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits);
  
        /* If there is an explicit integer bit, mask it off.  */
        if (mant_off == fmt->man_start
*************** floatformat_mantissa (const struct float
*** 521,537 ****
    int mant_bits_left;
    static char res[50];
    char buf[9];
  
    /* Make sure we have enough room to store the mantissa.  */
-   gdb_assert (fmt != NULL);
    gdb_assert (sizeof res > ((fmt->man_len + 7) / 8) * 2);
  
    mant_off = fmt->man_start;
    mant_bits_left = fmt->man_len;
    mant_bits = (mant_bits_left % 32) > 0 ? mant_bits_left % 32 : 32;
  
!   mant = get_field (uval, fmt->byteorder, fmt->totalsize,
! 		    mant_off, mant_bits);
  
    sprintf (res, "%lx", mant);
  
--- 561,589 ----
    int mant_bits_left;
    static char res[50];
    char buf[9];
+   enum floatformat_byteorders order;
+   unsigned char newfrom[FLOATFORMAT_LARGEST_BYTES];
+   
+   gdb_assert (fmt != NULL);
+   gdb_assert (fmt->totalsize
+ 	      <= FLOATFORMAT_LARGEST_BYTES * FLOATFORMAT_CHAR_BIT);
+ 
+   order = floatformat_normalize_byteorder (fmt, uval, newfrom);
+ 
+   if (order != fmt->byteorder)
+     uval = newfrom;
+ 
+   if (! fmt->exp_nan)
+     return 0;
  
    /* Make sure we have enough room to store the mantissa.  */
    gdb_assert (sizeof res > ((fmt->man_len + 7) / 8) * 2);
  
    mant_off = fmt->man_start;
    mant_bits_left = fmt->man_len;
    mant_bits = (mant_bits_left % 32) > 0 ? mant_bits_left % 32 : 32;
  
!   mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits);
  
    sprintf (res, "%lx", mant);
  
*************** floatformat_mantissa (const struct float
*** 540,547 ****
    
    while (mant_bits_left > 0)
      {
!       mant = get_field (uval, fmt->byteorder, fmt->totalsize,
! 			mant_off, 32);
  
        sprintf (buf, "%08lx", mant);
        strcat (res, buf);
--- 592,598 ----
    
    while (mant_bits_left > 0)
      {
!       mant = get_field (uval, order, fmt->totalsize, mant_off, 32);
  
        sprintf (buf, "%08lx", mant);
        strcat (res, buf);

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