diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2525350e7f0..7c07cc430f8 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,18 @@ +2005-01-21 Roger Sayle + + PR rtl-optimization/576 + * real.c (real_arithmetic): Change return type from void to bool + to return an indication that the result may be inexact. + * real.h (real_arithmeric): Update prototype. + * fold-const.c (const_binop): Don't constant fold floating + point expressions when the user specifies -frounding-math and + the result may depend upon the run-time rounding mode. + (fold_convert_const_real_from_real): Clean-up. + (fold_initializer): Ignore flag_rounding_math for initializers. + * simplify-rtx.c (simplify_binary_operation): Likewise, don't + constant fold FP operations with flag_rounding_math if the + result may depend upon the run-time rounding mode. + 2005-01-21 Tom Tromey * c-cppbuiltin.c (define__GNUC__): Correct assertion. diff --git a/gcc/fold-const.c b/gcc/fold-const.c index cdefe7611fb..cb822ed2ec5 100644 --- a/gcc/fold-const.c +++ b/gcc/fold-const.c @@ -1482,6 +1482,8 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc) REAL_VALUE_TYPE d1; REAL_VALUE_TYPE d2; REAL_VALUE_TYPE value; + REAL_VALUE_TYPE result; + bool inexact; tree t, type; d1 = TREE_REAL_CST (arg1); @@ -1510,9 +1512,18 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc) else if (REAL_VALUE_ISNAN (d2)) return arg2; - REAL_ARITHMETIC (value, code, d1, d2); + inexact = real_arithmetic (&value, code, &d1, &d2); + real_convert (&result, mode, &value); - t = build_real (type, real_value_truncate (mode, value)); + /* Don't constant fold this floating point operation if the + result may dependent upon the run-time rounding mode and + flag_rounding_math is set. */ + + if (flag_rounding_math + && (inexact || !real_identical (&result, &value))) + return NULL_TREE; + + t = build_real (type, result); TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2); TREE_CONSTANT_OVERFLOW (t) @@ -1808,20 +1819,11 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, tree arg1) static tree fold_convert_const_real_from_real (tree type, tree arg1) { + REAL_VALUE_TYPE value; tree t; - if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1))) - { - /* We make a copy of ARG1 so that we don't modify an - existing constant tree. */ - t = copy_node (arg1); - TREE_TYPE (t) = type; - return t; - } - - t = build_real (type, - real_value_truncate (TYPE_MODE (type), - TREE_REAL_CST (arg1))); + real_convert (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1)); + t = build_real (type, value); TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1); TREE_CONSTANT_OVERFLOW (t) @@ -9506,17 +9508,20 @@ fold_initializer (tree expr) { int saved_signaling_nans = flag_signaling_nans; int saved_trapping_math = flag_trapping_math; + int saved_rounding_math = flag_rounding_math; int saved_trapv = flag_trapv; tree result; flag_signaling_nans = 0; flag_trapping_math = 0; + flag_rounding_math = 0; flag_trapv = 0; result = fold (expr); flag_signaling_nans = saved_signaling_nans; flag_trapping_math = saved_trapping_math; + flag_rounding_math = saved_rounding_math; flag_trapv = saved_trapv; return result; diff --git a/gcc/real.c b/gcc/real.c index 5871d1e037c..a748b87b33a 100644 --- a/gcc/real.c +++ b/gcc/real.c @@ -972,9 +972,10 @@ do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a) } /* Perform the binary or unary operation described by CODE. - For a unary operation, leave OP1 NULL. */ + For a unary operation, leave OP1 NULL. This function returns + true if the result may be inexact due to loss of precision. */ -void +bool real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0, const REAL_VALUE_TYPE *op1) { @@ -983,20 +984,16 @@ real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0, switch (code) { case PLUS_EXPR: - do_add (r, op0, op1, 0); - break; + return do_add (r, op0, op1, 0); case MINUS_EXPR: - do_add (r, op0, op1, 1); - break; + return do_add (r, op0, op1, 1); case MULT_EXPR: - do_multiply (r, op0, op1); - break; + return do_multiply (r, op0, op1); case RDIV_EXPR: - do_divide (r, op0, op1); - break; + return do_divide (r, op0, op1); case MIN_EXPR: if (op1->cl == rvc_nan) @@ -1033,6 +1030,7 @@ real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0, default: gcc_unreachable (); } + return false; } /* Legacy. Similar, but return the result directly. */ diff --git a/gcc/real.h b/gcc/real.h index c477be11b62..b7cf3bb2f04 100644 --- a/gcc/real.h +++ b/gcc/real.h @@ -160,7 +160,7 @@ extern const struct real_format * /* Declare functions in real.c. */ /* Binary or unary arithmetic on tree_code. */ -extern void real_arithmetic (REAL_VALUE_TYPE *, int, const REAL_VALUE_TYPE *, +extern bool real_arithmetic (REAL_VALUE_TYPE *, int, const REAL_VALUE_TYPE *, const REAL_VALUE_TYPE *); /* Compare reals by tree_code. */ diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 91df355b9ac..92567fe3c41 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -1288,12 +1288,13 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode, } else { - REAL_VALUE_TYPE f0, f1, value; + REAL_VALUE_TYPE f0, f1, value, result; + bool inexact; REAL_VALUE_FROM_CONST_DOUBLE (f0, trueop0); REAL_VALUE_FROM_CONST_DOUBLE (f1, trueop1); - f0 = real_value_truncate (mode, f0); - f1 = real_value_truncate (mode, f1); + real_convert (&f0, mode, &f0); + real_convert (&f1, mode, &f1); if (HONOR_SNANS (mode) && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1))) @@ -1339,10 +1340,18 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode, /* Inf * 0 = NaN plus exception. */ return 0; - REAL_ARITHMETIC (value, rtx_to_tree_code (code), f0, f1); + inexact = real_arithmetic (&value, rtx_to_tree_code (code), + &f0, &f1); + real_convert (&result, mode, &value); - value = real_value_truncate (mode, value); - return CONST_DOUBLE_FROM_REAL_VALUE (value, mode); + /* Don't constant fold this floating point operation if the + result may dependent upon the run-time rounding mode and + flag_rounding_math is set. */ + if (flag_rounding_math + && (inexact || !real_identical (&result, &value))) + return NULL_RTX; + + return CONST_DOUBLE_FROM_REAL_VALUE (result, mode); } }