aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-lex.c
diff options
context:
space:
mode:
authorJoseph Myers <joseph@codesourcery.com>2009-03-30 02:50:44 +0100
committerJoseph Myers <jsm28@gcc.gnu.org>2009-03-30 02:50:44 +0100
commit8ce94e44465bcc958dc11270d9dee1775c7a4f43 (patch)
tree07c0a2aef08a00219e11f34b2e1a27c0dd432823 /gcc/c-lex.c
parent1e57bf475bf7651b30a5a3199bc669617c5004a6 (diff)
downloadgcc-8ce94e44465bcc958dc11270d9dee1775c7a4f43.zip
gcc-8ce94e44465bcc958dc11270d9dee1775c7a4f43.tar.gz
gcc-8ce94e44465bcc958dc11270d9dee1775c7a4f43.tar.bz2
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
Diffstat (limited to 'gcc/c-lex.c')
-rw-r--r--gcc/c-lex.c29
1 files changed, 24 insertions, 5 deletions
diff --git a/gcc/c-lex.c b/gcc/c-lex.c
index 5b71c3b..72a9590 100644
--- a/gcc/c-lex.c
+++ b/gcc/c-lex.c
@@ -605,8 +605,10 @@ static tree
interpret_float (const cpp_token *token, unsigned int flags)
{
tree type;
+ tree const_type;
tree value;
REAL_VALUE_TYPE real;
+ REAL_VALUE_TYPE real_trunc;
char *copy;
size_t copylen;
@@ -655,6 +657,10 @@ interpret_float (const cpp_token *token, unsigned int flags)
else
type = double_type_node;
+ const_type = excess_precision_type (type);
+ if (!const_type)
+ const_type = type;
+
/* Copy the constant to a nul-terminated buffer. If the constant
has any suffixes, cut them off; REAL_VALUE_ATOF/ REAL_VALUE_HTOF
can't handle them. */
@@ -675,13 +681,21 @@ interpret_float (const cpp_token *token, unsigned int flags)
memcpy (copy, token->val.str.text, copylen);
copy[copylen] = '\0';
- real_from_string3 (&real, copy, TYPE_MODE (type));
+ real_from_string3 (&real, copy, TYPE_MODE (const_type));
+ if (const_type != type)
+ /* Diagnosing if the result of converting the value with excess
+ precision to the semantic type would overflow (with associated
+ double rounding) is more appropriate than diagnosing if the
+ result of converting the string directly to the semantic type
+ would overflow. */
+ real_convert (&real_trunc, TYPE_MODE (type), &real);
/* Both C and C++ require a diagnostic for a floating constant
outside the range of representable values of its type. Since we
have __builtin_inf* to produce an infinity, this is now a
mandatory pedwarn if the target does not support infinities. */
- if (REAL_VALUE_ISINF (real))
+ if (REAL_VALUE_ISINF (real)
+ || (const_type != type && REAL_VALUE_ISINF (real_trunc)))
{
if (!MODE_HAS_INFINITIES (TYPE_MODE (type)))
pedwarn (input_location, 0, "floating constant exceeds range of %qT", type);
@@ -689,7 +703,8 @@ interpret_float (const cpp_token *token, unsigned int flags)
warning (OPT_Woverflow, "floating constant exceeds range of %qT", type);
}
/* We also give a warning if the value underflows. */
- else if (REAL_VALUES_EQUAL (real, dconst0))
+ else if (REAL_VALUES_EQUAL (real, dconst0)
+ || (const_type != type && REAL_VALUES_EQUAL (real_trunc, dconst0)))
{
REAL_VALUE_TYPE realvoidmode;
int overflow = real_from_string (&realvoidmode, copy);
@@ -698,9 +713,13 @@ interpret_float (const cpp_token *token, unsigned int flags)
}
/* Create a node with determined type and value. */
- value = build_real (type, real);
+ value = build_real (const_type, real);
if (flags & CPP_N_IMAGINARY)
- value = build_complex (NULL_TREE, convert (type, integer_zero_node), value);
+ value = build_complex (NULL_TREE, convert (const_type, integer_zero_node),
+ value);
+
+ if (type != const_type)
+ value = build1 (EXCESS_PRECISION_EXPR, type, value);
return value;
}