diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 13 | ||||
-rw-r--r-- | gcc/Makefile.in | 30 | ||||
-rw-r--r-- | gcc/config/dfp-bit.c | 541 | ||||
-rw-r--r-- | gcc/config/dfp-bit.h | 511 | ||||
-rw-r--r-- | gcc/doc/libgcc.texi | 200 | ||||
-rw-r--r-- | gcc/mklibgcc.in | 55 |
6 files changed, 1350 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2ac7d8b..a096147 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,5 +1,18 @@ 2006-01-18 Ben Elliston <bje@au.ibm.com> + * Makefile.in (D32PBIT_FUNCS): New. + (D64PBIT_FUNCS, D128PBIT_FUNCS): Likewise. + (libgcc.mk): Set D32PBIT, D64PBIT, D128PBIT, D32PBIT_FUNCS, + D64PBIT_FUNCS and D128PBIT_FUNCS. + (LIBGCC_DEPS): Include $(D32PBIT), $(D64PBIT), $(D128PBIT). + * mklibgcc.in Bring in the DFP support code if D32PBIT, D64PBIT or + D128PBIT are set. + (decnumber_dep): Define. + * doc/libgcc.texi (Decimal float library routines): New node. + * config/dfp-bit.h, config/dfp-bit.c: New files. + +2006-01-18 Ben Elliston <bje@au.ibm.com> + * expr.c (emit_move_change_mode): Always adjust addresses, not just during reload. Copy replacements only during reload. (emit_move_insn_1): Move MODE_DECIMAL_FLOAT modes by invoking diff --git a/gcc/Makefile.in b/gcc/Makefile.in index e791858..a993f97 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -1055,6 +1055,29 @@ TPBIT_FUNCS = _pack_tf _unpack_tf _addsub_tf _mul_tf _div_tf \ _lt_tf _le_tf _unord_tf _si_to_tf _tf_to_si _negate_tf _make_tf \ _tf_to_df _tf_to_sf _thenan_tf _tf_to_usi _usi_to_tf +D32PBIT_FUNCS = _addsub_sd _div_sd _mul_sd _plus_sd _minus_sd \ + _eq_sd _ne_sd _lt_sd _gt_sd _le_sd _ge_sd \ + _sd_to_si _sd_to_di _sd_to_usi _sd_to_udi \ + _si_to_sd _di_to_sd _usi_to_sd _udi_to_sd \ + _sd_to_sf _sd_to_df _sd_to_xf _sf_to_sd _df_to_sd _xf_to_sd \ + _sd_to_dd _sd_to_td _unord_sd _conv_sd + +D64PBIT_FUNCS = _addsub_dd _div_dd _mul_dd _plus_dd _minus_dd \ + _eq_dd _ne_dd _lt_dd _gt_dd _le_dd _ge_dd \ + _dd_to_si _dd_to_di _dd_to_usi _dd_to_udi \ + _si_to_dd _di_to_dd _usi_to_dd _udi_to_dd \ + _dd_to_sf _dd_to_df _dd_to_xf \ + _sf_to_dd _df_to_dd _xf_to_dd \ + _dd_to_sd _dd_to_td _unord_dd _conv_dd + +D128PBIT_FUNCS = _addsub_td _div_td _mul_td _plus_td _minus_td \ + _eq_td _ne_td _lt_td _gt_td _le_td _ge_td \ + _td_to_si _td_to_di _td_to_usi _td_to_udi \ + _si_to_td _di_to_td _usi_to_td _udi_to_td \ + _td_to_sf _td_to_df _td_to_xf \ + _sf_to_td _df_to_td _xf_to_td \ + _td_to_sd _td_to_dd _unord_td _conv_td + # These might cause a divide overflow trap and so are compiled with # unwinder info. LIB2_DIVMOD_FUNCS = _divdi3 _moddi3 _udivdi3 _umoddi3 _udiv_w_sdiv _udivmoddi4 @@ -1393,6 +1416,12 @@ libgcc.mk: config.status Makefile mklibgcc $(LIB2ADD) $(LIB2ADD_ST) specs \ DPBIT_FUNCS='$(DPBIT_FUNCS)' \ TPBIT='$(TPBIT)' \ TPBIT_FUNCS='$(TPBIT_FUNCS)' \ + D32PBIT='$(D32PBIT)' \ + D32PBIT_FUNCS='$(D32PBIT_FUNCS)' \ + D64PBIT='$(D64PBIT)' \ + D64PBIT_FUNCS='$(D64PBIT_FUNCS)' \ + D128PBIT='$(D128PBIT)' \ + D128PBIT_FUNCS='$(D128PBIT_FUNCS)' \ MULTILIBS=`$(GCC_FOR_TARGET) --print-multi-lib` \ EXTRA_MULTILIB_PARTS='$(EXTRA_MULTILIB_PARTS)' \ SHLIB_LINK='$(SHLIB_LINK)' \ @@ -1415,6 +1444,7 @@ LIBGCC_DEPS = $(GCC_PASSES) $(LANGUAGES) stmp-int-hdrs $(STMP_FIXPROTO) \ libgcc.mk $(srcdir)/libgcc2.c $(srcdir)/libgcov.c $(TCONFIG_H) \ $(MACHMODE_H) longlong.h gbl-ctors.h config.status $(srcdir)/libgcc2.h \ tsystem.h $(FPBIT) $(DPBIT) $(TPBIT) $(LIB2ADD) \ + $(D32PBIT) $(D64PBIT) $(D128PBIT) \ $(LIB2ADD_ST) $(LIB2ADDEH) $(LIB2ADDEHDEP) $(EXTRA_PARTS) \ $(srcdir)/config/$(LIB1ASMSRC) \ $(srcdir)/gcov-io.h $(srcdir)/gcov-io.c gcov-iov.h diff --git a/gcc/config/dfp-bit.c b/gcc/config/dfp-bit.c new file mode 100644 index 0000000..835586b --- /dev/null +++ b/gcc/config/dfp-bit.c @@ -0,0 +1,541 @@ +/* This is a software decimal floating point library. + Copyright (C) 2005, 2006 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +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. */ + +/* This implements IEEE 754R decimal floating point arithmetic, but + does not provide a mechanism for setting the rounding mode, or for + generating or handling exceptions. Conversions between decimal + floating point types and other types depend on C library functions. + + Contributed by Ben Elliston <bje@au.ibm.com>. */ + +/* The intended way to use this file is to make two copies, add `#define ' + to one copy, then compile both copies and add them to libgcc.a. */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> + +#include "config/dfp-bit.h" + +/* Forward declarations. */ +#if WIDTH == 32 || WIDTH_TO == 32 +void __host_to_ieee_32 (_Decimal32 in, decimal32 *out); +void __ieee_to_host_32 (decimal32 in, _Decimal32 *out); +#endif +#if WIDTH == 64 || WIDTH_TO == 64 +void __host_to_ieee_64 (_Decimal64 in, decimal64 *out); +void __ieee_to_host_64 (decimal64 in, _Decimal64 *out); +#endif +#if WIDTH == 128 || WIDTH_TO == 128 +void __host_to_ieee_128 (_Decimal128 in, decimal128 *out); +void __ieee_to_host_128 (decimal128 in, _Decimal128 *out); +#endif + +/* A pointer to a unary decNumber operation. */ +typedef decNumber* (*dfp_unary_func) + (decNumber *, decNumber *, decContext *); + +/* A pointer to a binary decNumber operation. */ +typedef decNumber* (*dfp_binary_func) + (decNumber *, decNumber *, decNumber *, decContext *); + +extern unsigned long __dec_byte_swap (unsigned long); + +/* Unary operations. */ + +static inline DFP_C_TYPE +dfp_unary_op (dfp_unary_func op, DFP_C_TYPE arg) +{ + DFP_C_TYPE result; + decContext context; + decNumber arg1, res; + IEEE_TYPE a, encoded_result; + + HOST_TO_IEEE (arg, &a); + + decContextDefault (&context, CONTEXT_INIT); + context.round = CONTEXT_ROUND; + + TO_INTERNAL (&a, &arg1); + + /* Perform the operation. */ + op (&res, &arg1, &context); + + if (CONTEXT_TRAPS && CONTEXT_ERRORS (context)) + DFP_RAISE (0); + + TO_ENCODED (&encoded_result, &res, &context); + IEEE_TO_HOST (encoded_result, &result); + return result; +} + +/* Binary operations. */ + +static inline DFP_C_TYPE +dfp_binary_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + DFP_C_TYPE result; + decContext context; + decNumber arg1, arg2, res; + IEEE_TYPE a, b, encoded_result; + + HOST_TO_IEEE (arg_a, &a); + HOST_TO_IEEE (arg_b, &b); + + decContextDefault (&context, CONTEXT_INIT); + context.round = CONTEXT_ROUND; + + TO_INTERNAL (&a, &arg1); + TO_INTERNAL (&b, &arg2); + + /* Perform the operation. */ + op (&res, &arg1, &arg2, &context); + + if (CONTEXT_TRAPS && CONTEXT_ERRORS (context)) + DFP_RAISE (0); + + TO_ENCODED (&encoded_result, &res, &context); + IEEE_TO_HOST (encoded_result, &result); + return result; +} + +/* Comparison operations. */ + +static inline int +dfp_compare_op (dfp_binary_func op, DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + IEEE_TYPE a, b; + decContext context; + decNumber arg1, arg2, res; + int result; + + HOST_TO_IEEE (arg_a, &a); + HOST_TO_IEEE (arg_b, &b); + + decContextDefault (&context, CONTEXT_INIT); + context.round = CONTEXT_ROUND; + + TO_INTERNAL (&a, &arg1); + TO_INTERNAL (&b, &arg2); + + /* Perform the comparison. */ + op (&res, &arg1, &arg2, &context); + + if (CONTEXT_TRAPS && CONTEXT_ERRORS (context)) + DFP_RAISE (0); + + if (decNumberIsNegative (&res)) + result = -1; + else if (decNumberIsZero (&res)) + result = 0; + else + result = 1; + + return result; +} + + +#if defined(L_conv_sd) +void +__host_to_ieee_32 (_Decimal32 in, decimal32 *out) +{ + uint32_t t; + + if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) + { + memcpy (&t, &in, 4); + t = __dec_byte_swap (t); + memcpy (out, &t, 4); + } + else + memcpy (out, &in, 4); +} + +void +__ieee_to_host_32 (decimal32 in, _Decimal32 *out) +{ + uint32_t t; + + if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) + { + memcpy (&t, &in, 4); + t = __dec_byte_swap (t); + memcpy (out, &t, 4); + } + else + memcpy (out, &in, 4); +} +#endif /* L_conv_sd */ + +#if defined(L_conv_dd) +static void +__swap64 (char *src, char *dst) +{ + uint32_t t1, t2; + + if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) + { + memcpy (&t1, src, 4); + memcpy (&t2, src + 4, 4); + t1 = __dec_byte_swap (t1); + t2 = __dec_byte_swap (t2); + memcpy (dst, &t2, 4); + memcpy (dst + 4, &t1, 4); + } + else + memcpy (dst, src, 8); +} + +void +__host_to_ieee_64 (_Decimal64 in, decimal64 *out) +{ + __swap64 ((char *) &in, (char *) out); +} + +void +__ieee_to_host_64 (decimal64 in, _Decimal64 *out) +{ + __swap64 ((char *) &in, (char *) out); +} +#endif /* L_conv_dd */ + +#if defined(L_conv_td) +static void +__swap128 (char *src, char *dst) +{ + uint32_t t1, t2, t3, t4; + + if (!LIBGCC2_FLOAT_WORDS_BIG_ENDIAN) + { + memcpy (&t1, src, 4); + memcpy (&t2, src + 4, 4); + memcpy (&t3, src + 8, 4); + memcpy (&t4, src + 12, 4); + t1 = __dec_byte_swap (t1); + t2 = __dec_byte_swap (t2); + t3 = __dec_byte_swap (t3); + t4 = __dec_byte_swap (t4); + memcpy (dst, &t4, 4); + memcpy (dst + 4, &t3, 4); + memcpy (dst + 8, &t2, 4); + memcpy (dst + 12, &t1, 4); + } + else + memcpy (dst, src, 16); +} + +void +__host_to_ieee_128 (_Decimal128 in, decimal128 *out) +{ + __swap128 ((char *) &in, (char *) out); +} + +void +__ieee_to_host_128 (decimal128 in, _Decimal128 *out) +{ + __swap128 ((char *) &in, (char *) out); +} +#endif /* L_conv_td */ + +#if defined(L_addsub_sd) || defined(L_addsub_dd) || defined(L_addsub_td) +DFP_C_TYPE +DFP_ADD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + return dfp_binary_op (decNumberAdd, arg_a, arg_b); +} + +DFP_C_TYPE +DFP_SUB (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + return dfp_binary_op (decNumberSubtract, arg_a, arg_b); +} +#endif /* L_addsub */ + +#if defined(L_mul_sd) || defined(L_mul_dd) || defined(L_mul_td) +DFP_C_TYPE +DFP_MULTIPLY (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + return dfp_binary_op (decNumberMultiply, arg_a, arg_b); +} +#endif /* L_mul */ + +#if defined(L_div_sd) || defined(L_div_dd) || defined(L_div_td) +DFP_C_TYPE +DFP_DIVIDE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + return dfp_binary_op (decNumberDivide, arg_a, arg_b); +} +#endif /* L_div */ + +#if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td) +CMPtype +DFP_EQ (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + int stat; + stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); + /* For EQ return zero for true, nonzero for false. */ + return stat != 0; +} +#endif /* L_eq */ + +#if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td) +CMPtype +DFP_NE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + int stat; + stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); + /* For NE return nonzero for true, zero for false. */ + return stat != 0; +} +#endif /* L_ne */ + +#if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td) +CMPtype +DFP_LT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + int stat; + stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); + /* For LT return -1 (<0) for true, 1 for false. */ + return (stat == -1) ? -1 : 1; +} +#endif /* L_lt */ + +#if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td) +CMPtype +DFP_GT (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + int stat; + stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); + /* For GT return 1 (>0) for true, -1 for false. */ + return (stat == 1) ? 1 : -1; +} +#endif + +#if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td) +CMPtype +DFP_LE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + int stat; + stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); + /* For LE return 0 (<= 0) for true, 1 for false. */ + return stat == 1; +} +#endif /* L_le */ + +#if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td) +CMPtype +DFP_GE (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + int stat; + stat = dfp_compare_op (decNumberCompare, arg_a, arg_b); + /* For GE return 1 (>=0) for true, -1 for false. */ + return (stat != -1) ? 1 : -1; +} +#endif /* L_ge */ + +#define BUFMAX 128 + +#if defined (L_sd_to_dd) || defined (L_sd_to_td) || defined (L_dd_to_sd) \ + || defined (L_dd_to_td) || defined (L_td_to_sd) || defined (L_td_to_dd) +DFP_C_TYPE_TO +DFP_TO_DFP (DFP_C_TYPE f_from) +{ + DFP_C_TYPE_TO f_to; + IEEE_TYPE s_from; + IEEE_TYPE_TO s_to; + decNumber d; + decContext context; + + decContextDefault (&context, CONTEXT_INIT); + context.round = CONTEXT_ROUND; + + HOST_TO_IEEE (f_from, &s_from); + TO_INTERNAL (&s_from, &d); + TO_ENCODED_TO (&s_to, &d, &context); + if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0) + DFP_RAISE (DEC_Inexact); + + IEEE_TO_HOST_TO (s_to, &f_to); + return f_to; +} +#endif + +#if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \ + || defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \ + || defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \ + || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi) +INT_TYPE +DFP_TO_INT (DFP_C_TYPE x) +{ + /* decNumber's decimal* types have the same format as C's _Decimal* + types, but they have different calling conventions. */ + + IEEE_TYPE s; + char buf[BUFMAX]; + char *pos; + decNumber qval, n1, n2; + decContext context; + + decContextDefault (&context, CONTEXT_INIT); + /* Need non-default rounding mode here. */ + context.round = DEC_ROUND_DOWN; + + HOST_TO_IEEE (x, &s); + TO_INTERNAL (&s, &n1); + /* Rescale if the exponent is less than zero. */ + decNumberToIntegralValue (&n2, &n1, &context); + /* Get a value to use for the quanitize call. */ + decNumberFromString (&qval, (char *) "1.0", &context); + /* Force the exponent to zero. */ + decNumberQuantize (&n1, &n2, &qval, &context); + /* This is based on text in N1107 secton 5.1; it might turn out to be + undefined behavior instead. */ + if (context.status & DEC_Invalid_operation) + { +#if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) + if (decNumberIsNegative(&n2)) + return INT_MIN; + else + return INT_MAX; +#elif defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) + if (decNumberIsNegative(&n2)) + /* Find a defined constant that will work here. */ + return (-9223372036854775807LL - 1LL); + else + /* Find a defined constant that will work here. */ + return 9223372036854775807LL; +#elif defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) + return UINT_MAX; +#elif defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi) + /* Find a defined constant that will work here. */ + return 18446744073709551615ULL; +#endif + } + /* Get a string, which at this point will not include an exponent. */ + decNumberToString (&n1, buf); + /* Ignore the fractional part. */ + pos = strchr (buf, '.'); + if (pos) + *pos = 0; + /* Use a C library function to convert to the integral type. */ + return STR_TO_INT (buf, NULL, 10); +} +#endif + +#if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \ + || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \ + || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \ + || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td) +DFP_C_TYPE +INT_TO_DFP (INT_TYPE i) +{ + DFP_C_TYPE f; + IEEE_TYPE s; + char buf[BUFMAX]; + decContext context; + + decContextDefault (&context, CONTEXT_INIT); + context.round = CONTEXT_ROUND; + + /* Use a C library function to get a floating point string. */ + sprintf (buf, INT_FMT ".0", CAST_FOR_FMT(i)); + /* Convert from the floating point string to a decimal* type. */ + FROM_STRING (&s, buf, &context); + IEEE_TO_HOST (s, &f); + if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0) + DFP_RAISE (DEC_Inexact); + return f; +} +#endif + +#if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \ + || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \ + || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \ + && LIBGCC2_HAS_XF_MODE) +BFP_TYPE +DFP_TO_BFP (DFP_C_TYPE f) +{ + IEEE_TYPE s; + char buf[BUFMAX]; + + HOST_TO_IEEE (f, &s); + /* Write the value to a string. */ + TO_STRING (&s, buf); + /* Read it as the binary floating point type and return that. */ + return STR_TO_BFP (buf, NULL); +} +#endif + +#if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \ + || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \ + || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \ + && LIBGCC2_HAS_XF_MODE) +DFP_C_TYPE +BFP_TO_DFP (BFP_TYPE x) +{ + DFP_C_TYPE f; + IEEE_TYPE s; + char buf[BUFMAX]; + decContext context; + + decContextDefault (&context, CONTEXT_INIT); + context.round = CONTEXT_ROUND; + + /* Use a C library function to write the floating point value to a string. */ +#ifdef BFP_VIA_TYPE + /* FIXME: Is threre a better way to output an XFmode variable in C? */ + sprintf (buf, BFP_FMT, (BFP_VIA_TYPE) x); +#else + sprintf (buf, BFP_FMT, x); +#endif + + /* Convert from the floating point string to a decimal* type. */ + FROM_STRING (&s, buf, &context); + IEEE_TO_HOST (s, &f); + if (CONTEXT_TRAPS && (context.status & DEC_Inexact) != 0) + DFP_RAISE (DEC_Inexact); + return f; +} +#endif + +#if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td) +CMPtype +DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b) +{ + decNumber arg1, arg2; + IEEE_TYPE a, b; + + HOST_TO_IEEE (arg_a, &a); + HOST_TO_IEEE (arg_b, &b); + TO_INTERNAL (&a, &arg1); + TO_INTERNAL (&b, &arg2); + return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2)); +} +#endif /* L_unord_sd || L_unord_dd || L_unord_td */ diff --git a/gcc/config/dfp-bit.h b/gcc/config/dfp-bit.h new file mode 100644 index 0000000..5f3a04e --- /dev/null +++ b/gcc/config/dfp-bit.h @@ -0,0 +1,511 @@ +/* Header file for dfp-bit.c. + Copyright (C) 2005, 2006 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. + +In addition to the permissions in the GNU General Public License, the +Free Software Foundation gives you unlimited permission to link the +compiled version of this file into combinations with other programs, +and to distribute those combinations without any restriction coming +from the use of this file. (The General Public License restrictions +do apply in other respects; for example, they cover modification of +the file, and distribution when not linked into a combine +executable.) + +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 _DFPBIT_H +#define _DFPBIT_H + +#include "tconfig.h" +#include "coretypes.h" +#include "tm.h" + +#ifndef LIBGCC2_FLOAT_WORDS_BIG_ENDIAN +#define LIBGCC2_FLOAT_WORDS_BIG_ENDIAN LIBGCC2_WORDS_BIG_ENDIAN +#endif + +#ifndef LIBGCC2_LONG_DOUBLE_TYPE_SIZE +#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE LONG_DOUBLE_TYPE_SIZE +#endif + +#ifndef LIBGCC2_HAS_XF_MODE +#define LIBGCC2_HAS_XF_MODE \ + (BITS_PER_UNIT == 8 && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 80) +#endif + +/* Depending on WIDTH, define a number of macros: + + DFP_C_TYPE: type of the arguments to the libgcc functions; + (eg _Decimal32) + + IEEE_TYPE: the corresponding (encoded) IEEE754R type; + (eg decimal32) + + TO_INTERNAL: the name of the decNumber function to convert an + encoded value into the decNumber internal representation; + + TO_ENCODED: the name of the decNumber function to convert an + internally represented decNumber into the encoded + representation. + + FROM_STRING: the name of the decNumber function to read an + encoded value from a string. + + TO_STRING: the name of the decNumber function to write an + encoded value to a string. */ + +#if WIDTH == 32 +#define DFP_C_TYPE _Decimal32 +#define IEEE_TYPE decimal32 +#define HOST_TO_IEEE __host_to_ieee_32 +#define IEEE_TO_HOST __ieee_to_host_32 +#define TO_INTERNAL __decimal32ToNumber +#define TO_ENCODED __decimal32FromNumber +#define FROM_STRING __decimal32FromString +#define TO_STRING __decimal32ToString +#elif WIDTH == 64 +#define DFP_C_TYPE _Decimal64 +#define IEEE_TYPE decimal64 +#define HOST_TO_IEEE __host_to_ieee_64 +#define IEEE_TO_HOST __ieee_to_host_64 +#define TO_INTERNAL __decimal64ToNumber +#define TO_ENCODED __decimal64FromNumber +#define FROM_STRING __decimal64FromString +#define TO_STRING __decimal64ToString +#elif WIDTH == 128 +#define DFP_C_TYPE _Decimal128 +#define IEEE_TYPE decimal128 +#define HOST_TO_IEEE __host_to_ieee_128 +#define IEEE_TO_HOST __ieee_to_host_128 +#define TO_INTERNAL __decimal128ToNumber +#define TO_ENCODED __decimal128FromNumber +#define FROM_STRING __decimal128FromString +#define TO_STRING __decimal128ToString +#else +#error invalid decimal float word width +#endif + +/* We define __DEC_EVAL_METHOD__ to 2, saying that we evaluate all + operations and constants to the range and precision of the _Decimal128 + type. Make it so. */ +#if WIDTH == 32 +#define CONTEXT_INIT DEC_INIT_DECIMAL32 +#elif WIDTH == 64 +#define CONTEXT_INIT DEC_INIT_DECIMAL64 +#elif WIDTH == 128 +#define CONTEXT_INIT DEC_INIT_DECIMAL128 +#endif + +/* Define CONTEXT_ROUND to obtain the current decNumber rounding mode. */ +extern enum rounding __decGetRound (void); +#define CONTEXT_ROUND __decGetRound () + +extern int __dfp_traps; +#define CONTEXT_TRAPS __dfp_traps +#define CONTEXT_ERRORS(context) context.status & DEC_Errors +extern void __dfp_raise (int); +#define DFP_RAISE(A) __dfp_raise(A) + +/* Conversions between different decimal float types use WIDTH_TO to + determine additional macros to define. */ + +#if defined (L_dd_to_sd) || defined (L_td_to_sd) +#define WIDTH_TO 32 +#elif defined (L_sd_to_dd) || defined (L_td_to_dd) +#define WIDTH_TO 64 +#elif defined (L_sd_to_td) || defined (L_dd_to_td) +#define WIDTH_TO 128 +#endif + +/* If WIDTH_TO is defined, define additional macros: + + DFP_C_TYPE_TO: type of the result of dfp to dfp conversion. + + IEEE_TYPE_TO: the corresponding (encoded) IEEE754R type. + + TO_ENCODED_TO: the name of the decNumber function to convert an + internally represented decNumber into the encoded representation + for the destination. */ + +#if WIDTH_TO == 32 +#define DFP_C_TYPE_TO _Decimal32 +#define IEEE_TYPE_TO decimal32 +#define TO_ENCODED_TO __decimal32FromNumber +#define IEEE_TO_HOST_TO __ieee_to_host_32 +#elif WIDTH_TO == 64 +#define DFP_C_TYPE_TO _Decimal64 +#define IEEE_TYPE_TO decimal64 +#define TO_ENCODED_TO __decimal64FromNumber +#define IEEE_TO_HOST_TO __ieee_to_host_64 +#elif WIDTH_TO == 128 +#define DFP_C_TYPE_TO _Decimal128 +#define IEEE_TYPE_TO decimal128 +#define TO_ENCODED_TO __decimal128FromNumber +#define IEEE_TO_HOST_TO __ieee_to_host_128 +#endif + +/* Conversions between decimal float types and integral types use INT_KIND + to determine the data type and C functions to use. */ + +#if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \ + || defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) +#define INT_KIND 1 +#elif defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \ + || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) +#define INT_KIND 2 +#elif defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \ + || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) +#define INT_KIND 3 +#elif defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi) \ + || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td) +#define INT_KIND 4 +#endif + +/* If INT_KIND is defined, define additional macros: + + INT_TYPE: The integer data type. + + INT_FMT: The format string for writing the integer to a string. + + CAST_FOR_FMT: Cast variable of INT_KIND to C type for sprintf. + This works for ILP32 and LP64, won't for other type size systems. + + STR_TO_INT: The function to read the integer from a string. */ + +#if INT_KIND == 1 +#define INT_TYPE SItype +#define INT_FMT "%d" +#define CAST_FOR_FMT(A) (int)A +#define STR_TO_INT strtol +#elif INT_KIND == 2 +#define INT_TYPE DItype +#define INT_FMT "%lld" +#define CAST_FOR_FMT(A) (long long)A +#define STR_TO_INT strtoll +#elif INT_KIND == 3 +#define INT_TYPE USItype +#define INT_FMT "%u" +#define CAST_FOR_FMT(A) (unsigned int)A +#define STR_TO_INT strtoul +#elif INT_KIND == 4 +#define INT_TYPE UDItype +#define INT_FMT "%llu" +#define CAST_FOR_FMT(A) (unsigned long long)A +#define STR_TO_INT strtoull +#endif + +/* Conversions between decimal float types and binary float types use + BFP_KIND to determine the data type and C functions to use. */ + +#if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \ + || defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) +#define BFP_KIND 1 +#elif defined (L_sd_to_df) || defined (L_dd_to_df ) || defined (L_td_to_df) \ + || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) +#define BFP_KIND 2 +#elif defined (L_sd_to_xf) || defined (L_dd_to_xf ) || defined (L_td_to_xf) \ + || defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td) +#define BFP_KIND 3 +#endif + +/* If BFP_KIND is defined, define additional macros: + + BFP_TYPE: The binary floating point data type. + + BFP_FMT: The format string for writing the value to a string. + + STR_TO_BFP: The function to read the value from a string. */ + +#if BFP_KIND == 1 +/* strtof is declared in <stdlib.h> only for C99. */ +extern float strtof (const char *, char **); +#define BFP_TYPE SFtype +#define BFP_FMT "%e" +#define STR_TO_BFP strtof + +#elif BFP_KIND == 2 +#define BFP_TYPE DFtype +#define BFP_FMT "%e" +#define STR_TO_BFP strtod + +#elif BFP_KIND == 3 +#if LIBGCC2_HAS_XF_MODE +/* These aren't used if XF mode is not supported. */ +#define BFP_TYPE XFtype +#define BFP_FMT "%e" +#define BFP_VIA_TYPE double +#define STR_TO_BFP strtod +#endif + +#endif /* BFP_KIND */ + +#if WIDTH == 128 || WIDTH_TO == 128 +#include "decimal128.h" +#endif +#if WIDTH == 64 || WIDTH_TO == 64 +#include "decimal64.h" +#endif +#if WIDTH == 32 || WIDTH_TO == 32 +#include "decimal32.h" +#endif +#include "decNumber.h" + +/* Names of arithmetic functions. */ + +#if WIDTH == 32 +#define DFP_ADD __addsd3 +#define DFP_SUB __subsd3 +#define DFP_MULTIPLY __mulsd3 +#define DFP_DIVIDE __divsd3 +#define DFP_EQ __eqsd2 +#define DFP_NE __nesd2 +#define DFP_LT __ltsd2 +#define DFP_GT __gtsd2 +#define DFP_LE __lesd2 +#define DFP_GE __gesd2 +#define DFP_UNORD __unordsd2 +#elif WIDTH == 64 +#define DFP_ADD __adddd3 +#define DFP_SUB __subdd3 +#define DFP_MULTIPLY __muldd3 +#define DFP_DIVIDE __divdd3 +#define DFP_EQ __eqdd2 +#define DFP_NE __nedd2 +#define DFP_LT __ltdd2 +#define DFP_GT __gtdd2 +#define DFP_LE __ledd2 +#define DFP_GE __gedd2 +#define DFP_UNORD __unorddd2 +#elif WIDTH == 128 +#define DFP_ADD __addtd3 +#define DFP_SUB __subtd3 +#define DFP_MULTIPLY __multd3 +#define DFP_DIVIDE __divtd3 +#define DFP_EQ __eqtd2 +#define DFP_NE __netd2 +#define DFP_LT __lttd2 +#define DFP_GT __gttd2 +#define DFP_LE __letd2 +#define DFP_GE __getd2 +#define DFP_UNORD __unordtd2 +#endif + +/* Names of functions to convert between different decimal float types. */ + +#if WIDTH == 32 +#if WIDTH_TO == 64 +#define DFP_TO_DFP __extendsddd2 +#elif WIDTH_TO == 128 +#define DFP_TO_DFP __extendsdtd2 +#endif +#elif WIDTH == 64 +#if WIDTH_TO == 32 +#define DFP_TO_DFP __truncddsd2 +#elif WIDTH_TO == 128 +#define DFP_TO_DFP __extendddtd2 +#endif +#elif WIDTH == 128 +#if WIDTH_TO == 32 +#define DFP_TO_DFP __trunctdsd2 +#elif WIDTH_TO == 64 +#define DFP_TO_DFP __trunctddd2 +#endif +#endif + +/* Names of functions to convert between decimal float and integers. */ + +#if WIDTH == 32 +#if INT_KIND == 1 +#define INT_TO_DFP __floatsisd +#define DFP_TO_INT __fixsdsi +#elif INT_KIND == 2 +#define INT_TO_DFP __floatdisd +#define DFP_TO_INT __fixsddi +#elif INT_KIND == 3 +#define INT_TO_DFP __floatunssisd +#define DFP_TO_INT __fixunssdsi +#elif INT_KIND == 4 +#define INT_TO_DFP __floatunsdisd +#define DFP_TO_INT __fixunssddi +#endif +#elif WIDTH == 64 +#if INT_KIND == 1 +#define INT_TO_DFP __floatsidd +#define DFP_TO_INT __fixddsi +#elif INT_KIND == 2 +#define INT_TO_DFP __floatdidd +#define DFP_TO_INT __fixdddi +#elif INT_KIND == 3 +#define INT_TO_DFP __floatunssidd +#define DFP_TO_INT __fixunsddsi +#elif INT_KIND == 4 +#define INT_TO_DFP __floatunsdidd +#define DFP_TO_INT __fixunsdddi +#endif +#elif WIDTH == 128 +#if INT_KIND == 1 +#define INT_TO_DFP __floatsitd +#define DFP_TO_INT __fixtdsi +#elif INT_KIND == 2 +#define INT_TO_DFP __floatditd +#define DFP_TO_INT __fixtddi +#elif INT_KIND == 3 +#define INT_TO_DFP __floatunssitd +#define DFP_TO_INT __fixunstdsi +#elif INT_KIND == 4 +#define INT_TO_DFP __floatunsditd +#define DFP_TO_INT __fixunstddi +#endif +#endif + +/* Names of functions to convert between decimal float and binary float. */ + +#if WIDTH == 32 +#if BFP_KIND == 1 +#define BFP_TO_DFP __extendsfsd +#define DFP_TO_BFP __truncsdsf +#elif BFP_KIND == 2 +#define BFP_TO_DFP __truncdfsd +#define DFP_TO_BFP __extendsddf +#elif BFP_KIND == 3 +#define BFP_TO_DFP __truncxfsd +#define DFP_TO_BFP __extendsdxf +#endif /* BFP_KIND */ + +#elif WIDTH == 64 +#if BFP_KIND == 1 +#define BFP_TO_DFP __extendsfdd +#define DFP_TO_BFP __truncddsf +#elif BFP_KIND == 2 +#define BFP_TO_DFP __extenddfdd +#define DFP_TO_BFP __truncdddf +#elif BFP_KIND == 3 +#define BFP_TO_DFP __truncxfdd +#define DFP_TO_BFP __extendddxf +#endif /* BFP_KIND */ + +#elif WIDTH == 128 +#if BFP_KIND == 1 +#define BFP_TO_DFP __extendsftd +#define DFP_TO_BFP __trunctdsf +#elif BFP_KIND == 2 +#define BFP_TO_DFP __extenddftd +#define DFP_TO_BFP __trunctddf +#elif BFP_KIND == 3 +#define BFP_TO_DFP __extendxftd +#define DFP_TO_BFP __trunctdxf +#endif /* BFP_KIND */ + +#endif /* WIDTH */ + +/* Some handy typedefs. */ + +typedef float SFtype __attribute__ ((mode (SF))); +typedef float DFtype __attribute__ ((mode (DF))); +#if LIBGCC2_HAS_XF_MODE +typedef float XFtype __attribute__ ((mode (XF))); +#endif /* LIBGCC2_HAS_XF_MODE */ + +typedef int SItype __attribute__ ((mode (SI))); +typedef int DItype __attribute__ ((mode (DI))); +typedef unsigned int USItype __attribute__ ((mode (SI))); +typedef unsigned int UDItype __attribute__ ((mode (DI))); + +/* The type of the result of a decimal float comparison. This must + match `word_mode' in GCC for the target. Default to SItype. */ + +#ifndef CMPtype +#define CMPtype SItype +#endif + +/* Prototypes. */ + +#if defined (L_mul_sd) || defined (L_mul_dd) || defined (L_mul_td) +extern DFP_C_TYPE DFP_MULTIPLY (DFP_C_TYPE, DFP_C_TYPE); +#endif + +#if defined (L_div_sd) || defined (L_div_dd) || defined (L_div_td) +extern DFP_C_TYPE DFP_DIVIDE (DFP_C_TYPE, DFP_C_TYPE); +#endif + +#if defined (L_addsub_sd) || defined (L_addsub_dd) || defined (L_addsub_td) +extern DFP_C_TYPE DFP_ADD (DFP_C_TYPE, DFP_C_TYPE); +extern DFP_C_TYPE DFP_SUB (DFP_C_TYPE, DFP_C_TYPE); +#endif + +#if defined (L_eq_sd) || defined (L_eq_dd) || defined (L_eq_td) +extern CMPtype DFP_EQ (DFP_C_TYPE, DFP_C_TYPE); +#endif + +#if defined (L_ne_sd) || defined (L_ne_dd) || defined (L_ne_td) +extern CMPtype DFP_NE (DFP_C_TYPE, DFP_C_TYPE); +#endif + +#if defined (L_lt_sd) || defined (L_lt_dd) || defined (L_lt_td) +extern CMPtype DFP_LT (DFP_C_TYPE, DFP_C_TYPE); +#endif + +#if defined (L_gt_sd) || defined (L_gt_dd) || defined (L_gt_td) +extern CMPtype DFP_GT (DFP_C_TYPE, DFP_C_TYPE); +#endif + +#if defined (L_le_sd) || defined (L_le_dd) || defined (L_le_td) +extern CMPtype DFP_LE (DFP_C_TYPE, DFP_C_TYPE); +#endif + +#if defined (L_ge_sd) || defined (L_ge_dd) || defined (L_ge_td) +extern CMPtype DFP_GE (DFP_C_TYPE, DFP_C_TYPE); +#endif + +#if defined (L_unord_sd) || defined (L_unord_dd) || defined (L_unord_td) +extern CMPtype DFP_UNORD (DFP_C_TYPE, DFP_C_TYPE); +#endif + +#if defined (L_sd_to_dd) || defined (L_sd_to_td) || defined (L_dd_to_sd) \ + || defined (L_dd_to_td) || defined (L_td_to_sd) || defined (L_td_to_dd) +extern DFP_C_TYPE_TO DFP_TO_DFP (DFP_C_TYPE); +#endif + +#if defined (L_sd_to_si) || defined (L_dd_to_si) || defined (L_td_to_si) \ + || defined (L_sd_to_di) || defined (L_dd_to_di) || defined (L_td_to_di) \ + || defined (L_sd_to_usi) || defined (L_dd_to_usi) || defined (L_td_to_usi) \ + || defined (L_sd_to_udi) || defined (L_dd_to_udi) || defined (L_td_to_udi) +extern INT_TYPE DFP_TO_INT (DFP_C_TYPE); +#endif + +#if defined (L_si_to_sd) || defined (L_si_to_dd) || defined (L_si_to_td) \ + || defined (L_di_to_sd) || defined (L_di_to_dd) || defined (L_di_to_td) \ + || defined (L_usi_to_sd) || defined (L_usi_to_dd) || defined (L_usi_to_td) \ + || defined (L_udi_to_sd) || defined (L_udi_to_dd) || defined (L_udi_to_td) +extern DFP_C_TYPE INT_TO_DFP (INT_TYPE); +#endif + +#if defined (L_sd_to_sf) || defined (L_dd_to_sf) || defined (L_td_to_sf) \ + || defined (L_sd_to_df) || defined (L_dd_to_df) || defined (L_td_to_df) \ + || ((defined (L_sd_to_xf) || defined (L_dd_to_xf) || defined (L_td_to_xf)) \ + && LIBGCC2_HAS_XF_MODE) +extern BFP_TYPE DFP_TO_BFP (DFP_C_TYPE); +#endif + +#if defined (L_sf_to_sd) || defined (L_sf_to_dd) || defined (L_sf_to_td) \ + || defined (L_df_to_sd) || defined (L_df_to_dd) || defined (L_df_to_td) \ + || ((defined (L_xf_to_sd) || defined (L_xf_to_dd) || defined (L_xf_to_td)) \ + && LIBGCC2_HAS_XF_MODE) +extern DFP_C_TYPE BFP_TO_DFP (BFP_TYPE); +#endif + +#endif /* _DFPBIT_H */ diff --git a/gcc/doc/libgcc.texi b/gcc/doc/libgcc.texi index c97bd8b..f67b117 100644 --- a/gcc/doc/libgcc.texi +++ b/gcc/doc/libgcc.texi @@ -39,6 +39,7 @@ and @code{@w{unsigned int}} correspond to @code{SImode}; @code{long} and @menu * Integer library routines:: * Soft float library routines:: +* Decimal float library routines:: * Exception handling routines:: * Miscellaneous routines:: @end menu @@ -485,6 +486,205 @@ These functions return the quotient of @math{@var{a} + i@var{b}} and + i@var{d})}), following the rules of C99 Annex G@. @end deftypefn +@node Decimal float library routines +@section Routines for decimal floating point emulation +@cindex decimal float library +@cindex IEEE-754R + +The software decimal floating point library implements IEEE 754R +decimal floating point arithmetic and is only activated on selected +targets. + +@subsection Arithmetic functions + +@deftypefn {Runtime Function} _Decimal32 __addsd3 (_Decimal32 @var{a}, _Decimal32 @var{b}) +@deftypefnx {Runtime Function} _Decimal64 __adddd3 (_Decimal64 @var{a}, _Decimal64 @var{b}) +@deftypefnx {Runtime Function} _Decimal128 __addtd3 (_Decimal128 @var{a}, _Decimal128 @var{b}) +These functions return the sum of @var{a} and @var{b}. +@end deftypefn + +@deftypefn {Runtime Function} _Decimal32 __subsd3 (_Decimal32 @var{a}, _Decimal32 @var{b}) +@deftypefnx {Runtime Function} _Decimal64 __subdd3 (_Decimal64 @var{a}, _Decimal64 @var{b}) +@deftypefnx {Runtime Function} _Decimal128 __subtd3 (_Decimal128 @var{a}, _Decimal128 @var{b}) +These functions return the difference between @var{b} and @var{a}; +that is, @w{@math{@var{a} - @var{b}}}. +@end deftypefn + +@deftypefn {Runtime Function} _Decimal32 __mulsd3 (_Decimal32 @var{a}, _Decimal32 @var{b}) +@deftypefnx {Runtime Function} _Decimal64 __muldd3 (_Decimal64 @var{a}, _Decimal64 @var{b}) +@deftypefnx {Runtime Function} _Decimal128 __multd3 (_Decimal128 @var{a}, _Decimal128 @var{b}) +These functions return the product of @var{a} and @var{b}. +@end deftypefn + +@deftypefn {Runtime Function} _Decimal32 __divsd3 (_Decimal32 @var{a}, _Decimal32 @var{b}) +@deftypefnx {Runtime Function} _Decimal64 __divdd3 (_Decimal64 @var{a}, _Decimal64 @var{b}) +@deftypefnx {Runtime Function} _Decimal128 __divtd3 (_Decimal128 @var{a}, _Decimal128 @var{b}) +These functions return the quotient of @var{a} and @var{b}; that is, +@w{@math{@var{a} / @var{b}}}. +@end deftypefn + +@deftypefn {Runtime Function} _Decimal32 __negsd2 (_Decimal32 @var{a}) +@deftypefnx {Runtime Function} _Decimal64 __negdd2 (_Decimal64 @var{a}) +@deftypefnx {Runtime Function} _Decimal128 __negtd2 (_Decimal128 @var{a}) +These functions return the negation of @var{a}. They simply flip the +sign bit, so they can produce negative zero and negative NaN@. +@end deftypefn + +@subsection Conversion functions + +@c DFP/DFP conversions +@deftypefn {Runtime Function} _Decimal64 __extendsddd2 (_Decimal32 @var{a}) +@deftypefnx {Runtime Function} _Decimal128 __extendsdtd2 (_Decimal32 @var{a}) +@deftypefnx {Runtime Function} _Decimal128 __extendddtd2 (_Decimal64 @var{a}) +@c DFP/binary FP conversions +@deftypefnx {Runtime Function} _Decimal32 __extendsfsd (float @var{a}) +@deftypefnx {Runtime Function} double __extendsddf (_Decimal32 @var{a}) +@deftypefnx {Runtime Function} {long double} __extendsdxf (_Decimal32 @var{a}) +@deftypefnx {Runtime Function} _Decimal64 __extendsfdd (float @var{a}) +@deftypefnx {Runtime Function} _Decimal64 __extenddfdd (double @var{a}) +@deftypefnx {Runtime Function} {long double} __extendddxf (_Decimal64 @var{a}) +@deftypefnx {Runtime Function} _Decimal128 __extendsftd (float @var{a}) +@deftypefnx {Runtime Function} _Decimal128 __extenddftd (double @var{a}) +@deftypefnx {Runtime Function} _Decimal128 __extendxftd ({long double} @var{a}) +These functions extend @var{a} to the wider mode of their return type. +@end deftypefn + +@c DFP/DFP conversions +@deftypefn {Runtime Function} _Decimal32 __truncddsd2 (_Decimal64 @var{a}) +@deftypefnx {Runtime Function} _Decimal32 __trunctdsd2 (_Decimal128 @var{a}) +@deftypefnx {Runtime Function} _Decimal64 __trunctddd2 (_Decimal128 @var{a}) +@c DFP/binary FP conversions +@deftypefnx {Runtime Function} float __truncsdsf (_Decimal32 @var{a}) +@deftypefnx {Runtime Function} _Decimal32 __truncdfsd (double @var{a}) +@deftypefnx {Runtime Function} _Decimal32 __truncxfsd ({long double} @var{a}) +@deftypefnx {Runtime Function} float __truncddsf (_Decimal64 @var{a}) +@deftypefnx {Runtime Function} double __truncdddf (_Decimal64 @var{a}) +@deftypefnx {Runtime Function} _Decimal64 __truncxfdd ({long double} @var{a}) +@deftypefnx {Runtime Function} float __trunctdsf (_Decimal128 @var{a}) +@deftypefnx {Runtime Function} double __trunctddf (_Decimal128 @var{a}) +@deftypefnx {Runtime Function} {long double} __trunctdxf (_Decimal128 @var{a}) +These functions truncate @var{a} to the narrower mode of their return +type. +@end deftypefn + +@deftypefn {Runtime Function} int __fixsdsi (_Decimal32 @var{a}) +@deftypefnx {Runtime Function} int __fixddsi (_Decimal64 @var{a}) +@deftypefnx {Runtime Function} int __fixtdsi (_Decimal128 @var{a}) +These functions convert @var{a} to a signed integer. +@end deftypefn + +@deftypefn {Runtime Function} long __fixsddi (_Decimal32 @var{a}) +@deftypefnx {Runtime Function} long __fixdddi (_Decimal64 @var{a}) +@deftypefnx {Runtime Function} long __fixtddi (_Decimal128 @var{a}) +These functions convert @var{a} to a signed long. +@end deftypefn + +@deftypefn {Runtime Function} {unsigned int} __fixunssdsi (_Decimal32 @var{a}) +@deftypefnx {Runtime Function} {unsigned int} __fixunsddsi (_Decimal64 @var{a}) +@deftypefnx {Runtime Function} {unsigned int} __fixunstdsi (_Decimal128 @var{a}) +These functions convert @var{a} to an unsigned integer. Negative values all become zero. +@end deftypefn + +@deftypefn {Runtime Function} {unsigned long} __fixunssddi (_Decimal32 @var{a}) +@deftypefnx {Runtime Function} {unsigned long} __fixunsdddi (_Decimal64 @var{a}) +@deftypefnx {Runtime Function} {unsigned long} __fixunstddi (_Decimal128 @var{a}) +These functions convert @var{a} to an unsigned long. Negative values +all become zero. +@end deftypefn + +@deftypefn {Runtime Function} _Decimal32 __floatsisd (int @var{i}) +@deftypefnx {Runtime Function} _Decimal64 __floatsidd (int @var{i}) +@deftypefnx {Runtime Function} _Decimal128 __floatsitd (int @var{i}) +These functions convert @var{i}, a signed integer, to decimal floating point. +@end deftypefn + +@deftypefn {Runtime Function} _Decimal32 __floatdisd (long @var{i}) +@deftypefnx {Runtime Function} _Decimal64 __floatdidd (long @var{i}) +@deftypefnx {Runtime Function} _Decimal128 __floatditd (long @var{i}) +These functions convert @var{i}, a signed long, to decimal floating point. +@end deftypefn + +@deftypefn {Runtime Function} _Decimal32 __floatunssisd (unsigned int @var{i}) +@deftypefnx {Runtime Function} _Decimal64 __floatunssidd (unsigned int @var{i}) +@deftypefnx {Runtime Function} _Decimal128 __floatunssitd (unsigned int @var{i}) +These functions convert @var{i}, an unsigned integer, to decimal floating point. +@end deftypefn + +@deftypefn {Runtime Function} _Decimal32 __floatunsdisd (unsigned long @var{i}) +@deftypefnx {Runtime Function} _Decimal64 __floatunsdidd (unsigned long @var{i}) +@deftypefnx {Runtime Function} _Decimal128 __floatunsditd (unsigned long @var{i}) +These functions convert @var{i}, an unsigned long, to decimal floating point. +@end deftypefn + +@subsection Comparison functions + +@deftypefn {Runtime Function} int __unordsd2 (_Decimal32 @var{a}, _Decimal32 @var{b}) +@deftypefnx {Runtime Function} int __unorddd2 (_Decimal64 @var{a}, _Decimal64 @var{b}) +@deftypefnx {Runtime Function} int __unordtd2 (_Decimal128 @var{a}, _Decimal128 @var{b}) +These functions return a nonzero value if either argument is NaN, otherwise 0. +@end deftypefn + +There is also a complete group of higher level functions which +correspond directly to comparison operators. They implement the ISO C +semantics for floating-point comparisons, taking NaN into account. +Pay careful attention to the return values defined for each set. +Under the hood, all of these routines are implemented as + +@smallexample + if (__unord@var{X}d2 (a, b)) + return @var{E}; + return __cmp@var{X}d2 (a, b); +@end smallexample + +@noindent +where @var{E} is a constant chosen to give the proper behavior for +NaN@. Thus, the meaning of the return value is different for each set. +Do not rely on this implementation; only the semantics documented +below are guaranteed. + +@deftypefn {Runtime Function} int __eqsd2 (_Decimal32 @var{a}, _Decimal32 @var{b}) +@deftypefnx {Runtime Function} int __eqdd2 (_Decimal64 @var{a}, _Decimal64 @var{b}) +@deftypefnx {Runtime Function} int __eqtd2 (_Decimal128 @var{a}, _Decimal128 @var{b}) +These functions return zero if neither argument is NaN, and @var{a} and +@var{b} are equal. +@end deftypefn + +@deftypefn {Runtime Function} int __nesd2 (_Decimal32 @var{a}, _Decimal32 @var{b}) +@deftypefnx {Runtime Function} int __nedd2 (_Decimal64 @var{a}, _Decimal64 @var{b}) +@deftypefnx {Runtime Function} int __netd2 (_Decimal128 @var{a}, _Decimal128 @var{b}) +These functions return a nonzero value if either argument is NaN, or +if @var{a} and @var{b} are unequal. +@end deftypefn + +@deftypefn {Runtime Function} int __gesd2 (_Decimal32 @var{a}, _Decimal32 @var{b}) +@deftypefnx {Runtime Function} int __gedd2 (_Decimal64 @var{a}, _Decimal64 @var{b}) +@deftypefnx {Runtime Function} int __getd2 (_Decimal128 @var{a}, _Decimal128 @var{b}) +These functions return a value greater than or equal to zero if +neither argument is NaN, and @var{a} is greater than or equal to +@var{b}. +@end deftypefn + +@deftypefn {Runtime Function} int __ltsd2 (_Decimal32 @var{a}, _Decimal32 @var{b}) +@deftypefnx {Runtime Function} int __ltdd2 (_Decimal64 @var{a}, _Decimal64 @var{b}) +@deftypefnx {Runtime Function} int __lttd2 (_Decimal128 @var{a}, _Decimal128 @var{b}) +These functions return a value less than zero if neither argument is +NaN, and @var{a} is strictly less than @var{b}. +@end deftypefn + +@deftypefn {Runtime Function} int __lesd2 (_Decimal32 @var{a}, _Decimal32 @var{b}) +@deftypefnx {Runtime Function} int __ledd2 (_Decimal64 @var{a}, _Decimal64 @var{b}) +@deftypefnx {Runtime Function} int __letd2 (_Decimal128 @var{a}, _Decimal128 @var{b}) +These functions return a value less than or equal to zero if neither +argument is NaN, and @var{a} is less than or equal to @var{b}. +@end deftypefn + +@deftypefn {Runtime Function} int __gtsd2 (_Decimal32 @var{a}, _Decimal32 @var{b}) +@deftypefnx {Runtime Function} int __gtdd2 (_Decimal64 @var{a}, _Decimal64 @var{b}) +@deftypefnx {Runtime Function} int __gttd2 (_Decimal128 @var{a}, _Decimal128 @var{b}) +These functions return a value greater than zero if neither argument +is NaN, and @var{a} is strictly greater than @var{b}. +@end deftypefn + @node Exception handling routines @section Language-independent routines for exception handling diff --git a/gcc/mklibgcc.in b/gcc/mklibgcc.in index ba85363..2162c05 100644 --- a/gcc/mklibgcc.in +++ b/gcc/mklibgcc.in @@ -28,6 +28,12 @@ # DPBIT_FUNCS # TPBIT # TPBIT_FUNCS +# D32PBIT +# D32PBIT_FUNCS +# D64PBIT +# D64PBIT_FUNCS +# D128PBIT +# D128PBIT_FUNCS # LIBGCC # MULTILIBS # EXTRA_MULTILIB_PARTS @@ -96,6 +102,12 @@ libgcov_c_dep='stmp-dirs $(srcdir)/libgcov.c $(srcdir)/gcov-io.h $(srcdir)/gcov- # Dependencies for fp-bit.c fpbit_c_dep='stmp-dirs config.status tsystem.h' +# Dependencies for decnumber and friends. This is an overzealous set, +# but at least we can be sure to recompile if anything gets modified. +decnumber_dep='stmp-dirs $(srcdir)/../libdecnumber/decContext.h $(srcdir)/../libdecnumber/decNumber.h + $(srcdir)/../libdecnumber/decNumberLocal.h $(srcdir)/../libdecnumber/decimal32.h $(srcdir)/../libdecnumber/decimal64.h + $(srcdir)/../libdecnumber/decimal128.h $(srcdir)/../libdecnumber/decDPD.h $(srcdir)/../libdecnumber/decUtility.h' + # Flag whether we need eh_dummy.c need_eh_dummy= @@ -349,6 +361,49 @@ for ml in $MULTILIBS; do fi done + if [ "@enable_decimal_float@" = "yes" -a -z "$libgcc_so" ]; then + # Bring in the DFP support code if D32PBIT, D64PBIT or D128PBIT are set. + if [ -n "$D32PBIT" -o -n "$D64PBIT" -o -n "$D128PBIT" ] ; then + dec_filenames="decContext decNumber decRound decLibrary decUtility" + fi + + # Only bring in decimal*.c files for types we support. + if [ -n "$D32PBIT" ] ; then + dec_filenames="$dec_filenames decimal32" + fi + if [ -n "$D64PBIT" ] ; then + dec_filenames="$dec_filenames decimal64" + fi + if [ -n "$D128PBIT" ] ; then + dec_filenames="$dec_filenames decimal128" + fi + + for name in $dec_filenames ; do + out="libgcc/${dir}/${name}${objext}" + echo $out: "\$(srcdir)/../libdecnumber/${name}.c" $decnumber_dep + echo " $gcc_compile" $flags -c "\$(srcdir)/../libdecnumber/${name}.c" -o $out + echo $libgcc_a: $out + done + + # For individual functions, loop over each variable by name. + for dpbit_var in D32PBIT D64PBIT D128PBIT ; do + dpfuncs_var="${dpbit_var}_FUNCS" + eval dpbit=\$$dpbit_var + eval dpfuncs=\$$dpfuncs_var + + if [ "$dpbit" ]; then + for name in $dpfuncs; do + out="libgcc/${dir}/${name}${objext}" + echo $out: $dpbit $fpbit_c_dep + echo " $gcc_compile" -DFINE_GRAINED_LIBRARIES $flags -DL$name \ + -c $dpbit -o $out + + echo $libgcc_a: $out + done + fi + done + fi + for file in $LIB2ADD; do name=`echo $file | sed -e 's/[.][cS]$//' -e 's/[.]asm$//'` oname=`echo $name | sed -e 's,.*/,,'` |