re PR middle-end/323 (optimized code gives strange floating point results)

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.

ada:
	* 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.

fortran:
	* options.c (gfc_post_options): Set
	flag_excess_precision_cmdline.  Give an error for
	-fexcess-precision=standard for processors where the option is
	significant.

java:
	* lang.c (java_post_options): Set flag_excess_precision_cmdline.
	Give an error for -fexcess-precision=standard for processors where
	the option is significant.

testsuite:
	* 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.

From-SVN: r145272
This commit is contained in:
Joseph Myers 2009-03-30 02:50:44 +01:00 committed by Joseph Myers
parent 1e57bf475b
commit 8ce94e4446
33 changed files with 1189 additions and 69 deletions

View file

@ -1,3 +1,66 @@
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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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)

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -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)),

View file

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

View file

@ -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:

View file

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

View file

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

View file

@ -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");

View file

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

View file

@ -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)

View file

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

View file

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

View file

@ -1,3 +1,13 @@
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

View file

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

View file

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

View file

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

View file

@ -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'" } */

View file

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

View file

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

View file

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

View file

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

View file

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