Commit d284eb28 by Roger Sayle Committed by Roger Sayle

re PR rtl-optimization/576 (gcc performs invalid optimization with float…

re PR rtl-optimization/576 (gcc performs invalid optimization with float operations when different rounding mode.)


	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.

From-SVN: r94020
parent a101957b
2005-01-21 Roger Sayle <roger@eyesopen.com>
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 <tromey@redhat.com> 2005-01-21 Tom Tromey <tromey@redhat.com>
* c-cppbuiltin.c (define__GNUC__): Correct assertion. * c-cppbuiltin.c (define__GNUC__): Correct assertion.
......
...@@ -1482,6 +1482,8 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc) ...@@ -1482,6 +1482,8 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
REAL_VALUE_TYPE d1; REAL_VALUE_TYPE d1;
REAL_VALUE_TYPE d2; REAL_VALUE_TYPE d2;
REAL_VALUE_TYPE value; REAL_VALUE_TYPE value;
REAL_VALUE_TYPE result;
bool inexact;
tree t, type; tree t, type;
d1 = TREE_REAL_CST (arg1); d1 = TREE_REAL_CST (arg1);
...@@ -1510,9 +1512,18 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc) ...@@ -1510,9 +1512,18 @@ const_binop (enum tree_code code, tree arg1, tree arg2, int notrunc)
else if (REAL_VALUE_ISNAN (d2)) else if (REAL_VALUE_ISNAN (d2))
return arg2; 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_OVERFLOW (t) = TREE_OVERFLOW (arg1) | TREE_OVERFLOW (arg2);
TREE_CONSTANT_OVERFLOW (t) TREE_CONSTANT_OVERFLOW (t)
...@@ -1808,20 +1819,11 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, tree arg1) ...@@ -1808,20 +1819,11 @@ fold_convert_const_int_from_real (enum tree_code code, tree type, tree arg1)
static tree static tree
fold_convert_const_real_from_real (tree type, tree arg1) fold_convert_const_real_from_real (tree type, tree arg1)
{ {
REAL_VALUE_TYPE value;
tree t; tree t;
if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg1))) real_convert (&value, TYPE_MODE (type), &TREE_REAL_CST (arg1));
{ t = build_real (type, value);
/* 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)));
TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1); TREE_OVERFLOW (t) = TREE_OVERFLOW (arg1);
TREE_CONSTANT_OVERFLOW (t) TREE_CONSTANT_OVERFLOW (t)
...@@ -9506,17 +9508,20 @@ fold_initializer (tree expr) ...@@ -9506,17 +9508,20 @@ fold_initializer (tree expr)
{ {
int saved_signaling_nans = flag_signaling_nans; int saved_signaling_nans = flag_signaling_nans;
int saved_trapping_math = flag_trapping_math; int saved_trapping_math = flag_trapping_math;
int saved_rounding_math = flag_rounding_math;
int saved_trapv = flag_trapv; int saved_trapv = flag_trapv;
tree result; tree result;
flag_signaling_nans = 0; flag_signaling_nans = 0;
flag_trapping_math = 0; flag_trapping_math = 0;
flag_rounding_math = 0;
flag_trapv = 0; flag_trapv = 0;
result = fold (expr); result = fold (expr);
flag_signaling_nans = saved_signaling_nans; flag_signaling_nans = saved_signaling_nans;
flag_trapping_math = saved_trapping_math; flag_trapping_math = saved_trapping_math;
flag_rounding_math = saved_rounding_math;
flag_trapv = saved_trapv; flag_trapv = saved_trapv;
return result; return result;
......
...@@ -972,9 +972,10 @@ do_fix_trunc (REAL_VALUE_TYPE *r, const REAL_VALUE_TYPE *a) ...@@ -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. /* 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, real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
const REAL_VALUE_TYPE *op1) const REAL_VALUE_TYPE *op1)
{ {
...@@ -983,20 +984,16 @@ real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0, ...@@ -983,20 +984,16 @@ real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
switch (code) switch (code)
{ {
case PLUS_EXPR: case PLUS_EXPR:
do_add (r, op0, op1, 0); return do_add (r, op0, op1, 0);
break;
case MINUS_EXPR: case MINUS_EXPR:
do_add (r, op0, op1, 1); return do_add (r, op0, op1, 1);
break;
case MULT_EXPR: case MULT_EXPR:
do_multiply (r, op0, op1); return do_multiply (r, op0, op1);
break;
case RDIV_EXPR: case RDIV_EXPR:
do_divide (r, op0, op1); return do_divide (r, op0, op1);
break;
case MIN_EXPR: case MIN_EXPR:
if (op1->cl == rvc_nan) if (op1->cl == rvc_nan)
...@@ -1033,6 +1030,7 @@ real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0, ...@@ -1033,6 +1030,7 @@ real_arithmetic (REAL_VALUE_TYPE *r, int icode, const REAL_VALUE_TYPE *op0,
default: default:
gcc_unreachable (); gcc_unreachable ();
} }
return false;
} }
/* Legacy. Similar, but return the result directly. */ /* Legacy. Similar, but return the result directly. */
......
...@@ -160,7 +160,7 @@ extern const struct real_format * ...@@ -160,7 +160,7 @@ extern const struct real_format *
/* Declare functions in real.c. */ /* Declare functions in real.c. */
/* Binary or unary arithmetic on tree_code. */ /* 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 *); const REAL_VALUE_TYPE *);
/* Compare reals by tree_code. */ /* Compare reals by tree_code. */
......
...@@ -1288,12 +1288,13 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode, ...@@ -1288,12 +1288,13 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
} }
else 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 (f0, trueop0);
REAL_VALUE_FROM_CONST_DOUBLE (f1, trueop1); REAL_VALUE_FROM_CONST_DOUBLE (f1, trueop1);
f0 = real_value_truncate (mode, f0); real_convert (&f0, mode, &f0);
f1 = real_value_truncate (mode, f1); real_convert (&f1, mode, &f1);
if (HONOR_SNANS (mode) if (HONOR_SNANS (mode)
&& (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1))) && (REAL_VALUE_ISNAN (f0) || REAL_VALUE_ISNAN (f1)))
...@@ -1339,10 +1340,18 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode, ...@@ -1339,10 +1340,18 @@ simplify_binary_operation (enum rtx_code code, enum machine_mode mode,
/* Inf * 0 = NaN plus exception. */ /* Inf * 0 = NaN plus exception. */
return 0; 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); /* Don't constant fold this floating point operation if the
return CONST_DOUBLE_FROM_REAL_VALUE (value, mode); 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);
} }
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment