On 12/3/19 10:31 AM, Stam Markianos-Wright wrote:
> 
> 
> On 12/2/19 9:27 PM, Joseph Myers wrote:
>> On Mon, 2 Dec 2019, Jeff Law wrote:
>>
>>>> 2019-11-13  Stam Markianos-Wright  <stam.markianos-wri...@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.
>>>>
>>>>
>>> Generally OK.  Please consider using "arm_bfloat_half" instead of
>>> "bfloat_half" for the name field in the arm_bfloat_half_format
>>> structure.  I'm not sure if that's really visible externally, but it
>>
> Hi both! Agreed that we want to be conservative. See latest diff 
> attached with the name field change (also pasted below).

.Ping :)
> 

>> Isn't this the same format used by AVX512_BF16 / Intel DL Boost (albeit
>> with Arm and Intel using different rounding modes)?
> 
> Yes it is remarkably similar, but there's really only so much variation 
> you can have with what is half an f32!
> 
> Cheers,
> Stam
> 
> 
>>
> 
> 
> diff --git a/gcc/real.h b/gcc/real.h
> index 0f660c9c671..2b337bb7f7d 100644
> --- a/gcc/real.h
> +++ b/gcc/real.h
> @@ -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;
> 
> 
>   /* 
> ====================================================================== */
> diff --git a/gcc/real.c b/gcc/real.c
> index 134240a6be9..07b63b6f27e 100644
> --- a/gcc/real.c
> +++ b/gcc/real.c
> @@ -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"
> +  };
> +
>   
>   /* A synthetic "format" for internal arithmetic.  It's the size of the
>      internal significand minus the two bits needed for proper rounding.

Reply via email to