* doublest.c (FLOATFORMAT_LARGEST_BYTES): New define.
authorRichard Earnshaw <richard.earnshaw@arm.com>
Sun, 5 Dec 2004 15:17:34 +0000 (15:17 +0000)
committerRichard Earnshaw <richard.earnshaw@arm.com>
Sun, 5 Dec 2004 15:17:34 +0000 (15:17 +0000)
(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.

gdb/ChangeLog
gdb/doublest.c

index 918ecdd895bbd6f4fb00b3c1c30ca800ac4caf03..8357edb5915e01b9adb51c3dd1d2e3523ec8e2b5 100644 (file)
@@ -1,3 +1,18 @@
+2004-12-05  Richard Earnshaw  <rearnsha@arm.com>
+
+       * 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.
+
 2004-12-04  Daniel Jacobowitz  <dan@debian.org>
 
        PR tui/1703
index 82441b6f15c3f8ba4183cee19f2bcd25ff22cd73..b36cbd79195e356d7fca9e1c21325ea7d212dea3 100644 (file)
    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);
@@ -54,8 +58,11 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
   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 || order == floatformat_littlebyte_bigword)
+  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
@@ -81,7 +88,7 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
   else
     result = 0;
   cur_bitshift += FLOATFORMAT_CHAR_BIT;
-  if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+  if (order == floatformat_little)
     ++cur_byte;
   else
     --cur_byte;
@@ -99,8 +106,6 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
        case floatformat_big:
          --cur_byte;
          break;
-       case floatformat_littlebyte_bigword:
-         break;
        }
     }
   if (len < sizeof(result) * FLOATFORMAT_CHAR_BIT)
@@ -109,6 +114,40 @@ get_field (unsigned char *data, enum floatformat_byteorders order,
   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.  */
@@ -125,51 +164,19 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
   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);
 
-  /* 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;
+  order = floatformat_normalize_byteorder (fmt, ufrom, newfrom);
 
-      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;
-       }
-    }
+  if (order != fmt->byteorder)
+    ufrom = newfrom;
 
-  exponent = get_field (ufrom, fmt->byteorder, fmt->totalsize,
-                       fmt->exp_start, fmt->exp_len);
+  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.  */
@@ -207,8 +214,7 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
     {
       mant_bits = min (mant_bits_left, 32);
 
-      mant = get_field (ufrom, fmt->byteorder, fmt->totalsize,
-                       mant_off, mant_bits);
+      mant = get_field (ufrom, order, fmt->totalsize, mant_off, mant_bits);
 
       dto += ldexp ((double) mant, exponent - mant_bits);
       exponent -= mant_bits;
@@ -217,7 +223,7 @@ convert_floatformat_to_doublest (const struct floatformat *fmt,
     }
 
   /* Negate it if negative.  */
-  if (get_field (ufrom, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1))
+  if (get_field (ufrom, order, fmt->totalsize, fmt->sign_start, 1))
     dto = -dto;
   *to = dto;
 }
@@ -236,8 +242,11 @@ put_field (unsigned char *data, enum floatformat_byteorders order,
   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 || order == floatformat_littlebyte_bigword)
