aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSandra Loosemore <sandra@codesourcery.com>2009-05-15 10:22:58 -0400
committerSandra Loosemore <sandra@gcc.gnu.org>2009-05-15 10:22:58 -0400
commitae63687c81723aecaaf23c7a906e4bbe44916f39 (patch)
treedefc8b4c498f81b113528376f579d4fe7297ed7f
parent1bd74ad9803518db3978dade5031dab2a481cc3a (diff)
downloadgcc-ae63687c81723aecaaf23c7a906e4bbe44916f39.zip
gcc-ae63687c81723aecaaf23c7a906e4bbe44916f39.tar.gz
gcc-ae63687c81723aecaaf23c7a906e4bbe44916f39.tar.bz2
real.c (encode_ieee_half): Define.
2009-05-15 Sandra Loosemore <sandra@codesourcery.com> gcc/ * real.c (encode_ieee_half): Define. (decode_ieee_half): Define. (ieee_half_format): Define. (arm_half_format): Define. * real.h (ieee_half_format): Declare. (arm_half_format): Declare. From-SVN: r147579
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/real.c161
-rw-r--r--gcc/real.h2
3 files changed, 172 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index d036aa9..2882330 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,14 @@
2009-05-15 Sandra Loosemore <sandra@codesourcery.com>
+ * real.c (encode_ieee_half): Define.
+ (decode_ieee_half): Define.
+ (ieee_half_format): Define.
+ (arm_half_format): Define.
+ * real.h (ieee_half_format): Declare.
+ (arm_half_format): Declare.
+
+2009-05-15 Sandra Loosemore <sandra@codesourcery.com>
+
* optabs.c (prepare_float_lib_cmp): Test that the comparison,
swapped, and reversed optabs exist before trying to use them.
diff --git a/gcc/real.c b/gcc/real.c
index 3803ed6..f4c493b 100644
--- a/gcc/real.c
+++ b/gcc/real.c
@@ -4513,6 +4513,167 @@ const struct real_format decimal_quad_format =
false
};
+/* Encode half-precision floats. This routine is used both for the IEEE
+ ARM alternative encodings. */
+static void
+encode_ieee_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 - 11)) & 0x3ff;
+
+ switch (r->cl)
+ {
+ case rvc_zero:
+ break;
+
+ case rvc_inf:
+ if (fmt->has_inf)
+ image |= 31 << 10;
+ else
+ image |= 0x7fff;
+ break;
+
+ case rvc_nan:
+ if (fmt->has_nans)
+ {
+ if (r->canonical)
+ sig = (fmt->canonical_nan_lsbs_set ? (1 << 9) - 1 : 0);
+ if (r->signalling == fmt->qnan_msb_set)
+ sig &= ~(1 << 9);
+ else
+ sig |= 1 << 9;
+ if (sig == 0)
+ sig = 1 << 8;
+
+ image |= 31 << 10;
+ image |= sig;
+ }
+ else
+ image |= 0x3ff;
+ break;
+
+ case rvc_normal:
+ /* Recall that IEEE numbers are interpreted as 1.F x 2**exp,
+ whereas the intermediate representation is 0.F x 2**exp.
+ Which means we're off by one. */
+ if (denormal)
+ exp = 0;
+ else
+ exp = REAL_EXP (r) + 15 - 1;
+ image |= exp << 10;
+ image |= sig;
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ buf[0] = image;
+}
+
+/* Decode half-precision floats. This routine is used both for the IEEE
+ ARM alternative encodings. */
+static void
+decode_ieee_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 >> 10) & 0x1f;
+
+ memset (r, 0, sizeof (*r));
+ image <<= HOST_BITS_PER_LONG - 11;
+ image &= ~SIG_MSB;
+
+ if (exp == 0)
+ {
+ if (image && fmt->has_denorm)
+ {
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, -14);
+ r->sig[SIGSZ-1] = image << 1;
+ normalize (r);
+ }
+ else if (fmt->has_signed_zero)
+ r->sign = sign;
+ }
+ else if (exp == 31 && (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 - 15 + 1);
+ r->sig[SIGSZ-1] = image | SIG_MSB;
+ }
+}
+
+/* Half-precision format, as specified in IEEE 754R. */
+const struct real_format ieee_half_format =
+ {
+ encode_ieee_half,
+ decode_ieee_half,
+ 2,
+ 11,
+ 11,
+ -13,
+ 16,
+ 15,
+ 15,
+ false,
+ true,
+ true,
+ true,
+ true,
+ true,
+ true,
+ false
+ };
+
+/* ARM's alternative half-precision format, similar to IEEE but with
+ no reserved exponent value for NaNs and infinities; rather, it just
+ extends the range of exponents by one. */
+const struct real_format arm_half_format =
+ {
+ encode_ieee_half,
+ decode_ieee_half,
+ 2,
+ 11,
+ 11,
+ -13,
+ 17,
+ 15,
+ 15,
+ false,
+ true,
+ false,
+ false,
+ true,
+ true,
+ false,
+ false
+ };
+
/* A synthetic "format" for internal arithmetic. It's the size of the
internal significand minus the two bits needed for proper rounding.
The encode and decode routines exist only to satisfy our paranoia
diff --git a/gcc/real.h b/gcc/real.h
index 47efac5..834a24b 100644
--- a/gcc/real.h
+++ b/gcc/real.h
@@ -303,6 +303,8 @@ extern const struct real_format real_internal_format;
extern const struct real_format decimal_single_format;
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;
/* ====================================================================== */