This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
PATCH: second stage of dfp-branch merge
- From: Ben Elliston <bje at au1 dot ibm dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 30 Nov 2005 23:19:17 +1100
- Subject: PATCH: second stage of dfp-branch merge
This is the second stage of my dfp-branch merge work.
This patch is a bit bigger than I had anticipated. I was planning on
sending patches to real.{h,c} and the new dfp.{h,c} files only, but a
few interdependencies pulled in a bit more of the work. It now
includes the most basic changes to add the new decimal float machine
modes and the new mode class.
The patch can be broken into a number of distinct pieces:
* Makefile.in changes (trivial to review);
* machmode.def, machmode.h, mode-classes.def, genmodes.c changes (easy);
* real.h, real.c, dfp.h and dfp.c changes (more involved).
Bootstrapped and regression tested on powerpc64-linux.
Okay for the trunk?
Ben
2005-11-30 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.
Index: machmode.h
===================================================================
--- machmode.h (revision 107693)
+++ machmode.h (working copy)
@@ -54,6 +54,7 @@ extern const unsigned char mode_class[NU
/* 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[NU
/* 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: real.c
===================================================================
--- real.c (revision 107693)
+++ real.c (working copy)
@@ -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_V
/* 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, co
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
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
{
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
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 *
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, H
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_V
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 RE
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,17 @@ real_from_string2 (const char *s, enum m
return r;
}
+/* Initialize r from a string and desired mode. */
+void
+real_from_string3 (REAL_VALUE_TYPE *r, const char *s, enum machine_mode mode)
+{
+ /* Also handle decimal floats. If decimal float modes were not
+ target specific, we could get rid of this wrapper. */
+ decimal_real_from_string (r, s, mode);
+ if (mode != VOIDmode)
+ real_convert (r, mode, r);
+}
+
/* Initialize R from the integer pair HIGH+LOW. */
void
@@ -2202,16 +2253,20 @@ real_maxval (REAL_VALUE_TYPE *r, int sig
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 +2298,20 @@ round_for_format (const struct real_form
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 +2346,10 @@ round_for_format (const struct real_form
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 +2449,10 @@ real_convert (REAL_VALUE_TYPE *r, enum m
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 +2552,8 @@ real_from_target (REAL_VALUE_TYPE *r, co
(*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 +2565,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 +4320,106 @@ const struct real_format i370_double_for
false
};
+static void
+encode_decimal_single (const struct real_format *fmt,
+ long *buf, const REAL_VALUE_TYPE *r)
+{
+ encode_decimal32 (fmt, buf, r);
+}
+
+static void
+decode_decimal_single (const struct real_format *fmt,
+ REAL_VALUE_TYPE *r, const long *buf)
+{
+ decode_decimal32 (fmt, r, buf);
+}
+
+static void
+encode_decimal_double (const struct real_format *fmt,
+ long *buf, const REAL_VALUE_TYPE *r)
+{
+ encode_decimal64 (fmt, buf, r);
+}
+
+static void
+decode_decimal_double (const struct real_format *fmt,
+ REAL_VALUE_TYPE *r, const long *buf)
+{
+ decode_decimal64 (fmt, r, buf);
+}
+
+static void
+encode_decimal_quad (const struct real_format *fmt,
+ long *buf, const REAL_VALUE_TYPE *r)
+{
+ encode_decimal128 (fmt, buf, r);
+}
+
+static void
+decode_decimal_quad (const struct real_format *fmt,
+ REAL_VALUE_TYPE *r, const long *buf)
+{
+ 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
Index: real.h
===================================================================
--- real.h (revision 107693)
+++ real.h (working copy)
@@ -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_
/* 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_dou
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_int
#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);
Index: mode-classes.def
===================================================================
--- mode-classes.def (revision 107693)
+++ mode-classes.def (working copy)
@@ -25,6 +25,7 @@ Software Foundation, 51 Franklin Street,
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: machmode.def
===================================================================
--- machmode.def (revision 107693)
+++ machmode.def (working copy)
@@ -87,6 +87,10 @@ Software Foundation, 51 Franklin Street,
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: genmodes.c
===================================================================
--- genmodes.c (revision 107693)
+++ genmodes.c (working copy)
@@ -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
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
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, co
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: Makefile.in
===================================================================
--- Makefile.in (revision 107693)
+++ Makefile.in (working copy)
@@ -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)/..
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-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) $(SY
$(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) \
Index: dfp.c
===================================================================
--- dfp.c (revision 0)
+++ dfp.c (revision 0)
@@ -0,0 +1,702 @@
+/* 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 a REAL_VALUE_TYPE (decimal encoded) from a decNumber.
+ Can utilize status passed in via decContext parameter, if some
+ previous operation had interesting status. */
+static void
+decimal_from_decnumber (REAL_VALUE_TYPE *r, decNumber *dn, decContext *set)
+{
+ 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 (set->status & DEC_Overflow)
+ r->cl = rvc_inf;
+ if (decNumberIsNegative (dn))
+ r->sign = 1;
+ r->decimal = 1;
+
+ if (r->cl != rvc_normal)
+ return;
+
+ decContextDefault (set, DEC_INIT_DECIMAL128);
+ set->traps = 0;
+
+ decimal128FromNumber ((decimal128 *) r->sig, dn, set);
+}
+
+/* Create decimal encoded R from string S. */
+static void
+decimal_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);
+}
+
+/* Wrapper to handle decimal strings too. */
+void
+decimal_real_from_string (REAL_VALUE_TYPE *r, const char *s,
+ enum machine_mode mode)
+{
+ if (!DECIMAL_FLOAT_MODE_P (mode))
+ real_from_string (r, s);
+ else
+ decimal_from_string (r, s);
+}
+
+/* Initialize a decNumber from a GCC 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);
+}
+
+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);
+}
+
+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);
+}
+
+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]);
+ }
+}
+
+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);
+}
+
+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]);
+ }
+}
+
+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)
+{
+ /* We convert to string then convert to decNumber then to
+ decimal128. */
+ char string[256];
+ real_to_decimal (string, from, sizeof (string), 0, 1);
+ decimal_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 not a decimal, create temporary decimal
+ 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);
+}
+
+/* Helper to real_convert, handling 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);
+}
+
+/* Helper to print out internal representation of decimal floating types. */
+
+/* Render R 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);
+}
+
+static bool
+decimal_do_multiply (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *op0,
+ const REAL_VALUE_TYPE *op1)
+{
+ decNumber dn, dn2, dn3;
+ decContext set;
+
+ 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);
+}
+
+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);
+}
+
+/* Helper to do_fix_trunc. */
+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);
+}
+
+/* Helper to real_to_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);
+}
+
+
+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);
+}
+
+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;
+ d128->bytes[0] ^= 1 << 7; /* Flip high bit */
+ r->sign ^= 1; /* Keep in sync. */
+ }
+ break;
+
+ case ABS_EXPR:
+ {
+ decimal128 *d128;
+ *r = *op0;
+ d128 = (decimal128 *) r->sig;
+ d128->bytes[0] &= 0x7f; /* Clear high bit */
+ r->sign = 0;
+ }
+ break;
+
+ case FIX_TRUNC_EXPR:
+ decimal_do_fix_trunc (r, op0);
+ break;
+
+ default:
+ gcc_unreachable ();
+ }
+
+ /* FIXME: All operations are 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_from_string (r, max);
+ if (sign)
+ r->sig[0] |= 0x80000000;
+}
Index: dfp.h
===================================================================
--- dfp.h (revision 0)
+++ dfp.h (revision 0)
@@ -0,0 +1,44 @@
+/* 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
+
+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 *);
+
+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 *);
+
+int decimal_do_compare (const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *, int);
+void decimal_real_from_string (REAL_VALUE_TYPE *, const char *, enum machine_mode );
+void decimal_round_for_format (const struct real_format *, REAL_VALUE_TYPE *);
+void decimal_real_convert (REAL_VALUE_TYPE *r, enum machine_mode, const REAL_VALUE_TYPE *a);
+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 */