aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog63
-rw-r--r--gcc/ada/ChangeLog8
-rw-r--r--gcc/ada/gcc-interface/misc.c7
-rw-r--r--gcc/c-common.c35
-rw-r--r--gcc/c-common.def7
-rw-r--r--gcc/c-cppbuiltin.c6
-rw-r--r--gcc/c-lex.c29
-rw-r--r--gcc/c-opts.c14
-rw-r--r--gcc/c-parser.c8
-rw-r--r--gcc/c-typeck.c274
-rw-r--r--gcc/common.opt4
-rw-r--r--gcc/config/i386/i386.h14
-rw-r--r--gcc/config/i386/i386.md89
-rw-r--r--gcc/convert.c3
-rw-r--r--gcc/defaults.h5
-rw-r--r--gcc/doc/invoke.texi33
-rw-r--r--gcc/flags.h15
-rw-r--r--gcc/fortran/ChangeLog8
-rw-r--r--gcc/fortran/options.c9
-rw-r--r--gcc/java/ChangeLog7
-rw-r--r--gcc/java/lang.c7
-rw-r--r--gcc/langhooks.c3
-rw-r--r--gcc/opts.c9
-rw-r--r--gcc/testsuite/ChangeLog10
-rw-r--r--gcc/testsuite/gcc.target/i386/excess-precision-1.c186
-rw-r--r--gcc/testsuite/gcc.target/i386/excess-precision-2.c34
-rw-r--r--gcc/testsuite/gcc.target/i386/excess-precision-3.c219
-rw-r--r--gcc/testsuite/gcc.target/i386/excess-precision-4.c8
-rw-r--r--gcc/testsuite/gcc.target/i386/excess-precision-5.c23
-rw-r--r--gcc/testsuite/gcc.target/i386/excess-precision-6.c20
-rw-r--r--gcc/toplev.c45
-rw-r--r--gcc/tree.c55
-rw-r--r--gcc/tree.h1
33 files changed, 1189 insertions, 69 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 49bbb0f..db553e9 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,68 @@
2009-03-30 Joseph Myers <joseph@codesourcery.com>
+ PR rtl-optimization/323
+ * c-common.c (c_fully_fold, convert_and_check,
+ c_common_truthvalue_conversion): Handle EXCESS_PRECISION_EXPR.
+ (c_fully_fold_internal): Disallow EXCESS_PRECISION_EXPR.
+ * c-common.def (EXCESS_PRECISION_EXPR): New.
+ * c-cppbuiltin.c (builtin_define_float_constants): Define
+ constants with enough digits for long double.
+ * c-lex.c (interpret_float): Interpret constant with excess
+ precision where appropriate.
+ * c-opts.c (c_common_post_options): Set
+ flag_excess_precision_cmdline. Give an error for
+ -fexcess-precision=standard for C++ for processors where the
+ option is significant.
+ * c-parser.c (c_parser_conditional_expression): Handle excess
+ precision in condition.
+ * c-typeck.c (convert_arguments): Handle arguments with excess
+ precision.
+ (build_unary_op): Move excess precision outside operation.
+ (build_conditional_expr): Likewise.
+ (build_compound_expr): Likewise.
+ (build_c_cast): Do cast on operand of EXCESS_PRECISION_EXPR.
+ (build_modify_expr): Handle excess precision in RHS.
+ (convert_for_assignment): Handle excess precision in converted
+ value.
+ (digest_init, output_init_element, process_init_element): Handle
+ excess precision in initializer.
+ (c_finish_return): Handle excess precision in return value.
+ (build_binary_op): Handle excess precision in operands and add
+ excess precision as needed for operation.
+ * common.opt (-fexcess-precision=): New option.
+ * config/i386/i386.h (X87_ENABLE_ARITH, X87_ENABLE_FLOAT): New.
+ * config/i386/i386.md (float<SSEMODEI24:mode><X87MODEF:mode>2):
+ For standard excess precision, output explicit conversion to and
+ truncation from XFmode.
+ (*float<SSEMODEI24:mode><X87MODEF:mode>2_1,
+ *float<SSEMODEI24:mode><X87MODEF:mode>2_i387_with_temp,
+ *float<SSEMODEI24:mode><X87MODEF:mode>2_i387, two unnamed
+ define_splits, floatdi<X87MODEF:mode>2_i387_with_xmm, two unnamed
+ define_splits, *floatunssi<mode>2_1, two unnamed define_splits,
+ floatunssi<mode>2, add<mode>3, sub<mode>3, mul<mode>3, divdf3,
+ divsf3, *fop_<mode>_comm_i387, *fop_<mode>_1_i387,
+ *fop_<MODEF:mode>_2_i387, *fop_<MODEF:mode>_3_i387,
+ *fop_df_4_i387, *fop_df_5_i387, *fop_df_6_i387, two unnamed
+ define_splits, sqrt<mode>2): Disable where appropriate for
+ standard excess precision.
+ * convert.c (convert_to_real): Do not shorten arithmetic to type
+ for which excess precision would be used.
+ * defaults.h (TARGET_FLT_EVAL_METHOD_NON_DEFAULT): Define.
+ * doc/invoke.texi (-fexcess-precision=): Document option.
+ (-mfpmath=): Correct index entry.
+ * flags.h (enum excess_precision, flag_excess_precision_cmdline,
+ flag_excess_precision): New.
+ * langhooks.c (lhd_post_options): Set
+ flag_excess_precision_cmdline.
+ * opts.c (common_handle_option): Handle -fexcess-precision=.
+ * toplev.c (flag_excess_precision_cmdline, flag_excess_precision,
+ init_excess_precision): New.
+ (lang_dependent_init_target): Call init_excess_precision.
+ * tree.c (excess_precision_type): New.
+ * tree.h (excess_precision_type): Declare.
+
+2009-03-30 Joseph Myers <joseph@codesourcery.com>
+
PR c/35235
* c-typeck.c (build_component_ref): Do not copy qualifiers from
non-lvalue to component.
diff --git a/gcc/ada/ChangeLog b/gcc/ada/ChangeLog
index 97bd2609..0b16cae 100644
--- a/gcc/ada/ChangeLog
+++ b/gcc/ada/ChangeLog
@@ -1,3 +1,11 @@
+2009-03-30 Joseph Myers <joseph@codesourcery.com>
+
+ PR rtl-optimization/323
+ * gcc-interface/misc.c (gnat_post_options): Set
+ flag_excess_precision_cmdline. Give an error for
+ -fexcess-precision=standard for processors where the option is
+ significant.
+
2009-03-27 H.J. Lu <hongjiu.lu@intel.com>
PR c/39323
diff --git a/gcc/ada/gcc-interface/misc.c b/gcc/ada/gcc-interface/misc.c
index ca672f8..329f68e 100644
--- a/gcc/ada/gcc-interface/misc.c
+++ b/gcc/ada/gcc-interface/misc.c
@@ -337,6 +337,13 @@ gnat_init_options (unsigned int argc, const char **argv)
bool
gnat_post_options (const char **pfilename ATTRIBUTE_UNUSED)
{
+ /* Excess precision other than "fast" requires front-end
+ support. */
+ if (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD
+ && TARGET_FLT_EVAL_METHOD_NON_DEFAULT)
+ sorry ("-fexcess-precision=standard for Ada");
+ flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
+
/* ??? The warning machinery is outsmarted by Ada. */
warn_unused_parameter = 0;
diff --git a/gcc/c-common.c b/gcc/c-common.c
index 9abd006..b1ac9bc 100644
--- a/gcc/c-common.c
+++ b/gcc/c-common.c
@@ -1131,6 +1131,7 @@ tree
c_fully_fold (tree expr, bool in_init, bool *maybe_const)
{
tree ret;
+ tree eptype = NULL_TREE;
bool dummy = true;
bool maybe_const_itself = true;
@@ -1142,8 +1143,15 @@ c_fully_fold (tree expr, bool in_init, bool *maybe_const)
if (!maybe_const)
maybe_const = &dummy;
+ if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
+ {
+ eptype = TREE_TYPE (expr);
+ expr = TREE_OPERAND (expr, 0);
+ }
ret = c_fully_fold_internal (expr, in_init, maybe_const,
&maybe_const_itself);
+ if (eptype)
+ ret = fold_convert (eptype, ret);
*maybe_const &= maybe_const_itself;
return ret;
}
@@ -1444,6 +1452,15 @@ c_fully_fold_internal (tree expr, bool in_init, bool *maybe_const_operands,
*maybe_const_itself &= op2_const_self;
goto out;
+ case EXCESS_PRECISION_EXPR:
+ /* Each case where an operand with excess precision may be
+ encountered must remove the EXCESS_PRECISION_EXPR around
+ inner operands and possibly put one around the whole
+ expression or possibly convert to the semantic type (which
+ c_fully_fold does); we cannot tell at this stage which is
+ appropriate in any particular case. */
+ gcc_unreachable ();
+
default:
/* Various codes may appear through folding built-in functions
and their arguments. */
@@ -2174,6 +2191,21 @@ tree
convert_and_check (tree type, tree expr)
{
tree result;
+ tree expr_for_warning;
+
+ /* Convert from a value with possible excess precision rather than
+ via the semantic type, but do not warn about values not fitting
+ exactly in the semantic type. */
+ if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
+ {
+ tree orig_type = TREE_TYPE (expr);
+ expr = TREE_OPERAND (expr, 0);
+ expr_for_warning = convert (orig_type, expr);
+ if (orig_type == type)
+ return expr_for_warning;
+ }
+ else
+ expr_for_warning = expr;
if (TREE_TYPE (expr) == type)
return expr;
@@ -2181,7 +2213,7 @@ convert_and_check (tree type, tree expr)
result = convert (type, expr);
if (!skip_evaluation && !TREE_OVERFLOW_P (expr) && result != error_mark_node)
- warnings_for_convert_and_check (type, expr, result);
+ warnings_for_convert_and_check (type, expr_for_warning, result);
return result;
}
@@ -3862,6 +3894,7 @@ c_common_truthvalue_conversion (location_t location, tree expr)
case NEGATE_EXPR:
case ABS_EXPR:
case FLOAT_EXPR:
+ case EXCESS_PRECISION_EXPR:
/* These don't change whether an object is nonzero or zero. */
return c_common_truthvalue_conversion (location, TREE_OPERAND (expr, 0));
diff --git a/gcc/c-common.def b/gcc/c-common.def
index c4027f7..1c59363 100644
--- a/gcc/c-common.def
+++ b/gcc/c-common.def
@@ -39,6 +39,13 @@ along with GCC; see the file COPYING3. If not see
not. */
DEFTREECODE (C_MAYBE_CONST_EXPR, "c_maybe_const_expr", tcc_expression, 2)
+/* An EXCESS_PRECISION_EXPR, currently only used for C and Objective
+ C, represents an expression evaluated in greater range or precision
+ than its type. The type of the EXCESS_PRECISION_EXPR is the
+ semantic type while the operand represents what is actually being
+ evaluated. */
+DEFTREECODE (EXCESS_PRECISION_EXPR, "excess_precision_expr", tcc_expression, 1)
+
/*
Local variables:
mode:c
diff --git a/gcc/c-cppbuiltin.c b/gcc/c-cppbuiltin.c
index c6112d8..5d6033d 100644
--- a/gcc/c-cppbuiltin.c
+++ b/gcc/c-cppbuiltin.c
@@ -98,6 +98,7 @@ builtin_define_float_constants (const char *name_prefix,
const double log10_2 = .30102999566398119521;
double log10_b;
const struct real_format *fmt;
+ const struct real_format *ldfmt;
char name[64], buf[128];
int dig, min_10_exp, max_10_exp;
@@ -105,6 +106,8 @@ builtin_define_float_constants (const char *name_prefix,
fmt = REAL_MODE_FORMAT (TYPE_MODE (type));
gcc_assert (fmt->b != 10);
+ ldfmt = REAL_MODE_FORMAT (TYPE_MODE (long_double_type_node));
+ gcc_assert (ldfmt->b != 10);
/* The radix of the exponent representation. */
if (type == float_type_node)
@@ -187,7 +190,8 @@ builtin_define_float_constants (const char *name_prefix,
The only macro we care about is this number for the widest supported
floating type, but we want this value for rendering constants below. */
{
- double d_decimal_dig = 1 + fmt->p * log10_b;
+ double d_decimal_dig
+ = 1 + (fmt->p < ldfmt->p ? ldfmt->p : fmt->p) * log10_b;
decimal_dig = d_decimal_dig;
if (decimal_dig < d_decimal_dig)
decimal_dig++;
diff --git a/gcc/c-lex.c b/gcc/c-lex.c
index 5b71c3b..72a9590 100644
--- a/gcc/c-lex.c
+++ b/gcc/c-lex.c
@@ -605,8 +605,10 @@ static tree
interpret_float (const cpp_token *token, unsigned int flags)
{
tree type;
+ tree const_type;
tree value;
REAL_VALUE_TYPE real;
+ REAL_VALUE_TYPE real_trunc;
char *copy;
size_t copylen;
@@ -655,6 +657,10 @@ interpret_float (const cpp_token *token, unsigned int flags)
else
type = double_type_node;
+ const_type = excess_precision_type (type);
+ if (!const_type)
+ const_type = type;
+
/* Copy the constant to a nul-terminated buffer. If the constant
has any suffixes, cut them off; REAL_VALUE_ATOF/ REAL_VALUE_HTOF
can't handle them. */
@@ -675,13 +681,21 @@ interpret_float (const cpp_token *token, unsigned int flags)
memcpy (copy, token->val.str.text, copylen);
copy[copylen] = '\0';
- real_from_string3 (&real, copy, TYPE_MODE (type));
+ real_from_string3 (&real, copy, TYPE_MODE (const_type));
+ if (const_type != type)
+ /* Diagnosing if the result of converting the value with excess
+ precision to the semantic type would overflow (with associated
+ double rounding) is more appropriate than diagnosing if the
+ result of converting the string directly to the semantic type
+ would overflow. */
+ real_convert (&real_trunc, TYPE_MODE (type), &real);
/* Both C and C++ require a diagnostic for a floating constant
outside the range of representable values of its type. Since we
have __builtin_inf* to produce an infinity, this is now a
mandatory pedwarn if the target does not support infinities. */
- if (REAL_VALUE_ISINF (real))
+ if (REAL_VALUE_ISINF (real)
+ || (const_type != type && REAL_VALUE_ISINF (real_trunc)))
{
if (!MODE_HAS_INFINITIES (TYPE_MODE (type)))
pedwarn (input_location, 0, "floating constant exceeds range of %qT", type);
@@ -689,7 +703,8 @@ interpret_float (const cpp_token *token, unsigned int flags)
warning (OPT_Woverflow, "floating constant exceeds range of %qT", type);
}
/* We also give a warning if the value underflows. */
- else if (REAL_VALUES_EQUAL (real, dconst0))
+ else if (REAL_VALUES_EQUAL (real, dconst0)
+ || (const_type != type && REAL_VALUES_EQUAL (real_trunc, dconst0)))
{
REAL_VALUE_TYPE realvoidmode;
int overflow = real_from_string (&realvoidmode, copy);
@@ -698,9 +713,13 @@ interpret_float (const cpp_token *token, unsigned int flags)
}
/* Create a node with determined type and value. */
- value = build_real (type, real);
+ value = build_real (const_type, real);
if (flags & CPP_N_IMAGINARY)
- value = build_complex (NULL_TREE, convert (type, integer_zero_node), value);
+ value = build_complex (NULL_TREE, convert (const_type, integer_zero_node),
+ value);
+
+ if (type != const_type)
+ value = build1 (EXCESS_PRECISION_EXPR, type, value);
return value;
}
diff --git a/gcc/c-opts.c b/gcc/c-opts.c
index 334577a..3953991 100644
--- a/gcc/c-opts.c
+++ b/gcc/c-opts.c
@@ -1013,6 +1013,20 @@ c_common_post_options (const char **pfilename)
C_COMMON_OVERRIDE_OPTIONS;
#endif
+ /* Excess precision other than "fast" requires front-end
+ support. */
+ if (c_dialect_cxx ())
+ {
+ if (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD
+ && TARGET_FLT_EVAL_METHOD_NON_DEFAULT)
+ sorry ("-fexcess-precision=standard for C++");
+ flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
+ }
+ else if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT)
+ flag_excess_precision_cmdline = (flag_iso
+ ? EXCESS_PRECISION_STANDARD
+ : EXCESS_PRECISION_FAST);
+
/* By default we use C99 inline semantics in GNU99 or C99 mode. C99
inline semantics are not supported in GNU89 or C89 mode. */
if (flag_gnu89_inline == -1)
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index 4d1b4d5..03a7194 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -4465,10 +4465,18 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after)
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_COLON))
{
+ tree eptype = NULL_TREE;
pedwarn (c_parser_peek_token (parser)->location, OPT_pedantic,
"ISO C forbids omitting the middle term of a ?: expression");
+ if (TREE_CODE (cond.value) == EXCESS_PRECISION_EXPR)
+ {
+ eptype = TREE_TYPE (cond.value);
+ cond.value = TREE_OPERAND (cond.value, 0);
+ }
/* Make sure first operand is calculated only once. */
exp1.value = c_save_expr (default_conversion (cond.value));
+ if (eptype)
+ exp1.value = build1 (EXCESS_PRECISION_EXPR, eptype, exp1.value);
cond.value = c_objc_common_truthvalue_conversion (cond_loc, exp1.value);
skip_evaluation += cond.value == truthvalue_true_node;
}
diff --git a/gcc/c-typeck.c b/gcc/c-typeck.c
index 2559b1d..8702373 100644
--- a/gcc/c-typeck.c
+++ b/gcc/c-typeck.c
@@ -2553,6 +2553,7 @@ convert_arguments (int nargs, tree *argarray,
int parmnum;
const bool type_generic = fundecl
&& lookup_attribute ("type generic", TYPE_ATTRIBUTES(TREE_TYPE (fundecl)));
+ bool type_generic_remove_excess_precision = false;
tree selector;
/* Change pointer to function to the function itself for
@@ -2564,6 +2565,30 @@ convert_arguments (int nargs, tree *argarray,
/* Handle an ObjC selector specially for diagnostics. */
selector = objc_message_selector ();
+ /* For type-generic built-in functions, determine whether excess
+ precision should be removed (classification) or not
+ (comparison). */
+ if (type_generic
+ && DECL_BUILT_IN (fundecl)
+ && DECL_BUILT_IN_CLASS (fundecl) == BUILT_IN_NORMAL)
+ {
+ switch (DECL_FUNCTION_CODE (fundecl))
+ {
+ case BUILT_IN_ISFINITE:
+ case BUILT_IN_ISINF:
+ case BUILT_IN_ISINF_SIGN:
+ case BUILT_IN_ISNAN:
+ case BUILT_IN_ISNORMAL:
+ case BUILT_IN_FPCLASSIFY:
+ type_generic_remove_excess_precision = true;
+ break;
+
+ default:
+ type_generic_remove_excess_precision = false;
+ break;
+ }
+ }
+
/* Scan the given expressions and types, producing individual
converted arguments and storing them in ARGARRAY. */
@@ -2573,9 +2598,11 @@ convert_arguments (int nargs, tree *argarray,
{
tree type = typetail ? TREE_VALUE (typetail) : 0;
tree val = TREE_VALUE (valtail);
+ tree valtype = TREE_TYPE (val);
tree rname = function;
int argnum = parmnum + 1;
const char *invalid_func_diag;
+ bool excess_precision = false;
bool npc;
if (type == void_type_node)
@@ -2591,6 +2618,19 @@ convert_arguments (int nargs, tree *argarray,
}
npc = null_pointer_constant_p (val);
+
+ /* If there is excess precision and a prototype, convert once to
+ the required type rather than converting via the semantic
+ type. Likewise without a prototype a float value represented
+ as long double should be converted once to double. But for
+ type-generic classification functions excess precision must
+ be removed here. */
+ if (TREE_CODE (val) == EXCESS_PRECISION_EXPR
+ && (type || !type_generic || !type_generic_remove_excess_precision))
+ {
+ val = TREE_OPERAND (val, 0);
+ excess_precision = true;
+ }
val = c_fully_fold (val, false, NULL);
STRIP_TYPE_NOPS (val);
@@ -2615,32 +2655,32 @@ convert_arguments (int nargs, tree *argarray,
unsigned int formal_prec = TYPE_PRECISION (type);
if (INTEGRAL_TYPE_P (type)
- && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
+ && TREE_CODE (valtype) == REAL_TYPE)
warning (0, "passing argument %d of %qE as integer "
"rather than floating due to prototype",
argnum, rname);
if (INTEGRAL_TYPE_P (type)
- && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
+ && TREE_CODE (valtype) == COMPLEX_TYPE)
warning (0, "passing argument %d of %qE as integer "
"rather than complex due to prototype",
argnum, rname);
else if (TREE_CODE (type) == COMPLEX_TYPE
- && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
+ && TREE_CODE (valtype) == REAL_TYPE)
warning (0, "passing argument %d of %qE as complex "
"rather than floating due to prototype",
argnum, rname);
else if (TREE_CODE (type) == REAL_TYPE
- && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+ && INTEGRAL_TYPE_P (valtype))
warning (0, "passing argument %d of %qE as floating "
"rather than integer due to prototype",
argnum, rname);
else if (TREE_CODE (type) == COMPLEX_TYPE
- && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+ && INTEGRAL_TYPE_P (valtype))
warning (0, "passing argument %d of %qE as complex "
"rather than integer due to prototype",
argnum, rname);
else if (TREE_CODE (type) == REAL_TYPE
- && TREE_CODE (TREE_TYPE (val)) == COMPLEX_TYPE)
+ && TREE_CODE (valtype) == COMPLEX_TYPE)
warning (0, "passing argument %d of %qE as floating "
"rather than complex due to prototype",
argnum, rname);
@@ -2648,7 +2688,7 @@ convert_arguments (int nargs, tree *argarray,
conversions between complex types, but that's too messy
to do now. */
else if (TREE_CODE (type) == REAL_TYPE
- && TREE_CODE (TREE_TYPE (val)) == REAL_TYPE)
+ && TREE_CODE (valtype) == REAL_TYPE)
{
/* Warn if any argument is passed as `float',
since without a prototype it would be `double'. */
@@ -2662,40 +2702,40 @@ convert_arguments (int nargs, tree *argarray,
for decimal float types. Warn of conversions with
binary float types and of precision narrowing due to
prototype. */
- else if (type != TREE_TYPE (val)
+ else if (type != valtype
&& (type == dfloat32_type_node
|| type == dfloat64_type_node
|| type == dfloat128_type_node
- || TREE_TYPE (val) == dfloat32_type_node
- || TREE_TYPE (val) == dfloat64_type_node
- || TREE_TYPE (val) == dfloat128_type_node)
+ || valtype == dfloat32_type_node
+ || valtype == dfloat64_type_node
+ || valtype == dfloat128_type_node)
&& (formal_prec
- <= TYPE_PRECISION (TREE_TYPE (val))
+ <= TYPE_PRECISION (valtype)
|| (type == dfloat128_type_node
- && (TREE_TYPE (val)
+ && (valtype
!= dfloat64_type_node
- && (TREE_TYPE (val)
+ && (valtype
!= dfloat32_type_node)))
|| (type == dfloat64_type_node
- && (TREE_TYPE (val)
+ && (valtype
!= dfloat32_type_node))))
warning (0, "passing argument %d of %qE as %qT "
"rather than %qT due to prototype",
- argnum, rname, type, TREE_TYPE (val));
+ argnum, rname, type, valtype);
}
/* Detect integer changing in width or signedness.
These warnings are only activated with
-Wtraditional-conversion, not with -Wtraditional. */
else if (warn_traditional_conversion && INTEGRAL_TYPE_P (type)
- && INTEGRAL_TYPE_P (TREE_TYPE (val)))
+ && INTEGRAL_TYPE_P (valtype))
{
tree would_have_been = default_conversion (val);
tree type1 = TREE_TYPE (would_have_been);
if (TREE_CODE (type) == ENUMERAL_TYPE
&& (TYPE_MAIN_VARIANT (type)
- == TYPE_MAIN_VARIANT (TREE_TYPE (val))))
+ == TYPE_MAIN_VARIANT (valtype)))
/* No warning if function asks for enum
and the actual arg is that enum type. */
;
@@ -2719,8 +2759,8 @@ convert_arguments (int nargs, tree *argarray,
unsigned type, it doesn't matter whether we
pass it as signed or unsigned; the value
certainly is the same either way. */
- else if (TYPE_PRECISION (TREE_TYPE (val)) < TYPE_PRECISION (type)
- && TYPE_UNSIGNED (TREE_TYPE (val)))
+ else if (TYPE_PRECISION (valtype) < TYPE_PRECISION (type)
+ && TYPE_UNSIGNED (valtype))
;
else if (TYPE_UNSIGNED (type))
warning (OPT_Wtraditional_conversion, "passing argument %d of %qE "
@@ -2732,6 +2772,10 @@ convert_arguments (int nargs, tree *argarray,
}
}
+ /* Possibly restore an EXCESS_PRECISION_EXPR for the
+ sake of better warnings from convert_and_check. */
+ if (excess_precision)
+ val = build1 (EXCESS_PRECISION_EXPR, valtype, val);
parmval = convert_for_assignment (type, val, ic_argpass, npc,
fundecl, function,
parmnum + 1);
@@ -2743,10 +2787,10 @@ convert_arguments (int nargs, tree *argarray,
}
argarray[parmnum] = parmval;
}
- else if (TREE_CODE (TREE_TYPE (val)) == REAL_TYPE
- && (TYPE_PRECISION (TREE_TYPE (val))
+ else if (TREE_CODE (valtype) == REAL_TYPE
+ && (TYPE_PRECISION (valtype)
< TYPE_PRECISION (double_type_node))
- && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (TREE_TYPE (val))))
+ && !DECIMAL_FLOAT_MODE_P (TYPE_MODE (valtype)))
{
if (type_generic)
argarray[parmnum] = val;
@@ -2754,6 +2798,10 @@ convert_arguments (int nargs, tree *argarray,
/* Convert `float' to `double'. */
argarray[parmnum] = convert (double_type_node, val);
}
+ else if (excess_precision && !type_generic)
+ /* A "double" argument with excess precision being passed
+ without a prototype or in variable arguments. */
+ argarray[parmnum] = convert (valtype, val);
else if ((invalid_func_diag =
targetm.calls.invalid_arg_for_unprototyped_fn (typelist, fundecl, val)))
{
@@ -2959,6 +3007,7 @@ build_unary_op (location_t location,
enum tree_code typecode;
tree val;
tree ret = error_mark_node;
+ tree eptype = NULL_TREE;
int noconvert = flag;
const char *invalid_op_diag;
bool int_operands;
@@ -2981,6 +3030,12 @@ build_unary_op (location_t location,
return error_mark_node;
}
+ if (TREE_CODE (arg) == EXCESS_PRECISION_EXPR)
+ {
+ eptype = TREE_TYPE (arg);
+ arg = TREE_OPERAND (arg, 0);
+ }
+
switch (code)
{
case CONVERT_EXPR:
@@ -3077,6 +3132,8 @@ build_unary_op (location_t location,
ret = fold_build1 (REALPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
else
ret = arg;
+ if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE)
+ eptype = TREE_TYPE (eptype);
goto return_build_unary_op;
case IMAGPART_EXPR:
@@ -3086,6 +3143,8 @@ build_unary_op (location_t location,
ret = fold_build1 (IMAGPART_EXPR, TREE_TYPE (TREE_TYPE (arg)), arg);
else
ret = omit_one_operand (TREE_TYPE (arg), integer_zero_node, arg);
+ if (eptype && TREE_CODE (eptype) == COMPLEX_TYPE)
+ eptype = TREE_TYPE (eptype);
goto return_build_unary_op;
case PREINCREMENT_EXPR:
@@ -3333,6 +3392,8 @@ build_unary_op (location_t location,
ret = build1 (NOP_EXPR, TREE_TYPE (ret), ret);
else if (TREE_CODE (ret) != INTEGER_CST && int_operands)
ret = note_integer_operands (ret);
+ if (eptype)
+ ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret);
protected_set_expr_location (ret, location);
return ret;
}
@@ -3512,6 +3573,7 @@ build_conditional_expr (tree ifexp, bool ifexp_bcp, tree op1, tree op2)
enum tree_code code1;
enum tree_code code2;
tree result_type = NULL;
+ tree ep_result_type = NULL;
tree orig_op1 = op1, orig_op2 = op2;
bool int_const, op1_int_operands, op2_int_operands, int_operands;
tree ret;
@@ -3544,6 +3606,28 @@ build_conditional_expr (tree ifexp, bool ifexp_bcp, tree op1, tree op2)
objc_ok = objc_compare_types (type1, type2, -3, NULL_TREE);
+ if ((TREE_CODE (op1) == EXCESS_PRECISION_EXPR
+ || TREE_CODE (op2) == EXCESS_PRECISION_EXPR)
+ && (code1 == INTEGER_TYPE || code1 == REAL_TYPE
+ || code1 == COMPLEX_TYPE)
+ && (code2 == INTEGER_TYPE || code2 == REAL_TYPE
+ || code2 == COMPLEX_TYPE))
+ {
+ ep_result_type = c_common_type (type1, type2);
+ if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR)
+ {
+ op1 = TREE_OPERAND (op1, 0);
+ type1 = TREE_TYPE (op1);
+ gcc_assert (TREE_CODE (type1) == code1);
+ }
+ if (TREE_CODE (op2) == EXCESS_PRECISION_EXPR)
+ {
+ op2 = TREE_OPERAND (op2, 0);
+ type2 = TREE_TYPE (op2);
+ gcc_assert (TREE_CODE (type2) == code2);
+ }
+ }
+
/* Quickly detect the usual case where op1 and op2 have the same type
after promotion. */
if (TYPE_MAIN_VARIANT (type1) == TYPE_MAIN_VARIANT (type2))
@@ -3741,6 +3825,8 @@ build_conditional_expr (tree ifexp, bool ifexp_bcp, tree op1, tree op2)
if (int_operands)
ret = note_integer_operands (ret);
}
+ if (ep_result_type)
+ ret = build1 (EXCESS_PRECISION_EXPR, ep_result_type, ret);
return ret;
}
@@ -3751,8 +3837,17 @@ build_conditional_expr (tree ifexp, bool ifexp_bcp, tree op1, tree op2)
tree
build_compound_expr (tree expr1, tree expr2)
{
+ tree eptype = NULL_TREE;
tree ret;
+ if (TREE_CODE (expr1) == EXCESS_PRECISION_EXPR)
+ expr1 = TREE_OPERAND (expr1, 0);
+ if (TREE_CODE (expr2) == EXCESS_PRECISION_EXPR)
+ {
+ eptype = TREE_TYPE (expr2);
+ expr2 = TREE_OPERAND (expr2, 0);
+ }
+
if (!TREE_SIDE_EFFECTS (expr1))
{
/* The left-hand operand of a comma expression is like an expression
@@ -3790,6 +3885,9 @@ build_compound_expr (tree expr1, tree expr2)
&& EXPR_INT_CONST_OPERANDS (expr2))
ret = note_integer_operands (ret);
+ if (eptype)
+ ret = build1 (EXCESS_PRECISION_EXPR, eptype, ret);
+
return ret;
}
@@ -3798,7 +3896,12 @@ build_compound_expr (tree expr1, tree expr2)
tree
build_c_cast (tree type, tree expr)
{
- tree value = expr;
+ tree value;
+
+ if (TREE_CODE (expr) == EXCESS_PRECISION_EXPR)
+ expr = TREE_OPERAND (expr, 0);
+
+ value = expr;
if (type == error_mark_node || expr == error_mark_node)
return error_mark_node;
@@ -4058,6 +4161,7 @@ build_modify_expr (location_t location,
{
tree result;
tree newrhs;
+ tree rhs_semantic_type = NULL_TREE;
tree lhstype = TREE_TYPE (lhs);
tree olhstype = lhstype;
bool npc;
@@ -4072,6 +4176,12 @@ build_modify_expr (location_t location,
if (!lvalue_or_else (lhs, lv_assign))
return error_mark_node;
+ if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
+ {
+ rhs_semantic_type = TREE_TYPE (rhs);
+ rhs = TREE_OPERAND (rhs, 0);
+ }
+
newrhs = rhs;
if (TREE_CODE (lhs) == C_MAYBE_CONST_EXPR)
@@ -4131,11 +4241,14 @@ build_modify_expr (location_t location,
TREE_TYPE (lhs) = lhstype;
}
- /* Convert new value to destination type. Fold it first for the
- sake of conversion warnings. */
+ /* Convert new value to destination type. Fold it first, then
+ restore any excess precision information, for the sake of
+ conversion warnings. */
npc = null_pointer_constant_p (newrhs);
newrhs = c_fully_fold (newrhs, false, NULL);
+ if (rhs_semantic_type)
+ newrhs = build1 (EXCESS_PRECISION_EXPR, rhs_semantic_type, newrhs);
newrhs = convert_for_assignment (lhstype, newrhs, ic_assign, npc,
NULL_TREE, NULL_TREE, 0);
if (TREE_CODE (newrhs) == ERROR_MARK)
@@ -4190,6 +4303,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
tree fundecl, tree function, int parmnum)
{
enum tree_code codel = TREE_CODE (type);
+ tree orig_rhs = rhs;
tree rhstype;
enum tree_code coder;
tree rname = NULL_TREE;
@@ -4242,6 +4356,9 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
} \
} while (0)
+ if (TREE_CODE (rhs) == EXCESS_PRECISION_EXPR)
+ rhs = TREE_OPERAND (rhs, 0);
+
rhstype = TREE_TYPE (rhs);
coder = TREE_CODE (rhstype);
@@ -4334,7 +4451,7 @@ convert_for_assignment (tree type, tree rhs, enum impl_conv errtype,
bool save = in_late_binary_op;
if (codel == BOOLEAN_TYPE)
in_late_binary_op = true;
- ret = convert_and_check (type, rhs);
+ ret = convert_and_check (type, orig_rhs);
if (codel == BOOLEAN_TYPE)
in_late_binary_op = save;
return ret;
@@ -4979,6 +5096,7 @@ digest_init (tree type, tree init, bool null_pointer_constant,
{
enum tree_code code = TREE_CODE (type);
tree inside_init = init;
+ tree semantic_type = NULL_TREE;
bool maybe_const = true;
if (type == error_mark_node
@@ -4989,6 +5107,11 @@ digest_init (tree type, tree init, bool null_pointer_constant,
STRIP_TYPE_NOPS (inside_init);
+ if (TREE_CODE (inside_init) == EXCESS_PRECISION_EXPR)
+ {
+ semantic_type = TREE_TYPE (inside_init);
+ inside_init = TREE_OPERAND (inside_init, 0);
+ }
inside_init = c_fully_fold (inside_init, require_constant, &maybe_const);
inside_init = decl_constant_value_for_optimization (inside_init);
@@ -5206,6 +5329,9 @@ digest_init (tree type, tree init, bool null_pointer_constant,
&& (TREE_CODE (init) == STRING_CST
|| TREE_CODE (init) == COMPOUND_LITERAL_EXPR))
inside_init = init = array_to_pointer_conversion (init);
+ if (semantic_type)
+ inside_init = build1 (EXCESS_PRECISION_EXPR, semantic_type,
+ inside_init);
inside_init
= convert_for_assignment (type, inside_init, ic_init,
null_pointer_constant,
@@ -6587,6 +6713,7 @@ static void
output_init_element (tree value, bool strict_string, tree type, tree field,
int pending, bool implicit)
{
+ tree semantic_type = NULL_TREE;
constructor_elt *celt;
bool maybe_const = true;
bool npc;
@@ -6617,6 +6744,11 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
}
npc = null_pointer_constant_p (value);
+ if (TREE_CODE (value) == EXCESS_PRECISION_EXPR)
+ {
+ semantic_type = TREE_TYPE (value);
+ value = TREE_OPERAND (value, 0);
+ }
value = c_fully_fold (value, require_constant_value, &maybe_const);
if (value == error_mark_node)
@@ -6658,6 +6790,8 @@ output_init_element (tree value, bool strict_string, tree type, tree field,
|| TREE_CHAIN (field)))))
return;
+ if (semantic_type)
+ value = build1 (EXCESS_PRECISION_EXPR, semantic_type, value);
value = digest_init (type, value, npc, strict_string,
require_constant_value);
if (value == error_mark_node)
@@ -6972,7 +7106,18 @@ process_init_element (struct c_expr value, bool implicit)
if (TREE_CODE (value.value) != COMPOUND_LITERAL_EXPR
|| !require_constant_value
|| flag_isoc99)
- value.value = c_save_expr (value.value);
+ {
+ tree semantic_type = NULL_TREE;
+ if (TREE_CODE (value.value) == EXCESS_PRECISION_EXPR)
+ {
+ semantic_type = TREE_TYPE (value.value);
+ value.value = TREE_OPERAND (value.value, 0);
+ }
+ value.value = c_save_expr (value.value);
+ if (semantic_type)
+ value.value = build1 (EXCESS_PRECISION_EXPR, semantic_type,
+ value.value);
+ }
}
while (1)
@@ -7465,8 +7610,16 @@ c_finish_return (tree retval)
if (retval)
{
+ tree semantic_type = NULL_TREE;
npc = null_pointer_constant_p (retval);
+ if (TREE_CODE (retval) == EXCESS_PRECISION_EXPR)
+ {
+ semantic_type = TREE_TYPE (retval);
+ retval = TREE_OPERAND (retval, 0);
+ }
retval = c_fully_fold (retval, false, NULL);
+ if (semantic_type)
+ retval = build1 (EXCESS_PRECISION_EXPR, semantic_type, retval);
}
if (!retval)
@@ -8281,7 +8434,8 @@ tree
build_binary_op (location_t location, enum tree_code code,
tree orig_op0, tree orig_op1, int convert_p)
{
- tree type0, type1;
+ tree type0, type1, orig_type0, orig_type1;
+ tree eptype;
enum tree_code code0, code1;
tree op0, op1;
tree ret = error_mark_node;
@@ -8297,6 +8451,10 @@ build_binary_op (location_t location, enum tree_code code,
In the simplest cases this is the common type of the arguments. */
tree result_type = NULL;
+ /* When the computation is in excess precision, the type of the
+ final EXCESS_PRECISION_EXPR. */
+ tree real_result_type = NULL;
+
/* Nonzero means operands have already been type-converted
in whatever way is necessary.
Zero means they need to be converted to RESULT_TYPE. */
@@ -8333,6 +8491,10 @@ build_binary_op (location_t location, enum tree_code code,
/* True means types are compatible as far as ObjC is concerned. */
bool objc_ok;
+ /* True means this is an arithmetic operation that may need excess
+ precision. */
+ bool may_need_excess_precision;
+
if (location == UNKNOWN_LOCATION)
location = input_location;
@@ -8360,8 +8522,8 @@ build_binary_op (location_t location, enum tree_code code,
op1 = orig_op1;
}
- type0 = TREE_TYPE (op0);
- type1 = TREE_TYPE (op1);
+ orig_type0 = type0 = TREE_TYPE (op0);
+ orig_type1 = type1 = TREE_TYPE (op1);
/* The expression codes of the data types of the arguments tell us
whether the arguments are integers, floating, pointers, etc. */
@@ -8385,6 +8547,45 @@ build_binary_op (location_t location, enum tree_code code,
return error_mark_node;
}
+ switch (code)
+ {
+ case PLUS_EXPR:
+ case MINUS_EXPR:
+ case MULT_EXPR:
+ case TRUNC_DIV_EXPR:
+ case CEIL_DIV_EXPR:
+ case FLOOR_DIV_EXPR:
+ case ROUND_DIV_EXPR:
+ case EXACT_DIV_EXPR:
+ may_need_excess_precision = true;
+ break;
+ default:
+ may_need_excess_precision = false;
+ break;
+ }
+ if (TREE_CODE (op0) == EXCESS_PRECISION_EXPR)
+ {
+ op0 = TREE_OPERAND (op0, 0);
+ type0 = TREE_TYPE (op0);
+ }
+ else if (may_need_excess_precision
+ && (eptype = excess_precision_type (type0)) != NULL_TREE)
+ {
+ type0 = eptype;
+ op0 = convert (eptype, op0);
+ }
+ if (TREE_CODE (op1) == EXCESS_PRECISION_EXPR)
+ {
+ op1 = TREE_OPERAND (op1, 0);
+ type1 = TREE_TYPE (op1);
+ }
+ else if (may_need_excess_precision
+ && (eptype = excess_precision_type (type1)) != NULL_TREE)
+ {
+ type1 = eptype;
+ op1 = convert (eptype, op1);
+ }
+
objc_ok = objc_compare_types (type0, type1, -3, NULL_TREE);
switch (code)
@@ -8929,7 +9130,14 @@ build_binary_op (location_t location, enum tree_code code,
}
if (build_type == NULL_TREE)
- build_type = result_type;
+ {
+ build_type = result_type;
+ if (type0 != orig_type0 || type1 != orig_type1)
+ {
+ gcc_assert (may_need_excess_precision && common);
+ real_result_type = c_common_type (orig_type0, orig_type1);
+ }
+ }
/* Treat expressions in initializers specially as they can't trap. */
if (int_const_or_overflow)
@@ -8950,6 +9158,8 @@ build_binary_op (location_t location, enum tree_code code,
else if (TREE_CODE (ret) != INTEGER_CST && int_operands
&& !in_late_binary_op)
ret = note_integer_operands (ret);
+ if (real_result_type)
+ ret = build1 (EXCESS_PRECISION_EXPR, real_result_type, ret);
protected_set_expr_location (ret, location);
return ret;
}
diff --git a/gcc/common.opt b/gcc/common.opt
index 023d773..3626c9e 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -491,6 +491,10 @@ fexpensive-optimizations
Common Report Var(flag_expensive_optimizations) Optimization
Perform a number of minor, expensive optimizations
+fexcess-precision=
+Common Joined RejectNegative
+-fexcess-precision=[fast|standard] Specify handling of excess floating-point precision
+
ffast-math
Common
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index e4d4463..89e26f6 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -611,6 +611,20 @@ enum target_cpu_default
#define TARGET_FLT_EVAL_METHOD \
(TARGET_MIX_SSE_I387 ? -1 : TARGET_SSE_MATH ? 0 : 2)
+/* Whether to allow x87 floating-point arithmetic on MODE (one of
+ SFmode, DFmode and XFmode) in the current excess precision
+ configuration. */
+#define X87_ENABLE_ARITH(MODE) \
+ (flag_excess_precision == EXCESS_PRECISION_FAST || (MODE) == XFmode)
+
+/* Likewise, whether to allow direct conversions from integer mode
+ IMODE (HImode, SImode or DImode) to MODE. */
+#define X87_ENABLE_FLOAT(MODE, IMODE) \
+ (flag_excess_precision == EXCESS_PRECISION_FAST \
+ || (MODE) == XFmode \
+ || ((MODE) == DFmode && (IMODE) == SImode) \
+ || (IMODE) == HImode)
+
/* target machine storage layout */
#define SHORT_TYPE_SIZE 16
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index a112198..9592f91 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -5137,13 +5137,28 @@
"TARGET_80387
|| ((<SSEMODEI24:MODE>mode != DImode || TARGET_64BIT)
&& SSE_FLOAT_MODE_P (<X87MODEF:MODE>mode) && TARGET_SSE_MATH)"
- "")
+ "
+{
+ if (!((<SSEMODEI24:MODE>mode != DImode || TARGET_64BIT)
+ && SSE_FLOAT_MODE_P (<X87MODEF:MODE>mode) && TARGET_SSE_MATH)
+ && !X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, <SSEMODEI24:MODE>mode))
+ {
+ rtx reg = gen_reg_rtx (XFmode);
+ emit_insn (gen_float<SSEMODEI24:mode>xf2 (reg, operands[1]));
+/* Avoid references to nonexistent function in dead code in XFmode case. */
+#define gen_truncxfxf2 gen_truncxfdf2
+ emit_insn (gen_truncxf<X87MODEF:mode>2 (operands[0], reg));
+#undef gen_truncxfxf2
+ DONE;
+ }
+}")
;; Pre-reload splitter to add memory clobber to the pattern.
(define_insn_and_split "*float<SSEMODEI24:mode><X87MODEF:mode>2_1"
[(set (match_operand:X87MODEF 0 "register_operand" "")
(float:X87MODEF (match_operand:SSEMODEI24 1 "register_operand" "")))]
"((TARGET_80387
+ && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, <SSEMODEI24:MODE>mode)
&& (!((<SSEMODEI24:MODE>mode != DImode || TARGET_64BIT)
&& SSE_FLOAT_MODE_P (<X87MODEF:MODE>mode) && TARGET_SSE_MATH)
|| TARGET_MIX_SSE_I387))
@@ -5524,7 +5539,8 @@
(float:X87MODEF
(match_operand:SSEMODEI24 1 "nonimmediate_operand" "m,?r")))
(clobber (match_operand:SSEMODEI24 2 "memory_operand" "=X,m"))]
- "TARGET_80387"
+ "TARGET_80387
+ && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, <SSEMODEI24:MODE>mode)"
"@
fild%z1\t%1
#"
@@ -5537,7 +5553,8 @@
[(set (match_operand:X87MODEF 0 "register_operand" "=f")
(float:X87MODEF
(match_operand:SSEMODEI24 1 "memory_operand" "m")))]
- "TARGET_80387"
+ "TARGET_80387
+ && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, <SSEMODEI24:MODE>mode)"
"fild%z1\t%1"
[(set_attr "type" "fmov")
(set_attr "mode" "<X87MODEF:MODE>")
@@ -5548,6 +5565,7 @@
(float:X87MODEF (match_operand:SSEMODEI24 1 "register_operand" "")))
(clobber (match_operand:SSEMODEI24 2 "memory_operand" ""))]
"TARGET_80387
+ && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, <SSEMODEI24:MODE>mode)
&& reload_completed
&& FP_REG_P (operands[0])"
[(set (match_dup 2) (match_dup 1))
@@ -5559,6 +5577,7 @@
(float:X87MODEF (match_operand:SSEMODEI24 1 "memory_operand" "")))
(clobber (match_operand:SSEMODEI24 2 "memory_operand" ""))]
"TARGET_80387
+ && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, <SSEMODEI24:MODE>mode)
&& reload_completed
&& FP_REG_P (operands[0])"
[(set (match_dup 0) (float:X87MODEF (match_dup 1)))]
@@ -5574,7 +5593,8 @@
(clobber (match_scratch:V4SI 3 "=X,x"))
(clobber (match_scratch:V4SI 4 "=X,x"))
(clobber (match_operand:DI 2 "memory_operand" "=X,m"))]
- "TARGET_80387 && TARGET_SSE2 && TARGET_INTER_UNIT_MOVES
+ "TARGET_80387 && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, DImode)
+ && TARGET_SSE2 && TARGET_INTER_UNIT_MOVES
&& !TARGET_64BIT && optimize_function_for_speed_p (cfun)"
"#"
[(set_attr "type" "multi")
@@ -5588,7 +5608,8 @@
(clobber (match_scratch:V4SI 3 ""))
(clobber (match_scratch:V4SI 4 ""))
(clobber (match_operand:DI 2 "memory_operand" ""))]
- "TARGET_80387 && TARGET_SSE2 && TARGET_INTER_UNIT_MOVES
+ "TARGET_80387 && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, DImode)
+ && TARGET_SSE2 && TARGET_INTER_UNIT_MOVES
&& !TARGET_64BIT && optimize_function_for_speed_p (cfun)
&& reload_completed
&& FP_REG_P (operands[0])"
@@ -5612,7 +5633,8 @@
(clobber (match_scratch:V4SI 3 ""))
(clobber (match_scratch:V4SI 4 ""))
(clobber (match_operand:DI 2 "memory_operand" ""))]
- "TARGET_80387 && TARGET_SSE2 && TARGET_INTER_UNIT_MOVES
+ "TARGET_80387 && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, DImode)
+ && TARGET_SSE2 && TARGET_INTER_UNIT_MOVES
&& !TARGET_64BIT && optimize_function_for_speed_p (cfun)
&& reload_completed
&& FP_REG_P (operands[0])"
@@ -5632,7 +5654,8 @@
(clobber (match_operand:DI 2 "memory_operand" "=m,m"))
(clobber (match_scratch:SI 3 "=X,x"))]
"!TARGET_64BIT
- && TARGET_80387 && TARGET_SSE"
+ && TARGET_80387 && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, SImode)
+ && TARGET_SSE"
"#"
[(set_attr "type" "multi")
(set_attr "mode" "<MODE>")])
@@ -5644,7 +5667,8 @@
(clobber (match_operand:DI 2 "memory_operand" ""))
(clobber (match_scratch:SI 3 ""))]
"!TARGET_64BIT
- && TARGET_80387 && TARGET_SSE
+ && TARGET_80387 && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, SImode)
+ && TARGET_SSE
&& reload_completed"
[(set (match_dup 2) (match_dup 1))
(set (match_dup 0)
@@ -5658,7 +5682,8 @@
(clobber (match_operand:DI 2 "memory_operand" ""))
(clobber (match_scratch:SI 3 ""))]
"!TARGET_64BIT
- && TARGET_80387 && TARGET_SSE
+ && TARGET_80387 && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, SImode)
+ && TARGET_SSE
&& reload_completed"
[(set (match_dup 2) (match_dup 3))
(set (match_dup 0)
@@ -5676,7 +5701,8 @@
(clobber (match_dup 2))
(clobber (match_scratch:SI 3 ""))])]
"!TARGET_64BIT
- && ((TARGET_80387 && TARGET_SSE)
+ && ((TARGET_80387 && X87_ENABLE_FLOAT (<X87MODEF:MODE>mode, SImode)
+ && TARGET_SSE)
|| (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH))"
{
if (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
@@ -7475,7 +7501,8 @@
[(set (match_operand:MODEF 0 "register_operand" "")
(plus:MODEF (match_operand:MODEF 1 "register_operand" "")
(match_operand:MODEF 2 "nonimmediate_operand" "")))]
- "TARGET_80387 || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
+ "(TARGET_80387 && X87_ENABLE_ARITH (<MODE>mode))
+ || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
"")
;; Subtract instructions
@@ -7835,7 +7862,8 @@
[(set (match_operand:MODEF 0 "register_operand" "")
(minus:MODEF (match_operand:MODEF 1 "register_operand" "")
(match_operand:MODEF 2 "nonimmediate_operand" "")))]
- "TARGET_80387 || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
+ "(TARGET_80387 && X87_ENABLE_ARITH (<MODE>mode))
+ || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
"")
;; Multiply instructions
@@ -8390,7 +8418,8 @@
[(set (match_operand:MODEF 0 "register_operand" "")
(mult:MODEF (match_operand:MODEF 1 "register_operand" "")
(match_operand:MODEF 2 "nonimmediate_operand" "")))]
- "TARGET_80387 || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
+ "(TARGET_80387 && X87_ENABLE_ARITH (<MODE>mode))
+ || (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
"")
;; SSE5 scalar multiply/add instructions are defined in sse.md.
@@ -8431,14 +8460,16 @@
[(set (match_operand:DF 0 "register_operand" "")
(div:DF (match_operand:DF 1 "register_operand" "")
(match_operand:DF 2 "nonimmediate_operand" "")))]
- "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)"
+ "(TARGET_80387 && X87_ENABLE_ARITH (DFmode))
+ || (TARGET_SSE2 && TARGET_SSE_MATH)"
"")
(define_expand "divsf3"
[(set (match_operand:SF 0 "register_operand" "")
(div:SF (match_operand:SF 1 "register_operand" "")
(match_operand:SF 2 "nonimmediate_operand" "")))]
- "TARGET_80387 || TARGET_SSE_MATH"
+ "(TARGET_80387 && X87_ENABLE_ARITH (SFmode))
+ || TARGET_SSE_MATH"
{
if (TARGET_SSE_MATH && TARGET_RECIP && optimize_insn_for_speed_p ()
&& flag_finite_math_only && !flag_trapping_math
@@ -16317,7 +16348,7 @@
(match_operator:MODEF 3 "binary_fp_operator"
[(match_operand:MODEF 1 "nonimmediate_operand" "%0")
(match_operand:MODEF 2 "nonimmediate_operand" "fm")]))]
- "TARGET_80387
+ "TARGET_80387 && X87_ENABLE_ARITH (<MODE>mode)
&& COMMUTATIVE_ARITH_P (operands[3])
&& !(MEM_P (operands[1]) && MEM_P (operands[2]))"
"* return output_387_binary_op (insn, operands);"
@@ -16431,7 +16462,8 @@
(match_operator:MODEF 3 "binary_fp_operator"
[(match_operand:MODEF 1 "nonimmediate_operand" "0,fm")
(match_operand:MODEF 2 "nonimmediate_operand" "fm,0")]))]
- "TARGET_80387 && !(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
+ "TARGET_80387 && X87_ENABLE_ARITH (<MODE>mode)
+ && !(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
&& !COMMUTATIVE_ARITH_P (operands[3])
&& !(MEM_P (operands[1]) && MEM_P (operands[2]))"
"* return output_387_binary_op (insn, operands);"
@@ -16451,7 +16483,8 @@
[(float:MODEF
(match_operand:X87MODEI12 1 "nonimmediate_operand" "m,?r"))
(match_operand:MODEF 2 "register_operand" "0,0")]))]
- "TARGET_80387 && !(SSE_FLOAT_MODE_P (<MODEF:MODE>mode) && TARGET_SSE_MATH)
+ "TARGET_80387 && X87_ENABLE_FLOAT (<MODEF:MODE>mode, <X87MODEI12:MODE>mode)
+ && !(SSE_FLOAT_MODE_P (<MODEF:MODE>mode) && TARGET_SSE_MATH)
&& (TARGET_USE_<X87MODEI12:MODE>MODE_FIOP || optimize_function_for_size_p (cfun))"
"* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
[(set (attr "type")
@@ -16470,7 +16503,8 @@
[(match_operand:MODEF 1 "register_operand" "0,0")
(float:MODEF
(match_operand:X87MODEI12 2 "nonimmediate_operand" "m,?r"))]))]
- "TARGET_80387 && !(SSE_FLOAT_MODE_P (<MODEF:MODE>mode) && TARGET_SSE_MATH)
+ "TARGET_80387 && X87_ENABLE_FLOAT (<MODEF:MODE>mode, <X87MODEI12:MODE>mode)
+ && !(SSE_FLOAT_MODE_P (<MODEF:MODE>mode) && TARGET_SSE_MATH)
&& (TARGET_USE_<X87MODEI12:MODE>MODE_FIOP || optimize_function_for_size_p (cfun))"
"* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
[(set (attr "type")
@@ -16489,7 +16523,8 @@
[(float_extend:DF
(match_operand:SF 1 "nonimmediate_operand" "fm,0"))
(match_operand:DF 2 "register_operand" "0,f")]))]
- "TARGET_80387 && !(TARGET_SSE2 && TARGET_SSE_MATH)
+ "TARGET_80387 && X87_ENABLE_ARITH (DFmode)
+ && !(TARGET_SSE2 && TARGET_SSE_MATH)
&& !(MEM_P (operands[1]) && MEM_P (operands[2]))"
"* return output_387_binary_op (insn, operands);"
[(set (attr "type")
@@ -16507,7 +16542,8 @@
[(match_operand:DF 1 "register_operand" "0,f")
(float_extend:DF
(match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
- "TARGET_80387 && !(TARGET_SSE2 && TARGET_SSE_MATH)"
+ "TARGET_80387 && X87_ENABLE_ARITH (DFmode)
+ && !(TARGET_SSE2 && TARGET_SSE_MATH)"
"* return output_387_binary_op (insn, operands);"
[(set (attr "type")
(cond [(match_operand:DF 3 "mult_operator" "")
@@ -16525,7 +16561,8 @@
(match_operand:SF 1 "register_operand" "0,f"))
(float_extend:DF
(match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
- "TARGET_80387 && !(TARGET_SSE2 && TARGET_SSE_MATH)"
+ "TARGET_80387 && X87_ENABLE_ARITH (DFmode)
+ && !(TARGET_SSE2 && TARGET_SSE_MATH)"
"* return output_387_binary_op (insn, operands);"
[(set (attr "type")
(cond [(match_operand:DF 3 "mult_operator" "")
@@ -16661,7 +16698,8 @@
[(float (match_operand:X87MODEI12 1 "register_operand" ""))
(match_operand 2 "register_operand" "")]))]
"reload_completed
- && X87_FLOAT_MODE_P (GET_MODE (operands[0]))"
+ && X87_FLOAT_MODE_P (GET_MODE (operands[0]))
+ && X87_ENABLE_FLOAT (GET_MODE (operands[0]), GET_MODE (operands[1]))"
[(const_int 0)]
{
operands[4] = ix86_force_to_memory (GET_MODE (operands[1]), operands[1]);
@@ -16681,7 +16719,8 @@
[(match_operand 1 "register_operand" "")
(float (match_operand:X87MODEI12 2 "register_operand" ""))]))]
"reload_completed
- && X87_FLOAT_MODE_P (GET_MODE (operands[0]))"
+ && X87_FLOAT_MODE_P (GET_MODE (operands[0]))
+ && X87_ENABLE_FLOAT (GET_MODE (operands[0]), GET_MODE (operands[2]))"
[(const_int 0)]
{
operands[4] = ix86_force_to_memory (GET_MODE (operands[2]), operands[2]);
@@ -16767,7 +16806,7 @@
[(set (match_operand:MODEF 0 "register_operand" "")
(sqrt:MODEF
(match_operand:MODEF 1 "nonimmediate_operand" "")))]
- "TARGET_USE_FANCY_MATH_387
+ "(TARGET_USE_FANCY_MATH_387 && X87_ENABLE_ARITH (<MODE>mode))
|| (SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)"
{
if (<MODE>mode == SFmode
diff --git a/gcc/convert.c b/gcc/convert.c
index e98b657..b6a9d3d 100644
--- a/gcc/convert.c
+++ b/gcc/convert.c
@@ -326,7 +326,8 @@ convert_to_real (tree type, tree expr)
&& (flag_unsafe_math_optimizations
|| (TYPE_PRECISION (newtype) == TYPE_PRECISION (type)
&& real_can_shorten_arithmetic (TYPE_MODE (itype),
- TYPE_MODE (type)))))
+ TYPE_MODE (type))
+ && !excess_precision_type (newtype))))
{
expr = build2 (TREE_CODE (expr), newtype,
fold (convert_to_real (newtype, arg0)),
diff --git a/gcc/defaults.h b/gcc/defaults.h
index 217c0d9..a1863cd 100644
--- a/gcc/defaults.h
+++ b/gcc/defaults.h
@@ -688,8 +688,11 @@ along with GCC; see the file COPYING3. If not see
#define FLOAT_WORDS_BIG_ENDIAN WORDS_BIG_ENDIAN
#endif
-#ifndef TARGET_FLT_EVAL_METHOD
+#ifdef TARGET_FLT_EVAL_METHOD
+#define TARGET_FLT_EVAL_METHOD_NON_DEFAULT 1
+#else
#define TARGET_FLT_EVAL_METHOD 0
+#define TARGET_FLT_EVAL_METHOD_NON_DEFAULT 0
#endif
#ifndef TARGET_DEC_EVAL_METHOD
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 4e2d931..19ac308 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -329,8 +329,9 @@ Objective-C and Objective-C++ Dialects}.
-fdata-sections -fdce -fdce @gol
-fdelayed-branch -fdelete-null-pointer-checks -fdse -fdse @gol
-fearly-inlining -fexpensive-optimizations -ffast-math @gol
--ffinite-math-only -ffloat-store -fforward-propagate @gol
--ffunction-sections -fgcse -fgcse-after-reload -fgcse-las -fgcse-lm @gol
+-ffinite-math-only -ffloat-store -fexcess-precision=@var{style} @gol
+-fforward-propagate -ffunction-sections @gol
+-fgcse -fgcse-after-reload -fgcse-las -fgcse-lm @gol
-fgcse-sm -fif-conversion -fif-conversion2 -findirect-inlining @gol
-finline-functions -finline-functions-called-once -finline-limit=@var{n} @gol
-finline-small-functions -fipa-cp -fipa-cp-clone -fipa-matrix-reorg -fipa-pta @gol
@@ -6783,6 +6784,32 @@ good, but a few programs rely on the precise definition of IEEE floating
point. Use @option{-ffloat-store} for such programs, after modifying
them to store all pertinent intermediate computations into variables.
+@item -fexcess-precision=@var{style}
+@opindex fexcess-precision
+This option allows further control over excess precision on machines
+where floating-point registers have more precision than the IEEE
+@code{float} and @code{double} types and the processor does not
+support operations rounding to those types. By default,
+@option{-fexcess-precision=fast} is in effect; this means that
+operations are carried out in the precision of the registers and that
+it is unpredictable when rounding to the types specified in the source
+code takes place. When compiling C, if
+@option{-fexcess-precision=standard} is specified then excess
+precision will follow the rules specified in ISO C99; in particular,
+both casts and assignments cause values to be rounded to their
+semantic types (whereas @option{-ffloat-store} only affects
+assignments). This option is enabled by default for C if a strict
+conformance option such as @option{-std=c99} is used.
+
+@opindex mfpmath
+@option{-fexcess-precision=standard} is not implemented for languages
+other than C, and has no effect if
+@option{-funsafe-math-optimizations} or @option{-ffast-math} is
+specified. On the x86, it also has no effect if @option{-mfpmath=sse}
+or @option{-mfpmath=sse+387} is specified; in the former case, IEEE
+semantics apply without excess precision, and in the latter, rounding
+is unpredictable.
+
@item -ffast-math
@opindex ffast-math
Sets @option{-fno-math-errno}, @option{-funsafe-math-optimizations},
@@ -11000,7 +11027,7 @@ specifying @option{-march=@var{cpu-type}} implies @option{-mtune=@var{cpu-type}}
A deprecated synonym for @option{-mtune}.
@item -mfpmath=@var{unit}
-@opindex march
+@opindex mfpmath
Generate floating point arithmetics for selected unit @var{unit}. The choices
for @var{unit} are:
diff --git a/gcc/flags.h b/gcc/flags.h
index e406bf1..e606f60 100644
--- a/gcc/flags.h
+++ b/gcc/flags.h
@@ -227,6 +227,21 @@ extern enum ira_region flag_ira_region;
extern unsigned int flag_ira_verbose;
+/* The options for excess precision. */
+enum excess_precision
+{
+ EXCESS_PRECISION_DEFAULT,
+ EXCESS_PRECISION_FAST,
+ EXCESS_PRECISION_STANDARD
+};
+
+/* The excess precision specified on the command line, or defaulted by
+ the front end. */
+extern enum excess_precision flag_excess_precision_cmdline;
+
+/* The excess precision currently in effect. */
+extern enum excess_precision flag_excess_precision;
+
/* Other basic status info about current function. */
diff --git a/gcc/fortran/ChangeLog b/gcc/fortran/ChangeLog
index 34d31ff..d4a24ddc 100644
--- a/gcc/fortran/ChangeLog
+++ b/gcc/fortran/ChangeLog
@@ -1,3 +1,11 @@
+2009-03-30 Joseph Myers <joseph@codesourcery.com>
+
+ PR rtl-optimization/323
+ * options.c (gfc_post_options): Set
+ flag_excess_precision_cmdline. Give an error for
+ -fexcess-precision=standard for processors where the option is
+ significant.
+
2009-03-29 Joseph Myers <joseph@codesourcery.com>
PR preprocessor/34695
diff --git a/gcc/fortran/options.c b/gcc/fortran/options.c
index 587fb36..17c577d 100644
--- a/gcc/fortran/options.c
+++ b/gcc/fortran/options.c
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3. If not see
#include "gfortran.h"
#include "target.h"
#include "cpp.h"
+#include "toplev.h"
+#include "tm.h"
gfc_option_t gfc_option;
@@ -228,6 +230,13 @@ gfc_post_options (const char **pfilename)
char *source_path;
int i;
+ /* Excess precision other than "fast" requires front-end
+ support. */
+ if (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD
+ && TARGET_FLT_EVAL_METHOD_NON_DEFAULT)
+ sorry ("-fexcess-precision=standard for Fortran");
+ flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
+
/* Issue an error if -fwhole-program was used. */
if (flag_whole_program)
gfc_fatal_error ("Option -fwhole-program is not supported for Fortran");
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog
index 6a7e44f..a72a2f9 100644
--- a/gcc/java/ChangeLog
+++ b/gcc/java/ChangeLog
@@ -1,3 +1,10 @@
+2009-03-30 Joseph Myers <joseph@codesourcery.com>
+
+ PR rtl-optimization/323
+ * lang.c (java_post_options): Set flag_excess_precision_cmdline.
+ Give an error for -fexcess-precision=standard for processors where
+ the option is significant.
+
2009-03-18 Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
* lang.opt: Unify help text for -Wdeprecated.
diff --git a/gcc/java/lang.c b/gcc/java/lang.c
index 2a962c0..c431141 100644
--- a/gcc/java/lang.c
+++ b/gcc/java/lang.c
@@ -528,6 +528,13 @@ java_post_options (const char **pfilename)
{
const char *filename = *pfilename;
+ /* Excess precision other than "fast" requires front-end
+ support. */
+ if (flag_excess_precision_cmdline == EXCESS_PRECISION_STANDARD
+ && TARGET_FLT_EVAL_METHOD_NON_DEFAULT)
+ sorry ("-fexcess-precision=standard for Java");
+ flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
+
/* An absolute requirement: if we're not using indirect dispatch, we
must always verify everything. */
if (! flag_indirect_dispatch)
diff --git a/gcc/langhooks.c b/gcc/langhooks.c
index bd01c3f..19641379 100644
--- a/gcc/langhooks.c
+++ b/gcc/langhooks.c
@@ -105,6 +105,9 @@ lhd_return_null_const_tree (const_tree ARG_UNUSED (t))
bool
lhd_post_options (const char ** ARG_UNUSED (pfilename))
{
+ /* Excess precision other than "fast" requires front-end
+ support. */
+ flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
return false;
}
diff --git a/gcc/opts.c b/gcc/opts.c
index 90f34df..e318790 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1728,6 +1728,15 @@ common_handle_option (size_t scode, const char *arg, int value,
return 0;
break;
+ case OPT_fexcess_precision_:
+ if (!strcmp (arg, "fast"))
+ flag_excess_precision_cmdline = EXCESS_PRECISION_FAST;
+ else if (!strcmp (arg, "standard"))
+ flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD;
+ else
+ error ("unknown excess precision style \"%s\"", arg);
+ break;
+
case OPT_ffast_math:
set_fast_math_flags (value);
break;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 23701aa..37dcc21 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,15 @@
2009-03-30 Joseph Myers <joseph@codesourcery.com>
+ PR rtl-optimization/323
+ * gcc.target/i386/excess-precision-1.c,
+ gcc.target/i386/excess-precision-2.c,
+ gcc.target/i386/excess-precision-3.c,
+ gcc.target/i386/excess-precision-4.c,
+ gcc.target/i386/excess-precision-5.c,
+ gcc.target/i386/excess-precision-6.c: New tests.
+
+2009-03-30 Joseph Myers <joseph@codesourcery.com>
+
PR c/35235
* gcc.dg/c99-array-lval-8.c: New test.
diff --git a/gcc/testsuite/gcc.target/i386/excess-precision-1.c b/gcc/testsuite/gcc.target/i386/excess-precision-1.c
new file mode 100644
index 0000000..3d5e7d2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/excess-precision-1.c
@@ -0,0 +1,186 @@
+/* Excess precision tests. Test that excess precision is carried
+ through various operations. */
+/* { dg-do run } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-O2 -fexcess-precision=standard" } */
+
+#include <float.h>
+
+extern void abort (void);
+extern void exit (int);
+
+volatile float f1 = 1.0f;
+volatile float f2 = 0x1.0p-30f;
+volatile float f3 = 0x1.0p-60f;
+volatile double d1 = 1.0;
+volatile double d2 = 0x1.0p-30;
+volatile double d3 = 0x1.0p-60;
+volatile float fadd1 = 1.0f + 0x1.0p-30f;
+volatile double dadd2 = 1.0 + 0x1.0p-30 + 0x1.0p-60;
+volatile long double ldadd1 = 1.0l + 0x1.0p-30l;
+volatile long double ldadd2 = 1.0l + 0x1.0p-30l + 0x1.0p-60l;
+
+void
+test_add (void)
+{
+ if (f1 + f2 != ldadd1)
+ abort ();
+ if (f1 + f2 + f3 != ldadd2)
+ abort ();
+ if (d1 + d2 != ldadd1)
+ abort ();
+ if (d1 + d2 + d3 != ldadd2)
+ abort ();
+ if (f1 + d2 + f3 != ldadd2)
+ abort ();
+ if (f1 + f2 == fadd1)
+ abort ();
+ if (f1 + f2 <= fadd1)
+ abort ();
+ if (f1 + f2 < fadd1)
+ abort ();
+ if (d1 + d2 + d3 == dadd2)
+ abort ();
+ if (!(d1 + d2 + d3 > dadd2))
+ abort ();
+ if (!(d1 + d2 + d3 >= dadd2))
+ abort ();
+}
+
+volatile long double ldsub1 = 1.0l - 0x1.0p-30l;
+volatile long double ldsub2 = 1.0l - 0x1.0p-30l - 0x1.0p-60l;
+
+void
+test_sub (void)
+{
+ if (f1 - f2 != ldsub1)
+ abort ();
+ if (f1 - f2 - f3 != ldsub2)
+ abort ();
+ if (d1 - d2 != ldsub1)
+ abort ();
+ if (d1 - d2 - d3 != ldsub2)
+ abort ();
+ if (f1 - d2 - f3 != ldsub2)
+ abort ();
+ if (+(f1 - d2 - f3) != ldsub2)
+ abort ();
+ if (-(f1 - d2 - f3) != -ldsub2)
+ abort ();
+}
+
+volatile float flt_min = FLT_MIN;
+volatile double dbl_min = DBL_MIN;
+volatile long double flt_min2 = (long double)FLT_MIN * (long double)FLT_MIN;
+volatile long double dbl_min3 = (long double)DBL_MIN * (long double)DBL_MIN * (long double)DBL_MIN;
+
+void
+test_mul (void)
+{
+ if (flt_min * flt_min != flt_min2)
+ abort ();
+ if (flt_min * flt_min == 0)
+ abort ();
+ if (flt_min * flt_min == 0)
+ abort ();
+ if (!(flt_min * flt_min))
+ abort ();
+ if (dbl_min * dbl_min * dbl_min != dbl_min3)
+ abort ();
+ if ((long double)(dbl_min * dbl_min * dbl_min) != dbl_min3)
+ abort ();
+ if ((0, dbl_min * dbl_min * dbl_min) != dbl_min3)
+ abort ();
+ if (dbl_min * dbl_min * dbl_min == 0)
+ abort ();
+ if ((flt_min * flt_min ? dbl_min * dbl_min * dbl_min : 0) == 0)
+ abort ();
+ if ((flt_min * flt_min ? : 0) == 0)
+ abort ();
+}
+
+volatile float f4 = 0x1.0p100f;
+volatile double d4 = 0x1.0p100;
+volatile long double flt_div = 0x1.0p100l / (long double) FLT_MIN;
+volatile long double dbl_div = 0x1.0p100l / (long double) DBL_MIN;
+
+void
+test_div (void)
+{
+ if (f4 / flt_min != flt_div)
+ abort ();
+ if (d4 / dbl_min != dbl_div)
+ abort ();
+}
+
+volatile float f5 = 0x1.0p30;
+
+void
+test_cast (void)
+{
+ if ((int)(f1 + f5) != 0x40000001)
+ abort ();
+}
+
+volatile float _Complex f1c = 1.0f + 1.0if;
+volatile float _Complex f2c = 0x1.0p-30f + 0x1.0p-31if;
+volatile float _Complex f3c = 0x1.0p-60f + 0x1.0p-59if;
+volatile double _Complex d1c = 1.0 + 1.0i;
+volatile double _Complex d2c = 0x1.0p-30 + 0x1.0p-31i;
+volatile double _Complex d3c = 0x1.0p-60 + 0x1.0p-59i;
+volatile long double _Complex ldadd1c = 1.0l + 0x1.0p-30l + 1.0il + 0x1.0p-31il;
+volatile long double _Complex ldadd2c = 1.0l + 0x1.0p-30l + 0x1.0p-60l + 1.0il + 0x1.0p-31il + 0x1.0p-59il;
+volatile long double _Complex ldadd2cc = 1.0l + 0x1.0p-30l + 0x1.0p-60l - 1.0il - 0x1.0p-31il - 0x1.0p-59il;
+volatile float _Complex flt_minc = FLT_MIN;
+volatile double _Complex dbl_minc = DBL_MIN;
+volatile float _Complex f4c = 0x1.0p100f;
+volatile double _Complex d4c = 0x1.0p100;
+
+void
+test_complex (void)
+{
+ if (f1c + f2c != ldadd1c)
+ abort ();
+ if (f1c + f2c + f3c != ldadd2c)
+ abort ();
+ if (d1c + d2c != ldadd1c)
+ abort ();
+ if (d1c + d2c + d3c != ldadd2c)
+ abort ();
+ if (__real__ (f1c + f2c + f3c) != ldadd2)
+ abort ();
+ if (__imag__ (d1c + d2c + d3c) != __imag__ ldadd2c)
+ abort ();
+ if (~(d1c + d2c + d3c) != ldadd2cc)
+ abort ();
+ /* The following call libgcc functions and so would fail unless they
+ call those for long double. */
+ if (flt_minc * flt_minc != flt_min2)
+ abort ();
+ if (dbl_minc * dbl_minc * dbl_minc != dbl_min3)
+ abort ();
+ if (f4c / flt_minc != flt_div)
+ abort ();
+ if (d4c / dbl_minc != dbl_div)
+ abort ();
+ if (f4 / flt_minc != flt_div)
+ abort ();
+ if (d4 / dbl_minc != dbl_div)
+ abort ();
+ if (f4c / flt_min != flt_div)
+ abort ();
+ if (d4c / dbl_min != dbl_div)
+ abort ();
+}
+
+int
+main (void)
+{
+ test_add ();
+ test_sub ();
+ test_mul ();
+ test_div ();
+ test_cast ();
+ test_complex ();
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.target/i386/excess-precision-2.c b/gcc/testsuite/gcc.target/i386/excess-precision-2.c
new file mode 100644
index 0000000..1075cd0
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/excess-precision-2.c
@@ -0,0 +1,34 @@
+/* Excess precision tests. Test excess precision of constants. */
+/* { dg-do run } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-O2 -fexcess-precision=standard" } */
+
+#include <float.h>
+
+extern void abort (void);
+extern void exit (int);
+
+volatile long double ldadd1 = 1.0l + 0x1.0p-30l;
+volatile long double ld11f = 1.1f;
+volatile long double ld11d = 1.1;
+volatile long double ld11 = 1.1;
+
+void
+test_const (void)
+{
+ if (1.0f + 0x1.0p-30f != ldadd1)
+ abort ();
+ if (ld11f != ld11)
+ abort ();
+ if (ld11d != ld11)
+ abort ();
+ if (1.1f != ld11)
+ abort ();
+}
+
+int
+main (void)
+{
+ test_const ();
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.target/i386/excess-precision-3.c b/gcc/testsuite/gcc.target/i386/excess-precision-3.c
new file mode 100644
index 0000000..0cdcb3d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/excess-precision-3.c
@@ -0,0 +1,219 @@
+/* Excess precision tests. Test excess precision is removed when
+ necessary. */
+/* { dg-do run } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-O2 -fexcess-precision=standard" } */
+
+#include <float.h>
+#include <stdarg.h>
+
+extern void abort (void);
+extern void exit (int);
+
+volatile float f1 = 1.0f;
+volatile float f2 = 0x1.0p-30f;
+volatile float f3 = 0x1.0p-60f;
+volatile double d1 = 1.0;
+volatile double d2 = 0x1.0p-30;
+volatile double d3 = 0x1.0p-60;
+volatile float fadd1 = 1.0f + 0x1.0p-30f;
+volatile double dadd2 = 1.0 + 0x1.0p-30 + 0x1.0p-60;
+volatile double dh = 0x1.0p-24;
+volatile float fha = 1.0f + 0x1.0p-23f;
+
+void
+test_assign (void)
+{
+ float f;
+ double d;
+ f = f1 + f2;
+ if (f != fadd1)
+ abort ();
+ d = f1 + f2;
+ if (d != dadd2)
+ abort ();
+ d = d1 + d2 + d3;
+ if (d != dadd2)
+ abort ();
+ /* Verify rounding direct to float without double rounding. */
+ f = d1 + dh + d3;
+ if (f != fha)
+ abort ();
+}
+
+void
+test_init (void)
+{
+ float f = f1 + f2;
+ double d = d1 + d2 + d3;
+ if (f != fadd1)
+ abort ();
+ if (d != dadd2)
+ abort ();
+}
+
+volatile int i1 = 0x40000001;
+volatile unsigned int u1 = 0x80000001u;
+volatile long long ll1 = 0x4000000000000001ll;
+volatile unsigned long long ull1 = 0x8000000000000001ull;
+
+void
+test_cast (void)
+{
+ if ((float)(f1 + f2) != fadd1)
+ abort ();
+ if ((double)(d1 + d2 + d3) != dadd2)
+ abort ();
+ if ((double)(f1 + f2 + f3) != dadd2)
+ abort ();
+ if ((float)i1 != 0x1.0p30f)
+ abort ();
+ if ((float)u1 != 0x1.0p31f)
+ abort ();
+ if ((float)ll1 != 0x1.0p62f)
+ abort ();
+ if ((float)ull1 != 0x1.0p63f)
+ abort ();
+ if ((double)ll1 != 0x1.0p62)
+ abort ();
+ if ((double)ull1 != 0x1.0p63)
+ abort ();
+}
+
+static inline void
+check_float (float f)
+{
+ if (f != fadd1)
+ abort ();
+}
+
+static inline void
+check_double (double d)
+{
+ if (d != dadd2)
+ abort ();
+}
+
+static inline void
+check_float_nonproto (f)
+ float f;
+{
+ if (f != fadd1)
+ abort ();
+}
+
+static inline void
+check_double_nonproto (d)
+ double d;
+{
+ if (d != dadd2)
+ abort ();
+}
+
+static void
+check_double_va (int i, ...)
+{
+ va_list ap;
+ va_start (ap, i);
+ if (va_arg (ap, double) != dadd2)
+ abort ();
+ va_end (ap);
+}
+
+void
+test_call (void)
+{
+ check_float (f1 + f2);
+ check_double (d1 + d2 + d3);
+ check_double (f1 + f2 + f3);
+ check_float_nonproto (f1 + f2);
+ check_double_nonproto (d1 + d2 + d3);
+ check_double_nonproto (f1 + f2 + f3);
+ check_double_va (0, d1 + d2 + d3);
+ check_double_va (0, f1 + f2 + f3);
+}
+
+static inline float
+return_float (void)
+{
+ return f1 + f2;
+}
+
+static inline double
+return_double1 (void)
+{
+ return d1 + d2 + d3;
+}
+
+static inline double
+return_double2 (void)
+{
+ return f1 + f2 + f3;
+}
+
+void
+test_return (void)
+{
+ if (return_float () != fadd1)
+ abort ();
+ if (return_double1 () != dadd2)
+ abort ();
+ if (return_double2 () != dadd2)
+ abort ();
+}
+
+volatile float flt_min = FLT_MIN;
+volatile double dbl_min = DBL_MIN;
+volatile float flt_max = FLT_MAX;
+volatile double dbl_max = DBL_MAX;
+
+void
+test_builtin (void)
+{
+ /* Classification macros convert to the semantic type. signbit and
+ comparison macros do not. */
+ if (!__builtin_isinf (flt_max * flt_max))
+ abort ();
+ if (!__builtin_isinf (dbl_max * dbl_max))
+ abort ();
+ if (__builtin_isnormal (flt_max * flt_max))
+ abort ();
+ if (__builtin_isnormal (dbl_max * dbl_max))
+ abort ();
+ if (__builtin_isfinite (flt_max * flt_max))
+ abort ();
+ if (__builtin_isfinite (dbl_max * dbl_max))
+ abort ();
+ if (!__builtin_isgreater (flt_min * flt_min, 0.0f))
+ abort ();
+ if (!__builtin_isgreaterequal (flt_min * flt_min, 0.0f))
+ abort ();
+ if (!__builtin_isless (0.0f, flt_min * flt_min))
+ abort ();
+ if (__builtin_islessequal (flt_min * flt_min, 0.0f))
+ abort ();
+ if (!__builtin_islessgreater (flt_min * flt_min, 0.0f))
+ abort ();
+ if (!__builtin_isgreater (dbl_min * dbl_min, 0.0))
+ abort ();
+ if (!__builtin_isgreaterequal (dbl_min * dbl_min, 0.0))
+ abort ();
+ if (!__builtin_isless (0.0, dbl_min * dbl_min))
+ abort ();
+ if (__builtin_islessequal (dbl_min * dbl_min, 0.0))
+ abort ();
+ if (!__builtin_islessgreater (dbl_min * dbl_min, 0.0))
+ abort ();
+}
+
+int
+main (void)
+{
+ test_assign ();
+ test_init ();
+ test_cast ();
+ test_call ();
+ test_return ();
+ test_builtin ();
+ exit (0);
+}
diff --git a/gcc/testsuite/gcc.target/i386/excess-precision-4.c b/gcc/testsuite/gcc.target/i386/excess-precision-4.c
new file mode 100644
index 0000000..db44b0f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/excess-precision-4.c
@@ -0,0 +1,8 @@
+/* Excess precision tests. Test diagnostics for excess precision of
+ constants. */
+/* { dg-do compile } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-fexcess-precision=standard" } */
+
+float f = 0.0f * 1e50f; /* { dg-warning "floating constant exceeds range of 'float'" } */
+double d = 0.0 * 1e400; /* { dg-warning "floating constant exceeds range of 'double'" } */
diff --git a/gcc/testsuite/gcc.target/i386/excess-precision-5.c b/gcc/testsuite/gcc.target/i386/excess-precision-5.c
new file mode 100644
index 0000000..9c76592
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/excess-precision-5.c
@@ -0,0 +1,23 @@
+/* Excess precision tests. Verify excess precision doesn't affect
+ actual types. */
+/* { dg-do compile } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-fexcess-precision=standard" } */
+
+float f;
+double d;
+
+void
+test_types (void)
+{
+ float *fp;
+ double *dp;
+#define CHECK_FLOAT(E) fp = &(typeof(E)){0}
+#define CHECK_DOUBLE(E) dp = &(typeof(E)){0}
+ CHECK_FLOAT (f + f);
+ CHECK_DOUBLE (d + d);
+ CHECK_FLOAT (f * f / f);
+ CHECK_DOUBLE (d * d / d);
+ CHECK_FLOAT (f ? f - f : f);
+ CHECK_DOUBLE (d ? d - d : d);
+}
diff --git a/gcc/testsuite/gcc.target/i386/excess-precision-6.c b/gcc/testsuite/gcc.target/i386/excess-precision-6.c
new file mode 100644
index 0000000..1d421c9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/excess-precision-6.c
@@ -0,0 +1,20 @@
+/* Excess precision tests. Make sure sqrt is not inlined for float or
+ double. */
+/* { dg-do compile } */
+/* { dg-require-effective-target ilp32 } */
+/* { dg-options "-O2 -fno-math-errno -fexcess-precision=standard" } */
+
+float f;
+double d;
+
+float fr;
+double dr;
+
+void
+test_builtins (void)
+{
+ fr = __builtin_sqrtf (f);
+ dr = __builtin_sqrt (d);
+}
+
+/* { dg-final { scan-assembler-not "fsqrt" } } */
diff --git a/gcc/toplev.c b/gcc/toplev.c
index 8417cfe..72f3d30 100644
--- a/gcc/toplev.c
+++ b/gcc/toplev.c
@@ -281,6 +281,11 @@ enum ira_region flag_ira_region = IRA_REGION_MIXED;
unsigned int flag_ira_verbose = 5;
+/* Set the default for excess precision. */
+
+enum excess_precision flag_excess_precision_cmdline = EXCESS_PRECISION_DEFAULT;
+enum excess_precision flag_excess_precision = EXCESS_PRECISION_DEFAULT;
+
/* Nonzero means change certain warnings into errors.
Usually these are warnings about failure to conform to some standard. */
@@ -2033,11 +2038,51 @@ backend_init (void)
backend_init_target ();
}
+/* Initialize excess precision settings. */
+static void
+init_excess_precision (void)
+{
+ /* Adjust excess precision handling based on the target options. If
+ the front end cannot handle it, flag_excess_precision_cmdline
+ will already have been set accordingly in the post_options
+ hook. */
+ gcc_assert (flag_excess_precision_cmdline != EXCESS_PRECISION_DEFAULT);
+ flag_excess_precision = flag_excess_precision_cmdline;
+ if (flag_unsafe_math_optimizations)
+ flag_excess_precision = EXCESS_PRECISION_FAST;
+ if (flag_excess_precision == EXCESS_PRECISION_STANDARD)
+ {
+ int flt_eval_method = TARGET_FLT_EVAL_METHOD;
+ switch (flt_eval_method)
+ {
+ case -1:
+ case 0:
+ /* Either the target acts unpredictably (-1) or has all the
+ operations required not to have excess precision (0). */
+ flag_excess_precision = EXCESS_PRECISION_FAST;
+ break;
+ case 1:
+ case 2:
+ /* In these cases, predictable excess precision makes
+ sense. */
+ break;
+ default:
+ /* Any other implementation-defined FLT_EVAL_METHOD values
+ require the compiler to handle the associated excess
+ precision rules in excess_precision_type. */
+ gcc_unreachable ();
+ }
+ }
+}
+
/* Initialize things that are both lang-dependent and target-dependent.
This function can be called more than once if target parameters change. */
static void
lang_dependent_init_target (void)
{
+ /* This determines excess precision settings. */
+ init_excess_precision ();
+
/* This creates various _DECL nodes, so needs to be called after the
front end is initialized. It also depends on the HAVE_xxx macros
generated from the target machine description. */
diff --git a/gcc/tree.c b/gcc/tree.c
index 9a6e000..76cba27 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -6258,6 +6258,61 @@ build_complex_type (tree component_type)
return build_qualified_type (t, TYPE_QUALS (component_type));
}
+
+/* If TYPE is a real or complex floating-point type and the target
+ does not directly support arithmetic on TYPE then return the wider
+ type to be used for arithmetic on TYPE. Otherwise, return
+ NULL_TREE. */
+
+tree
+excess_precision_type (tree type)
+{
+ if (flag_excess_precision != EXCESS_PRECISION_FAST)
+ {
+ int flt_eval_method = TARGET_FLT_EVAL_METHOD;
+ switch (TREE_CODE (type))
+ {
+ case REAL_TYPE:
+ switch (flt_eval_method)
+ {
+ case 1:
+ if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
+ return double_type_node;
+ break;
+ case 2:
+ if (TYPE_MODE (type) == TYPE_MODE (float_type_node)
+ || TYPE_MODE (type) == TYPE_MODE (double_type_node))
+ return long_double_type_node;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ case COMPLEX_TYPE:
+ if (TREE_CODE (TREE_TYPE (type)) != REAL_TYPE)
+ return NULL_TREE;
+ switch (flt_eval_method)
+ {
+ case 1:
+ if (TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (float_type_node))
+ return complex_double_type_node;
+ break;
+ case 2:
+ if (TYPE_MODE (TREE_TYPE (type)) == TYPE_MODE (float_type_node)
+ || (TYPE_MODE (TREE_TYPE (type))
+ == TYPE_MODE (double_type_node)))
+ return complex_long_double_type_node;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return NULL_TREE;
+}
/* Return OP, stripped of any conversions to wider types as much as is safe.
Converting the value back to OP's type makes a value equivalent to OP.
diff --git a/gcc/tree.h b/gcc/tree.h
index 0eb2dc6..dbd0faa 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4040,6 +4040,7 @@ extern bool tree_expr_nonnegative_p (tree);
extern bool tree_expr_nonnegative_warnv_p (tree, bool *);
extern bool may_negate_without_overflow_p (const_tree);
extern tree strip_array_types (tree);
+extern tree excess_precision_type (tree);
/* Construct various nodes representing fract or accum data types. */