+  if (order == floatformat_little)
     {
       int excess = FLOATFORMAT_CHAR_BIT - (total_len % FLOATFORMAT_CHAR_BIT);
       cur_byte = (total_len / FLOATFORMAT_CHAR_BIT) 
@@ -260,7 +269,7 @@ put_field (unsigned char *data, enum floatformat_byteorders order,
        (stuff_to_put & ((1 << FLOATFORMAT_CHAR_BIT) - 1)) << (-cur_bitshift);
     }
   cur_bitshift += FLOATFORMAT_CHAR_BIT;
-  if (order == floatformat_little || order == floatformat_littlebyte_bigword)
+  if (order == floatformat_little)
     ++cur_byte;
   else
     --cur_byte;
@@ -279,7 +288,7 @@ put_field (unsigned char *data, enum floatformat_byteorders order,
        *(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)
+      if (order == floatformat_little)
        ++cur_byte;
       else
        --cur_byte;
@@ -347,6 +356,10 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
   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) 
@@ -356,30 +369,30 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
   if (dfrom != dfrom)          /* Result is NaN */
     {
       /* From is NaN */
-      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+      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, fmt->byteorder, fmt->totalsize, fmt->man_start,
+      put_field (uto, order, fmt->totalsize, fmt->man_start,
                 32, 1);
-      return;
+      goto finalize_byteorder;
     }
 
   /* If negative, set the sign bit.  */
   if (dfrom < 0)
     {
-      put_field (uto, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1, 1);
+      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, fmt->byteorder, fmt->totalsize, fmt->exp_start,
+      put_field (uto, order, 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,
+      put_field (uto, order, fmt->totalsize, fmt->man_start,
                 fmt->man_len, 0);
-      return;
+      goto finalize_byteorder;
     }
 
 #ifdef HAVE_LONG_DOUBLE
@@ -388,7 +401,7 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
   mant = frexp (dfrom, &exponent);
 #endif
 
-  put_field (uto, fmt->byteorder, fmt->totalsize, fmt->exp_start, fmt->exp_len,
+  put_field (uto, order, fmt->totalsize, fmt->exp_start, fmt->exp_len,
             exponent + fmt->exp_bias - 1);
 
   mant_bits_left = fmt->man_len;
@@ -429,23 +442,31 @@ convert_doublest_to_floatformat (CONST struct floatformat *fmt,
          mant_long >>= 32 - mant_bits;
        }
 
-      put_field (uto, fmt->byteorder, fmt->totalsize,
+      put_field (uto, order, fmt->totalsize,
                 mant_off, mant_bits, mant_long);
       mant_off += mant_bits;
       mant_bits_left -= mant_bits;
     }
-  if (fmt->byteorder == floatformat_littlebyte_bigword)
+
+ finalize_byteorder:
+  /* Do we need to byte-swap the words in the result?  */
+  if (order != fmt->byteorder)
     {
-      int count;
-      unsigned char *swaplow = uto;
-      unsigned char *swaphigh = uto + 4;
+      int words;
+      unsigned char *curword = uto;
       unsigned char tmp;
 
-      for (count = 0; count < 4; count++)
+      words = fmt->totalsize / FLOATFORMAT_CHAR_BIT;
+      words >>= 2;
+      while (words-- > 0)
        {
-         tmp = *swaplow;
-         *swaplow++ = *swaphigh;
-         *swaphigh++ = tmp;
+         tmp = curword[0];
+         curword[0] = curword[3];
+         curword[3] = tmp;
+         tmp = curword[1];
+         curword[1] = curword[2];
+         curword[2] = tmp;
+         curword += 4;
        }
     }
 }
@@ -457,8 +478,19 @@ int
 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);
-  return get_field (uval, fmt->byteorder, fmt->totalsize, fmt->sign_start, 1);
+  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.  */
@@ -471,14 +503,23 @@ floatformat_is_nan (const struct floatformat *fmt, char *val)
   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, fmt->byteorder, fmt->totalsize,
-                       fmt->exp_start, fmt->exp_len);
+  exponent = get_field (uval, order, fmt->totalsize, fmt->exp_start,
+                       fmt->exp_len);
 
   if (exponent != fmt->exp_nan)
     return 0;
@@ -490,8 +531,7 @@ floatformat_is_nan (const struct floatformat *fmt, char *val)
     {
       mant_bits = min (mant_bits_left, 32);
 
-      mant = get_field (uval, fmt->byteorder, fmt->totalsize,
-                       mant_off, mant_bits);
+      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
@@ -521,17 +561,29 @@ floatformat_mantissa (const struct floatformat *fmt, char *val)
   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 (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);
+  mant = get_field (uval, order, fmt->totalsize, mant_off, mant_bits);
 
   sprintf (res, "%lx", mant);
 
@@ -540,8 +592,7 @@ floatformat_mantissa (const struct floatformat *fmt, char *val)
   
   while (mant_bits_left > 0)
     {
-      mant = get_field (uval, fmt->byteorder, fmt->totalsize,
-                       mant_off, 32);
+      mant = get_field (uval, order, fmt->totalsize, mant_off, 32);
 
       sprintf (buf, "%08lx", mant);
       strcat (res, buf);