]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
dfp.h, dfp.c: New files.
authorJon Grimm <jgrimm2@us.ibm.com>
Fri, 2 Dec 2005 02:30:42 +0000 (02:30 +0000)
committerBen Elliston <bje@gcc.gnu.org>
Fri, 2 Dec 2005 02:30:42 +0000 (13:30 +1100)
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

gcc/ChangeLog
gcc/Makefile.in
gcc/dfp.c [new file with mode: 0644]
gcc/dfp.h [new file with mode: 0644]
gcc/genmodes.c
gcc/machmode.def
gcc/machmode.h
gcc/mode-classes.def
gcc/real.c
gcc/real.h

index e40030ad5fcad4d0a118488c8bea51358866e0eb..ea64c3b95e80433a208a716e1e9a24270764321e 100644 (file)
@@ -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.
index de573ca839c144f69fab944b4928ebcb0b353489..a464dd23e27d3be8729618facd587990394eb3ff 100644 (file)
@@ -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 (file)
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 (file)
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 */
index 142dde4e7378a016906607896958e17f0ebcf9e0..d8ba5df01484c5fdb2d23d3e93cf301d5a7f8e85 100644 (file)
@@ -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 ();
 }
 
index 46895214e07cc3e95e3a564af4830d13fe1c211f..ffb675d14f0354c0f6d70d8310e7815a1b8af1d0 100644 (file)
@@ -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.  */
 
index 1ba5963326cb32ffedae5f3d18893277cc6a452c..3948fc9388b4d067c16fe1a7c89b24a8fcdd9b4e 100644 (file)
@@ -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.  */
index 08f679ea78f716c0935e8732350dfd7de4b8cbae..7fc7a9b3c80b4efda2f7182b923843c5b94f7ca2 100644 (file)
@@ -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 */                 \
index 9b165ec0c97bc84be88c2b777db7b0d866c95db1..043270c4c7d39610aea5acf2e82f44ac0d082a84 100644 (file)
@@ -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
   };
 \f
+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
+  };
+\f
 /* The "twos-complement" c4x format is officially defined as
 
        x = s(~s).f * 2**e
index 23605639db94865e718abdfbdae9e4e82209a705..3eecb92fbcdb187cf7d11ca50ef74933d4314cdf 100644 (file)
@@ -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);