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 | |
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')
-rw-r--r-- | gcc/ChangeLog | 69 | ||||
-rw-r--r-- | gcc/Makefile.in | 19 | ||||
-rw-r--r-- | gcc/dfp.c | 725 | ||||
-rw-r--r-- | gcc/dfp.h | 47 | ||||
-rw-r--r-- | gcc/genmodes.c | 65 | ||||
-rw-r--r-- | gcc/machmode.def | 9 | ||||
-rw-r--r-- | gcc/machmode.h | 9 | ||||
-rw-r--r-- | gcc/mode-classes.def | 1 | ||||
-rw-r--r-- | gcc/real.c | 217 | ||||
-rw-r--r-- | gcc/real.h | 37 |
10 files changed, 1165 insertions, 33 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index e40030ad5fc..ea64c3b95e8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,72 @@ +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. + 2005-12-02 Alan Modra <amodra@bigpond.net.au> * simplify-rtx.c (simplify_plus_minus): Do simplify constants. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index de573ca839c..a464dd23e27 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -298,6 +298,11 @@ GMPINC = @GMPINC@ CPPLIB = ../libcpp/libcpp.a CPPINC = -I$(srcdir)/../libcpp/include +# Where to find decNumber +DECNUM = $(srcdir)/../libdecnumber +DECNUMINC = -I$(DECNUM) +LIBDECNUMBER = ../libdecnumber/libdecnumber.a + # Substitution type for target's getgroups 2nd arg. TARGET_GETGROUPS_T = @TARGET_GETGROUPS_T@ @@ -766,6 +771,8 @@ SYSTEM_H = system.h hwint.h $(srcdir)/../include/libiberty.h PREDICT_H = predict.h predict.def CPPLIB_H = $(srcdir)/../libcpp/include/line-map.h \ $(srcdir)/../libcpp/include/cpplib.h +DECNUM_H = $(DECNUM)/decContext.h $(DECNUM)/decDPD.h $(DECNUM)/decNumber.h \ + $(DECNUM)/decimal32.h $(DECNUM)/decimal64.h $(DECNUM)/decimal128.h MKDEPS_H = $(srcdir)/../libcpp/include/mkdeps.h SYMTAB_H = $(srcdir)/../libcpp/include/symtab.h CPP_ID_DATA_H = $(CPPLIB_H) $(srcdir)/../libcpp/include/cpp-id-data.h @@ -806,7 +813,7 @@ LIBIBERTY = ../libiberty/libiberty.a BUILD_LIBIBERTY = $(build_objdir)/libiberty/libiberty.a # Dependencies on the intl and portability libraries. -LIBDEPS= $(CPPLIB) $(LIBIBERTY) $(LIBINTL_DEP) $(LIBICONV_DEP) +LIBDEPS= $(CPPLIB) $(LIBIBERTY) $(LIBINTL_DEP) $(LIBICONV_DEP) $(LIBDECNUMBER) # Likewise, for use in the tools that must run on this machine # even if we are cross-building GCC. @@ -814,7 +821,7 @@ BUILD_LIBDEPS= $(BUILD_LIBIBERTY) # How to link with both our special library facilities # and the system's installed libraries. -LIBS = @LIBS@ $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) +LIBS = @LIBS@ $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) $(LIBDECNUMBER) # Any system libraries needed just for GNAT. SYSLIBS = @GNAT_LIBEXC@ @@ -844,7 +851,7 @@ BUILD_VARRAY = build/varray.o # libintl.h will be found in ../intl if we are using the included libintl. INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \ -I$(srcdir)/../include @INCINTL@ \ - $(CPPINC) $(GMPINC) + $(CPPINC) $(GMPINC) $(DECNUMINC) .c.o: $(CC) -c $(ALL_CFLAGS) $(ALL_CPPFLAGS) $< $(OUTPUT_OPTION) @@ -963,7 +970,7 @@ OBJS-common = \ cfgloopanal.o cfgloopmanip.o loop-init.o loop-unswitch.o loop-unroll.o \ cfgrtl.o combine.o conflict.o convert.o coverage.o cse.o cselib.o \ dbxout.o ddg.o tree-ssa-loop-ch.o loop-invariant.o tree-ssa-loop-im.o \ - debug.o df.o diagnostic.o dojump.o dominance.o loop-doloop.o \ + debug.o df.o dfp.o diagnostic.o dojump.o dominance.o loop-doloop.o \ dwarf2asm.o dwarf2out.o emit-rtl.o except.o explow.o loop-iv.o \ expmed.o expr.o final.o flow.o fold-const.o function.o gcse.o \ genrtl.o ggc-common.o global.o graph.o gtype-desc.o \ @@ -997,7 +1004,7 @@ OBJS = $(OBJS-common) $(out_object_file) $(OBJS-archive) OBJS-onestep = libbackend.o $(OBJS-archive) -BACKEND = main.o @TREEBROWSER@ libbackend.a $(CPPLIB) +BACKEND = main.o @TREEBROWSER@ libbackend.a $(CPPLIB) $(LIBDECNUMBER) # Files to be copied after each stage in building. STAGECOPYSTUFF = insn-flags.h insn-config.h insn-codes.h \ @@ -2146,6 +2153,8 @@ emit-rtl.o : emit-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(RTL_H) \ $(HASHTAB_H) $(TM_P_H) debug.h langhooks.h tree-pass.h gt-emit-rtl.h real.o : real.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ toplev.h $(TM_P_H) real.h +dfp.o : dfp.c dfp.h $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \ + toplev.h $(TM_P_H) real.h $(DECNUM_H) integrate.o : integrate.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(RTL_H) $(TREE_H) $(FLAGS_H) debug.h $(INTEGRATE_H) insn-config.h \ $(EXPR_H) real.h $(REGS_H) intl.h function.h output.h $(RECOG_H) \ diff --git a/gcc/dfp.c b/gcc/dfp.c new file mode 100644 index 00000000000..ab057517480 --- /dev/null +++ b/gcc/dfp.c @@ -0,0 +1,725 @@ +/* Decimal floating point support. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +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, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#include "config.h" +#include "system.h" +#include "coretypes.h" +#include "tm.h" +#include "tree.h" +#include "toplev.h" +#include "real.h" +#include "tm_p.h" +#include "dfp.h" + +/* The order of the following headers is important for making sure + decNumber structure is large enough to hold decimal128 digits. */ + +#include "decimal128.h" +#include "decimal64.h" +#include "decimal32.h" +#include "decNumber.h" + +static unsigned long +dfp_byte_swap (unsigned long in) +{ + unsigned long out; + unsigned char *p = (unsigned char *) &out; + union { + unsigned long i; + unsigned char b[4]; + } u; + + u.i = in; + p[0] = u.b[3]; + p[1] = u.b[2]; + p[2] = u.b[1]; + p[3] = u.b[0]; + + return out; +} + +/* Initialize R (a real with the decimal flag set) from DN. Can + utilize status passed in via CONTEXT, if a previous operation had + interesting status. */ + +static void +decimal_from_decnumber (REAL_VALUE_TYPE *r, decNumber *dn, decContext *context) +{ + memset (r, 0, sizeof (REAL_VALUE_TYPE)); + + r->cl = rvc_normal; + if (decNumberIsZero (dn)) + r->cl = rvc_zero; + if (decNumberIsNaN (dn)) + r->cl = rvc_nan; + if (decNumberIsInfinite (dn)) + r->cl = rvc_inf; + if (context->status & DEC_Overflow) + r->cl = rvc_inf; + if (decNumberIsNegative (dn)) + r->sign = 1; + r->decimal = 1; + + if (r->cl != rvc_normal) + return; + + decContextDefault (context, DEC_INIT_DECIMAL128); + context->traps = 0; + + decimal128FromNumber ((decimal128 *) r->sig, dn, context); +} + +/* Create decimal encoded R from string S. */ + +void +decimal_real_from_string (REAL_VALUE_TYPE *r, const char *s) +{ + decNumber dn; + decContext set; + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + decNumberFromString (&dn, (char *) s, &set); + + /* It would be more efficient to store directly in decNumber format, + but that is impractical from current data structure size. + Encoding as a decimal128 is much more compact. */ + decimal_from_decnumber (r, &dn, &set); +} + +/* Initialize a decNumber from a REAL_VALUE_TYPE. */ + +static void +decimal_to_decnumber (const REAL_VALUE_TYPE *r, decNumber *dn) +{ + decContext set; + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + switch (r->cl) + { + case rvc_zero: + decNumberZero (dn); + break; + case rvc_inf: + decNumberFromString (dn, (char *)"Infinity", &set); + break; + case rvc_nan: + if (r->signalling) + decNumberFromString (dn, (char *)"snan", &set); + else + decNumberFromString (dn, (char *)"nan", &set); + break; + case rvc_normal: + gcc_assert (r->decimal); + decimal128ToNumber ((decimal128 *) r->sig, dn); + break; + default: + gcc_unreachable (); + } + + /* Fix up sign bit. */ + if (r->sign != decNumberIsNegative (dn)) + decNumberNegate (dn); +} + +/* Encode a real into an IEEE 754R decimal32 type. */ + +void +encode_decimal32 (const struct real_format *fmt ATTRIBUTE_UNUSED, + long *buf, const REAL_VALUE_TYPE *r) +{ + decNumber dn; + decimal32 d32; + decContext set; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + decimal_to_decnumber (r, &dn); + decimal32FromNumber (&d32, &dn, &set); + + if (FLOAT_WORDS_BIG_ENDIAN) + buf[0] = *(uint32_t *) d32.bytes; + else + buf[0] = dfp_byte_swap (*(uint32_t *) d32.bytes); +} + +/* Decode an IEEE 754R decimal32 type into a real. */ + +void decode_decimal32 (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) +{ + decNumber dn; + decimal32 d32; + decContext set; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + if (FLOAT_WORDS_BIG_ENDIAN) + *((uint32_t *) d32.bytes) = (uint32_t) buf[0]; + else + *((uint32_t *) d32.bytes) = dfp_byte_swap ((uint32_t) buf[0]); + + decimal32ToNumber (&d32, &dn); + decimal_from_decnumber (r, &dn, &set); +} + +/* Encode a real into an IEEE 754R decimal64 type. */ + +void +encode_decimal64 (const struct real_format *fmt ATTRIBUTE_UNUSED, + long *buf, const REAL_VALUE_TYPE *r) +{ + decNumber dn; + decimal64 d64; + decContext set; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + decimal_to_decnumber (r, &dn); + decimal64FromNumber (&d64, &dn, &set); + + if (FLOAT_WORDS_BIG_ENDIAN) + { + buf[0] = *(uint32_t *) &d64.bytes[0]; + buf[1] = *(uint32_t *) &d64.bytes[4]; + } + else + { + buf[1] = dfp_byte_swap (*(uint32_t *) &d64.bytes[0]); + buf[0] = dfp_byte_swap (*(uint32_t *) &d64.bytes[4]); + } +} + +/* Decode an IEEE 754R decimal64 type into a real. */ + +void +decode_decimal64 (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) +{ + decNumber dn; + decimal64 d64; + decContext set; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + if (FLOAT_WORDS_BIG_ENDIAN) + { + *((uint32_t *) &d64.bytes[0]) = (uint32_t) buf[0]; + *((uint32_t *) &d64.bytes[4]) = (uint32_t) buf[1]; + } + else + { + *((uint32_t *) &d64.bytes[0]) = dfp_byte_swap ((uint32_t) buf[1]); + *((uint32_t *) &d64.bytes[4]) = dfp_byte_swap ((uint32_t) buf[0]); + } + + decimal64ToNumber (&d64, &dn); + decimal_from_decnumber (r, &dn, &set); +} + +/* Encode a real into an IEEE 754R decimal128 type. */ + +void +encode_decimal128 (const struct real_format *fmt ATTRIBUTE_UNUSED, + long *buf, const REAL_VALUE_TYPE *r) +{ + decNumber dn; + decContext set; + decimal128 d128; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + decimal_to_decnumber (r, &dn); + decimal128FromNumber (&d128, &dn, &set); + + if (FLOAT_WORDS_BIG_ENDIAN) + { + buf[0] = *(uint32_t *) &d128.bytes[0]; + buf[1] = *(uint32_t *) &d128.bytes[4]; + buf[2] = *(uint32_t *) &d128.bytes[8]; + buf[3] = *(uint32_t *) &d128.bytes[12]; + } + else + { + buf[0] = dfp_byte_swap (*(uint32_t *) &d128.bytes[12]); + buf[1] = dfp_byte_swap (*(uint32_t *) &d128.bytes[8]); + buf[2] = dfp_byte_swap (*(uint32_t *) &d128.bytes[4]); + buf[3] = dfp_byte_swap (*(uint32_t *) &d128.bytes[0]); + } +} + +/* Decode an IEEE 754R decimal128 type into a real. */ + +void +decode_decimal128 (const struct real_format *fmt ATTRIBUTE_UNUSED, + REAL_VALUE_TYPE *r, const long *buf) +{ + decNumber dn; + decimal128 d128; + decContext set; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + if (FLOAT_WORDS_BIG_ENDIAN) + { + *((uint32_t *) &d128.bytes[0]) = (uint32_t) buf[0]; + *((uint32_t *) &d128.bytes[4]) = (uint32_t) buf[1]; + *((uint32_t *) &d128.bytes[8]) = (uint32_t) buf[2]; + *((uint32_t *) &d128.bytes[12]) = (uint32_t) buf[3]; + } + else + { + *((uint32_t *) &d128.bytes[0]) = dfp_byte_swap ((uint32_t) buf[3]); + *((uint32_t *) &d128.bytes[4]) = dfp_byte_swap ((uint32_t) buf[2]); + *((uint32_t *) &d128.bytes[8]) = dfp_byte_swap ((uint32_t) buf[1]); + *((uint32_t *) &d128.bytes[12]) = dfp_byte_swap ((uint32_t) buf[0]); + } + + decimal128ToNumber (&d128, &dn); + decimal_from_decnumber (r, &dn, &set); +} + +/* Helper function to convert from a binary real internal + representation. */ + +static void +decimal_to_binary (REAL_VALUE_TYPE *to, const REAL_VALUE_TYPE *from, + enum machine_mode mode) +{ + char string[256]; + decimal128 *d128; + d128 = (decimal128 *) from->sig; + + decimal128ToString (d128, string); + real_from_string3 (to, string, mode); +} + + +/* Helper function to convert from a binary real internal + representation. */ + +static void +decimal_from_binary (REAL_VALUE_TYPE *to, const REAL_VALUE_TYPE *from) +{ + char string[256]; + + /* We convert to string, then to decNumber then to decimal128. */ + real_to_decimal (string, from, sizeof (string), 0, 1); + decimal_real_from_string (to, string); +} + +/* Helper function to real.c:do_compare() to handle decimal internal + represenation including when one of the operands is still in the + binary internal representation. */ + +int +decimal_do_compare (const REAL_VALUE_TYPE *a, const REAL_VALUE_TYPE *b, + int nan_result) +{ + decContext set; + decNumber dn, dn2, dn3; + REAL_VALUE_TYPE a1, b1; + + /* If either operand is non-decimal, create temporary versions. */ + if (!a->decimal) + { + decimal_from_binary (&a1, a); + a = &a1; + } + if (!b->decimal) + { + decimal_from_binary (&b1, b); + b = &b1; + } + + /* Convert into decNumber form for comparison operation. */ + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + decimal128ToNumber ((decimal128 *) a->sig, &dn2); + decimal128ToNumber ((decimal128 *) b->sig, &dn3); + + /* Finally, do the comparison. */ + decNumberCompare (&dn, &dn2, &dn3, &set); + + /* Return the comparison result. */ + if (decNumberIsNaN (&dn)) + return nan_result; + else if (decNumberIsZero (&dn)) + return 0; + else if (decNumberIsNegative (&dn)) + return -1; + else + return 1; +} + +/* Helper to round_for_format, handling decimal float types. */ + +void +decimal_round_for_format (const struct real_format *fmt, REAL_VALUE_TYPE *r) +{ + decNumber dn; + decContext set; + + /* Real encoding occurs later. */ + if (r->cl != rvc_normal) + return; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + decimal128ToNumber ((decimal128 *) r->sig, &dn); + + if (fmt == &decimal_quad_format) + { + /* The internal format is already in this format. */ + return; + } + else if (fmt == &decimal_single_format) + { + decimal32 d32; + decContextDefault (&set, DEC_INIT_DECIMAL32); + set.traps = 0; + + decimal32FromNumber (&d32, &dn, &set); + decimal32ToNumber (&d32, &dn); + } + else if (fmt == &decimal_double_format) + { + decimal64 d64; + decContextDefault (&set, DEC_INIT_DECIMAL64); + set.traps = 0; + + decimal64FromNumber (&d64, &dn, &set); + decimal64ToNumber (&d64, &dn); + } + else + gcc_unreachable (); + + decimal_from_decnumber (r, &dn, &set); +} + +/* Extend or truncate to a new mode. Handles conversions between + binary and decimal types. */ + +void +decimal_real_convert (REAL_VALUE_TYPE *r, enum machine_mode mode, + const REAL_VALUE_TYPE *a) +{ + const struct real_format *fmt = REAL_MODE_FORMAT (mode); + + if (a->decimal && fmt->b == 10) + return; + if (a->decimal) + decimal_to_binary (r, a, mode); + else + decimal_from_binary (r, a); +} + +/* Render R_ORIG 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. Currently, not honoring + DIGITS or CROP_TRAILING_ZEROS. */ + +void decimal_real_to_decimal (char *str, const REAL_VALUE_TYPE *r_orig, + size_t buf_size, + size_t digits ATTRIBUTE_UNUSED, + int crop_trailing_zeros ATTRIBUTE_UNUSED) +{ + decimal128 *d128 = (decimal128*) r_orig->sig; + + /* decimal128ToString requires space for at least 24 characters; + Require two more for suffix. */ + gcc_assert (buf_size >= 24); + decimal128ToString (d128, str); +} + +static bool +decimal_do_add (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0, + const REAL_VALUE_TYPE *op1, int subtract_p) +{ + decNumber dn; + decContext set; + decNumber dn2, dn3; + + decimal_to_decnumber (op0, &dn2); + decimal_to_decnumber (op1, &dn3); + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + if (subtract_p) + decNumberSubtract (&dn, &dn2, &dn3, &set); + else + decNumberAdd (&dn, &dn2, &dn3, &set); + + decimal_from_decnumber (r, &dn, &set); + + /* Return true, if inexact. */ + return (set.status & DEC_Inexact); +} + +/* Compute R = OP0 * OP1. */ + +static bool +decimal_do_multiply (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0, + const REAL_VALUE_TYPE *op1) +{ + decContext set; + decNumber dn, dn2, dn3; + + decimal_to_decnumber (op0, &dn2); + decimal_to_decnumber (op1, &dn3); + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + decNumberMultiply (&dn, &dn2, &dn3, &set); + decimal_from_decnumber (r, &dn, &set); + + /* Return true, if inexact. */ + return (set.status & DEC_Inexact); +} + +/* Compute R = OP0 / OP1. */ + +static bool +decimal_do_divide (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0, + const REAL_VALUE_TYPE *op1) +{ + decContext set; + decNumber dn, dn2, dn3; + + decimal_to_decnumber (op0, &dn2); + decimal_to_decnumber (op1, &dn3); + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + + decNumberDivide (&dn, &dn2, &dn3, &set); + decimal_from_decnumber (r, &dn, &set); + + /* Return true, if inexact. */ + return (set.status & DEC_Inexact); +} + +/* Set R to A truncated to an integral value toward zero (decimal + floating point). */ + +void +decimal_do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a) +{ + decNumber dn, dn2; + decContext set; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + set.round = DEC_ROUND_DOWN; + decimal128ToNumber ((decimal128 *) a->sig, &dn2); + + decNumberToIntegralValue (&dn, &dn2, &set); + decimal_from_decnumber (r, &dn, &set); +} + +/* Render decimal float value R as an integer. */ + +HOST_WIDE_INT +decimal_real_to_integer (const REAL_VALUE_TYPE *r) +{ + decContext set; + decNumber dn, dn2, dn3; + REAL_VALUE_TYPE to; + char string[256]; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + set.round = DEC_ROUND_DOWN; + decimal128ToNumber ((decimal128 *) r->sig, &dn); + + decNumberToIntegralValue (&dn2, &dn, &set); + decNumberZero (&dn3); + decNumberRescale (&dn, &dn2, &dn3, &set); + + /* Convert to REAL_VALUE_TYPE and call appropriate conversion + function. */ + decNumberToString (&dn, string); + real_from_string (&to, string); + return real_to_integer (&to); +} + +/* Likewise, but to an integer pair, HI+LOW. */ + +void +decimal_real_to_integer2 (HOST_WIDE_INT *plow, HOST_WIDE_INT *phigh, + const REAL_VALUE_TYPE *r) +{ + decContext set; + decNumber dn, dn2, dn3; + REAL_VALUE_TYPE to; + char string[256]; + + decContextDefault (&set, DEC_INIT_DECIMAL128); + set.traps = 0; + set.round = DEC_ROUND_DOWN; + decimal128ToNumber ((decimal128 *) r->sig, &dn); + + decNumberToIntegralValue (&dn2, &dn, &set); + decNumberZero (&dn3); + decNumberRescale (&dn, &dn2, &dn3, &set); + + /* Conver to REAL_VALUE_TYPE and call appropriate conversion + function. */ + decNumberToString (&dn, string); + real_from_string (&to, string); + real_to_integer2 (plow, phigh, &to); +} + +/* Perform the decimal floating point operation described by COODE. + For a unary operation, leave OP1 NULL. This function returns true + if the result may be inexact due to loss of precision. */ + +bool +decimal_real_arithmetic (REAL_VALUE_TYPE *r, int icode, + const REAL_VALUE_TYPE *op0, + const REAL_VALUE_TYPE *op1) +{ + enum tree_code code = icode; + REAL_VALUE_TYPE a1; + REAL_VALUE_TYPE b1; + + /* If either op is not a decimal, create a temporary decimal + versions. */ + if (!op0->decimal) + { + decimal_from_binary (&a1, op0); + op0 = &a1; + } + if (op1 && !op1->decimal) + { + decimal_from_binary (&b1, op1); + op1 = &b1; + } + + switch (code) + { + case PLUS_EXPR: + (void) decimal_do_add (r, op0, op1, 0); + break; + + case MINUS_EXPR: + (void) decimal_do_add (r, op0, op1, 1); + break; + + case MULT_EXPR: + (void) decimal_do_multiply (r, op0, op1); + break; + + case RDIV_EXPR: + (void) decimal_do_divide (r, op0, op1); + break; + + case MIN_EXPR: + if (op1->cl == rvc_nan) + *r = *op1; + else if (real_compare (UNLT_EXPR, op0, op1)) + *r = *op0; + else + *r = *op1; + break; + + case MAX_EXPR: + if (op1->cl == rvc_nan) + *r = *op1; + else if (real_compare (LT_EXPR, op0, op1)) + *r = *op1; + else + *r = *op0; + break; + + case NEGATE_EXPR: + { + decimal128 *d128; + *r = *op0; + d128 = (decimal128 *) r->sig; + /* Flip high bit. */ + d128->bytes[0] ^= 1 << 7; + /* Keep sign field in sync. */ + r->sign ^= 1; + } + break; + + case ABS_EXPR: + { + decimal128 *d128; + *r = *op0; + d128 = (decimal128 *) r->sig; + /* Clear high bit. */ + d128->bytes[0] &= 0x7f; + /* Keep sign field in sync. */ + r->sign = 0; + } + break; + + case FIX_TRUNC_EXPR: + decimal_do_fix_trunc (r, op0); + break; + + default: + gcc_unreachable (); + } + + /* FIXME: Indicate all operations as inexact for now due to unknown + working precision. */ + return true; +} + +/* Fills R with the largest finite value representable in mode MODE. + If SIGN is nonzero, R is set to the most negative finite value. */ + +void +decimal_real_maxval (REAL_VALUE_TYPE *r, int sign, enum machine_mode mode) +{ + char *max; + + switch (mode) + { + case SDmode: + max = (char *) "9.999999E96"; + break; + case DDmode: + max = (char *) "9.999999999999999E384"; + break; + case TDmode: + max = (char *) "9.999999999999999999999999999999999E6144"; + break; + default: + gcc_unreachable (); + } + + decimal_real_from_string (r, max); + if (sign) + r->sig[0] |= 0x80000000; +} diff --git a/gcc/dfp.h b/gcc/dfp.h new file mode 100644 index 00000000000..d7f5b01cc7d --- /dev/null +++ b/gcc/dfp.h @@ -0,0 +1,47 @@ +/* Decimal floating point support functions for GNU compiler. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GCC. + +GCC is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +GCC is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +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, 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301, USA. */ + +#ifndef GCC_DFP_H +#define GCC_DFP_H + +/* Encode REAL_VALUE_TYPEs into 32/64/128-bit IEEE 754R encoded values. */ +void encode_decimal32 (const struct real_format *fmt, long *, const REAL_VALUE_TYPE *); +void encode_decimal64 (const struct real_format *fmt, long *, const REAL_VALUE_TYPE *); +void decode_decimal128 (const struct real_format *, REAL_VALUE_TYPE *, const long *); + +/* Decode 32/64/128-bit IEEE 754R encoded values into REAL_VALUE_TYPEs. */ +void decode_decimal32 (const struct real_format *, REAL_VALUE_TYPE *, const long *); +void decode_decimal64 (const struct real_format *, REAL_VALUE_TYPE *, const long *); +void encode_decimal128 (const struct real_format *fmt, long *, const REAL_VALUE_TYPE *); + +/* Arithmetic and conversion functions. */ +int decimal_do_compare (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, int); +void decimal_real_from_string (REAL_VALUE_TYPE *, const char *); +void decimal_round_for_format (const struct real_format *, REAL_VALUE_TYPE *); +void decimal_real_convert (REAL_VALUE_TYPE *, enum machine_mode, const REAL_VALUE_TYPE *); +void decimal_real_to_decimal (char *, const REAL_VALUE_TYPE *, size_t, size_t, int); +void decimal_do_fix_trunc (REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); +bool decimal_real_arithmetic (REAL_VALUE_TYPE *, int, const REAL_VALUE_TYPE *, + const REAL_VALUE_TYPE *); +void decimal_real_maxval (REAL_VALUE_TYPE *, int, enum machine_mode); +void decimal_real_to_integer2 (HOST_WIDE_INT *, HOST_WIDE_INT *, const REAL_VALUE_TYPE *); +HOST_WIDE_INT decimal_real_to_integer (const REAL_VALUE_TYPE *); + +#endif /* GCC_DFP_H */ diff --git a/gcc/genmodes.c b/gcc/genmodes.c index 142dde4e737..d8ba5df0148 100644 --- a/gcc/genmodes.c +++ b/gcc/genmodes.c @@ -60,7 +60,7 @@ struct mode_data unsigned int bytesize; /* storage size in addressable units */ unsigned int ncomponents; /* number of subunits */ unsigned int alignment; /* mode alignment */ - const char *format; /* floating point format - MODE_FLOAT only */ + const char *format; /* floating point format - float modes only */ struct mode_data *component; /* mode of components */ struct mode_data *wider; /* next wider mode */ @@ -72,6 +72,7 @@ struct mode_data const char *file; /* file and line of definition, */ unsigned int line; /* for error reporting */ + unsigned int counter; /* Rank ordering of modes */ }; static struct mode_data *modes[MAX_MODE_CLASS]; @@ -82,7 +83,7 @@ static const struct mode_data blank_mode = { 0, "<unknown>", MAX_MODE_CLASS, -1U, -1U, -1U, -1U, 0, 0, 0, 0, 0, 0, - "<unknown>", 0 + "<unknown>", 0, 0 }; static htab_t modes_by_name; @@ -146,6 +147,7 @@ new_mode (enum mode_class cl, const char *name, const char *file, unsigned int line) { struct mode_data *m; + static unsigned int count = 0; m = find_mode (name); if (m) @@ -163,6 +165,7 @@ new_mode (enum mode_class cl, const char *name, if (file) m->file = trim_filename (file); m->line = line; + m->counter = count++; m->next = modes[cl]; modes[cl] = m; @@ -323,11 +326,12 @@ complete_mode (struct mode_data *m) case MODE_INT: case MODE_FLOAT: + case MODE_DECIMAL_FLOAT: /* A scalar mode must have a byte size, may have a bit size, and must not have components. A float mode must have a format. */ validate_mode (m, OPTIONAL, SET, UNSET, UNSET, - m->cl == MODE_FLOAT ? SET : UNSET); + m->cl != MODE_INT ? SET : UNSET); m->ncomponents = 1; m->component = 0; @@ -429,17 +433,22 @@ make_complex_modes (enum mode_class cl, This inconsistency should be eliminated. */ if (cl == MODE_FLOAT) { - char *p; + char *p, *q = 0; strncpy (buf, m->name, sizeof buf); p = strchr (buf, 'F'); if (p == 0) + q = strchr (buf, 'D'); + if (p == 0 && q == 0) { - error ("%s:%d: float mode \"%s\" has no 'F'", + error ("%s:%d: float mode \"%s\" has no 'F' or 'D'", m->file, m->line, m->name); continue; } - *p = 'C'; + if (p != 0) + *p = 'C'; + else + snprintf (buf, sizeof buf, "C%s", m->name); } else snprintf (buf, sizeof buf, "C%s", m->name); @@ -540,6 +549,23 @@ make_float_mode (const char *name, m->format = format; } +#define DECIMAL_FLOAT_MODE(N, Y, F) \ + FRACTIONAL_DECIMAL_FLOAT_MODE (N, -1U, Y, F) +#define FRACTIONAL_DECIMAL_FLOAT_MODE(N, B, Y, F) \ + make_decimal_float_mode (#N, B, Y, #F, __FILE__, __LINE__) + +static void +make_decimal_float_mode (const char *name, + unsigned int precision, unsigned int bytesize, + const char *format, + const char *file, unsigned int line) +{ + struct mode_data *m = new_mode (MODE_DECIMAL_FLOAT, name, file, line); + m->bytesize = bytesize; + m->precision = precision; + m->format = format; +} + #define RESET_FLOAT_FORMAT(N, F) \ reset_float_format (#N, #F, __FILE__, __LINE__) static void ATTRIBUTE_UNUSED @@ -552,9 +578,9 @@ reset_float_format (const char *name, const char *format, error ("%s:%d: no mode \"%s\"", file, line, name); return; } - if (m->cl != MODE_FLOAT) + if (m->cl != MODE_FLOAT && m->cl != MODE_DECIMAL_FLOAT) { - error ("%s:%d: mode \"%s\" is not class FLOAT", file, line, name); + error ("%s:%d: mode \"%s\" is not a FLOAT class", file, line, name); return; } m->format = format; @@ -675,7 +701,12 @@ cmp_modes (const void *a, const void *b) return -1; if (!m->component && !n->component) - return 0; + { + if (m->counter < n->counter) + return -1; + else + return 1; + } if (m->component->bytesize > n->component->bytesize) return 1; @@ -687,7 +718,10 @@ cmp_modes (const void *a, const void *b) else if (m->component->precision < n->component->precision) return -1; - return 0; + if (m->counter < n->counter) + return -1; + else + return 1; } static void @@ -1083,15 +1117,24 @@ emit_real_format_for_mode (void) format); #else print_decl ("struct real_format *\n", "real_format_for_mode", - "MAX_MODE_FLOAT - MIN_MODE_FLOAT + 1"); + "MAX_MODE_FLOAT - MIN_MODE_FLOAT + 1 " + "+ MAX_MODE_DECIMAL_FLOAT - MIN_MODE_DECIMAL_FLOAT + 1"); #endif + /* The beginning of the table is entries for float modes. */ for (m = modes[MODE_FLOAT]; m; m = m->next) if (!strcmp (m->format, "0")) tagged_printf ("%s", m->format, m->name); else tagged_printf ("&%s", m->format, m->name); + /* The end of the table is entries for decimal float modes. */ + for (m = modes[MODE_DECIMAL_FLOAT]; m; m = m->next) + if (!strcmp (m->format, "0")) + tagged_printf ("%s", m->format, m->name); + else + tagged_printf ("&%s", m->format, m->name); + print_closer (); } diff --git a/gcc/machmode.def b/gcc/machmode.def index 46895214e07..ffb675d14f0 100644 --- a/gcc/machmode.def +++ b/gcc/machmode.def @@ -87,6 +87,10 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA using floating point format FORMAT. All of the bits of its representation are significant. + DECIMAL FLOAT_MODE (MODE, BYTESIZE); + declares MODE to be of class DECIMAL_FLOAT and BYTESIZE bytes + wide. All of the bits of its representation are significant. + FRACTIONAL_FLOAT_MODE (MODE, PRECISION, BYTESIZE, FORMAT); declares MODE to be of class FLOAT, BYTESIZE bytes wide in storage, but with only PRECISION significant bits, using @@ -186,6 +190,11 @@ CC_MODE (CC); COMPLEX_MODES (INT); COMPLEX_MODES (FLOAT); +/* Decimal floating point modes. */ +DECIMAL_FLOAT_MODE (SD, 4, decimal_single_format); +DECIMAL_FLOAT_MODE (DD, 8, decimal_double_format); +DECIMAL_FLOAT_MODE (TD, 16, decimal_quad_format); + /* The symbol Pmode stands for one of the above machine modes (usually SImode). The tm.h file specifies which one. It is not a distinct mode. */ diff --git a/gcc/machmode.h b/gcc/machmode.h index 1ba5963326c..3948fc9388b 100644 --- a/gcc/machmode.h +++ b/gcc/machmode.h @@ -54,6 +54,7 @@ extern const unsigned char mode_class[NUM_MACHINE_MODES]; /* Nonzero if MODE is a floating-point mode. */ #define FLOAT_MODE_P(MODE) \ (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE) == MODE_DECIMAL_FLOAT \ || GET_MODE_CLASS (MODE) == MODE_COMPLEX_FLOAT \ || GET_MODE_CLASS (MODE) == MODE_VECTOR_FLOAT) @@ -74,12 +75,18 @@ extern const unsigned char mode_class[NUM_MACHINE_MODES]; /* Nonzero if MODE is a scalar floating point mode. */ #define SCALAR_FLOAT_MODE_P(MODE) \ - (GET_MODE_CLASS (MODE) == MODE_FLOAT) + (GET_MODE_CLASS (MODE) == MODE_FLOAT \ + || GET_MODE_CLASS (MODE) == MODE_DECIMAL_FLOAT) + +/* Nonzero if MODE is a decimal floating point mode. */ +#define DECIMAL_FLOAT_MODE_P(MODE) \ + (GET_MODE_CLASS (MODE) == MODE_DECIMAL_FLOAT) /* Nonzero if CLASS modes can be widened. */ #define CLASS_HAS_WIDER_MODES_P(CLASS) \ (CLASS == MODE_INT \ || CLASS == MODE_FLOAT \ + || CLASS == MODE_DECIMAL_FLOAT \ || CLASS == MODE_COMPLEX_FLOAT) /* Get the size in bytes and bits of an object of mode MODE. */ diff --git a/gcc/mode-classes.def b/gcc/mode-classes.def index 08f679ea78f..7fc7a9b3c80 100644 --- a/gcc/mode-classes.def +++ b/gcc/mode-classes.def @@ -25,6 +25,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA DEF_MODE_CLASS (MODE_INT), /* integer */ \ DEF_MODE_CLASS (MODE_PARTIAL_INT), /* integer with padding bits */ \ DEF_MODE_CLASS (MODE_FLOAT), /* floating point */ \ + DEF_MODE_CLASS (MODE_DECIMAL_FLOAT), /* decimal floating point */ \ DEF_MODE_CLASS (MODE_COMPLEX_INT), /* complex numbers */ \ DEF_MODE_CLASS (MODE_COMPLEX_FLOAT), \ DEF_MODE_CLASS (MODE_VECTOR_INT), /* SIMD vectors */ \ 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 diff --git a/gcc/real.h b/gcc/real.h index 23605639db9..3eecb92fbcd 100644 --- a/gcc/real.h +++ b/gcc/real.h @@ -35,7 +35,7 @@ enum real_value_class { }; #define SIGNIFICAND_BITS (128 + HOST_BITS_PER_LONG) -#define EXP_BITS (32 - 5) +#define EXP_BITS (32 - 6) #define MAX_EXP ((1 << (EXP_BITS - 1)) - 1) #define SIGSZ (SIGNIFICAND_BITS / HOST_BITS_PER_LONG) #define SIG_MSB ((unsigned long)1 << (HOST_BITS_PER_LONG - 1)) @@ -46,6 +46,7 @@ struct real_value GTY(()) sure they're packed together, otherwise REAL_VALUE_TYPE_SIZE will be miscomputed. */ unsigned int /* ENUM_BITFIELD (real_value_class) */ cl : 2; + unsigned int decimal : 1; unsigned int sign : 1; unsigned int signalling : 1; unsigned int canonical : 1; @@ -155,12 +156,20 @@ struct real_format }; -/* The target format used for each floating floating point mode. - Indexed by MODE - QFmode. */ +/* The target format used for each floating point mode. + Float modes are followed by decimal float modes, with entries for + float modes indexed by (MODE - first float mode), and entries for + decimal float modes indexed by (MODE - first decimal float mode) + + the number of float modes. */ extern const struct real_format * - real_format_for_mode[MAX_MODE_FLOAT - MIN_MODE_FLOAT + 1]; + real_format_for_mode[MAX_MODE_FLOAT - MIN_MODE_FLOAT + 1 + + MAX_MODE_DECIMAL_FLOAT - MIN_MODE_DECIMAL_FLOAT + 1]; -#define REAL_MODE_FORMAT(MODE) (real_format_for_mode[(MODE) - MIN_MODE_FLOAT]) +#define REAL_MODE_FORMAT(MODE) \ + (real_format_for_mode[DECIMAL_FLOAT_MODE_P (MODE) \ + ? ((MODE - MIN_MODE_DECIMAL_FLOAT) \ + + (MAX_MODE_FLOAT - MIN_MODE_FLOAT + 1)) \ + : (MODE - MIN_MODE_FLOAT)]) /* The following macro determines whether the floating point format is composite, i.e. may contain non-consecutive mantissa bits, in which @@ -214,6 +223,8 @@ extern void real_to_integer2 (HOST_WIDE_INT *, HOST_WIDE_INT *, /* Initialize R from a decimal or hexadecimal string. */ extern void real_from_string (REAL_VALUE_TYPE *, const char *); +/* Wrapper to allow different internal representation for decimal floats. */ +extern void real_from_string3 (REAL_VALUE_TYPE *, const char *, enum machine_mode); /* Initialize R from an integer pair HIGH/LOW. */ extern void real_from_integer (REAL_VALUE_TYPE *, enum machine_mode, @@ -260,6 +271,9 @@ extern const struct real_format i370_double_format; extern const struct real_format c4x_single_format; extern const struct real_format c4x_extended_format; 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; /* ====================================================================== */ @@ -302,6 +316,19 @@ extern const struct real_format real_internal_format; #define REAL_VALUE_FROM_UNSIGNED_INT(r, lo, hi, mode) \ real_from_integer (&(r), mode, lo, hi, 1) +/* Real values to IEEE 754R decimal floats. */ + +/* IN is a REAL_VALUE_TYPE. OUT is an array of longs. */ +#define REAL_VALUE_TO_TARGET_DECIMAL128(IN, OUT) \ + real_to_target (OUT, &(IN), mode_for_size (128, MODE_DECIMAL_FLOAT, 0)) + +#define REAL_VALUE_TO_TARGET_DECIMAL64(IN, OUT) \ + real_to_target (OUT, &(IN), mode_for_size (64, MODE_DECIMAL_FLOAT, 0)) + +/* IN is a REAL_VALUE_TYPE. OUT is a long. */ +#define REAL_VALUE_TO_TARGET_DECIMAL32(IN, OUT) \ + ((OUT) = real_to_target (NULL, &(IN), mode_for_size (32, MODE_DECIMAL_FLOAT, 0))) + extern REAL_VALUE_TYPE real_value_truncate (enum machine_mode, REAL_VALUE_TYPE); |