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:
parent
1e57bf475b
commit
8ce94e4446
33 changed files with 1189 additions and 69 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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++;
|
||||
|
|
29
gcc/c-lex.c
29
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;
|
||||
}
|
||||
|
|
14
gcc/c-opts.c
14
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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
274
gcc/c-typeck.c
274
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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)),
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
15
gcc/flags.h
15
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. */
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
186
gcc/testsuite/gcc.target/i386/excess-precision-1.c
Normal file
186
gcc/testsuite/gcc.target/i386/excess-precision-1.c
Normal 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);
|
||||
}
|
34
gcc/testsuite/gcc.target/i386/excess-precision-2.c
Normal file
34
gcc/testsuite/gcc.target/i386/excess-precision-2.c
Normal 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);
|
||||
}
|
219
gcc/testsuite/gcc.target/i386/excess-precision-3.c
Normal file
219
gcc/testsuite/gcc.target/i386/excess-precision-3.c
Normal 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);
|
||||
}
|
8
gcc/testsuite/gcc.target/i386/excess-precision-4.c
Normal file
8
gcc/testsuite/gcc.target/i386/excess-precision-4.c
Normal 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'" } */
|
23
gcc/testsuite/gcc.target/i386/excess-precision-5.c
Normal file
23
gcc/testsuite/gcc.target/i386/excess-precision-5.c
Normal 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);
|
||||
}
|
20
gcc/testsuite/gcc.target/i386/excess-precision-6.c
Normal file
20
gcc/testsuite/gcc.target/i386/excess-precision-6.c
Normal 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" } } */
|
45
gcc/toplev.c
45
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. */
|
||||
|
|
55
gcc/tree.c
55
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.
|
||||
|
|
|
@ -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. */
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue