Commit 8e7b3a43 by Kazu Hirata Committed by Kazu Hirata

fold-const.c (fold): Remove variable "invert".

	* fold-const.c (fold): Remove variable "invert".
	Move the handling of relational expressions that can be folded
	to a constant ...
	(fold_relational_const): ... here.
	(tree_expr_nonzero_p): New.

From-SVN: r79745
parent c048d56d
2004-03-20 Kazu Hirata <kazu@cs.umass.edu>
* fold-const.c (fold): Remove variable "invert".
Move the handling of relational expressions that can be folded
to a constant ...
(fold_relational_const): ... here.
(tree_expr_nonzero_p): New.
2004-03-20 Joseph S. Myers <jsm@polyomino.org.uk> 2004-03-20 Joseph S. Myers <jsm@polyomino.org.uk>
PR c/14635 PR c/14635
......
...@@ -115,6 +115,7 @@ static bool tree_swap_operands_p (tree, tree, bool); ...@@ -115,6 +115,7 @@ static bool tree_swap_operands_p (tree, tree, bool);
static tree fold_negate_const (tree, tree); static tree fold_negate_const (tree, tree);
static tree fold_abs_const (tree, tree); static tree fold_abs_const (tree, tree);
static tree fold_relational_const (enum tree_code, tree, tree, tree);
/* The following constants represent a bit based encoding of GCC's /* The following constants represent a bit based encoding of GCC's
comparison operators. This encoding simplifies transformations comparison operators. This encoding simplifies transformations
...@@ -5391,7 +5392,6 @@ fold (tree expr) ...@@ -5391,7 +5392,6 @@ fold (tree expr)
tree arg0 = NULL_TREE, arg1 = NULL_TREE; tree arg0 = NULL_TREE, arg1 = NULL_TREE;
enum tree_code code = TREE_CODE (t); enum tree_code code = TREE_CODE (t);
int kind = TREE_CODE_CLASS (code); int kind = TREE_CODE_CLASS (code);
int invert;
/* WINS will be nonzero when the switch is done /* WINS will be nonzero when the switch is done
if all operands are constant. */ if all operands are constant. */
int wins = 1; int wins = 1;
...@@ -7919,92 +7919,9 @@ fold (tree expr) ...@@ -7919,92 +7919,9 @@ fold (tree expr)
integer_zero_node)); integer_zero_node));
} }
/* From here on, the only cases we handle are when the result is /* Both ARG0 and ARG1 are known to be constants at this point. */
known to be a constant. t1 = fold_relational_const (code, type, arg0, arg1);
return (t1 == NULL_TREE ? t : t1);
To compute GT, swap the arguments and do LT.
To compute GE, do LT and invert the result.
To compute LE, swap the arguments, do LT and invert the result.
To compute NE, do EQ and invert the result.
Therefore, the code below must handle only EQ and LT. */
if (code == LE_EXPR || code == GT_EXPR)
{
tem = arg0, arg0 = arg1, arg1 = tem;
code = swap_tree_comparison (code);
}
/* Note that it is safe to invert for real values here because we
will check below in the one case that it matters. */
t1 = NULL_TREE;
invert = 0;
if (code == NE_EXPR || code == GE_EXPR)
{
invert = 1;
code = invert_tree_comparison (code);
}
/* Compute a result for LT or EQ if args permit;
otherwise return T. */
if (TREE_CODE (arg0) == INTEGER_CST && TREE_CODE (arg1) == INTEGER_CST)
{
if (code == EQ_EXPR)
t1 = build_int_2 (tree_int_cst_equal (arg0, arg1), 0);
else
t1 = build_int_2 ((TREE_UNSIGNED (TREE_TYPE (arg0))
? INT_CST_LT_UNSIGNED (arg0, arg1)
: INT_CST_LT (arg0, arg1)),
0);
}
#if 0 /* This is no longer useful, but breaks some real code. */
/* Assume a nonexplicit constant cannot equal an explicit one,
since such code would be undefined anyway.
Exception: on sysvr4, using #pragma weak,
a label can come out as 0. */
else if (TREE_CODE (arg1) == INTEGER_CST
&& !integer_zerop (arg1)
&& TREE_CONSTANT (arg0)
&& TREE_CODE (arg0) == ADDR_EXPR
&& code == EQ_EXPR)
t1 = build_int_2 (0, 0);
#endif
/* Two real constants can be compared explicitly. */
else if (TREE_CODE (arg0) == REAL_CST && TREE_CODE (arg1) == REAL_CST)
{
/* If either operand is a NaN, the result is false with two
exceptions: First, an NE_EXPR is true on NaNs, but that case
is already handled correctly since we will be inverting the
result for NE_EXPR. Second, if we had inverted a LE_EXPR
or a GE_EXPR into a LT_EXPR, we must return true so that it
will be inverted into false. */
if (REAL_VALUE_ISNAN (TREE_REAL_CST (arg0))
|| REAL_VALUE_ISNAN (TREE_REAL_CST (arg1)))
t1 = build_int_2 (invert && code == LT_EXPR, 0);
else if (code == EQ_EXPR)
t1 = build_int_2 (REAL_VALUES_EQUAL (TREE_REAL_CST (arg0),
TREE_REAL_CST (arg1)),
0);
else
t1 = build_int_2 (REAL_VALUES_LESS (TREE_REAL_CST (arg0),
TREE_REAL_CST (arg1)),
0);
}
if (t1 == NULL_TREE)
return t;
if (invert)
TREE_INT_CST_LOW (t1) ^= 1;
TREE_TYPE (t1) = type;
if (TREE_CODE (type) == BOOLEAN_TYPE)
return lang_hooks.truthvalue_conversion (t1);
return t1;
case COND_EXPR: case COND_EXPR:
/* Pedantic ANSI C says that a conditional expression is never an lvalue, /* Pedantic ANSI C says that a conditional expression is never an lvalue,
...@@ -8963,6 +8880,106 @@ tree_expr_nonnegative_p (tree t) ...@@ -8963,6 +8880,106 @@ tree_expr_nonnegative_p (tree t)
return 0; return 0;
} }
/* Return true when T is an address and is known to be nonzero.
For floating point we further ensure that T is not denormal.
Similar logic is present in nonzero_address in rtlanal.h */
static bool
tree_expr_nonzero_p (tree t)
{
tree type = TREE_TYPE (t);
/* Doing something usefull for floating point would need more work. */
if (!INTEGRAL_TYPE_P (type) && !POINTER_TYPE_P (type))
return false;
switch (TREE_CODE (t))
{
case ABS_EXPR:
if (!TREE_UNSIGNED (type) && !flag_wrapv)
return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
case INTEGER_CST:
return !integer_zerop (t);
case PLUS_EXPR:
if (!TREE_UNSIGNED (type) && !flag_wrapv)
{
/* With the presence of negative values it is hard
to say something. */
if (!tree_expr_nonnegative_p (TREE_OPERAND (t, 0))
|| !tree_expr_nonnegative_p (TREE_OPERAND (t, 1)))
return false;
/* One of operands must be positive and the other non-negative. */
return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
|| tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
}
break;
case MULT_EXPR:
if (!TREE_UNSIGNED (type) && !flag_wrapv)
{
return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
&& tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
}
break;
case NOP_EXPR:
{
tree inner_type = TREE_TYPE (TREE_OPERAND (t, 0));
tree outer_type = TREE_TYPE (t);
return (TYPE_PRECISION (inner_type) >= TYPE_PRECISION (outer_type)
&& tree_expr_nonzero_p (TREE_OPERAND (t, 0)));
}
break;
case ADDR_EXPR:
/* Weak declarations may link to NULL. */
if (DECL_P (TREE_OPERAND (t, 0)))
return !DECL_WEAK (TREE_OPERAND (t, 0));
/* Constants and all other cases are never weak. */
return true;
case COND_EXPR:
return (tree_expr_nonzero_p (TREE_OPERAND (t, 1))
&& tree_expr_nonzero_p (TREE_OPERAND (t, 2)));
case MIN_EXPR:
return (tree_expr_nonzero_p (TREE_OPERAND (t, 0))
&& tree_expr_nonzero_p (TREE_OPERAND (t, 1)));
case MAX_EXPR:
if (tree_expr_nonzero_p (TREE_OPERAND (t, 0)))
{
/* When both operands are nonzero, then MAX must be too. */
if (tree_expr_nonzero_p (TREE_OPERAND (t, 1)))
return true;
/* MAX where operand 0 is positive is positive. */
return tree_expr_nonnegative_p (TREE_OPERAND (t, 0));
}
/* MAX where operand 1 is positive is positive. */
else if (tree_expr_nonzero_p (TREE_OPERAND (t, 1))
&& tree_expr_nonnegative_p (TREE_OPERAND (t, 1)))
return true;
break;
case COMPOUND_EXPR:
case MODIFY_EXPR:
case BIND_EXPR:
return tree_expr_nonzero_p (TREE_OPERAND (t, 1));
case SAVE_EXPR:
case NON_LVALUE_EXPR:
return tree_expr_nonzero_p (TREE_OPERAND (t, 0));
default:
break;
}
return false;
}
/* Return true if `r' is known to be non-negative. /* Return true if `r' is known to be non-negative.
Only handles constants at the moment. */ Only handles constants at the moment. */
...@@ -9094,4 +9111,95 @@ fold_abs_const (tree arg0, tree type) ...@@ -9094,4 +9111,95 @@ fold_abs_const (tree arg0, tree type)
return t; return t;
} }
/* Given CODE, a relational operator, the target type, TYPE and two
constant operands OP0 and OP1, return the result of the
relational operation. If the result is not a compile time
constant, then return NULL_TREE. */
static tree
fold_relational_const (enum tree_code code, tree type, tree op0, tree op1)
{
tree tem;
int invert;
/* From here on, the only cases we handle are when the result is
known to be a constant.
To compute GT, swap the arguments and do LT.
To compute GE, do LT and invert the result.
To compute LE, swap the arguments, do LT and invert the result.
To compute NE, do EQ and invert the result.
Therefore, the code below must handle only EQ and LT. */
if (code == LE_EXPR || code == GT_EXPR)
{
tem = op0, op0 = op1, op1 = tem;
code = swap_tree_comparison (code);
}
/* Note that it is safe to invert for real values here because we
will check below in the one case that it matters. */
tem = NULL_TREE;
invert = 0;
if (code == NE_EXPR || code == GE_EXPR)
{
invert = 1;
code = invert_tree_comparison (code);
}
/* Compute a result for LT or EQ if args permit;
Otherwise return T. */
if (TREE_CODE (op0) == INTEGER_CST && TREE_CODE (op1) == INTEGER_CST)
{
if (code == EQ_EXPR)
tem = build_int_2 (tree_int_cst_equal (op0, op1), 0);
else
tem = build_int_2 ((TREE_UNSIGNED (TREE_TYPE (op0))
? INT_CST_LT_UNSIGNED (op0, op1)
: INT_CST_LT (op0, op1)),
0);
}
else if (code == EQ_EXPR && !TREE_SIDE_EFFECTS (op0)
&& integer_zerop (op1) && tree_expr_nonzero_p (op0))
tem = build_int_2 (0, 0);
/* Two real constants can be compared explicitly. */
else if (TREE_CODE (op0) == REAL_CST && TREE_CODE (op1) == REAL_CST)
{
/* If either operand is a NaN, the result is false with two
exceptions: First, an NE_EXPR is true on NaNs, but that case
is already handled correctly since we will be inverting the
result for NE_EXPR. Second, if we had inverted a LE_EXPR
or a GE_EXPR into a LT_EXPR, we must return true so that it
will be inverted into false. */
if (REAL_VALUE_ISNAN (TREE_REAL_CST (op0))
|| REAL_VALUE_ISNAN (TREE_REAL_CST (op1)))
tem = build_int_2 (invert && code == LT_EXPR, 0);
else if (code == EQ_EXPR)
tem = build_int_2 (REAL_VALUES_EQUAL (TREE_REAL_CST (op0),
TREE_REAL_CST (op1)),
0);
else
tem = build_int_2 (REAL_VALUES_LESS (TREE_REAL_CST (op0),
TREE_REAL_CST (op1)),
0);
}
if (tem == NULL_TREE)
return NULL_TREE;
if (invert)
TREE_INT_CST_LOW (tem) ^= 1;
TREE_TYPE (tem) = type;
if (TREE_CODE (type) == BOOLEAN_TYPE)
return (*lang_hooks.truthvalue_conversion) (tem);
return tem;
}
#include "gt-fold-const.h" #include "gt-fold-const.h"
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