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
This commit is contained in:
parent
a101957b98
commit
d284eb28eb
@ -1,3 +1,18 @@
|
||||
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>
|
||||
|
||||
* c-cppbuiltin.c (define__GNUC__): Correct assertion.
|
||||
|
@ -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;
|
||||
|
18
gcc/real.c
18
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. */
|
||||
|
@ -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. */
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user