/* Render R as a decimal floating point constant. Emit DIGITS significant
digits in the result, bounded by BUF_SIZE. If DIGITS is 0, choose the
maximum for the representation. If CROP_TRAILING_ZEROS, strip trailing
- zeros. */
+ zeros. If MODE is VOIDmode, round to nearest value. Otherwise, round
+ to a string that, when parsed back in mode MODE, yields the same value. */
#define M_LOG10_2 0.30102999566398119521
void
-real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
- size_t digits, int crop_trailing_zeros)
+real_to_decimal_for_mode (char *str, const REAL_VALUE_TYPE *r_orig,
+ size_t buf_size, size_t digits,
+ int crop_trailing_zeros, enum machine_mode mode)
{
+ const struct real_format *fmt = NULL;
const REAL_VALUE_TYPE *one, *ten;
REAL_VALUE_TYPE r, pten, u, v;
int dec_exp, cmp_one, digit;
size_t max_digits;
char *p, *first, *last;
bool sign;
+ bool round_up;
+
+ if (mode != VOIDmode)
+ {
+ fmt = REAL_MODE_FORMAT (mode);
+ gcc_assert (fmt);
+ }
r = *r_orig;
switch (r.cl)
digit = rtd_divmod (&r, &pten);
/* Round the result. */
- if (digit == 5)
+ if (fmt && fmt->round_towards_zero)
{
- /* Round to nearest. If R is nonzero there are additional
- nonzero digits to be extracted. */
+ /* If the format uses round towards zero when parsing the string
+ back in, we need to always round away from zero here. */
if (cmp_significand_0 (&r))
digit++;
- /* Round to even. */
- else if ((p[-1] - '0') & 1)
- digit++;
+ round_up = digit > 0;
}
- if (digit > 5)
+ else
+ {
+ if (digit == 5)
+ {
+ /* Round to nearest. If R is nonzero there are additional
+ nonzero digits to be extracted. */
+ if (cmp_significand_0 (&r))
+ digit++;
+ /* Round to even. */
+ else if ((p[-1] - '0') & 1)
+ digit++;
+ }
+
+ round_up = digit > 5;
+ }
+
+ if (round_up)
{
while (p > first)
{
/* Append the exponent. */
sprintf (last, "e%+d", dec_exp);
+
+#ifdef ENABLE_CHECKING
+ /* Verify that we can read the original value back in. */
+ if (mode != VOIDmode)
+ {
+ real_from_string (&r, str);
+ real_convert (&r, mode, &r);
+ gcc_assert (real_identical (&r, r_orig));
+ }
+#endif
+}
+
+/* Likewise, except always uses round-to-nearest. */
+
+void
+real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size,
+ size_t digits, int crop_trailing_zeros)
+{
+ real_to_decimal_for_mode (str, r_orig, buf_size,
+ digits, crop_trailing_zeros, VOIDmode);
}
/* Render R as a hexadecimal floating point constant. Emit DIGITS
do_divide (r, r, &pten);
}
-/* Returns the special REAL_VALUE_TYPE enumerated by E. */
+/* Returns the special REAL_VALUE_TYPE corresponding to 'e'. */
const REAL_VALUE_TYPE *
-get_real_const (enum real_value_const e)
+dconst_e_ptr (void)
{
- static REAL_VALUE_TYPE value[rv_max];
+ static REAL_VALUE_TYPE value;
+
+ /* Initialize mathematical constants for constant folding builtins.
+ These constants need to be given to at least 160 bits precision. */
+ if (value.cl == rvc_zero)
+ {
+ mpfr_t m;
+ mpfr_init2 (m, SIGNIFICAND_BITS);
+ mpfr_set_ui (m, 1, GMP_RNDN);
+ mpfr_exp (m, m, GMP_RNDN);
+ real_from_mpfr (&value, m, NULL_TREE, GMP_RNDN);
+ mpfr_clear (m);
+
+ }
+ return &value;
+}
- gcc_assert (e < rv_max);
+/* Returns the special REAL_VALUE_TYPE corresponding to 1/3. */
+
+const REAL_VALUE_TYPE *
+dconst_third_ptr (void)
+{
+ static REAL_VALUE_TYPE value;
/* Initialize mathematical constants for constant folding builtins.
These constants need to be given to at least 160 bits precision. */
- if (value[e].cl == rvc_zero)
- switch (e)
+ if (value.cl == rvc_zero)
{
- case rv_e:
- {
- mpfr_t m;
- mpfr_init2 (m, SIGNIFICAND_BITS);
- mpfr_set_ui (m, 1, GMP_RNDN);
- mpfr_exp (m, m, GMP_RNDN);
- real_from_mpfr (&value[e], m, NULL_TREE, GMP_RNDN);
- mpfr_clear (m);
- }
- break;
- case rv_third:
- real_arithmetic (&value[e], RDIV_EXPR, &dconst1, real_digit (3));
- break;
- case rv_sqrt2:
- {
- mpfr_t m;
- mpfr_init2 (m, SIGNIFICAND_BITS);
- mpfr_sqrt_ui (m, 2, GMP_RNDN);
- real_from_mpfr (&value[e], m, NULL_TREE, GMP_RNDN);
- mpfr_clear (m);
- }
- break;
- default:
- gcc_unreachable();
+ real_arithmetic (&value, RDIV_EXPR, &dconst1, real_digit (3));
}
+ return &value;
+}
+
+/* Returns the special REAL_VALUE_TYPE corresponding to sqrt(2). */
- return &value[e];
+const REAL_VALUE_TYPE *
+dconst_sqrt2_ptr (void)
+{
+ static REAL_VALUE_TYPE value;
+
+ /* Initialize mathematical constants for constant folding builtins.
+ These constants need to be given to at least 160 bits precision. */
+ if (value.cl == rvc_zero)
+ {
+ mpfr_t m;
+ mpfr_init2 (m, SIGNIFICAND_BITS);
+ mpfr_sqrt_ui (m, 2, GMP_RNDN);
+ real_from_mpfr (&value, m, NULL_TREE, GMP_RNDN);
+ mpfr_clear (m);
+ }
+ return &value;
}
/* Fills R with +Inf. */
required to be the value of the long double rounded to the
nearest double. Rounding means we need a slightly smaller
value for LDBL_MAX. */
- clear_significand_bit (r, SIGNIFICAND_BITS - fmt->pnan);
+ clear_significand_bit (r, SIGNIFICAND_BITS - fmt->pnan - 1);
}
}
round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r)
{
int p2, np2, i, w;
- unsigned long sticky;
- bool guard, lsb;
int emin2m1, emax2;
+ bool round_up = false;
if (r->decimal)
{
}
}
- /* There are P2 true significand bits, followed by one guard bit,
- followed by one sticky bit, followed by stuff. Fold nonzero
- stuff into the sticky bit. */
+ if (!fmt->round_towards_zero)
+ {
+ /* There are P2 true significand bits, followed by one guard bit,
+ followed by one sticky bit, followed by stuff. Fold nonzero
+ stuff into the sticky bit. */
+ unsigned long sticky;
+ bool guard, lsb;
+
+ sticky = 0;
+ for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i)
+ sticky |= r->sig[i];
+ sticky |= r->sig[w]
+ & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1);
- sticky = 0;
- for (i = 0, w = (np2 - 1) / HOST_BITS_PER_LONG; i < w; ++i)
- sticky |= r->sig[i];
- sticky |=
- r->sig[w] & (((unsigned long)1 << ((np2 - 1) % HOST_BITS_PER_LONG)) - 1);
+ guard = test_significand_bit (r, np2 - 1);
+ lsb = test_significand_bit (r, np2);
- guard = test_significand_bit (r, np2 - 1);
- lsb = test_significand_bit (r, np2);
+ /* Round to even. */
+ round_up = guard && (sticky || lsb);
+ }
- /* Round to even. */
- if (guard && (sticky || lsb))
+ if (round_up)
{
REAL_VALUE_TYPE u;
get_zero (&u, 0);
128,
31,
31,
+ false,
+ true,
true,
true,
true,
128,
31,
31,
+ false,
+ true,
true,
true,
true,
128,
31,
31,
+ false,
+ true,
true,
true,
true,
true,
true
};
+
+/* SPU Single Precision (Extended-Range Mode) format is the same as IEEE
+ single precision with the following differences:
+ - Infinities are not supported. Instead MAX_FLOAT or MIN_FLOAT
+ are generated.
+ - NaNs are not supported.
+ - The range of non-zero numbers in binary is
+ (001)[1.]000...000 to (255)[1.]111...111.
+ - Denormals can be represented, but are treated as +0.0 when
+ used as an operand and are never generated as a result.
+ - -0.0 can be represented, but a zero result is always +0.0.
+ - the only supported rounding mode is trunction (towards zero). */
+const struct real_format spu_single_format =
+ {
+ encode_ieee_single,
+ decode_ieee_single,
+ 2,
+ 24,
+ 24,
+ -125,
+ 129,
+ 31,
+ 31,
+ true,
+ false,
+ false,
+ false,
+ true,
+ true,
+ false,
+ false
+ };
\f
/* IEEE double-precision format. */
1024,
63,
63,
+ false,
+ true,
true,
true,
true,
1024,
63,
63,
+ false,
+ true,
true,
true,
true,
1024,
63,
63,
+ false,
+ true,
true,
true,
true,
16384,
95,
95,
+ false,
+ true,
true,
true,
true,
16384,
79,
79,
+ false,
+ true,
true,
true,
true,
16384,
79,
79,
+ false,
+ true,
true,
true,
true,
16384,
79,
79,
+ false,
+ true,
true,
true,
true,
1024,
127,
-1,
+ false,
+ true,
true,
true,
true,
1024,
127,
-1,
+ false,
+ true,
true,
true,
true,
16384,
127,
127,
+ false,
+ true,
true,
true,
true,
16384,
127,
127,
+ false,
+ true,
true,
true,
true,
false,
false,
false,
+ false,
+ false,
false
};
false,
false,
false,
+ false,
+ false,
false
};
false,
false,
false,
+ false,
+ false,
false
};
\f
decode_decimal128 (fmt, r, buf);
}
-/* Single precision decimal floating point (IEEE 754R). */
+/* Single precision decimal floating point (IEEE 754). */
const struct real_format decimal_single_format =
{
encode_decimal_single,
96,
31,
31,
+ false,
+ true,
true,
true,
true,
false
};
-/* Double precision decimal floating point (IEEE 754R). */
+/* Double precision decimal floating point (IEEE 754). */
const struct real_format decimal_double_format =
{
encode_decimal_double,
384,
63,
63,
+ false,
+ true,
true,
true,
true,
false
};
-/* Quad precision decimal floating point (IEEE 754R). */
+/* Quad precision decimal floating point (IEEE 754). */
const struct real_format decimal_quad_format =
{
encode_decimal_quad,
6144,
127,
127,
+ false,
+ true,
true,
true,
true,
MAX_EXP,
-1,
-1,
+ false,
+ false,
true,
true,
false,