You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING. If not, write to the Free
- Software Foundation, 59 Temple Place - Suite 330, Boston, MA
- 02111-1307, USA. */
+ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA. */
#include "config.h"
#include "system.h"
#include "toplev.h"
#include "real.h"
#include "tm_p.h"
+#include "dfp.h"
/* The floating point model used internally is not exactly IEEE 754
compliant, and close to the description in the ISO C99 standard,
int shift = 0, exp;
int i, j;
+ if (r->decimal)
+ return;
+
/* Find the first word that is nonzero. */
for (i = SIGSZ - 1; i >= 0; i--)
if (r->sig[i] == 0)
r->cl = rvc_normal;
r->sign = sign;
SET_REAL_EXP (r, exp);
+ /* Zero out the remaining fields. */
+ r->signalling = 0;
+ r->canonical = 0;
+ r->decimal = 0;
/* Re-normalize the result. */
normalize (r);
if (a->sign != b->sign)
return -a->sign - -b->sign;
+ if (a->decimal || b->decimal)
+ return decimal_do_compare (a, b, nan_result);
+
if (REAL_EXP (a) > REAL_EXP (b))
ret = 1;
else if (REAL_EXP (a) < REAL_EXP (b))
break;
case rvc_normal:
+ if (r->decimal)
+ {
+ decimal_do_fix_trunc (r, a);
+ return;
+ }
if (REAL_EXP (r) <= 0)
get_zero (r, r->sign);
else if (REAL_EXP (r) < SIGNIFICAND_BITS)
}
/* Perform the binary or unary operation described by CODE.
- For a unary operation, leave OP1 NULL. */
+ For a unary operation, leave OP1 NULL. This function returns
+ true if the result may be inexact due to loss of precision. */
-void
+bool
real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
const REAL_VALUE_TYPE *op1)
{
enum tree_code code = icode;
+ if (op0->decimal || (op1 && op1->decimal))
+ return decimal_real_arithmetic (r, icode, op0, op1);
+
switch (code)
{
case PLUS_EXPR:
- do_add (r, op0, op1, 0);
- break;
+ return do_add (r, op0, op1, 0);
case MINUS_EXPR:
- do_add (r, op0, op1, 1);
- break;
+ return do_add (r, op0, op1, 1);
case MULT_EXPR:
- do_multiply (r, op0, op1);
- break;
+ return do_multiply (r, op0, op1);
case RDIV_EXPR:
- do_divide (r, op0, op1);
- break;
+ return do_divide (r, op0, op1);
case MIN_EXPR:
if (op1->cl == rvc_nan)
default:
gcc_unreachable ();
}
+ return false;
}
/* Legacy. Similar, but return the result directly. */
return true;
case rvc_normal:
+ if (a->decimal != b->decimal)
+ return false;
if (REAL_EXP (a) != REAL_EXP (b))
return false;
break;
return i;
case rvc_normal:
+ if (r->decimal)
+ return decimal_real_to_integer (r);
+
if (REAL_EXP (r) <= 0)
goto underflow;
/* Only force overflow for unsigned overflow. Signed overflow is
break;
case rvc_normal:
+ if (r->decimal)
+ {
+ decimal_real_to_integer2 (plow, phigh, r);
+ return;
+ }
+
exp = REAL_EXP (r);
if (exp <= 0)
goto underflow;
gcc_unreachable ();
}
+ if (r.decimal)
+ {
+ decimal_real_to_decimal (str, &r, buf_size, digits, crop_trailing_zeros);
+ return;
+ }
+
/* Bound the number of digits printed by the size of the representation. */
max_digits = SIGNIFICAND_BITS * M_LOG10_2;
if (digits == 0 || digits > max_digits)
gcc_unreachable ();
}
+ if (r->decimal)
+ {
+ /* Hexadecimal format for decimal floats is not interesting. */
+ strcpy (str, "N/A");
+ return;
+ }
+
if (digits == 0)
digits = SIGNIFICAND_BITS / 4;
|= (unsigned long) d << (pos % HOST_BITS_PER_LONG);
pos -= 4;
}
+ else if (d)
+ /* Ensure correct rounding by setting last bit if there is
+ a subsequent nonzero digit. */
+ r->sig[0] |= 1;
exp += 4;
str++;
}
|= (unsigned long) d << (pos % HOST_BITS_PER_LONG);
pos -= 4;
}
+ else if (d)
+ /* Ensure correct rounding by setting last bit if there is
+ a subsequent nonzero digit. */
+ r->sig[0] |= 1;
str++;
}
}
+
+ /* If the mantissa is zero, ignore the exponent. */
+ if (!cmp_significand_0 (r))
+ goto underflow;
+
if (*str == 'p' || *str == 'P')
{
bool exp_neg = false;
}
}
+ /* If the mantissa is zero, ignore the exponent. */
+ if (r->cl == rvc_zero)
+ goto underflow;
+
if (*str == 'e' || *str == 'E')
{
bool exp_neg = false;
return r;
}
+/* Initialize R from string S and desired MODE. */
+
+void
+real_from_string3 (REAL_VALUE_TYPE *r, const char *s, enum machine_mode mode)
+{
+ if (DECIMAL_FLOAT_MODE_P (mode))
+ decimal_real_from_string (r, s);
+ else
+ real_from_string (r, s);
+
+ if (mode != VOIDmode)
+ real_convert (r, mode, r);
+}
+
/* Initialize R from the integer pair HIGH+LOW. */
void
get_zero (r, 0);
else
{
+ memset (r, 0, sizeof (*r));
r->cl = rvc_normal;
r->sign = high < 0 && !unsigned_p;
SET_REAL_EXP (r, 2 * HOST_BITS_PER_WIDE_INT);
{
r->sig[SIGSZ-1] = high;
r->sig[SIGSZ-2] = low;
- memset (r->sig, 0, sizeof(long)*(SIGSZ-2));
}
else
{
r->sig[SIGSZ-2] = high;
r->sig[SIGSZ-3] = low >> (HOST_BITS_PER_LONG - 1) >> 1;
r->sig[SIGSZ-4] = low;
- if (SIGSZ > 4)
- memset (r->sig, 0, sizeof(long)*(SIGSZ-4));
}
normalize (r);
else
{
int base = 10, d;
- bool neg = false;
memset (r, 0, sizeof (*r));
r->cl = rvc_nan;
while (ISSPACE (*str))
str++;
if (*str == '-')
- str++, neg = true;
+ str++;
else if (*str == '+')
str++;
if (*str == '0')
{
- if (*++str == 'x')
- str++, base = 16;
+ str++;
+ if (*str == 'x' || *str == 'X')
+ {
+ base = 16;
+ str++;
+ }
else
base = 8;
}
fmt = REAL_MODE_FORMAT (mode);
gcc_assert (fmt);
+ memset (r, 0, sizeof (*r));
+
+ if (fmt->b == 10)
+ decimal_real_maxval (r, sign, mode);
+ else
+ {
+ r->cl = rvc_normal;
+ r->sign = sign;
+ SET_REAL_EXP (r, fmt->emax * fmt->log2_b);
- r->cl = rvc_normal;
- r->sign = sign;
- r->signalling = 0;
- r->canonical = 0;
- SET_REAL_EXP (r, fmt->emax * fmt->log2_b);
-
- np2 = SIGNIFICAND_BITS - fmt->p * fmt->log2_b;
- memset (r->sig, -1, SIGSZ * sizeof (unsigned long));
- clear_significand_below (r, np2);
+ np2 = SIGNIFICAND_BITS - fmt->p * fmt->log2_b;
+ memset (r->sig, -1, SIGSZ * sizeof (unsigned long));
+ clear_significand_below (r, np2);
+ }
}
/* Fills R with 2**N. */
bool guard, lsb;
int emin2m1, emax2;
+ if (r->decimal)
+ {
+ if (fmt->b == 10)
+ {
+ decimal_round_for_format (fmt, r);
+ return;
+ }
+ /* FIXME. We can come here via fp_easy_constant
+ (e.g. -O0 on '_Decimal32 x = 1.0 + 2.0dd'), but have not
+ investigated whether this convert needs to be here, or
+ something else is missing. */
+ decimal_real_convert (r, DFmode, r);
+ }
+
p2 = fmt->p * fmt->log2_b;
emin2m1 = (fmt->emin - 1) * fmt->log2_b;
emax2 = fmt->emax * fmt->log2_b;
the true base. */
if (fmt->log2_b != 1)
{
- int shift = REAL_EXP (r) & (fmt->log2_b - 1);
+ int shift;
+
+ gcc_assert (fmt->b != 10);
+ shift = REAL_EXP (r) & (fmt->log2_b - 1);
if (shift)
{
shift = fmt->log2_b - shift;
gcc_assert (fmt);
*r = *a;
+
+ if (a->decimal || fmt->b == 10)
+ decimal_real_convert (r, mode, a);
+
round_for_format (fmt, r);
/* round_for_format de-normalizes denormals. Undo just that part. */
bool
exact_real_truncate (enum machine_mode mode, const REAL_VALUE_TYPE *a)
{
+ const struct real_format *fmt;
REAL_VALUE_TYPE t;
+ int emin2m1;
+
+ fmt = REAL_MODE_FORMAT (mode);
+ gcc_assert (fmt);
+
+ /* Don't allow conversion to denormals. */
+ emin2m1 = (fmt->emin - 1) * fmt->log2_b;
+ if (REAL_EXP (a) <= emin2m1)
+ return false;
+
+ /* After conversion to the new mode, the value must be identical. */
real_convert (&t, mode, a);
return real_identical (&t, a);
}
(*fmt->decode) (fmt, r, buf);
}
-/* Return the number of bits in the significand for MODE. */
+/* Return the number of bits of the largest binary value that the
+ significand of MODE will hold. */
/* ??? Legacy. Should get access to real_format directly. */
int
if (fmt == NULL)
return 0;
+ if (fmt->b == 10)
+ {
+ /* Return the size in bits of the largest binary value that can be
+ held by the decimal coefficient for this mode. This is one more
+ than the number of bits required to hold the largest coefficient
+ of this mode. */
+ double log2_10 = 3.3219281;
+ return fmt->p * log2_10;
+ }
return fmt->p * fmt->log2_b;
}
-125,
128,
31,
+ 31,
true,
true,
true,
-125,
128,
31,
+ 31,
true,
true,
true,
-1021,
1024,
63,
+ 63,
true,
true,
true,
-1021,
1024,
63,
+ 63,
true,
true,
true,
-16382,
16384,
95,
+ 95,
true,
true,
true,
-16381,
16384,
79,
+ 79,
true,
true,
true,
-16381,
16384,
79,
+ 79,
true,
true,
true,
-16381,
16384,
79,
+ 79,
true,
true,
true,
53,
-1021 + 53,
1024,
+ 127,
-1,
true,
true,
53,
-1021 + 53,
1024,
+ 127,
-1,
true,
true,
-16381,
16384,
127,
+ 127,
true,
true,
true,
-16381,
16384,
127,
+ 127,
true,
true,
true,
-127,
127,
15,
+ 15,
false,
false,
false,
-127,
127,
15,
+ 15,
false,
false,
false,
-1023,
1023,
15,
+ 15,
false,
false,
false,
-64,
63,
31,
+ 31,
false,
false,
false, /* ??? The encoding does allow for "unnormals". */
-64,
63,
63,
+ 63,
false,
false,
false, /* ??? The encoding does allow for "unnormals". */
false
};
\f
+/* Encode real R into a single precision DFP value in BUF. */
+static void
+encode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ long *buf ATTRIBUTE_UNUSED,
+ const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
+{
+ encode_decimal32 (fmt, buf, r);
+}
+
+/* Decode a single precision DFP value in BUF into a real R. */
+static void
+decode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
+ const long *buf ATTRIBUTE_UNUSED)
+{
+ decode_decimal32 (fmt, r, buf);
+}
+
+/* Encode real R into a double precision DFP value in BUF. */
+static void
+encode_decimal_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ long *buf ATTRIBUTE_UNUSED,
+ const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
+{
+ encode_decimal64 (fmt, buf, r);
+}
+
+/* Decode a double precision DFP value in BUF into a real R. */
+static void
+decode_decimal_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
+ const long *buf ATTRIBUTE_UNUSED)
+{
+ decode_decimal64 (fmt, r, buf);
+}
+
+/* Encode real R into a quad precision DFP value in BUF. */
+static void
+encode_decimal_quad (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ long *buf ATTRIBUTE_UNUSED,
+ const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
+{
+ encode_decimal128 (fmt, buf, r);
+}
+
+/* Decode a quad precision DFP value in BUF into a real R. */
+static void
+decode_decimal_quad (const struct real_format *fmt ATTRIBUTE_UNUSED,
+ REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
+ const long *buf ATTRIBUTE_UNUSED)
+{
+ decode_decimal128 (fmt, r, buf);
+}
+
+/* Single precision decimal floating point (IEEE 754R). */
+const struct real_format decimal_single_format =
+ {
+ encode_decimal_single,
+ decode_decimal_single,
+ 10,
+ 1, /* log10 */
+ 7,
+ 7,
+ -95,
+ 96,
+ 31,
+ 31,
+ true,
+ true,
+ true,
+ true,
+ true
+ };
+
+/* Double precision decimal floating point (IEEE 754R). */
+const struct real_format decimal_double_format =
+ {
+ encode_decimal_double,
+ decode_decimal_double,
+ 10,
+ 1, /* log10 */
+ 16,
+ 16,
+ -383,
+ 384,
+ 63,
+ 63,
+ true,
+ true,
+ true,
+ true,
+ true
+ };
+
+/* Quad precision decimal floating point (IEEE 754R). */
+const struct real_format decimal_quad_format =
+ {
+ encode_decimal_quad,
+ decode_decimal_quad,
+ 10,
+ 1, /* log10 */
+ 34,
+ 34,
+ -6143,
+ 6144,
+ 127,
+ 127,
+ true,
+ true,
+ true,
+ true,
+ true
+ };
+\f
/* The "twos-complement" c4x format is officially defined as
x = s(~s).f * 2**e
24,
-126,
128,
+ 23,
-1,
false,
false,
32,
-126,
128,
+ 31,
-1,
false,
false,
-MAX_EXP,
MAX_EXP,
-1,
+ -1,
true,
true,
false,