[Patch 14/17] [libgcc, ARM] Generalise float-to-half conversion function.
authorJames Greenhalgh <james.greenhalgh@arm.com>
Wed, 23 Nov 2016 17:30:02 +0000 (17:30 +0000)
committerJames Greenhalgh <jgreenhalgh@gcc.gnu.org>
Wed, 23 Nov 2016 17:30:02 +0000 (17:30 +0000)
libgcc/

* config/arm/fp16.c (struct format): New.
(binary32): New.
(__gnu_float2h_internal): New.  Body moved from
__gnu_f2h_internal and generalize.
(_gnu_f2h_internal): Move body to function __gnu_float2h_internal.
Call it with binary32.

Co-Authored-By: Matthew Wahab <matthew.wahab@arm.com>
From-SVN: r242781

libgcc/ChangeLog
libgcc/config/arm/fp16.c

index a229f2ac5858d742928586849ede05687156c18f..0f6283467c29b5cebb33cd586dd02fb2b7ed5f0a 100644 (file)
@@ -1,3 +1,13 @@
+2016-11-23  James Greenhalgh  <james.greenhalgh@arm.com>
+           Matthew Wahab  <matthew.wahab@arm.com>
+
+       * config/arm/fp16.c (struct format): New.
+       (binary32): New.
+       (__gnu_float2h_internal): New.  Body moved from
+       __gnu_f2h_internal and generalize.
+       (_gnu_f2h_internal): Move body to function __gnu_float2h_internal.
+       Call it with binary32.
+
 2016-11-23  James Greenhalgh  <james.greenhalgh@arm.com>
 
        * soft-fp/extendhftf2.c: Update from glibc.
index 39c863c9dfead3de8af70919c66caa66b615df68..76f73275b00204000e7a5fdb3c3c86e7aa2d0968 100644 (file)
    see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
    <http://www.gnu.org/licenses/>.  */
 
+struct format
+{
+  /* Number of bits.  */
+  unsigned long long size;
+  /* Exponent bias.  */
+  unsigned long long bias;
+  /* Exponent width in bits.  */
+  unsigned long long exponent;
+  /* Significand precision in explicitly stored bits.  */
+  unsigned long long significand;
+};
+
+static const struct format
+binary32 =
+{
+  32,   /* size.  */
+  127,  /* bias.  */
+  8,    /* exponent.  */
+  23    /* significand.  */
+};
+
 static inline unsigned short
-__gnu_f2h_internal(unsigned int a, int ieee)
+__gnu_float2h_internal (const struct format* fmt,
+                       unsigned long long a, int ieee)
 {
-  unsigned short sign = (a >> 16) & 0x8000;
-  int aexp = (a >> 23) & 0xff;
-  unsigned int mantissa = a & 0x007fffff;
-  unsigned int mask;
-  unsigned int increment;
+  unsigned long long point = 1ULL << fmt->significand;
+  unsigned short sign = (a >> (fmt->size - 16)) & 0x8000;
+  int aexp;
+  unsigned long long mantissa;
+  unsigned long long mask;
+  unsigned long long increment;
+
+  /* Get the exponent and mantissa encodings.  */
+  mantissa = a & (point - 1);
 
-  if (aexp == 0xff)
+  mask = (1 << fmt->exponent) - 1;
+  aexp = (a >> fmt->significand) & mask;
+
+  /* Infinity, NaN and alternative format special case.  */
+  if (((unsigned int) aexp) == mask)
     {
       if (!ieee)
        return sign;
       if (mantissa == 0)
        return sign | 0x7c00;   /* Infinity.  */
       /* Remaining cases are NaNs.  Convert SNaN to QNaN.  */
-      return sign | 0x7e00 | (mantissa >> 13);
+      return sign | 0x7e00 | (mantissa >> (fmt->significand - 10));
     }
 
+  /* Zero.  */
   if (aexp == 0 && mantissa == 0)
     return sign;
 
-  aexp -= 127;
+  /* Construct the exponent and mantissa.  */
+  aexp -= fmt->bias;
+
+  /* Decimal point is immediately after the significand.  */
+  mantissa |= point;
 
-  /* Decimal point between bits 22 and 23.  */
-  mantissa |= 0x00800000;
   if (aexp < -14)
     {
-      mask = 0x00ffffff;
+      mask = point | (point - 1);
+      /* Minimum exponent for half-precision is 2^-24.  */
       if (aexp >= -25)
        mask >>= 25 + aexp;
     }
   else
-    mask = 0x00001fff;
+    mask = (point - 1) >> 10;
 
   /* Round.  */
   if (mantissa & mask)
@@ -64,8 +98,8 @@ __gnu_f2h_internal(unsigned int a, int ieee)
       if ((mantissa & mask) == increment)
        increment = mantissa & (increment << 1);
       mantissa += increment;
-      if (mantissa >= 0x01000000)
-               {
+      if (mantissa >= (point << 1))
+       {
          mantissa >>= 1;
          aexp++;
        }
@@ -91,9 +125,29 @@ __gnu_f2h_internal(unsigned int a, int ieee)
       aexp = -14;
     }
 
-  /* We leave the leading 1 in the mantissa, and subtract one
-     from the exponent bias to compensate.  */
-  return sign | (((aexp + 14) << 10) + (mantissa >> 13));
+  /* Encode the final 16-bit floating-point value.
+
+     This is formed of the sign bit, the bias-adjusted exponent, and the
+     calculated mantissa, with the following caveats:
+
+     1.  The mantissa calculated after rounding could have a leading 1.
+        To compensate for this, subtract one from the exponent bias (15)
+        before adding it to the calculated exponent.
+     2.  When we were calculating rounding, we left the mantissa with the
+        number of bits of the source operand, it needs reduced to ten
+        bits (+1 for the afforementioned leading 1) by shifting right by
+        the number of bits in the source mantissa - 10.
+     3.  To ensure the leading 1 in the mantissa is applied to the exponent
+        we need to add the mantissa rather than apply an arithmetic "or"
+        to it.  */
+
+  return sign | (((aexp + 14) << 10) + (mantissa >> (fmt->significand - 10)));
+}
+
+static inline unsigned short
+__gnu_f2h_internal (unsigned int a, int ieee)
+{
+  return __gnu_float2h_internal (&binary32, (unsigned long long) a, ieee);
 }
 
 unsigned int