Add ARM-specific Bfloat format support to middle-end
authorStam Markianos-Wright <stam.markianos-wright@arm.com>
Wed, 11 Dec 2019 10:27:30 +0000 (10:27 +0000)
committerKyrylo Tkachov <ktkachov@gcc.gnu.org>
Wed, 11 Dec 2019 10:27:30 +0000 (10:27 +0000)
2019-12-11  Stam Markianos-Wright  <stam.markianos-wright@arm.com>

* real.c (struct arm_bfloat_half_format,
encode_arm_bfloat_half, decode_arm_bfloat_half): New.
* real.h (arm_bfloat_half_format): New.

From-SVN: r279216

gcc/ChangeLog
gcc/real.c
gcc/real.h

index 6ea6db926e9083a49b84076fb8d553cb89abbe74..b7375074d0a74feafbe32c83c25e6183c88e5f8d 100644 (file)
@@ -1,3 +1,9 @@
+2019-12-11  Stam Markianos-Wright  <stam.markianos-wright@arm.com>
+
+       * real.c (struct arm_bfloat_half_format,
+       encode_arm_bfloat_half, decode_arm_bfloat_half): New.
+       * real.h (arm_bfloat_half_format): New.
+
 2019-12-11  Hongtao Liu  <hongtao.liu@intel.com>
 
        PR target/92865
index 134240a6be988cc8edaad061ad1b5da87b6900a7..07b63b6f27e90ac518c5679c1338813b81d00fed 100644 (file)
@@ -4799,6 +4799,116 @@ decode_ieee_half (const struct real_format *fmt, REAL_VALUE_TYPE *r,
     }
 }
 
+/* Encode arm_bfloat types.  */
+static void
+encode_arm_bfloat_half (const struct real_format *fmt, long *buf,
+                   const REAL_VALUE_TYPE *r)
+{
+  unsigned long image, sig, exp;
+  unsigned long sign = r->sign;
+  bool denormal = (r->sig[SIGSZ-1] & SIG_MSB) == 0;
+
+  image = sign << 15;
+  sig = (r->sig[SIGSZ-1] >> (HOST_BITS_PER_LONG - 8)) & 0x7f;
+
+  switch (r->cl)
+    {
+    case rvc_zero:
+      break;
+
+    case rvc_inf:
+      if (fmt->has_inf)
+       image |= 255 << 7;
+      else
+       image |= 0x7fff;
+      break;
+
+    case rvc_nan:
+      if (fmt->has_nans)
+       {
+         if (r->canonical)
+           sig = (fmt->canonical_nan_lsbs_set ? (1 << 6) - 1 : 0);
+         if (r->signalling == fmt->qnan_msb_set)
+           sig &= ~(1 << 6);
+         else
+           sig |= 1 << 6;
+         if (sig == 0)
+           sig = 1 << 5;
+
+         image |= 255 << 7;
+         image |= sig;
+       }
+      else
+       image |= 0x7fff;
+      break;
+
+    case rvc_normal:
+      if (denormal)
+       exp = 0;
+      else
+      exp = REAL_EXP (r) + 127 - 1;
+      image |= exp << 7;
+      image |= sig;
+      break;
+
+    default:
+      gcc_unreachable ();
+    }
+
+  buf[0] = image;
+}
+
+/* Decode arm_bfloat types.  */
+static void
+decode_arm_bfloat_half (const struct real_format *fmt, REAL_VALUE_TYPE *r,
+                   const long *buf)
+{
+  unsigned long image = buf[0] & 0xffff;
+  bool sign = (image >> 15) & 1;
+  int exp = (image >> 7) & 0xff;
+
+  memset (r, 0, sizeof (*r));
+  image <<= HOST_BITS_PER_LONG - 8;
+  image &= ~SIG_MSB;
+
+  if (exp == 0)
+    {
+      if (image && fmt->has_denorm)
+       {
+         r->cl = rvc_normal;
+         r->sign = sign;
+         SET_REAL_EXP (r, -126);
+         r->sig[SIGSZ-1] = image << 1;
+         normalize (r);
+       }
+      else if (fmt->has_signed_zero)
+       r->sign = sign;
+    }
+  else if (exp == 255 && (fmt->has_nans || fmt->has_inf))
+    {
+      if (image)
+       {
+         r->cl = rvc_nan;
+         r->sign = sign;
+         r->signalling = (((image >> (HOST_BITS_PER_LONG - 2)) & 1)
+                          ^ fmt->qnan_msb_set);
+         r->sig[SIGSZ-1] = image;
+       }
+      else
+       {
+         r->cl = rvc_inf;
+         r->sign = sign;
+       }
+    }
+  else
+    {
+      r->cl = rvc_normal;
+      r->sign = sign;
+      SET_REAL_EXP (r, exp - 127 + 1);
+      r->sig[SIGSZ-1] = image | SIG_MSB;
+    }
+}
+
 /* Half-precision format, as specified in IEEE 754R.  */
 const struct real_format ieee_half_format =
   {
@@ -4848,6 +4958,33 @@ const struct real_format arm_half_format =
     false,
     "arm_half"
   };
+
+/* ARM Bfloat half-precision format.  This format resembles a truncated
+   (16-bit) version of the 32-bit IEEE 754 single-precision floating-point
+   format.  */
+const struct real_format arm_bfloat_half_format =
+  {
+    encode_arm_bfloat_half,
+    decode_arm_bfloat_half,
+    2,
+    8,
+    8,
+    -125,
+    128,
+    15,
+    15,
+    0,
+    false,
+    true,
+    true,
+    true,
+    true,
+    true,
+    true,
+    false,
+    "arm_bfloat_half"
+  };
+
 \f
 /* A synthetic "format" for internal arithmetic.  It's the size of the
    internal significand minus the two bits needed for proper rounding.
index 0f660c9c671c26fe21e3d85fbec219e234a24e7c..2b337bb7f7d275270868334e28e337dc82bf5248 100644 (file)
@@ -368,6 +368,7 @@ extern const struct real_format decimal_double_format;
 extern const struct real_format decimal_quad_format;
 extern const struct real_format ieee_half_format;
 extern const struct real_format arm_half_format;
+extern const struct real_format arm_bfloat_half_format;
 
 
 /* ====================================================================== */