diff options
author | bje <bje@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-12-02 02:30:42 +0000 |
---|---|---|
committer | bje <bje@138bc75d-0d04-0410-961f-82ee72b054a4> | 2005-12-02 02:30:42 +0000 |
commit | 3c28f41a5c47111104ef608679448ae441408286 (patch) | |
tree | 50f43816a8c573b7d0fa0fd8a2d390dce801a672 /gcc/real.c | |
parent | c31fdaf6c04044990088f65f9316c458793feb44 (diff) | |
download | gcc-3c28f41a5c47111104ef608679448ae441408286.tar.gz |
2005-12-02 Jon Grimm <jgrimm2@us.ibm.com>
Janis Johnson <janis187@us.ibm.com>
David Edelsohn <dje@watson.ibm.com>
Ben Elliston <bje@au.ibm.com>
* dfp.h, dfp.c: New files.
* Makefile.in (DECNUM, DECNUMINC, LIBDECNUMBER): New variables.
(DECNUM_H): Likewise.
(LIBDEPS, LIBS, BACKEND): Append $(LIBDECNUMBER).
(INCLUDES): Append $(DECNUMINC).
(OBJS-common): Add dfp.o.
(dfp.o): New rule.
* real.h (EXP_BITS): Pinch one bit to ..
(struct real_value): Add decimal field.
(real_format): Change table size, update documentation.
(REAL_MODE_FORMAT): Update for to handle float, decimal float.
(real_from_string3): Declare.
(decimal_single_format): Declare.
(decimal_double_format): Declare.
(decimal_quad_format): Declare.
(REAL_VALUE_TO_TARGET_DECIMAL32): New.
(REAL_VALUE_TO_TARGET_DECIMAL64): New.
(REAL_VALUE_TO_TARGET_DECIMAL128): New.
* real.c: Include dfp.h.
(normalize): Early return for decimal floats.
(do_add): Zero decimal field.
(do_compare): Call do_decimal_compare for decimal floats.
(do_fix_trunc): Likewise, call decimal_do_fix_trunc.
(real_arithmetic): Call decimal_real_arithmetic for decimal
floating point operands.
(real_identical): If a and b are of differing radix, return false.
(real_to_integer): Call decimal_real_to_integer if the value is a
decimal float.
(real_to_integer2): Likewise, call decimal_real_to_integer2.
(real_to_decimal): Likewise, call decimal_real_to_decimal.
(real_to_hexadecimal): Place "N/A" in the return string for
decimal float.
(real_from_string3): New variant, given a mode.
(real_maxval): Use decimal_real_maxval for decimal floats.
(round_for_format): Use decimal_round_for_format for decimals.
(real_convert): Use decimal_real_convert where appropriate.
(significand_size): Handle base 10.
(encode_decimal_single, decode_decimal_single,
encode_decimal_double, decode_decimal_double, encode_decimal_quad,
decode_decimal_quad): New functions.
(decimal_single_format): New.
(decimal_double_format): New.
(decimal_quad_format): New.
* machmode.def: Add SD, DD and TD decimal floating point modes.
* machmode.h (FLOAT_MODE_P, SCALAR_FLOAT_MODE_P, MODES_WIDEN_P):
Include MODE_DECIMAL_FLOAT.
(DECIMAL_FLOAT_MODE_P): New.
* mode-classes.def (MODE_DECIMAL_FLOAT): New mode class.
* genmodes.c (struct mode_data): Add counter field.
(struct mode_data): Update comment for format.
(blank_mode): Initialise counter field.
(new_mode): Increment counter field for each mode defined.
(complete_mode): Handle MODE_DECIMAL_FLOAT, update check for mode
using a format.
(make_complex_modes): Handle modes containing `D'.
(DECIMAL_FLOAT_MODE, FRACTIONAL_DECIMAL_FLOAT_MODE): New.
(make_decimal_float_mode): New.
(reset_float_format): Handle MODE_DECIMAL_FLOAT.
(cmp_modes): Compare counter field if other characteristics
similar.
(emit_real_format_for_mode): Support formats for decimal floats.
* doc/rtl.texi (Machine Modes): Document SD, DD and TDmodes.
Document MODE_DECIMAL_FLOAT.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@107861 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/real.c')
-rw-r--r-- | gcc/real.c | 217 |
1 files changed, 206 insertions, 11 deletions
diff --git a/gcc/real.c b/gcc/real.c index 9b165ec0c97..043270c4c7d 100644 --- a/gcc/real.c +++ b/gcc/real.c @@ -29,6 +29,7 @@ #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, @@ -480,6 +481,9 @@ normalize (REAL_VALUE_TYPE *r) 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) @@ -643,6 +647,7 @@ do_add (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a, /* Zero out the remaining fields. */ r->signalling = 0; r->canonical = 0; + r->decimal = 0; /* Re-normalize the result. */ normalize (r); @@ -938,6 +943,9 @@ do_compare (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b, 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)) @@ -963,6 +971,11 @@ do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a) 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) @@ -984,6 +997,9 @@ real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0, { enum tree_code code = icode; + if (op0->decimal || (op1 && op1->decimal)) + return decimal_real_arithmetic (r, icode, op0, op1); + switch (code) { case PLUS_EXPR: @@ -1187,6 +1203,8 @@ real_identical (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b) return true; case rvc_normal: + if (a->decimal != b->decimal) + return false; if (REAL_EXP (a) != REAL_EXP (b)) return false; break; @@ -1269,6 +1287,9 @@ real_to_integer (const REAL_VALUE_TYPE *r) 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 @@ -1330,6 +1351,12 @@ real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh, break; case rvc_normal: + if (r->decimal) + { + decimal_real_to_integer2 (plow, phigh, r); + return; + } + exp = REAL_EXP (r); if (exp <= 0) goto underflow; @@ -1448,6 +1475,12 @@ real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, size_t buf_size, 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) @@ -1714,6 +1747,13 @@ real_to_hexadecimal (char *str, const REAL_VALUE_TYPE *r, size_t buf_size, 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; @@ -1957,6 +1997,20 @@ real_from_string2 (const char *s, enum machine_mode mode) 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 @@ -2202,16 +2256,20 @@ real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode) 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. */ @@ -2243,6 +2301,20 @@ round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r) 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; @@ -2277,7 +2349,10 @@ round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r) 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; @@ -2377,6 +2452,10 @@ real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode, 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. */ @@ -2476,7 +2555,8 @@ real_from_target (REAL_VALUE_TYPE *r, const long *buf, enum machine_mode mode) (*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 @@ -2488,6 +2568,15 @@ significand_size (enum machine_mode mode) 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; } @@ -4234,6 +4323,112 @@ const struct real_format i370_double_format = false }; +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +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); +} + +/* Proposed IEEE 754r decimal floating point. */ +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 + }; + +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 + }; + +const struct real_format decimal_quad_format = + { + encode_decimal_quad, + decode_decimal_quad, + 10, + 1, /* log10 */ + 34, + 34, + -6414, + 6413, + 127, + 127, + true, + true, + true, + true, + true + }; + /* The "twos-complement" c4x format is officially defined as x = s(~s).f * 2**e |