aboutsummaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authorJanis Johnson <janis187@us.ibm.com>2007-09-11 01:11:16 +0000
committerJanis Johnson <janis@gcc.gnu.org>2007-09-11 01:11:16 +0000
commitf3d110ef046e4dd98a82ba8a6365427181c16b1e (patch)
tree200c6b2a83392535448b0fad1e529f6969081b6a /gcc/config
parent9fc777ad2561e542ef0eec9d94ee8cb5edc68554 (diff)
downloadgcc-f3d110ef046e4dd98a82ba8a6365427181c16b1e.zip
gcc-f3d110ef046e4dd98a82ba8a6365427181c16b1e.tar.gz
gcc-f3d110ef046e4dd98a82ba8a6365427181c16b1e.tar.bz2
re PR c/30013 (Multiple flaws in decimal floating-point arithmetic conversions fixed)
gcc/ PR c/30013 * config/dfp-bit.c: Don't skip TFmode conversions; move strto* declarations to top. (DFP_TO_BFP): Use for either XFmode or TFmode. (BFP_TO_DFP): Use for either XFmode or TFmode; always use cast of BFP_VIA_TYPE. * config/dfp-bit.h: Include float.h. (LONG_DOUBLE_HAS_XF_MODE, LONG_DOUBLE_HAS_TF_MODE): Define if long double is one of these modes, rather than using LIBGCC_HAS_*F_MODE which doesn't mean the same thing. (BFP_KIND): Use 4 to mean TFmode. (BFP_FMT): Specify the number of decimal digits based on the number of mantissa digits. (BFP_VIA_TYPE): Binary float type to use as cast for sprintf. (BFP_TO_DFP, DFP_TO_BFP): Define names for TFmode variants. (STR_TO_BFP): Use strtold for XFmode or TFmode. (TFtype): Define if TFmode is supported. * doc/libgcc.texi (Decimal float library routines): Document TF conversion functions. gcc/testsuite/ * gcc.dg/dfp/convert-bfp.c: Replace SKIP_LONG_DOUBLE with runtime checks for size of long double. * gcc.dg/dfp/convert.h: New file. * gcc.dg/dfp/convert-bfp-2.c: New test. * gcc.dg/dfp/convert-bfp-3.c: Ditto. * gcc.dg/dfp/convert-bfp-4.c: Ditto. * gcc.dg/dfp/convert-bfp-5.c: Ditto. * gcc.dg/dfp/convert-bfp-6.c: Ditto. * gcc.dg/dfp/convert-bfp-7.c: Ditto. * gcc.dg/dfp/convert-bfp-8.c: Ditto. * gcc.dg/dfp/convert-bfp-9.c: Ditto. * gcc.dg/dfp/convert-bfp-10.c: Ditto. * gcc.dg/dfp/convert-bfp-11.c: Ditto. From-SVN: r128361
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/dfp-bit.c28
-rw-r--r--gcc/config/dfp-bit.h78
2 files changed, 70 insertions, 36 deletions
diff --git a/gcc/config/dfp-bit.c b/gcc/config/dfp-bit.c
index 6a1bc30..8ee4dec 100644
--- a/gcc/config/dfp-bit.c
+++ b/gcc/config/dfp-bit.c
@@ -34,16 +34,11 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
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. */
-
-/* FIXME: This implementation doesn't support TFmode conversions. */
-#if !(defined (L_sd_to_tf) || defined (L_dd_to_tf) \
- || defined (L_td_to_tf) || defined (L_tf_to_sd) \
- || defined (L_tf_to_dd) || defined (L_tf_to_td))
-
#include <stdio.h>
#include <stdlib.h>
+/* FIXME: compile with -std=gnu99 to get these from stdlib.h */
+extern float strtof (const char *, char **);
+extern long double strtold (const char *, char **);
#include <string.h>
#include <limits.h>
@@ -471,7 +466,9 @@ INT_TO_DFP (INT_TYPE i)
#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)
+ && LONG_DOUBLE_HAS_XF_MODE) \
+ || ((defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf)) \
+ && LONG_DOUBLE_HAS_TF_MODE)
BFP_TYPE
DFP_TO_BFP (DFP_C_TYPE f)
{
@@ -489,7 +486,9 @@ DFP_TO_BFP (DFP_C_TYPE f)
#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)
+ && LONG_DOUBLE_HAS_XF_MODE) \
+ || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \
+ && LONG_DOUBLE_HAS_TF_MODE)
DFP_C_TYPE
BFP_TO_DFP (BFP_TYPE x)
{
@@ -502,12 +501,7 @@ BFP_TO_DFP (BFP_TYPE x)
DFP_INIT_ROUNDMODE (context.round);
/* Use a C library function to write the floating point value to a string. */
-#ifdef BFP_VIA_TYPE
- /* FIXME: Is there 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);
@@ -543,7 +537,3 @@ DFP_UNORD (DFP_C_TYPE arg_a, DFP_C_TYPE arg_b)
return (decNumberIsNaN (&arg1) || decNumberIsNaN (&arg2));
}
#endif /* L_unord_sd || L_unord_dd || L_unord_td */
-
-/* !(L_sd_to_tf || L_dd_to_tf || L_td_to_tf \
- || L_tf_to_sd || L_tf_to_dd || L_tf_to_td) */
-#endif
diff --git a/gcc/config/dfp-bit.h b/gcc/config/dfp-bit.h
index 7c47387..27c6a8a 100644
--- a/gcc/config/dfp-bit.h
+++ b/gcc/config/dfp-bit.h
@@ -30,6 +30,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#ifndef _DFPBIT_H
#define _DFPBIT_H
+#include <float.h>
#include <fenv.h>
#include <decRound.h>
#include <decExcept.h>
@@ -49,10 +50,15 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE LONG_DOUBLE_TYPE_SIZE
#endif
-#ifndef LIBGCC2_HAS_XF_MODE
-#define LIBGCC2_HAS_XF_MODE \
+/* We need to know the size of long double that the C library supports.
+ Don't use LIBGCC2_HAS_XF_MODE or LIBGCC2_HAS_TF_MODE here because
+ some targets set both of those. */
+
+#define LONG_DOUBLE_HAS_XF_MODE \
(BITS_PER_UNIT == 8 && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 80)
-#endif
+
+#define LONG_DOUBLE_HAS_TF_MODE \
+ (BITS_PER_UNIT == 8 && LIBGCC2_LONG_DOUBLE_TYPE_SIZE == 128)
/* Depending on WIDTH, define a number of macros:
@@ -242,6 +248,9 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
#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
+#elif defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf) \
+ || defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)
+#define BFP_KIND 4
#endif
/* If BFP_KIND is defined, define additional macros:
@@ -249,29 +258,48 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
BFP_TYPE: The binary floating point data type.
BFP_FMT: The format string for writing the value to a string.
+ The number of decimal digits printed is
+ ceil (nbits / log2 (10.) + 1)
+ as described in David Matula's CACM 19(3) 716-723 June 1968 paper.
+ BFP_VIA_TYPE: Type to which to cast a variable of BPF_TYPE for a
+ call to sprintf.
+
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 BFP_FMT "%.9e"
+#define BFP_VIA_TYPE double
#define STR_TO_BFP strtof
#elif BFP_KIND == 2
#define BFP_TYPE DFtype
-#define BFP_FMT "%e"
+#define BFP_FMT "%.17e"
+#define BFP_VIA_TYPE double
#define STR_TO_BFP strtod
#elif BFP_KIND == 3
-#if LIBGCC2_HAS_XF_MODE
-/* These aren't used if XF mode is not supported. */
+#if LONG_DOUBLE_HAS_XF_MODE
#define BFP_TYPE XFtype
-#define BFP_FMT "%e"
-#define BFP_VIA_TYPE double
-#define STR_TO_BFP strtod
-#endif
+#define BFP_FMT "%.21Le"
+#define BFP_VIA_TYPE long double
+#define STR_TO_BFP strtold
+#endif /* LONG_DOUBLE_HAS_XF_MODE */
+
+#elif BFP_KIND == 4
+#if LONG_DOUBLE_HAS_TF_MODE
+#define BFP_TYPE TFtype
+#if LDBL_MANT_DIG == 106
+#define BFP_FMT "%.33Le"
+#elif LDBL_MANT_DIG == 113
+#define BFP_FMT "%.36Le"
+#else
+#error "unknown long double size, cannot define BFP_FMT"
+#endif /* LDBL_MANT_DIG */
+#define STR_TO_BFP strtold
+#define BFP_VIA_TYPE long double
+#endif /* LONG_DOUBLE_HAS_TF_MODE */
#endif /* BFP_KIND */
@@ -455,6 +483,9 @@ extern float strtof (const char *, char **);
#elif BFP_KIND == 3
#define BFP_TO_DFP DPD_BID_NAME(__dpd_truncxfsd,__bid_truncxfsd)
#define DFP_TO_BFP DPD_BID_NAME(__dpd_extendsdxf,__bid_extendsdxf)
+#elif BFP_KIND == 4
+#define BFP_TO_DFP DPD_BID_NAME(__dpd_trunctfsd,__bid_trunctfsd)
+#define DFP_TO_BFP DPD_BID_NAME(__dpd_extendsdtf,__bid_extendsdtf)
#endif /* BFP_KIND */
#elif WIDTH == 64
@@ -467,6 +498,9 @@ extern float strtof (const char *, char **);
#elif BFP_KIND == 3
#define BFP_TO_DFP DPD_BID_NAME(__dpd_truncxfdd,__bid_truncxfdd)
#define DFP_TO_BFP DPD_BID_NAME(__dpd_extendddxf,__bid_extendddxf)
+#elif BFP_KIND == 4
+#define BFP_TO_DFP DPD_BID_NAME(__dpd_trunctfdd,__bid_trunctfdd)
+#define DFP_TO_BFP DPD_BID_NAME(__dpd_extendddtf,__bid_extendddtf)
#endif /* BFP_KIND */
#elif WIDTH == 128
@@ -479,6 +513,9 @@ extern float strtof (const char *, char **);
#elif BFP_KIND == 3
#define BFP_TO_DFP DPD_BID_NAME(__dpd_extendxftd,__bid_extendxftd)
#define DFP_TO_BFP DPD_BID_NAME(__dpd_trunctdxf,__bid_trunctdxf)
+#elif BFP_KIND == 4
+#define BFP_TO_DFP DPD_BID_NAME(__dpd_extendtftd,__bid_extendtftd)
+#define DFP_TO_BFP DPD_BID_NAME(__dpd_trunctdtf,__bid_trunctdtf)
#endif /* BFP_KIND */
#endif /* WIDTH */
@@ -487,9 +524,12 @@ extern float strtof (const char *, char **);
typedef float SFtype __attribute__ ((mode (SF)));
typedef float DFtype __attribute__ ((mode (DF)));
-#if LIBGCC2_HAS_XF_MODE
+#if LONG_DOUBLE_HAS_XF_MODE
typedef float XFtype __attribute__ ((mode (XF)));
-#endif /* LIBGCC2_HAS_XF_MODE */
+#endif /* LONG_DOUBLE_HAS_XF_MODE */
+#if LONG_DOUBLE_HAS_TF_MODE
+typedef float TFtype __attribute__ ((mode (TF)));
+#endif /* LONG_DOUBLE_HAS_TF_MODE */
typedef int SItype __attribute__ ((mode (SI)));
typedef int DItype __attribute__ ((mode (DI)));
@@ -566,14 +606,18 @@ extern DFP_C_TYPE INT_TO_DFP (INT_TYPE);
#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)
+ && LONG_DOUBLE_HAS_XF_MODE) \
+ || ((defined (L_sd_to_tf) || defined (L_dd_to_tf) || defined (L_td_to_tf)) \
+ && LONG_DOUBLE_HAS_TF_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)
+ && LONG_DOUBLE_HAS_XF_MODE) \
+ || ((defined (L_tf_to_sd) || defined (L_tf_to_dd) || defined (L_tf_to_td)) \
+ && LONG_DOUBLE_HAS_TF_MODE)
extern DFP_C_TYPE BFP_TO_DFP (BFP_TYPE);
#endif