diff options
author | Richard Henderson <rth@redhat.com> | 2002-09-03 13:21:35 -0700 |
---|---|---|
committer | Richard Henderson <rth@gcc.gnu.org> | 2002-09-03 13:21:35 -0700 |
commit | d57a4b98c468fbef724a721228b713c27cccf784 (patch) | |
tree | beb40aea471a9c4ff00226d241b1df74eeee7c7f /gcc/c-common.c | |
parent | 527347f04d1d1229e4d2e96c207d7df66caa4df3 (diff) | |
download | gcc-d57a4b98c468fbef724a721228b713c27cccf784.zip gcc-d57a4b98c468fbef724a721228b713c27cccf784.tar.gz gcc-d57a4b98c468fbef724a721228b713c27cccf784.tar.bz2 |
Makefile.in (USER_H): Add ginclude/float.h.
* Makefile.in (USER_H): Add ginclude/float.h.
(FLOAT_H): Remove.
(stmp-int-hdrs, install-mkheaders): Don't handle FLOAT_H.
(mostlyclean): Don't remove float.h intermediate files.
(distclean): Don't remove float.h.
* config.gcc: Remove all float_format references.
* configure.in (float_format, float_h_file): Remove.
* c-common.c: Include tree-inline.h.
(builtin_define_with_int_value): New.
(builtin_define_type_precision): Use it.
(builtin_define_float_constants): New.
(cb_register_builtins): Use it. Define __FLT_RADIX__ and
__FLT_EVAL_METHOD__.
* defaults.h (TARGET_FLT_EVAL_METHOD): New.
* config/i386/i386.h (TARGET_FLT_EVAL_METHOD): New.
* config/m68k/m68k.h (TARGET_FLT_EVAL_METHOD): New.
* doc/tm.texi (INTEL_EXTENDED_IEEE_FORMAT): Mention moto 96-bit format.
(TARGET_FLT_EVAL_METHOD): New.
* config/float-c4x.h, config/float-i128.h, config/float-i32.h,
config/float-i386.h, config/float-i64.h, config/float-m68k.h,
config/float-sh.h, config/float-sparc.h, config/float-vax.h: Remove.
* ginclude/float.h: New.
From-SVN: r56769
Diffstat (limited to 'gcc/c-common.c')
-rw-r--r-- | gcc/c-common.c | 304 |
1 files changed, 302 insertions, 2 deletions
diff --git a/gcc/c-common.c b/gcc/c-common.c index 4587991..2cdc435 100644 --- a/gcc/c-common.c +++ b/gcc/c-common.c @@ -38,6 +38,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "target.h" #include "langhooks.h" #include "except.h" /* For USING_SJLJ_EXCEPTIONS. */ +#include "tree-inline.h" cpp_reader *parse_in; /* Declared in c-pragma.h. */ @@ -761,9 +762,13 @@ static bool get_nonnull_operand PARAMS ((tree, void builtin_define_std PARAMS ((const char *)); static void builtin_define_with_value PARAMS ((const char *, const char *, int)); +static void builtin_define_with_int_value PARAMS ((const char *, + HOST_WIDE_INT)); static void builtin_define_type_max PARAMS ((const char *, tree, int)); static void cpp_define_data_format PARAMS ((cpp_reader *)); static void builtin_define_type_precision PARAMS ((const char *, tree)); +static void builtin_define_float_constants PARAMS ((const char *, + const char *, tree)); /* Table of machine-independent attributes common to all C-like languages. */ const struct attribute_spec c_common_attribute_table[] = @@ -4682,6 +4687,7 @@ cpp_define_data_format (pfile) cpp_reader *pfile; { const char *format; + /* Define endianness enumeration values. */ cpp_define (pfile, "__GCC_LITTLE_ENDIAN__=0"); cpp_define (pfile, "__GCC_BIG_ENDIAN__=1"); @@ -4772,9 +4778,270 @@ builtin_define_type_precision (name, type) const char *name; tree type; { - char buf[8]; - sprintf (buf, "%d", (int) TYPE_PRECISION (type)); + builtin_define_with_int_value (name, TYPE_PRECISION (type)); +} + +/* Define the float.h constants for TYPE using NAME_PREFIX and FP_SUFFIX. */ +static void +builtin_define_float_constants (name_prefix, fp_suffix, type) + const char *name_prefix; + const char *fp_suffix; + tree type; +{ + /* Used to convert radix-based values to base 10 values in several cases. + + In the max_exp -> max_10_exp conversion for 128-bit IEEE, we need at + least 6 significant digits for correct results. Using the fraction + formed by (log(2)*1e6)/(log(10)*1e6) overflows a 32-bit integer as an + intermediate; perhaps someone can find a better approximation, in the + mean time, I suspect using doubles won't harm the bootstrap here. */ + + const double log10_2 = .30102999566398119521; + const double log10_16 = 1.20411998265592478085; + const double log10_b + = TARGET_FLOAT_FORMAT == IBM_FLOAT_FORMAT ? log10_16 : log10_2; + + const int log2_b = TARGET_FLOAT_FORMAT == IBM_FLOAT_FORMAT ? 4 : 1; + + char name[64], buf[128]; + int mant_dig, max_exp, min_exp; + int dig, min_10_exp, max_10_exp; + + /* ??? This information should be shared with real.c. */ + +#ifndef INTEL_EXTENDED_IEEE_FORMAT +#define INTEL_EXTENDED_IEEE_FORMAT 0 +#endif +#ifndef TARGET_G_FLOAT +#define TARGET_G_FLOAT 0 +#endif + + switch (TARGET_FLOAT_FORMAT) + { + case IEEE_FLOAT_FORMAT: + switch (TYPE_PRECISION (type)) + { + case 32: + /* ??? Handle MIPS r5900, which doesn't implement Inf or NaN, + but rather reuses the largest exponent as a normal number. */ + mant_dig = 24; + min_exp = -125; + max_exp = 128; + break; + case 64: + mant_dig = 53; + min_exp = -1021; + max_exp = 1024; + break; + case 128: + if (!INTEL_EXTENDED_IEEE_FORMAT) + { + mant_dig = 113; + min_exp = -16381; + max_exp = 16384; + break; + } + /* FALLTHRU */ + case 96: + mant_dig = 64; + max_exp = 16384; + if (INTEL_EXTENDED_IEEE_FORMAT) + min_exp = -16381; + else + /* ??? Otherwise assume m68k. */ + min_exp = -16382; + break; + default: + abort (); + } + break; + + case VAX_FLOAT_FORMAT: + switch (TYPE_PRECISION (type)) + { + case 32: /* F_FLOAT */ + mant_dig = 24; + min_exp = -127; + max_exp = 127; + break; + case 64: /* G_FLOAT or D_FLOAT */ + if (TARGET_G_FLOAT) + { + mant_dig = 53; + min_exp = -1023; + max_exp = 1023; + } + else + { + mant_dig = 56; + min_exp = -127; + max_exp = 127; + } + break; + case 128: /* H_FLOAT */ + mant_dig = 114; + min_exp = -16383; + max_exp = 16383; + break; + default: + abort (); + } + break; + + case IBM_FLOAT_FORMAT: + switch (TYPE_PRECISION (type)) + { + case 32: + mant_dig = 6; + min_exp = -64; + max_exp = 63; + break; + case 64: + mant_dig = 14; + min_exp = -64; + max_exp = 63; + break; + default: + abort (); + } + break; + + case C4X_FLOAT_FORMAT: + switch (TYPE_PRECISION (type)) + { + case 32: + mant_dig = 24; + min_exp = -126; + max_exp = 128; + break; + case 64: + mant_dig = 32; + min_exp = -126; + max_exp = 128; + break; + default: + abort (); + } + break; + + default: + abort (); + } + + /* The number of radix digits, p, in the floating-point significand. */ + sprintf (name, "__%s_MANT_DIG__", name_prefix); + builtin_define_with_int_value (name, mant_dig); + + /* The number of decimal digits, q, such that any floating-point number + with q decimal digits can be rounded into a floating-point number with + p radix b digits and back again without change to the q decimal digits, + + p log10 b if b is a power of 10 + floor((p - 1) log10 b) otherwise + */ + dig = (mant_dig - 1) * log10_b; + sprintf (name, "__%s_DIG__", name_prefix); + builtin_define_with_int_value (name, dig); + + /* The minimum negative int x such that b**(x-1) is a normalised float. */ + sprintf (name, "__%s_MIN_EXP__", name_prefix); + sprintf (buf, "(%d)", min_exp); + builtin_define_with_value (name, buf, 0); + + /* The minimum negative int x such that 10**x is a normalized float, + + ceil (log10 (b ** (min_exp - 1))) + = ceil (log10 (b) * (min_exp - 1)) + + Recall that min_exp is negative, so the integer truncation calculates + the ceiling, not the floor, in this case. */ + min_10_exp = (min_exp - 1) * log10_b; + sprintf (name, "__%s_MIN_10_EXP__", name_prefix); + sprintf (buf, "(%d)", min_10_exp); builtin_define_with_value (name, buf, 0); + + /* The maximum int x such that b**(x-1) is a representable float. */ + sprintf (name, "__%s_MAX_EXP__", name_prefix); + builtin_define_with_int_value (name, max_exp); + + /* The maximum int x such that 10**x is in the range of representable + finite floating-point numbers, + + floor (log10((1 - b**-p) * b**max_exp)) + = floor (log10(1 - b**-p) + log10(b**max_exp)) + = floor (log10(1 - b**-p) + log10(b)*max_exp) + + The safest thing to do here is to just compute this number. But since + we don't link cc1 with libm, we cannot. We could implement log10 here + a series expansion, but that seems too much effort because: + + Note that the first term, for all extant p, is a number exceedingly close + to zero, but slightly negative. Note that the second term is an integer + scaling an irrational number, and that because of the floor we are only + interested in its integral portion. + + In order for the first term to have any effect on the integral portion + of the second term, the second term has to be exceedingly close to an + integer itself (e.g. 123.000000000001 or something). Getting a result + that close to an integer requires that the irrational multiplicand have + a long series of zeros in its expansion, which doesn't occur in the + first 20 digits or so of log10(b). + + Hand-waving aside, crunching all of the sets of constants above by hand + does not yield a case for which the first term is significant, which + in the end is all that matters. */ + max_10_exp = max_exp * log10_b; + sprintf (name, "__%s_MAX_10_EXP__", name_prefix); + builtin_define_with_int_value (name, max_10_exp); + + /* Since, for the supported formats, B is always a power of 2, we + construct the following numbers directly as a hexadecimal constants. */ + + /* The maximum representable finite floating-point number, + (1 - b**-p) * b**max_exp */ + { + int i, n; + char *p; + sprintf (name, "__%s_MAX__", name_prefix); + + strcpy (buf, "0x0."); + + n = mant_dig * log2_b; + for (i = 0, p = buf + 4; i + 3 < n; i += 4) + *p++ = 'f'; + if (i < n) + *p++ = "08ce"[n - i]; + sprintf (p, "p%d%s", max_exp * log2_b, fp_suffix); + builtin_define_with_value (name, buf, 0); + } + + /* The minimum normalized positive floating-point number, b**(min_exp-1). */ + sprintf (name, "__%s_MIN__", name_prefix); + sprintf (buf, "0x1p%d%s", (min_exp - 1) * log2_b, fp_suffix); + builtin_define_with_value (name, buf, 0); + + /* The difference between 1 and the least value greater than 1 that is + representable in the given floating point type, b**(1-p). */ + sprintf (name, "__%s_EPSILON__", name_prefix); + sprintf (buf, "0x1p%d%s", (1 - mant_dig) * log2_b, fp_suffix); + builtin_define_with_value (name, buf, 0); + + if (type == long_double_type_node) + { + /* The number of decimal digits, n, such that any floating-point number + in the widest supported floating type with pmax radix b digits can be + rounded to a floating-point number with n decimal digits and back + again without change to the value, + + pmax log10(b) if b is a power of 10 + ceil(1 + pmax * log10(b)) otherwise + */ + double d_decimal_dig = 1 + mant_dig * log10_b; + int decimal_dig = d_decimal_dig; + if (decimal_dig < d_decimal_dig) + decimal_dig++; + builtin_define_with_int_value ("__DECIMAL_DIG__", decimal_dig); + } } /* Hook that registers front end and target-specific built-ins. */ @@ -4830,6 +5097,20 @@ cb_register_builtins (pfile) builtin_define_type_precision ("__DOUBLE_BIT__", double_type_node); builtin_define_type_precision ("__LONG_DOUBLE_BIT__", long_double_type_node); + /* float.h needs to know these. */ + + /* The radix of the exponent representation. */ + builtin_define_with_int_value ("__FLT_RADIX__", + (TARGET_FLOAT_FORMAT == IBM_FLOAT_FORMAT + ? 16 : 2)); + + builtin_define_with_int_value ("__FLT_EVAL_METHOD__", + TARGET_FLT_EVAL_METHOD); + + builtin_define_float_constants ("FLT", "F", float_type_node); + builtin_define_float_constants ("DBL", "", double_type_node); + builtin_define_float_constants ("LDBL", "L", long_double_type_node); + /* For use in assembly language. */ builtin_define_with_value ("__REGISTER_PREFIX__", REGISTER_PREFIX, 0); builtin_define_with_value ("__USER_LABEL_PREFIX__", user_label_prefix, 0); @@ -4956,6 +5237,25 @@ builtin_define_with_value (macro, expansion, is_str) cpp_define (parse_in, buf); } +/* Pass an object-like macro and an integer value to define it to. */ +static void +builtin_define_with_int_value (macro, value) + const char *macro; + HOST_WIDE_INT value; +{ + char *buf; + size_t mlen = strlen (macro); + size_t vlen = 18; + size_t extra = 2; /* space for = and NUL. */ + + buf = alloca (mlen + vlen + extra); + memcpy (buf, macro, mlen); + buf[mlen] = '='; + sprintf (buf + mlen + 1, HOST_WIDE_INT_PRINT_DEC, value); + + cpp_define (parse_in, buf); +} + /* Define MAX for TYPE based on the precision of the type, which is assumed to be signed. IS_LONG is 1 for type "long" and 2 for "long long". */ |