dfp.h, dfp.c: New files.

2005-12-02  Jon Grimm  <jgrimm2@us.ibm.com>
	    Janis Johnson  <janis187@us.ibm.com>
	    David Edelsohn  <dje@watson.ibm.com>
	    Ben Elliston  <bje@au.ibm.com>

	* dfp.h, dfp.c: New files.
	* Makefile.in (DECNUM, DECNUMINC, LIBDECNUMBER): New variables.
	(DECNUM_H): Likewise.
	(LIBDEPS, LIBS, BACKEND): Append $(LIBDECNUMBER).
	(INCLUDES): Append $(DECNUMINC).
	(OBJS-common): Add dfp.o.
	(dfp.o): New rule.
	* real.h (EXP_BITS): Pinch one bit to ..
	(struct real_value): Add decimal field.
	(real_format): Change table size, update documentation.
	(REAL_MODE_FORMAT): Update for to handle float, decimal float.
	(real_from_string3): Declare.
	(decimal_single_format): Declare.
	(decimal_double_format): Declare.
	(decimal_quad_format): Declare.
	(REAL_VALUE_TO_TARGET_DECIMAL32): New.
	(REAL_VALUE_TO_TARGET_DECIMAL64): New.
	(REAL_VALUE_TO_TARGET_DECIMAL128): New.
	* real.c: Include dfp.h.
	(normalize): Early return for decimal floats.
	(do_add): Zero decimal field.
	(do_compare): Call do_decimal_compare for decimal floats.
	(do_fix_trunc): Likewise, call decimal_do_fix_trunc.
	(real_arithmetic): Call decimal_real_arithmetic for decimal
	floating point operands.
	(real_identical): If a and b are of differing radix, return false.
	(real_to_integer): Call decimal_real_to_integer if the value is a
	decimal float.
	(real_to_integer2): Likewise, call decimal_real_to_integer2.
	(real_to_decimal): Likewise, call decimal_real_to_decimal.
	(real_to_hexadecimal): Place "N/A" in the return string for
	decimal float.
	(real_from_string3): New variant, given a mode.
	(real_maxval): Use decimal_real_maxval for decimal floats.
	(round_for_format): Use decimal_round_for_format for decimals.
	(real_convert): Use decimal_real_convert where appropriate.
	(significand_size): Handle base 10.
	(encode_decimal_single, decode_decimal_single,
	encode_decimal_double, decode_decimal_double, encode_decimal_quad,
	decode_decimal_quad): New functions.
	(decimal_single_format): New.
	(decimal_double_format): New.
	(decimal_quad_format): New.
	* machmode.def: Add SD, DD and TD decimal floating point modes.
	* machmode.h (FLOAT_MODE_P, SCALAR_FLOAT_MODE_P, MODES_WIDEN_P):
	Include MODE_DECIMAL_FLOAT.
	(DECIMAL_FLOAT_MODE_P): New.
	* mode-classes.def (MODE_DECIMAL_FLOAT): New mode class.
	* genmodes.c (struct mode_data): Add counter field.
	(struct mode_data): Update comment for format.
	(blank_mode): Initialise counter field.
	(new_mode): Increment counter field for each mode defined.
	(complete_mode): Handle MODE_DECIMAL_FLOAT, update check for mode
	using a format.
	(make_complex_modes): Handle modes containing `D'.
	(DECIMAL_FLOAT_MODE, FRACTIONAL_DECIMAL_FLOAT_MODE): New.
	(make_decimal_float_mode): New.
	(reset_float_format): Handle MODE_DECIMAL_FLOAT.
	(cmp_modes): Compare counter field if other characteristics
	similar.
	(emit_real_format_for_mode): Support formats for decimal floats.
	* doc/rtl.texi (Machine Modes): Document SD, DD and TDmodes.
	Document MODE_DECIMAL_FLOAT.

Co-Authored-By: Ben Elliston <bje@au.ibm.com>
Co-Authored-By: David Edelsohn <dje@watson.ibm.com>
Co-Authored-By: Janis Johnson <janis187@us.ibm.com>

From-SVN: r107861
This commit is contained in:
Jon Grimm 2005-12-02 02:30:42 +00:00 committed by Ben Elliston
parent 8da15291d0
commit 909e225622
10 changed files with 1165 additions and 33 deletions

View 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.

View 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) \

725
gcc/dfp.c Normal file
View File

@ -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;
}

47
gcc/dfp.h Normal file
View File

@ -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 */

View 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 ();
}

View 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. */

View 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. */

View 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 */ \

View 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
};
static void
encode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
long *buf ATTRIBUTE_UNUSED,
const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
{
encode_decimal32 (fmt, buf, r);
}
static void
decode_decimal_single (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
const long *buf ATTRIBUTE_UNUSED)
{
decode_decimal32 (fmt, r, buf);
}
static void
encode_decimal_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
long *buf ATTRIBUTE_UNUSED,
const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
{
encode_decimal64 (fmt, buf, r);
}
static void
decode_decimal_double (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
const long *buf ATTRIBUTE_UNUSED)
{
decode_decimal64 (fmt, r, buf);
}
static void
encode_decimal_quad (const struct real_format *fmt ATTRIBUTE_UNUSED,
long *buf ATTRIBUTE_UNUSED,
const REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED)
{
encode_decimal128 (fmt, buf, r);
}
static void
decode_decimal_quad (const struct real_format *fmt ATTRIBUTE_UNUSED,
REAL_VALUE_TYPE *r ATTRIBUTE_UNUSED,
const long *buf ATTRIBUTE_UNUSED)
{
decode_decimal128 (fmt, r, buf);
}
/* Proposed IEEE 754r decimal floating point. */
const struct real_format decimal_single_format =
{
encode_decimal_single,
decode_decimal_single,
10,
1, /* log10 */
7,
7,
-95,
96,
31,
31,
true,
true,
true,
true,
true
};
const struct real_format decimal_double_format =
{
encode_decimal_double,
decode_decimal_double,
10,
1, /* log10 */
16,
16,
-383,
384,
63,
63,
true,
true,
true,
true,
true
};
const struct real_format decimal_quad_format =
{
encode_decimal_quad,
decode_decimal_quad,
10,
1, /* log10 */
34,
34,
-6414,
6413,
127,
127,
true,
true,
true,
true,
true
};
/* The "twos-complement" c4x format is officially defined as
x = s(~s).f * 2**e

View 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);