diff options
author | Stam Markianos-Wright <stam.markianos-wright@arm.com> | 2019-12-11 10:27:30 +0000 |
---|---|---|
committer | Kyrylo Tkachov <ktkachov@gcc.gnu.org> | 2019-12-11 10:27:30 +0000 |
commit | d5ffd47e9a739770aa7ef5ad06c07fe9f16a3260 (patch) | |
tree | 050d28a558531ce02ebb0324e99c1aa61d15f801 | |
parent | e6c90dba73291435c244decb9a89c47019cc5a45 (diff) | |
download | gcc-d5ffd47e9a739770aa7ef5ad06c07fe9f16a3260.tar.gz |
Add ARM-specific Bfloat format support to middle-end
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
-rw-r--r-- | gcc/ChangeLog | 6 | ||||
-rw-r--r-- | gcc/real.c | 137 | ||||
-rw-r--r-- | gcc/real.h | 1 |
3 files changed, 144 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 6ea6db926e9..b7375074d0a 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -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 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. 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; /* ====================================================================== */ |