fold-const.c (fold_inf_compare): New function to simplify FP comparisons against +Infinity or -Infinity.

* fold-const.c (fold_inf_compare):  New function to simplify FP
	comparisons against +Infinity or -Infinity.
	(fold):  Optimize floating point comparisons against Infs and NaNs.

	* gcc.c-torture/execute/ieee/fp-cmp-6.c: New test case.
	* gcc.c-torture/execute/ieee/fp-cmp-7.c: New test case.

From-SVN: r64945
This commit is contained in:
Roger Sayle 2003-03-28 02:41:14 +00:00 committed by Roger Sayle
parent 36875565eb
commit 9ddae796cd
5 changed files with 149 additions and 14 deletions

View File

@ -1,3 +1,9 @@
2003-03-27 Roger Sayle <roger@eyesopen.com>
* fold-const.c (fold_inf_compare): New function to simplify FP
comparisons against +Infinity or -Infinity.
(fold): Optimize floating point comparisons against Infs and NaNs.
2003-03-27 Janis Johnson <janis187@us.ibm.com>
* libgcov.c: Provide only dummy functions if libc is not available.

View File

@ -114,6 +114,7 @@ static tree fold_binary_op_with_conditional_arg
static bool fold_real_zero_addition_p PARAMS ((tree, tree, int));
static tree fold_mathfn_compare PARAMS ((enum built_in_function,
enum tree_code, tree, tree, tree));
static tree fold_inf_compare PARAMS ((enum tree_code, tree, tree, tree));
/* The following constants represent a bit based encoding of GCC's
comparison operators. This encoding simplifies transformations
@ -4798,6 +4799,62 @@ fold_mathfn_compare (fcode, code, type, arg0, arg1)
return NULL_TREE;
}
/* Subroutine of fold() that optimizes comparisons against Infinities,
either +Inf or -Inf.
CODE is the comparison operator: EQ_EXPR, NE_EXPR, GT_EXPR, LT_EXPR,
GE_EXPR or LE_EXPR. TYPE is the type of the result and ARG0 and ARG1
are the operands of the comparison. ARG1 must be a TREE_REAL_CST.
The function returns the constant folded tree if a simplification
can be made, and NULL_TREE otherwise. */
static tree
fold_inf_compare (code, type, arg0, arg1)
enum tree_code code;
tree type, arg0, arg1;
{
/* For negative infinity swap the sense of the comparison. */
if (REAL_VALUE_NEGATIVE (TREE_REAL_CST (arg1)))
code = swap_tree_comparison (code);
switch (code)
{
case GT_EXPR:
/* x > +Inf is always false, if with ignore sNANs. */
if (HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg0))))
return NULL_TREE;
return omit_one_operand (type,
convert (type, integer_zero_node),
arg0);
case LE_EXPR:
/* x <= +Inf is always true, if we don't case about NaNs. */
if (! HONOR_NANS (TYPE_MODE (TREE_TYPE (arg0))))
return omit_one_operand (type,
convert (type, integer_one_node),
arg0);
/* x <= +Inf is the same as x == x, i.e. isfinite(x). */
if ((*lang_hooks.decls.global_bindings_p) () == 0
&& ! contains_placeholder_p (arg0))
{
arg0 = save_expr (arg0);
return fold (build (EQ_EXPR, type, arg0, arg0));
}
break;
case EQ_EXPR: /* ??? x == +Inf is x > DBL_MAX */
case GE_EXPR: /* ??? x >= +Inf is x > DBL_MAX */
case LT_EXPR: /* ??? x < +Inf is x <= DBL_MAX */
case NE_EXPR: /* ??? x != +Inf is !(x > DBL_MAX) */
default:
break;
}
return NULL_TREE;
}
/* Perform constant folding and related simplification of EXPR.
The related simplifications include x*1 => x, x*0 => 0, etc.,
@ -6317,20 +6374,42 @@ fold (expr)
&& TREE_CODE (arg1) == NEGATE_EXPR)
return fold (build (code, type, TREE_OPERAND (arg1, 0),
TREE_OPERAND (arg0, 0)));
/* (-a) CMP CST -> a swap(CMP) (-CST) */
if (TREE_CODE (arg0) == NEGATE_EXPR && TREE_CODE (arg1) == REAL_CST)
return
fold (build
(swap_tree_comparison (code), type,
TREE_OPERAND (arg0, 0),
build_real (TREE_TYPE (arg1),
REAL_VALUE_NEGATE (TREE_REAL_CST (arg1)))));
/* IEEE doesn't distinguish +0 and -0 in comparisons. */
/* a CMP (-0) -> a CMP 0 */
if (TREE_CODE (arg1) == REAL_CST
&& REAL_VALUE_MINUS_ZERO (TREE_REAL_CST (arg1)))
return fold (build (code, type, arg0,
build_real (TREE_TYPE (arg1), dconst0)));
if (TREE_CODE (arg1) == REAL_CST)
{
REAL_VALUE_TYPE cst;
cst = TREE_REAL_CST (arg1);
/* (-a) CMP CST -> a swap(CMP) (-CST) */
if (TREE_CODE (arg0) == NEGATE_EXPR)
return
fold (build (swap_tree_comparison (code), type,
TREE_OPERAND (arg0, 0),
build_real (TREE_TYPE (arg1),
REAL_VALUE_NEGATE (cst))));
/* IEEE doesn't distinguish +0 and -0 in comparisons. */
/* a CMP (-0) -> a CMP 0 */
if (REAL_VALUE_MINUS_ZERO (cst))
return fold (build (code, type, arg0,
build_real (TREE_TYPE (arg1), dconst0)));
/* x != NaN is always true, other ops are always false. */
if (REAL_VALUE_ISNAN (cst)
&& ! HONOR_SNANS (TYPE_MODE (TREE_TYPE (arg1))))
{
t = (code == NE_EXPR) ? integer_one_node : integer_zero_node;
return omit_one_operand (type, convert (type, t), arg0);
}
/* Fold comparisons against infinity. */
if (REAL_VALUE_ISINF (cst))
{
tem = fold_inf_compare (code, type, arg0, arg1);
if (tem != NULL_TREE)
return tem;
}
}
/* If this is a comparison of a real constant with a PLUS_EXPR
or a MINUS_EXPR of a real constant, we can convert it into a

View File

@ -1,3 +1,8 @@
2003-03-27 Roger Sayle <roger@eyesopen.com>
* gcc.c-torture/execute/ieee/fp-cmp-6.c: New test case.
* gcc.c-torture/execute/ieee/fp-cmp-7.c: New test case.
2003-03-27 Mark Mitchell <mark@codesourcery.com>
* lib/gcov.exp (run-gcov): Add branches and calls options, rather

View File

@ -0,0 +1,31 @@
const double dnan = 1.0/0.0 - 1.0/0.0;
double x = 1.0;
extern void link_error ();
main ()
{
#if ! defined (__vax__) && ! defined (_CRAY)
/* NaN is an IEEE unordered operand. All these test should be false. */
if (dnan == dnan)
link_error ();
if (dnan != x)
x = 1.0;
else
link_error ();
if (dnan < x)
link_error ();
if (dnan > x)
link_error ();
if (dnan <= x)
link_error ();
if (dnan >= x)
link_error ();
if (dnan == x)
link_error ();
#endif
exit (0);
}

View File

@ -0,0 +1,14 @@
extern void link_error ();
void foo(double x)
{
if (x > __builtin_inf())
link_error ();
}
int main ()
{
foo (1.0);
return 0;
}