aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Grimm <jgrimm2@us.ibm.com>2005-12-02 02:30:42 +0000
committerBen Elliston <bje@gcc.gnu.org>2005-12-02 13:30:42 +1100
commit909e2256221436f25d53bd2fec7cf85634cdb8ec (patch)
tree50f43816a8c573b7d0fa0fd8a2d390dce801a672
parent8da15291d0387b0391e4842e841561d63ea636de (diff)
downloadgcc-909e2256221436f25d53bd2fec7cf85634cdb8ec.zip
gcc-909e2256221436f25d53bd2fec7cf85634cdb8ec.tar.gz
gcc-909e2256221436f25d53bd2fec7cf85634cdb8ec.tar.bz2
dfp.h, dfp.c: New files.
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. Co-Authored-By: Ben Elliston <bje@au.ibm.com> Co-Authored-By: David Edelsohn <dje@watson.ibm.com> Co-Authored-By: Janis Johnson <janis187@us.ibm.com> From-SVN: r107861
-rw-r--r--gcc/ChangeLog69
-rw-r--r--gcc/Makefile.in19
-rw-r--r--gcc/dfp.c725
-rw-r--r--gcc/dfp.h47
-rw-r--r--gcc/genmodes.c65
-rw-r--r--gcc/machmode.def9
-rw-r--r--gcc/machmode.h9
-rw-r--r--gcc/mode-classes.def1
-rw-r--r--gcc/real.c217
-rw-r--r--gcc/real.h37
10 files changed, 1165 insertions, 33 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index e40030a..ea64c3b 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 de573ca8..a464dd2 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 0000000..ab05751
--- /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 0000000..d7f5b01
--- /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 142dde4..d8ba5df 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 4689521..ffb675d 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 1ba5963..3948fc9 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 08f679e..7fc7a9b 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 9b165ec..043270c 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 23605639..3eecb92 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);